mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
refactor(browser): split browser cores via build ARG, add core selector (#237)
* refactor(browser): split browser cores via build ARG, add core selector - Replace playwright official image with ubuntu:noble base in both docker/Dockerfile.browser and devenv/Dockerfile.browser; install browsers at build time driven by ARG/ENV BROWSER_CORES - Add GET /cores endpoint to Browser Gateway reporting available cores - Proxy GET /browser-contexts/cores in Go handler to Browser Gateway - Add `core` field to BrowserContextConfigModel and GatewayBrowserContext; context creation selects the appropriate browser instance by core - Frontend context-setting page fetches available cores and renders a core selector; saves core as part of the config JSON - install.sh prompts for browser core selection and writes BROWSER_CORES to .env; builds the browser image locally before docker compose up - Regenerate OpenAPI spec and TypeScript SDK * fix: lint
This commit is contained in:
@@ -1,7 +1,36 @@
|
||||
import { chromium } from 'playwright'
|
||||
import { chromium, firefox } from 'playwright'
|
||||
import type { Browser } from 'playwright'
|
||||
|
||||
export const initBrowser = async () => {
|
||||
return await chromium.launch({
|
||||
headless: true,
|
||||
})
|
||||
export type BrowserCore = 'chromium' | 'firefox'
|
||||
|
||||
export const browsers = new Map<BrowserCore, Browser>()
|
||||
|
||||
export const initBrowsers = async (): Promise<Map<BrowserCore, Browser>> => {
|
||||
const raw = process.env.BROWSER_CORES ?? 'chromium'
|
||||
const cores = raw.split(',').map(s => s.trim()) as BrowserCore[]
|
||||
|
||||
for (const core of cores) {
|
||||
if (core === 'chromium') {
|
||||
browsers.set('chromium', await chromium.launch({ headless: true }))
|
||||
} else if (core === 'firefox') {
|
||||
browsers.set('firefox', await firefox.launch({ headless: true }))
|
||||
}
|
||||
}
|
||||
|
||||
if (browsers.size === 0) {
|
||||
browsers.set('chromium', await chromium.launch({ headless: true }))
|
||||
}
|
||||
|
||||
return browsers
|
||||
}
|
||||
|
||||
export const getBrowser = (core: BrowserCore = 'chromium'): Browser => {
|
||||
const b = browsers.get(core) ?? browsers.values().next().value
|
||||
if (!b) throw new Error(`Browser core "${core}" is not available`)
|
||||
return b
|
||||
}
|
||||
|
||||
export const getAvailableCores = (): BrowserCore[] => {
|
||||
const raw = process.env.BROWSER_CORES ?? 'chromium'
|
||||
return raw.split(',').map(s => s.trim()) as BrowserCore[]
|
||||
}
|
||||
@@ -2,13 +2,16 @@ import { Elysia } from 'elysia'
|
||||
import { loadConfig } from '@memoh/config'
|
||||
import { corsMiddleware } from './middlewares/cors'
|
||||
import { errorMiddleware } from './middlewares/error'
|
||||
import { initBrowser } from './browser'
|
||||
import { initBrowsers, browsers } from './browser'
|
||||
import { contextModule } from './modules/context'
|
||||
import { devicesModule } from './modules/devices'
|
||||
import { coresModule } from './modules/cores'
|
||||
|
||||
const config = loadConfig('../../config.toml')
|
||||
|
||||
export const browser = await initBrowser()
|
||||
await initBrowsers()
|
||||
|
||||
export { browsers }
|
||||
|
||||
const app = new Elysia()
|
||||
.use(corsMiddleware)
|
||||
@@ -16,10 +19,13 @@ const app = new Elysia()
|
||||
.get('/health', () => ({
|
||||
status: 'ok',
|
||||
}))
|
||||
.use(coresModule)
|
||||
.use(contextModule)
|
||||
.use(devicesModule)
|
||||
.onStop(async () => {
|
||||
for (const browser of browsers.values()) {
|
||||
await browser.close()
|
||||
}
|
||||
})
|
||||
.listen({
|
||||
port: config.browser_gateway.port ?? 8083,
|
||||
@@ -28,4 +34,3 @@ const app = new Elysia()
|
||||
})
|
||||
|
||||
console.log(`🌐 Browser Gateway is running at ${app.server!.url}`)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
export const BrowserContextConfigModel = z.object({
|
||||
core: z.enum(['chromium', 'firefox']).optional().default('chromium'),
|
||||
viewport: z.object({
|
||||
width: z.number(),
|
||||
height: z.number(),
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Elysia } from 'elysia'
|
||||
import { storage } from '../storage'
|
||||
import { z } from 'zod'
|
||||
import { BrowserContextConfigModel } from '../models'
|
||||
import { browser } from '..'
|
||||
import { getBrowser } from '../browser'
|
||||
import { actionModule } from './action'
|
||||
|
||||
export const contextModule = new Elysia({ prefix: '/context' })
|
||||
@@ -14,7 +14,7 @@ export const contextModule = new Elysia({ prefix: '/context' })
|
||||
const { id } = query
|
||||
const entry = storage.get(id)
|
||||
if (!entry) return null
|
||||
return { id: entry.id, name: entry.name, config: entry.config }
|
||||
return { id: entry.id, name: entry.name, core: entry.core, config: entry.config }
|
||||
}, {
|
||||
query: z.object({
|
||||
id: z.string(),
|
||||
@@ -24,6 +24,8 @@ export const contextModule = new Elysia({ prefix: '/context' })
|
||||
'/',
|
||||
async ({ body }) => {
|
||||
const { name, config, id } = body
|
||||
const core = config.core ?? 'chromium'
|
||||
const browser = getBrowser(core)
|
||||
const context = await browser.newContext({
|
||||
viewport: config.viewport,
|
||||
userAgent: config.userAgent,
|
||||
@@ -37,8 +39,8 @@ export const contextModule = new Elysia({ prefix: '/context' })
|
||||
ignoreHTTPSErrors: config.ignoreHTTPSErrors,
|
||||
proxy: config.proxy,
|
||||
})
|
||||
storage.set(id, { id, name, context, config })
|
||||
return { id, name, config }
|
||||
storage.set(id, { id, name, core, context, config })
|
||||
return { id, name, core, config }
|
||||
},
|
||||
{
|
||||
body: z.object({
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Elysia } from 'elysia'
|
||||
import { getAvailableCores } from '../browser'
|
||||
|
||||
export const coresModule = new Elysia({ prefix: '/cores' })
|
||||
.get('/', () => {
|
||||
return { cores: getAvailableCores() }
|
||||
})
|
||||
@@ -1,9 +1,11 @@
|
||||
import type { BrowserContext, Page } from 'playwright'
|
||||
import type { BrowserContextConfig } from '../models'
|
||||
import type { BrowserCore } from '../browser'
|
||||
|
||||
export interface GatewayBrowserContext {
|
||||
id: string
|
||||
name: string
|
||||
core: BrowserCore
|
||||
context: BrowserContext
|
||||
config: BrowserContextConfig
|
||||
activePage?: Page
|
||||
|
||||
@@ -393,6 +393,9 @@
|
||||
"timezoneId": "Timezone",
|
||||
"timezonePlaceholder": "e.g. America/New_York",
|
||||
"ignoreHTTPSErrors": "Ignore HTTPS Errors",
|
||||
"core": "Browser Core",
|
||||
"chromium": "Chromium",
|
||||
"firefox": "Firefox",
|
||||
"config": "Configuration"
|
||||
},
|
||||
"mcp": {
|
||||
|
||||
@@ -389,6 +389,9 @@
|
||||
"timezoneId": "时区",
|
||||
"timezonePlaceholder": "例如 Asia/Shanghai",
|
||||
"ignoreHTTPSErrors": "忽略 HTTPS 错误",
|
||||
"core": "浏览器内核",
|
||||
"chromium": "Chromium",
|
||||
"firefox": "Firefox",
|
||||
"config": "配置"
|
||||
},
|
||||
"mcp": {
|
||||
|
||||
@@ -41,6 +41,31 @@
|
||||
{{ $t('browserContext.config') }}
|
||||
</h3>
|
||||
|
||||
<FormField
|
||||
v-slot="{ value, handleChange }"
|
||||
name="core"
|
||||
>
|
||||
<FormItem>
|
||||
<Label>{{ $t('browserContext.core') }}</Label>
|
||||
<FormControl>
|
||||
<div class="flex gap-3">
|
||||
<button
|
||||
v-for="c in availableCores"
|
||||
:key="c"
|
||||
type="button"
|
||||
class="flex items-center gap-2 px-3 py-1.5 rounded-md border text-sm transition-colors"
|
||||
:class="value === c
|
||||
? 'border-primary bg-primary/10 text-primary font-medium'
|
||||
: 'border-border bg-card text-muted-foreground hover:bg-accent'"
|
||||
@click="handleChange(c)"
|
||||
>
|
||||
{{ $t(`browserContext.${c}`) }}
|
||||
</button>
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
@@ -212,10 +237,11 @@ import {
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import z from 'zod'
|
||||
import { useForm } from 'vee-validate'
|
||||
import { useMutation, useQueryCache } from '@pinia/colada'
|
||||
import { useMutation, useQuery, useQueryCache } from '@pinia/colada'
|
||||
import { putBrowserContextsById, deleteBrowserContextsById } from '@memoh/sdk'
|
||||
import { getBrowserContextsCoresQuery } from '@memoh/sdk/colada'
|
||||
import type { BrowsercontextsBrowserContext } from '@memoh/sdk'
|
||||
import { inject, watch, type Ref } from 'vue'
|
||||
import { inject, watch, computed, type Ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { useDialogMutation } from '@/composables/useDialogMutation'
|
||||
@@ -228,7 +254,11 @@ const queryCache = useQueryCache()
|
||||
|
||||
const curContext = inject<Ref<BrowsercontextsBrowserContext | undefined>>('curBrowserContext')
|
||||
|
||||
const { data: coresData } = useQuery(getBrowserContextsCoresQuery())
|
||||
const availableCores = computed(() => coresData.value?.cores ?? ['chromium'])
|
||||
|
||||
interface ConfigShape {
|
||||
core?: string
|
||||
viewport?: { width?: number; height?: number }
|
||||
userAgent?: string
|
||||
deviceScaleFactor?: number
|
||||
@@ -251,6 +281,7 @@ function parseConfig(ctx: BrowsercontextsBrowserContext | undefined): ConfigShap
|
||||
|
||||
const schema = toTypedSchema(z.object({
|
||||
name: z.string().min(1),
|
||||
core: z.enum(['chromium', 'firefox']).optional(),
|
||||
viewportWidth: z.coerce.number().optional(),
|
||||
viewportHeight: z.coerce.number().optional(),
|
||||
userAgent: z.string().optional(),
|
||||
@@ -269,6 +300,7 @@ watch(() => curContext?.value, (ctx) => {
|
||||
form.resetForm({
|
||||
values: {
|
||||
name: ctx.name || '',
|
||||
core: (cfg.core as 'chromium' | 'firefox') ?? 'chromium',
|
||||
viewportWidth: cfg.viewport?.width ?? 1280,
|
||||
viewportHeight: cfg.viewport?.height ?? 720,
|
||||
userAgent: cfg.userAgent ?? '',
|
||||
@@ -307,7 +339,9 @@ const handleSave = form.handleSubmit(async (values) => {
|
||||
const id = curContext?.value?.id
|
||||
if (!id) return
|
||||
|
||||
const config: Record<string, any> = {}
|
||||
const config: Record<string, any> = {
|
||||
core: values.core ?? 'chromium',
|
||||
}
|
||||
if (values.viewportWidth || values.viewportHeight) {
|
||||
config.viewport = {
|
||||
width: values.viewportWidth || 1280,
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
FROM mcr.microsoft.com/playwright:v1.50.0-noble
|
||||
FROM ubuntu:noble
|
||||
|
||||
ARG BROWSER_CORES=chromium,firefox
|
||||
ENV BROWSER_CORES=$BROWSER_CORES
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends unzip curl nodejs npm && \
|
||||
curl -fsSL https://bun.sh/install | bash && \
|
||||
npm install -g playwright@1.50.0 && \
|
||||
for core in $(echo "$BROWSER_CORES" | tr ',' ' '); do \
|
||||
npx playwright install --with-deps "$core"; \
|
||||
done && \
|
||||
npm uninstall -g playwright && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends unzip && rm -rf /var/lib/apt/lists/*
|
||||
RUN curl -fsSL https://bun.sh/install | bash
|
||||
ENV PATH="/root/.bun/bin:${PATH}"
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
@@ -141,9 +141,13 @@ services:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: devenv/Dockerfile.browser
|
||||
args:
|
||||
BROWSER_CORES: ${BROWSER_CORES:-chromium,firefox}
|
||||
container_name: memoh-dev-browser
|
||||
working_dir: /workspace/apps/browser
|
||||
command: ["bun", "run", "--watch", "src/index.ts"]
|
||||
environment:
|
||||
- BROWSER_CORES=${BROWSER_CORES:-chromium,firefox}
|
||||
volumes:
|
||||
- ..:/workspace
|
||||
- node_modules:/workspace/node_modules
|
||||
|
||||
@@ -118,8 +118,15 @@ services:
|
||||
|
||||
browser:
|
||||
image: memohai/browser:latest
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.browser
|
||||
args:
|
||||
BROWSER_CORES: ${BROWSER_CORES:-chromium,firefox}
|
||||
container_name: memoh-browser
|
||||
profiles: [browser]
|
||||
environment:
|
||||
- BROWSER_CORES=${BROWSER_CORES:-chromium,firefox}
|
||||
volumes:
|
||||
- ${MEMOH_CONFIG:-./config.toml}:/config.toml:ro
|
||||
ports:
|
||||
|
||||
@@ -15,7 +15,10 @@ COPY apps/browser/ ./apps/browser/
|
||||
|
||||
RUN cd apps/browser && bun run build
|
||||
|
||||
FROM mcr.microsoft.com/playwright:v1.50.0-noble
|
||||
FROM ubuntu:noble
|
||||
|
||||
ARG BROWSER_CORES=chromium,firefox
|
||||
ENV BROWSER_CORES=$BROWSER_CORES
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -29,7 +32,9 @@ COPY --from=builder /build/apps/browser/node_modules /app/node_modules
|
||||
COPY --from=builder /build/apps/browser/package.json /app/package.json
|
||||
COPY --from=builder /build/node_modules /node_modules
|
||||
|
||||
RUN npx playwright install --with-deps chromium
|
||||
RUN for core in $(echo "$BROWSER_CORES" | tr ',' ' '); do \
|
||||
bun /app/node_modules/.bin/playwright install --with-deps "$core"; \
|
||||
done
|
||||
|
||||
EXPOSE 8083
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -8,17 +11,20 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/memohai/memoh/internal/browsercontexts"
|
||||
"github.com/memohai/memoh/internal/config"
|
||||
)
|
||||
|
||||
type BrowserContextsHandler struct {
|
||||
service *browsercontexts.Service
|
||||
logger *slog.Logger
|
||||
browserGatewayURL string
|
||||
}
|
||||
|
||||
func NewBrowserContextsHandler(log *slog.Logger, service *browsercontexts.Service) *BrowserContextsHandler {
|
||||
func NewBrowserContextsHandler(log *slog.Logger, service *browsercontexts.Service, cfg config.Config) *BrowserContextsHandler {
|
||||
return &BrowserContextsHandler{
|
||||
service: service,
|
||||
logger: log.With(slog.String("handler", "browser_contexts")),
|
||||
browserGatewayURL: cfg.BrowserGateway.BaseURL(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +32,7 @@ func (h *BrowserContextsHandler) Register(e *echo.Echo) {
|
||||
group := e.Group("/browser-contexts")
|
||||
group.POST("", h.Create)
|
||||
group.GET("", h.List)
|
||||
group.GET("/cores", h.GetCores)
|
||||
group.GET("/:id", h.Get)
|
||||
group.PUT("/:id", h.Update)
|
||||
group.DELETE("/:id", h.Delete)
|
||||
@@ -139,3 +146,41 @@ func (h *BrowserContextsHandler) Delete(c echo.Context) error {
|
||||
}
|
||||
return c.NoContent(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// GetCores godoc
|
||||
// @Summary Get available browser cores
|
||||
// @Description Get the list of browser cores available in the Browser Gateway container
|
||||
// @Tags browser-contexts
|
||||
// @Produce json
|
||||
// @Success 200 {object} BrowserCoresResponse
|
||||
// @Failure 502 {object} ErrorResponse
|
||||
// @Router /browser-contexts/cores [get].
|
||||
func (h *BrowserContextsHandler) GetCores(c echo.Context) error {
|
||||
url := fmt.Sprintf("%s/cores/", h.browserGatewayURL)
|
||||
req, err := http.NewRequestWithContext(c.Request().Context(), http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadGateway, "failed to create request")
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req) //nolint:gosec // URL is from trusted internal config
|
||||
if err != nil {
|
||||
h.logger.Warn("browser gateway unreachable", slog.String("error", err.Error()))
|
||||
return c.JSON(http.StatusOK, BrowserCoresResponse{Cores: []string{"chromium"}})
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadGateway, "failed to read browser gateway response")
|
||||
}
|
||||
|
||||
var result BrowserCoresResponse
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadGateway, "failed to parse browser gateway response")
|
||||
}
|
||||
return c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// BrowserCoresResponse is the response for the GetCores endpoint.
|
||||
type BrowserCoresResponse struct {
|
||||
Cores []string `json:"cores"`
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -611,6 +611,10 @@ export type HandlersBatchDeleteRequest = {
|
||||
ids?: Array<string>;
|
||||
};
|
||||
|
||||
export type HandlersBrowserCoresResponse = {
|
||||
cores?: Array<string>;
|
||||
};
|
||||
|
||||
export type HandlersChannelMeta = {
|
||||
capabilities?: ChannelChannelCapabilities;
|
||||
config_schema?: ChannelConfigSchema;
|
||||
@@ -5944,6 +5948,31 @@ export type PostBrowserContextsResponses = {
|
||||
|
||||
export type PostBrowserContextsResponse = PostBrowserContextsResponses[keyof PostBrowserContextsResponses];
|
||||
|
||||
export type GetBrowserContextsCoresData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/browser-contexts/cores';
|
||||
};
|
||||
|
||||
export type GetBrowserContextsCoresErrors = {
|
||||
/**
|
||||
* Bad Gateway
|
||||
*/
|
||||
502: HandlersErrorResponse;
|
||||
};
|
||||
|
||||
export type GetBrowserContextsCoresError = GetBrowserContextsCoresErrors[keyof GetBrowserContextsCoresErrors];
|
||||
|
||||
export type GetBrowserContextsCoresResponses = {
|
||||
/**
|
||||
* OK
|
||||
*/
|
||||
200: HandlersBrowserCoresResponse;
|
||||
};
|
||||
|
||||
export type GetBrowserContextsCoresResponse = GetBrowserContextsCoresResponses[keyof GetBrowserContextsCoresResponses];
|
||||
|
||||
export type DeleteBrowserContextsByIdData = {
|
||||
body?: never;
|
||||
path: {
|
||||
|
||||
+21
-1
@@ -99,6 +99,7 @@ WORKSPACE="$WORKSPACE_DEFAULT"
|
||||
MEMOH_DATA_DIR="$MEMOH_DATA_DIR_DEFAULT"
|
||||
USE_CN_MIRROR="${USE_CN_MIRROR:-false}"
|
||||
USE_SPARSE="${USE_SPARSE:-false}"
|
||||
BROWSER_CORES="${BROWSER_CORES:-chromium,firefox}"
|
||||
|
||||
if [ "$SILENT" = false ]; then
|
||||
echo "Configure Memoh (press Enter to use defaults):" > /dev/tty
|
||||
@@ -148,6 +149,19 @@ if [ "$SILENT" = false ]; then
|
||||
y|Y|yes|YES) USE_SPARSE=true ;;
|
||||
esac
|
||||
|
||||
echo "" > /dev/tty
|
||||
echo " Browser core selection:" > /dev/tty
|
||||
echo " 1) Chromium only (smaller image)" > /dev/tty
|
||||
echo " 2) Firefox only" > /dev/tty
|
||||
echo " 3) Both Chromium and Firefox (default)" > /dev/tty
|
||||
printf " Browser core [3]: " > /dev/tty
|
||||
read -r input < /dev/tty || true
|
||||
case "$input" in
|
||||
1) BROWSER_CORES="chromium" ;;
|
||||
2) BROWSER_CORES="firefox" ;;
|
||||
*) BROWSER_CORES="chromium,firefox" ;;
|
||||
esac
|
||||
|
||||
echo "" > /dev/tty
|
||||
fi
|
||||
|
||||
@@ -222,11 +236,17 @@ fi
|
||||
echo POSTGRES_PASSWORD="${PG_PASS}" >> .env
|
||||
echo MEMOH_CONFIG=./config.toml >> .env
|
||||
echo MEMOH_DATA_DIR="{$MEMOH_DATA_DIR}" >> .env
|
||||
echo BROWSER_CORES="${BROWSER_CORES}" >> .env
|
||||
echo USE_SPARSE="${USE_SPARSE}" >> .env
|
||||
echo "${GREEN}✓ Browser cores: ${BROWSER_CORES}${NC}"
|
||||
|
||||
echo ""
|
||||
echo "${GREEN}Pulling latest Docker images...${NC}"
|
||||
$DOCKER compose $COMPOSE_FILES $COMPOSE_PROFILES pull
|
||||
$DOCKER compose $COMPOSE_FILES $COMPOSE_PROFILES pull --ignore-buildable
|
||||
|
||||
echo ""
|
||||
echo "${GREEN}Building browser image (cores: ${BROWSER_CORES})...${NC}"
|
||||
$DOCKER compose $COMPOSE_FILES $COMPOSE_PROFILES build browser
|
||||
|
||||
echo ""
|
||||
echo "${GREEN}Starting services (first startup may take a few minutes)...${NC}"
|
||||
|
||||
@@ -5482,6 +5482,32 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/browser-contexts/cores": {
|
||||
"get": {
|
||||
"description": "Get the list of browser cores available in the Browser Gateway container",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"browser-contexts"
|
||||
],
|
||||
"summary": "Get available browser cores",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.BrowserCoresResponse"
|
||||
}
|
||||
},
|
||||
"502": {
|
||||
"description": "Bad Gateway",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/browser-contexts/{id}": {
|
||||
"get": {
|
||||
"description": "Get browser context by ID",
|
||||
@@ -10039,6 +10065,17 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.BrowserCoresResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cores": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.ChannelMeta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -5473,6 +5473,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/browser-contexts/cores": {
|
||||
"get": {
|
||||
"description": "Get the list of browser cores available in the Browser Gateway container",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"browser-contexts"
|
||||
],
|
||||
"summary": "Get available browser cores",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.BrowserCoresResponse"
|
||||
}
|
||||
},
|
||||
"502": {
|
||||
"description": "Bad Gateway",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/browser-contexts/{id}": {
|
||||
"get": {
|
||||
"description": "Get browser context by ID",
|
||||
@@ -10030,6 +10056,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.BrowserCoresResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cores": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.ChannelMeta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -1001,6 +1001,13 @@ definitions:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
handlers.BrowserCoresResponse:
|
||||
properties:
|
||||
cores:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
handlers.ChannelMeta:
|
||||
properties:
|
||||
capabilities:
|
||||
@@ -6178,6 +6185,24 @@ paths:
|
||||
summary: Update a browser context
|
||||
tags:
|
||||
- browser-contexts
|
||||
/browser-contexts/cores:
|
||||
get:
|
||||
description: Get the list of browser cores available in the Browser Gateway
|
||||
container
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handlers.BrowserCoresResponse'
|
||||
"502":
|
||||
description: Bad Gateway
|
||||
schema:
|
||||
$ref: '#/definitions/handlers.ErrorResponse'
|
||||
summary: Get available browser cores
|
||||
tags:
|
||||
- browser-contexts
|
||||
/channels:
|
||||
get:
|
||||
description: List channel meta information including capabilities and schemas
|
||||
|
||||
Reference in New Issue
Block a user