Skip to content
← Public packages

@kody/browser-run

Call Cloudflare Browser Run Quick Actions and reuse shared sessions with createBrowserContext.

src/sessions/connect.ts

68 lines · 2.1 KB · TypeScript
import { number, object, optional, parse, string } from 'remix/data-schema'
import {
	ISOLATION_INSTRUCTIONS,
	authorizationHeader,
	browserWsEndpoint,
	browserWsEndpointAlias,
	pickAuth,
	requireAccountId,
} from '../client.ts'

const connectInput = object(
	{
		accountId: string(),
		sessionId: string(),
		apiTokenSecret: optional(string()),
		keepAliveMs: optional(number()),
	},
	{ unknownKeys: 'error' },
)

/**
 * Build connect info for an existing Browser Run sessionId (WS endpoint +
 * Authorization guidance for puppeteer-core / CDP). Does not open the socket
 * from Kody (Workers cannot hold long-lived CDP); use the returned values in
 * a Worker or external Node process, then createBrowserContext + disconnect.
 *
 * @param raw.accountId - Cloudflare account id
 * @param raw.sessionId - Existing session UUID
 * @param raw.keepAliveMs - Optional keep_alive query param
 * @param raw.apiTokenSecret - Optional alternate secret name
 * @returns `{ sessionId, browserWSEndpoint, headers guidance, instructions }`
 *
 * @example
 * import connect from 'kody:@kody/browser-run/sessions/connect'
 * const info = await connect({
 *   accountId: 'YOUR_ACCOUNT_ID',
 *   sessionId: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
 * })
 */
export default async function connectSession(raw: unknown = {}) {
	const input = parse(connectInput, raw ?? {})
	const auth = pickAuth(input)
	const accountId = requireAccountId(auth)
	const sessionId = String(input.sessionId).trim()
	if (!sessionId) throw new Error('sessionId is required.')

	return {
		ok: true,
		accountId,
		sessionId,
		browserWSEndpoint: browserWsEndpoint(accountId, sessionId, input.keepAliveMs),
		browserWSEndpointAlias: browserWsEndpointAlias(
			accountId,
			sessionId,
			input.keepAliveMs,
		),
		authorizationHeaderTemplate: authorizationHeader(auth),
		puppeteerConnectExample: {
			browserWSEndpoint: browserWsEndpoint(accountId, sessionId, input.keepAliveMs),
			headers: {
				Authorization: authorizationHeader(auth),
			},
		},
		isolation: 'createBrowserContext' as const,
		disconnectNotClose: true as const,
		instructions: ISOLATION_INSTRUCTIONS,
	}
}