@runlane/realtime 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as realtimeTiming, r as invalidOptions, t as realtimeClock } from "./time-sHQYGDPD.mjs";
1
+ import { a as invalidOptions, i as realtimeTiming, n as streamSelectionQuery, r as realtimeClock } from "./wire-BEevjo-K.mjs";
2
2
  import { ErrorCode, ErrorCode as ErrorCode$1, RunReadPermission, RunReadPermission as RunReadPermission$1, RunSubscriptionEventType, RunlaneError, RunlaneError as RunlaneError$1, RunlaneLogAttribute, RunlaneLogEventType, RunlaneLogLevel, RunlaneMetricAttribute, RunlaneMetricName, RunlaneSpanName, contractDefaults, createDurationSchema, createRunlaneIdSchema, realtimeDefaults, recordRunlaneTelemetryLog, recordRunlaneTelemetryMetric, runAccessGrantSchema, runCursorSchema, runRealtimeErrorCodeSchema, runRealtimeSnapshotSchema, runStatusValues, runStreamNameSchema, runWithRunlaneTelemetrySpan, verifiedRunTokenSchema } from "@runlane/contracts/realtime";
3
3
  import { createFunctionSchema, objectSurfaceSchema, waitForAbortableTimeout } from "@runlane/utilities/browser";
4
4
  import { encode } from "eventsource-encoder";
@@ -320,7 +320,7 @@ function parseRoute(request) {
320
320
  retryable: false
321
321
  });
322
322
  const url = new URL(request.url);
323
- if (Array.from(url.searchParams.keys()).some((key) => key !== "after") || url.searchParams.getAll("after").length > 1) throw invalidRequest("Only one after query parameter is accepted; use Authorization for credentials.");
323
+ if (Array.from(url.searchParams.keys()).some((key) => key !== "after" && key !== streamSelectionQuery.name) || url.searchParams.getAll("after").length > 1) throw invalidRequest("Only one after and one streams query parameter are accepted; use Authorization for credentials.");
324
324
  const match = /\/runs\/([^/]+)\/(events|streams\/([^/]+))$/.exec(url.pathname);
325
325
  if (match?.[1] === void 0) throw new RunlaneError$1({
326
326
  code: ErrorCode$1.RunNotFound,
@@ -335,9 +335,12 @@ function parseRoute(request) {
335
335
  } catch (cause) {
336
336
  throw invalidRequest("Run id or stream name is invalid.", cause);
337
337
  }
338
+ const selections = url.searchParams.getAll(streamSelectionQuery.name);
339
+ if (selections.length > 1 || selections.length === 1 && (name !== void 0 || selections[0] !== streamSelectionQuery.none)) throw invalidRequest("Stream selection requires one streams=none parameter on the events route.");
338
340
  return {
339
341
  runId,
340
342
  ...name === void 0 ? {} : { name },
343
+ ...selections.length === 1 ? { streams: false } : {},
341
344
  ...parseResumeCursor(request, url)
342
345
  };
343
346
  }
@@ -472,7 +475,7 @@ async function* sourceFrames(source, route, grant, signal) {
472
475
  for await (const event of source.runs.subscribe(route.runId, {
473
476
  after: route.after,
474
477
  signal,
475
- streams: grant.permissions.includes(RunReadPermission$1.Streams) ? grant.streams : false
478
+ streams: route.streams === false || !grant.permissions.includes(RunReadPermission$1.Streams) ? false : grant.streams
476
479
  })) {
477
480
  if (signal.aborted) return;
478
481
  const projected = projectEvent(event, grant);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["RunReadPermission","encoder","RunReadPermission","RunlaneError","ErrorCode","z","RunlaneError","ErrorCode","RunReadPermission"],"sources":["../src/access.ts","../src/tokens.ts","../src/handler.ts"],"sourcesContent":["import {\n RunReadPermission,\n runRealtimeSnapshotSchema,\n RunSubscriptionEventType,\n type RunAccessGrant,\n type RunSubscriptionEvent,\n type RuntimeRunSubscriptionEvent,\n} from '@runlane/contracts/realtime'\n\nexport function intersectGrants(app: RunAccessGrant, token?: RunAccessGrant): RunAccessGrant {\n if (token === undefined) return app\n const permissions = app.permissions.filter((permission) => token.permissions.includes(permission))\n let streams = app.streams ?? token.streams\n if (app.streams !== undefined && token.streams !== undefined)\n streams = app.streams.filter((name) => token.streams?.includes(name))\n return { permissions, ...(streams === undefined ? {} : { streams }) }\n}\n\nexport function permitsStream(grant: RunAccessGrant, name: string): boolean {\n return (\n grant.permissions.includes(RunReadPermission.Streams) &&\n (grant.streams === undefined || grant.streams.includes(name))\n )\n}\n\nexport function projectEvent(\n event: RuntimeRunSubscriptionEvent,\n grant: RunAccessGrant,\n): RunSubscriptionEvent | undefined {\n if (event.type === RunSubscriptionEventType.Stream) return permitsStream(grant, event.record.name) ? event : undefined\n if (event.type === RunSubscriptionEventType.Meta)\n return grant.permissions.includes(RunReadPermission.Meta) ? event : undefined\n if (!grant.permissions.includes(RunReadPermission.Status)) return undefined\n if (event.type === RunSubscriptionEventType.Status) {\n const status = { ...event }\n if (!grant.permissions.includes(RunReadPermission.Output)) {\n delete status.output\n delete status.failure\n }\n if (status.failure !== undefined) {\n status.failure = runRealtimeSnapshotSchema.shape.failure.parse(status.failure)\n }\n return status\n }\n return { ...event, run: projectSnapshot(event.run, grant) }\n}\n\nfunction projectSnapshot(\n source: Extract<RunSubscriptionEvent, { type: RunSubscriptionEventType.Snapshot }>['run'],\n grant: RunAccessGrant,\n) {\n const { meta, output, failure, ...status } = runRealtimeSnapshotSchema.parse(source)\n return {\n ...status,\n ...(grant.permissions.includes(RunReadPermission.Meta) && meta !== undefined ? { meta } : {}),\n ...(grant.permissions.includes(RunReadPermission.Output)\n ? {\n ...(output === undefined ? {} : { output }),\n ...(failure === undefined ? {} : { failure }),\n }\n : {}),\n }\n}\n","import {\n createDurationSchema,\n ErrorCode,\n recordRunlaneTelemetryLog,\n recordRunlaneTelemetryMetric,\n runAccessGrantSchema,\n RunlaneError,\n RunlaneLogAttribute,\n RunlaneLogEventType,\n RunlaneLogLevel,\n RunlaneMetricAttribute,\n RunlaneMetricName,\n RunReadPermission,\n verifiedRunTokenSchema,\n type DurationString,\n type Environment,\n type RunlaneTelemetryRecordingContext,\n type VerifiedRunToken,\n} from '@runlane/contracts/realtime'\nimport { base64url, CompactSign, compactVerify } from 'jose'\nimport { z } from 'zod'\n\nimport { realtimeClock, realtimeTiming } from './time.js'\n\nconst tokenPartsSchema = z.tuple([z.string(), z.string(), z.string()])\nconst headerSchema = z.strictObject({ alg: z.literal('HS256'), typ: z.literal('JWT'), kid: z.string().min(1).max(128) })\nconst algorithmSchema = z.object({\n name: z.literal('HMAC'),\n hash: z.object({ name: z.literal('SHA-256') }),\n length: z.number().int().min(256),\n})\nconst encoder = new TextEncoder()\nconst decoder = new TextDecoder('utf-8', { fatal: true })\nconst maximumTokenLength = 16_384\n\n/** Strict construction schema; claim and header constraints remain the canonical owners. */\nexport const realtimeTokenOptionsSchema = z\n .strictObject({\n audience: verifiedRunTokenSchema.shape.audience,\n keyId: headerSchema.shape.kid,\n key: z.instanceof(CryptoKey),\n verifyKeys: z.record(headerSchema.shape.kid, z.instanceof(CryptoKey)).readonly().optional(),\n })\n .refine(\n (tokens) => !Object.hasOwn(tokens.verifyKeys ?? {}, tokens.keyId),\n 'tokens.keyId must not also appear in verifyKeys.',\n )\n\n/** Active signing/verification key and previous verify-only keys. Keep all keys server-side. */\nexport type RunlaneRealtimeTokenOptions = Readonly<z.output<typeof realtimeTokenOptionsSchema>>\n\nconst createTokenOptionsSchema = z.strictObject({\n // The complete claims schema validates and brands this identifier before signing.\n runId: z.string(),\n grant: runAccessGrantSchema.optional(),\n expiresIn: createDurationSchema('expiresIn must be whole seconds between 1s and realtime.maxTokenTTL.').optional(),\n})\n/** Minting inputs for one run. The app must check access before calling createToken. */\nexport type CreateRealtimeTokenOptions = Readonly<z.input<typeof createTokenOptionsSchema>> & {\n readonly expiresIn?: DurationString\n}\n\n/** Signs one run/environment/audience grant using an HMAC-SHA256 key of at least 256 bits. */\nexport async function signRunToken(\n environment: Environment,\n tokens: RunlaneRealtimeTokenOptions,\n input: CreateRealtimeTokenOptions,\n): Promise<string> {\n try {\n const options = createTokenOptionsSchema.parse(input)\n const header = headerSchema.parse({ alg: 'HS256', typ: 'JWT', kid: tokens.keyId })\n requireHmacKey(tokens.key, 'sign')\n const ttl = tokenLifetime(options.expiresIn?.milliseconds)\n const issuedAt = Math.floor(realtimeClock.now() / 1000)\n const claims = verifiedRunTokenSchema.parse({\n environment,\n runId: options.runId,\n grant: options.grant ?? { permissions: Object.values(RunReadPermission) },\n audience: tokens.audience,\n issuedAt,\n expiresAt: issuedAt + ttl / 1000,\n version: 1,\n })\n const token = await new CompactSign(encoder.encode(JSON.stringify(claims)))\n .setProtectedHeader(header)\n .sign(tokens.key)\n if (token.length > maximumTokenLength) throw invalidToken()\n return token\n } catch (cause) {\n if (cause instanceof RunlaneError) throw cause\n const message =\n cause instanceof z.ZodError\n ? `Token ${cause.issues[0]?.path.join('.') ?? 'expiresIn'} is invalid: ${cause.issues[0]?.message ?? 'Check the token options.'}`\n : 'Token signing failed; check key and claims.'\n const field = cause instanceof z.ZodError ? cause.issues[0]?.path[0] : undefined\n let code = ErrorCode.InternalError\n if (cause instanceof z.ZodError) {\n code =\n field === 'environment' || field === 'runId' || field === 'grant'\n ? ErrorCode.ValidationFailed\n : ErrorCode.ConfigurationInvalid\n }\n throw new RunlaneError({ code, message, retryable: false, cause })\n }\n}\n\nfunction tokenLifetime(ttl = realtimeTiming.tokenTTL): number {\n if (ttl < 1000 || ttl > realtimeTiming.maxTokenTTL || ttl % 1000 !== 0)\n throw new RunlaneError({\n code: ErrorCode.ConfigurationInvalid,\n message: 'expiresIn must be whole seconds between 1s and realtime.maxTokenTTL.',\n retryable: false,\n })\n return ttl\n}\n\n/** Verifies a scoped token and records only bounded rejection reasons through the supplied telemetry. */\nexport async function verifyRunToken(\n token: string,\n options: { readonly audience: string; readonly keys: Readonly<Record<string, CryptoKey>> },\n diagnostics: RunlaneTelemetryRecordingContext = {},\n operation = 'verify',\n): Promise<VerifiedRunToken> {\n let reason: TokenRejectionReason = TokenRejectionReason.Malformed\n try {\n if (token.length > maximumTokenLength) throw invalidToken()\n const [head, body, signature] = tokenPartsSchema.parse(token.split('.'))\n reason = TokenRejectionReason.Header\n const header = headerSchema.parse(JSON.parse(decoder.decode(decodeBase64(head))))\n reason = TokenRejectionReason.UnknownKey\n const key = Object.hasOwn(options.keys, header.kid) ? options.keys[header.kid] : undefined\n if (key === undefined) throw invalidToken()\n reason = TokenRejectionReason.Key\n requireHmacKey(key, 'verify')\n reason = TokenRejectionReason.Signature\n decodeBase64(signature)\n const verified = await compactVerify(token, key, { algorithms: ['HS256'] })\n reason = TokenRejectionReason.Claims\n decodeBase64(body)\n const claims = verifiedRunTokenSchema.parse(JSON.parse(decoder.decode(verified.payload)))\n const now = Math.floor(realtimeClock.now() / 1000)\n const rejection = tokenClaimRejection(claims, options.audience, now)\n if (rejection !== undefined) {\n reason = rejection\n throw invalidToken()\n }\n return claims\n } catch (cause) {\n recordRunlaneTelemetryMetric(diagnostics, {\n name: RunlaneMetricName.RealtimeTokenRejectedCount,\n value: 1,\n attributes: { [RunlaneMetricAttribute.Operation]: operation, [RunlaneMetricAttribute.Reason]: reason },\n })\n recordRunlaneTelemetryLog(diagnostics, {\n type: RunlaneLogEventType.RealtimeTokenRejected,\n level: RunlaneLogLevel.Warn,\n attributes: { [RunlaneLogAttribute.Operation]: operation, [RunlaneLogAttribute.Reason]: reason },\n })\n throw invalidToken(cause)\n }\n}\n\nfunction tokenClaimRejection(\n claims: VerifiedRunToken,\n audience: string,\n now: number,\n): TokenRejectionReason | undefined {\n if (claims.audience !== audience) return TokenRejectionReason.Audience\n if (claims.issuedAt > now + realtimeTiming.issuedAtLeeway / 1000) return TokenRejectionReason.IssuedAt\n if (claims.expiresAt <= now) return TokenRejectionReason.Expired\n if (claims.expiresAt <= claims.issuedAt || (claims.expiresAt - claims.issuedAt) * 1000 > realtimeTiming.maxTokenTTL)\n return TokenRejectionReason.Lifetime\n return undefined\n}\n\n/** Shared key policy for signing, verification, and handler startup checks. */\nexport function requireHmacKey(key: CryptoKey, usage: KeyUsage): void {\n if (\n !(key instanceof CryptoKey) ||\n key.type !== 'secret' ||\n !algorithmSchema.safeParse(key.algorithm).success ||\n !key.usages.includes(usage)\n )\n throw new RunlaneError({\n code: ErrorCode.ConfigurationInvalid,\n message: `key must be an HMAC-SHA256 key of at least 256 bits with ${usage} usage.`,\n retryable: false,\n })\n}\n\nfunction decodeBase64(value: string): Uint8Array {\n if (!/^[A-Za-z0-9_-]+$/.test(value)) throw invalidToken()\n const bytes = base64url.decode(value)\n if (base64url.encode(bytes) !== value) throw invalidToken()\n return bytes\n}\n\nfunction invalidToken(cause?: unknown): RunlaneError {\n return new RunlaneError({\n code: ErrorCode.AccessDenied,\n message: 'Run access denied.',\n retryable: false,\n cause,\n })\n}\n\nenum TokenRejectionReason {\n Malformed = 'malformed',\n Header = 'header',\n UnknownKey = 'unknown_key',\n Key = 'key',\n Signature = 'signature',\n Claims = 'claims',\n Audience = 'audience',\n IssuedAt = 'issued_at',\n Expired = 'expired',\n Lifetime = 'lifetime',\n}\n","import {\n contractDefaults,\n createDurationSchema,\n createRunlaneIdSchema,\n ErrorCode,\n realtimeDefaults,\n recordRunlaneTelemetryLog,\n recordRunlaneTelemetryMetric,\n runAccessGrantSchema,\n runCursorSchema,\n RunlaneError,\n RunlaneLogAttribute,\n RunlaneLogEventType,\n RunlaneLogLevel,\n RunlaneMetricAttribute,\n RunlaneMetricName,\n RunlaneSpanName,\n RunReadPermission,\n runRealtimeErrorCodeSchema,\n runStatusValues,\n runStreamNameSchema,\n runWithRunlaneTelemetrySpan,\n type RealtimeErrorData,\n type RunAccessGrant,\n type RunCursor,\n type RunId,\n type RunlaneTelemetryRecordingContext,\n type RunReadPage,\n type RunStreamRecord,\n type VerifiedRunToken,\n} from '@runlane/contracts/realtime'\nimport {\n createFunctionSchema,\n objectSurfaceSchema,\n waitForAbortableTimeout,\n type Awaitable,\n} from '@runlane/utilities/browser'\nimport { encode } from 'eventsource-encoder'\nimport * as z from 'zod'\n\nimport { intersectGrants, permitsStream, projectEvent } from './access.js'\nimport { invalidOptions } from './errors.js'\nimport { type RunlaneRealtimeSource } from './source.js'\nimport { realtimeClock, realtimeTiming } from './time.js'\nimport {\n realtimeTokenOptionsSchema,\n requireHmacKey,\n signRunToken,\n verifyRunToken,\n type CreateRealtimeTokenOptions,\n type RunlaneRealtimeTokenOptions,\n} from './tokens.js'\n\n/** Server options require authorize, tokens, or both. Configured authorization limits every valid connection. */\nexport interface RunlaneRealtimeOptions extends RunlaneTelemetryRecordingContext {\n readonly runlane: RunlaneRealtimeSource\n readonly authorize?: (input: {\n readonly request: Request\n readonly runId: RunId\n readonly token?: VerifiedRunToken\n }) => Awaitable<RunAccessGrant | undefined>\n readonly tokens?: RunlaneRealtimeTokenOptions\n}\n/** Authorization callback for a separately defined policy; undefined denies access to the run. */\nexport type RunlaneRealtimeAuthorize = NonNullable<RunlaneRealtimeOptions['authorize']>\n\n/** Server entry for authorized reads and request-independent token minting. */\nexport interface RunlaneRealtime {\n /** Serves SSE reads; authorize, when configured, limits every valid connection. */\n readonly handle: (request: Request) => Promise<Response>\n /** Mint after the app checks access. Does not call authorize or check run existence. */\n readonly createToken: (options: CreateRealtimeTokenOptions) => Promise<string>\n}\ninterface Route {\n readonly runId: RunId\n readonly name?: string\n readonly after?: RunCursor\n}\ninterface Frame {\n readonly event: string\n readonly cursor?: RunCursor\n readonly data: object\n}\nconst encoder = new TextEncoder()\nconst runIdSchema = createRunlaneIdSchema<'run'>('Run id')\nconst pollInterval = createDurationSchema().parse(contractDefaults.streams.pollInterval).milliseconds\n\nconst handlerOptionsSchema = z\n .strictObject({\n runlane: objectSurfaceSchema,\n authorize: createFunctionSchema<RunlaneRealtimeAuthorize>('authorize must be a function.').optional(),\n tokens: realtimeTokenOptionsSchema.optional(),\n telemetry: objectSurfaceSchema.optional(),\n onTelemetryError: createFunctionSchema<NonNullable<RunlaneRealtimeOptions['onTelemetryError']>>(\n 'onTelemetryError must be a function.',\n ).optional(),\n })\n .refine(\n (options) => options.authorize !== undefined || options.tokens !== undefined,\n 'Configure authorize for session access, tokens for bearer access, or both.',\n )\n\n/** Mounts authorized, bounded SSE reads without starting workers or adding runtime storage work. */\nexport function createRunlaneRealtime(options: RunlaneRealtimeOptions): RunlaneRealtime {\n const checked = handlerOptionsSchema.safeParse(options)\n if (!checked.success) throw invalidOptions(checked.error, 'handler')\n const tokens = checked.data.tokens\n if (tokens !== undefined) {\n requireHmacKey(tokens.key, 'sign')\n requireHmacKey(tokens.key, 'verify')\n for (const key of Object.values(tokens.verifyKeys ?? {})) requireHmacKey(key, 'verify')\n }\n const verification =\n tokens === undefined\n ? undefined\n : {\n audience: tokens.audience,\n keys: { ...tokens.verifyKeys, [tokens.keyId]: tokens.key },\n }\n return {\n async createToken(input) {\n if (tokens === undefined)\n throw new RunlaneError({\n code: ErrorCode.ConfigurationInvalid,\n message: 'Configure tokens before calling createToken.',\n })\n return signRunToken(options.runlane.environment, tokens, input)\n },\n async handle(request) {\n let operation = 'subscribe'\n try {\n const route = parseRoute(request)\n operation = route.name === undefined ? 'subscribe' : 'read'\n const token = await requestToken(request, route.runId, options, verification)\n const grant = await authorizeGrant(options, request, route, token, operation)\n return await openConnection(options, request, route, grant, token)\n } catch (cause) {\n const error = publicError(cause)\n if (error.code === ErrorCode.AccessDenied) recordDenial(options, cause, operation)\n return Response.json(\n { error },\n {\n status: request.method === 'GET' ? httpStatus(error.code) : 405,\n headers: { 'cache-control': 'no-store', ...(request.method === 'GET' ? {} : { allow: 'GET' }) },\n },\n )\n }\n },\n }\n}\n\nasync function authorizeGrant(\n options: RunlaneRealtimeOptions,\n request: Request,\n route: Route,\n token: VerifiedRunToken | undefined,\n operation: string,\n): Promise<RunAccessGrant> {\n let app: RunAccessGrant | undefined\n try {\n app =\n options.authorize === undefined\n ? token?.grant\n : await options.authorize({ request, runId: route.runId, ...(token === undefined ? {} : { token }) })\n } catch (cause) {\n recordRunlaneTelemetryMetric(options, {\n name: RunlaneMetricName.RealtimeAuthorizationErrorCount,\n value: 1,\n attributes: {\n [RunlaneMetricAttribute.Operation]: operation,\n [RunlaneMetricAttribute.Reason]: 'authorize_exception',\n },\n })\n recordRunlaneTelemetryLog(options, {\n type: RunlaneLogEventType.RealtimeAuthorizationFailed,\n level: RunlaneLogLevel.Error,\n attributes: {\n [RunlaneLogAttribute.Operation]: operation,\n [RunlaneLogAttribute.Reason]: 'authorize_exception',\n },\n })\n throw new RunlaneError({ code: ErrorCode.InternalError, message: 'Realtime authorization failed.', cause })\n }\n if (app === undefined) throw accessDenied()\n const parsed = runAccessGrantSchema.safeParse(app)\n if (!parsed.success) throw invalidRequest('Realtime grant is invalid.', parsed.error)\n const grant = intersectGrants(parsed.data, token?.grant)\n if (grant.permissions.length === 0 || (route.name !== undefined && !permitsStream(grant, route.name)))\n throw accessDenied()\n return grant\n}\n\nfunction recordDenial(options: RunlaneRealtimeOptions, cause: unknown, operation: string): void {\n const reason =\n accessDenialReasonSchema.safeParse(cause instanceof RunlaneError ? cause.meta?.reason : undefined).data ??\n 'token_rejected'\n if (reason !== 'token_rejected')\n recordRunlaneTelemetryLog(options, {\n type: RunlaneLogEventType.RealtimeAuthorizationDenied,\n level: RunlaneLogLevel.Warn,\n attributes: { [RunlaneLogAttribute.Operation]: operation, [RunlaneLogAttribute.Reason]: reason },\n })\n recordRunlaneTelemetryMetric(options, {\n name: RunlaneMetricName.RealtimeAuthorizationDeniedCount,\n value: 1,\n attributes: { [RunlaneMetricAttribute.Operation]: operation, [RunlaneMetricAttribute.Reason]: reason },\n })\n}\n\nfunction parseRoute(request: Request): Route {\n if (request.method !== 'GET')\n throw new RunlaneError({\n code: ErrorCode.ValidationFailed,\n message: 'Realtime routes require GET.',\n retryable: false,\n })\n const url = new URL(request.url)\n if (Array.from(url.searchParams.keys()).some((key) => key !== 'after') || url.searchParams.getAll('after').length > 1)\n throw invalidRequest('Only one after query parameter is accepted; use Authorization for credentials.')\n const match = /\\/runs\\/([^/]+)\\/(events|streams\\/([^/]+))$/.exec(url.pathname)\n if (match?.[1] === undefined)\n throw new RunlaneError({\n code: ErrorCode.RunNotFound,\n message: 'Realtime route was not found.',\n retryable: false,\n })\n let runId: RunId\n let name: string | undefined\n try {\n runId = runIdSchema.parse(decodeURIComponent(match[1]))\n name = match[3] === undefined ? undefined : runStreamNameSchema.parse(decodeURIComponent(match[3]))\n } catch (cause) {\n throw invalidRequest('Run id or stream name is invalid.', cause)\n }\n return { runId, ...(name === undefined ? {} : { name }), ...parseResumeCursor(request, url) }\n}\n\nfunction parseResumeCursor(request: Request, url: URL): Pick<Route, 'after'> {\n const header = request.headers.get('last-event-id')\n const query = url.searchParams.get('after')\n if (header !== null && query !== null && header !== query) throw invalidCursor()\n const raw = header ?? query\n const parsed = raw === null ? undefined : runCursorSchema.safeParse(raw)\n if (parsed !== undefined && !parsed.success) throw invalidCursor()\n return parsed?.success ? { after: parsed.data } : {}\n}\n\nasync function openConnection(\n options: RunlaneRealtimeOptions,\n request: Request,\n route: Route,\n grant: RunAccessGrant,\n token?: VerifiedRunToken,\n): Promise<Response> {\n const started = realtimeClock.now()\n const operation = route.name === undefined ? 'subscribe' : 'read'\n const control = new AbortController()\n const expires = Math.min(\n started + realtimeTiming.connectionDuration,\n token === undefined ? Infinity : token.expiresAt * 1000,\n )\n const stop = () => control.abort()\n request.signal.addEventListener('abort', stop, { once: true })\n if (request.signal.aborted) stop()\n const expiry = setTimeout(stop, Math.max(0, expires - realtimeClock.now()))\n const frames = sourceFrames(options.runlane, route, grant, control.signal)\n let pending: Promise<IteratorResult<Frame, void>> | undefined\n let cursor = route.after\n let closed = false\n const finish = () => {\n if (closed) return\n closed = true\n clearTimeout(expiry)\n request.signal.removeEventListener('abort', stop)\n control.abort()\n void frames.return().catch(() => undefined)\n recordRunlaneTelemetryMetric(options, {\n name: RunlaneMetricName.RealtimeConnectionDurationMs,\n value: Math.max(0, realtimeClock.now() - started),\n attributes: { [RunlaneMetricAttribute.Operation]: operation },\n })\n }\n const next = async (): Promise<Uint8Array | undefined> => {\n if (control.signal.aborted || realtimeClock.now() >= expires) return undefined\n pending ??= runWithRunlaneTelemetrySpan(\n options,\n { name: route.name === undefined ? RunlaneSpanName.RealtimeSubscribe : RunlaneSpanName.RealtimeRead },\n () => frames.next(),\n ).catch((cause: unknown) => {\n // Record the source failure before converting it to the public transport contract.\n const { cursor, ...error } = publicSourceError(cause)\n throw new RunlaneError({ ...error, cause, ...(cursor === undefined ? {} : { meta: { cursor } }) })\n })\n const timer = new AbortController()\n const abortTimer = () => timer.abort()\n control.signal.addEventListener('abort', abortTimer, { once: true })\n try {\n const result = await Promise.race([\n pending,\n waitForAbortableTimeout(realtimeTiming.heartbeatInterval, timer.signal).then(() => undefined),\n ])\n if (realtimeClock.now() >= expires) return undefined\n if (result === undefined) return encoder.encode(encode({ comment: 'heartbeat' }))\n pending = undefined\n if (result.done) return undefined\n const frame = result.value\n const bytes = encodeFrame(frame, cursor)\n cursor = frame.cursor ?? cursor\n return bytes\n } finally {\n timer.abort()\n control.signal.removeEventListener('abort', abortTimer)\n }\n }\n let first: Uint8Array | undefined\n try {\n first = await next()\n } catch (cause) {\n finish()\n throw cause\n }\n // No automatic prefetch: only a reader pull advances the core iterator.\n const body = new ReadableStream<Uint8Array>(\n {\n start(controller) {\n const end = () => {\n if (closed) return\n controller.close()\n finish()\n }\n control.signal.addEventListener('abort', end, { once: true })\n if (control.signal.aborted) end()\n },\n async pull(controller) {\n try {\n const bytes = control.signal.aborted || realtimeClock.now() >= expires ? undefined : (first ?? (await next()))\n if (closed) return\n first = undefined\n if (bytes === undefined) {\n controller.close()\n finish()\n return\n }\n controller.enqueue(bytes)\n } catch (cause) {\n if (closed) return\n controller.enqueue(\n encoder.encode(encode({ event: 'error', data: JSON.stringify(publicError(cause, cursor)) })),\n )\n controller.close()\n finish()\n }\n },\n cancel() {\n finish()\n },\n },\n { highWaterMark: 0 },\n )\n return new Response(body, {\n headers: {\n 'content-type': 'text/event-stream; charset=utf-8',\n 'cache-control': 'no-store',\n 'x-accel-buffering': 'no',\n },\n })\n}\n\nfunction encodeFrame(frame: Frame, cursor?: RunCursor): Uint8Array {\n const data = JSON.stringify(frame.data)\n const bytes = encoder.encode(\n encode({ event: frame.event, data, ...(frame.cursor === undefined ? {} : { id: frame.cursor }) }),\n )\n if (bytes.byteLength > realtimeDefaults.maxEventBytes)\n throw new RunlaneError({\n code: ErrorCode.EventTooLarge,\n message: 'Realtime event exceeds the serialized UTF-8 byte limit.',\n retryable: false,\n ...(cursor === undefined ? {} : { meta: { cursor } }),\n })\n return bytes\n}\n\nasync function* sourceFrames(\n source: RunlaneRealtimeSource,\n route: Route,\n grant: RunAccessGrant,\n signal: AbortSignal,\n): AsyncGenerator<Frame, void> {\n if (route.name === undefined) {\n for await (const event of source.runs.subscribe(route.runId, {\n after: route.after,\n signal,\n streams: grant.permissions.includes(RunReadPermission.Streams) ? grant.streams : false,\n })) {\n if (signal.aborted) return\n const projected = projectEvent(event, grant)\n yield projected === undefined\n ? { event: 'checkpoint', cursor: event.cursor, data: {} }\n : { event: projected.type, cursor: projected.cursor, data: projected }\n }\n if (!signal.aborted) yield { event: 'end', data: {} }\n return\n }\n yield* namedFrames(source, route.runId, route.name, route.after, signal)\n}\n\nasync function* namedFrames(\n source: RunlaneRealtimeSource,\n runId: RunId,\n name: string,\n initial: RunCursor | undefined,\n signal: AbortSignal,\n): AsyncGenerator<Frame, void> {\n let after = initial\n let terminal = false\n while (!signal.aborted) {\n const controller = new AbortController()\n const waiting = source.lane?.runSignal\n ?.wait({\n environment: source.environment,\n runId,\n signal: AbortSignal.any([signal, controller.signal]),\n timeoutMs: pollInterval,\n })\n .catch((cause: unknown) => {\n throw new RunlaneError({\n code: ErrorCode.AdapterContractViolation,\n message: 'Lane run signal wait must not reject.',\n cause,\n })\n })\n // A provider may reject before the page read finishes or while the consumer pauses.\n void waiting?.catch(() => undefined)\n try {\n const page = await source.runs.readStream(runId, name, { after, limit: contractDefaults.pagination.defaultLimit })\n yield* namedPageFrames(page, after)\n after = page.cursor\n if (page.hasMore) continue\n if (terminal && page.records.length === 0) {\n yield { event: 'end', data: {} }\n return\n }\n terminal = await readNamedRunTerminal(source, runId)\n if (terminal) continue\n if (page.records.length === 0) await (waiting ?? waitForAbortableTimeout(pollInterval, signal))\n } finally {\n controller.abort()\n await waiting\n }\n }\n}\n\nasync function readNamedRunTerminal(source: RunlaneRealtimeSource, runId: RunId): Promise<boolean> {\n const run = await source.runs.get(runId)\n if (run === undefined)\n throw new RunlaneError({\n code: ErrorCode.RunNotFound,\n message: 'Run was not found.',\n retryable: false,\n })\n return runStatusValues.isTerminal(run.status)\n}\n\nfunction* namedPageFrames(page: RunReadPage<RunStreamRecord>, after?: RunCursor): Generator<Frame, void> {\n for (const [index, record] of page.records.entries()) {\n const last = index === page.records.length - 1\n yield {\n event: 'stream',\n ...(last ? { cursor: page.cursor } : {}),\n data: { ...(last ? { cursor: page.cursor } : {}), record },\n }\n }\n if (page.records.length === 0 && page.cursor !== after) yield { event: 'checkpoint', cursor: page.cursor, data: {} }\n}\n\nfunction publicError(cause: unknown, cursor?: RunCursor): RealtimeErrorData {\n const checkpoint =\n cursor ?? (cause instanceof RunlaneError ? runCursorSchema.safeParse(cause.meta?.cursor).data : undefined)\n const resume = checkpoint === undefined ? {} : { cursor: checkpoint }\n if (cause instanceof RunlaneError) {\n const code = runRealtimeErrorCodeSchema.safeParse(cause.code)\n if (code.success && code.data !== ErrorCode.InternalError) {\n return { code: code.data, message: cause.message, retryable: cause.retryable, ...resume }\n }\n }\n return {\n code: ErrorCode.InternalError,\n message: 'Realtime request failed.',\n retryable: true,\n ...resume,\n }\n}\nfunction publicSourceError(cause: unknown): RealtimeErrorData {\n const error = publicError(cause)\n if (cause instanceof RunlaneError) {\n switch (cause.code) {\n case ErrorCode.ConfigurationInvalid:\n case ErrorCode.ValidationFailed:\n return { ...error, code: ErrorCode.ValidationFailed, message: 'Realtime request is invalid.', retryable: false }\n case ErrorCode.RunCursorInvalid:\n return { ...error, code: ErrorCode.RunCursorInvalid, message: 'Run cursor is invalid.', retryable: false }\n case ErrorCode.RunNotFound:\n return { ...error, code: ErrorCode.RunNotFound, message: 'Run was not found.', retryable: false }\n case ErrorCode.OperationCancelled:\n return {\n ...error,\n code: ErrorCode.Disconnected,\n message: 'Realtime runtime is closing; reconnect to resume.',\n retryable: true,\n }\n }\n }\n return error\n}\nfunction httpStatus(code: ErrorCode): number {\n if (code === ErrorCode.AccessDenied) return 403\n if (code === ErrorCode.RunNotFound) return 404\n if (code === ErrorCode.ValidationFailed || code === ErrorCode.RunCursorInvalid) return 400\n return 500\n}\nenum AccessDenialReason {\n ApplicationDenied = 'application_denied',\n AuthorizationHeader = 'authorization_header',\n VerificationUnconfigured = 'verification_unconfigured',\n TokenScope = 'token_scope',\n}\nconst accessDenialReasonSchema = z.enum(AccessDenialReason)\n\nfunction accessDenied(reason: AccessDenialReason = AccessDenialReason.ApplicationDenied): RunlaneError {\n return new RunlaneError({ code: ErrorCode.AccessDenied, message: 'Run access denied.', meta: { reason } })\n}\nfunction invalidRequest(message: string, cause?: unknown): RunlaneError {\n return new RunlaneError({ code: ErrorCode.ValidationFailed, message, retryable: false, cause })\n}\nfunction invalidCursor(): RunlaneError {\n return new RunlaneError({\n code: ErrorCode.RunCursorInvalid,\n message: 'Run cursor is invalid or conflicts with after.',\n retryable: false,\n })\n}\n\nasync function requestToken(\n request: Request,\n runId: RunId,\n options: RunlaneRealtimeOptions,\n verification: Parameters<typeof verifyRunToken>[1] | undefined,\n): Promise<VerifiedRunToken | undefined> {\n const supplied = request.headers.get('authorization')\n if (supplied === null) return undefined\n const match = /^Bearer ([a-z0-9_.-]+)$/i.exec(supplied)\n if (match?.[1] === undefined) throw accessDenied(AccessDenialReason.AuthorizationHeader)\n if (verification === undefined) throw accessDenied(AccessDenialReason.VerificationUnconfigured)\n const token = await verifyRunToken(\n match[1],\n verification,\n options,\n new URL(request.url).pathname.endsWith('/events') ? 'subscribe' : 'read',\n )\n if (token.runId !== runId || token.environment.name !== options.runlane.environment.name)\n throw accessDenied(AccessDenialReason.TokenScope)\n return token\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["RunReadPermission","encoder","RunReadPermission","RunlaneError","ErrorCode","z","RunlaneError","ErrorCode","RunReadPermission"],"sources":["../src/access.ts","../src/tokens.ts","../src/handler.ts"],"sourcesContent":["import {\n RunReadPermission,\n runRealtimeSnapshotSchema,\n RunSubscriptionEventType,\n type RunAccessGrant,\n type RunSubscriptionEvent,\n type RuntimeRunSubscriptionEvent,\n} from '@runlane/contracts/realtime'\n\nexport function intersectGrants(app: RunAccessGrant, token?: RunAccessGrant): RunAccessGrant {\n if (token === undefined) return app\n const permissions = app.permissions.filter((permission) => token.permissions.includes(permission))\n let streams = app.streams ?? token.streams\n if (app.streams !== undefined && token.streams !== undefined)\n streams = app.streams.filter((name) => token.streams?.includes(name))\n return { permissions, ...(streams === undefined ? {} : { streams }) }\n}\n\nexport function permitsStream(grant: RunAccessGrant, name: string): boolean {\n return (\n grant.permissions.includes(RunReadPermission.Streams) &&\n (grant.streams === undefined || grant.streams.includes(name))\n )\n}\n\nexport function projectEvent(\n event: RuntimeRunSubscriptionEvent,\n grant: RunAccessGrant,\n): RunSubscriptionEvent | undefined {\n if (event.type === RunSubscriptionEventType.Stream) return permitsStream(grant, event.record.name) ? event : undefined\n if (event.type === RunSubscriptionEventType.Meta)\n return grant.permissions.includes(RunReadPermission.Meta) ? event : undefined\n if (!grant.permissions.includes(RunReadPermission.Status)) return undefined\n if (event.type === RunSubscriptionEventType.Status) {\n const status = { ...event }\n if (!grant.permissions.includes(RunReadPermission.Output)) {\n delete status.output\n delete status.failure\n }\n if (status.failure !== undefined) {\n status.failure = runRealtimeSnapshotSchema.shape.failure.parse(status.failure)\n }\n return status\n }\n return { ...event, run: projectSnapshot(event.run, grant) }\n}\n\nfunction projectSnapshot(\n source: Extract<RunSubscriptionEvent, { type: RunSubscriptionEventType.Snapshot }>['run'],\n grant: RunAccessGrant,\n) {\n const { meta, output, failure, ...status } = runRealtimeSnapshotSchema.parse(source)\n return {\n ...status,\n ...(grant.permissions.includes(RunReadPermission.Meta) && meta !== undefined ? { meta } : {}),\n ...(grant.permissions.includes(RunReadPermission.Output)\n ? {\n ...(output === undefined ? {} : { output }),\n ...(failure === undefined ? {} : { failure }),\n }\n : {}),\n }\n}\n","import {\n createDurationSchema,\n ErrorCode,\n recordRunlaneTelemetryLog,\n recordRunlaneTelemetryMetric,\n runAccessGrantSchema,\n RunlaneError,\n RunlaneLogAttribute,\n RunlaneLogEventType,\n RunlaneLogLevel,\n RunlaneMetricAttribute,\n RunlaneMetricName,\n RunReadPermission,\n verifiedRunTokenSchema,\n type DurationString,\n type Environment,\n type RunlaneTelemetryRecordingContext,\n type VerifiedRunToken,\n} from '@runlane/contracts/realtime'\nimport { base64url, CompactSign, compactVerify } from 'jose'\nimport { z } from 'zod'\n\nimport { realtimeClock, realtimeTiming } from './time.js'\n\nconst tokenPartsSchema = z.tuple([z.string(), z.string(), z.string()])\nconst headerSchema = z.strictObject({ alg: z.literal('HS256'), typ: z.literal('JWT'), kid: z.string().min(1).max(128) })\nconst algorithmSchema = z.object({\n name: z.literal('HMAC'),\n hash: z.object({ name: z.literal('SHA-256') }),\n length: z.number().int().min(256),\n})\nconst encoder = new TextEncoder()\nconst decoder = new TextDecoder('utf-8', { fatal: true })\nconst maximumTokenLength = 16_384\n\n/** Strict construction schema; claim and header constraints remain the canonical owners. */\nexport const realtimeTokenOptionsSchema = z\n .strictObject({\n audience: verifiedRunTokenSchema.shape.audience,\n keyId: headerSchema.shape.kid,\n key: z.instanceof(CryptoKey),\n verifyKeys: z.record(headerSchema.shape.kid, z.instanceof(CryptoKey)).readonly().optional(),\n })\n .refine(\n (tokens) => !Object.hasOwn(tokens.verifyKeys ?? {}, tokens.keyId),\n 'tokens.keyId must not also appear in verifyKeys.',\n )\n\n/** Active signing/verification key and previous verify-only keys. Keep all keys server-side. */\nexport type RunlaneRealtimeTokenOptions = Readonly<z.output<typeof realtimeTokenOptionsSchema>>\n\nconst createTokenOptionsSchema = z.strictObject({\n // The complete claims schema validates and brands this identifier before signing.\n runId: z.string(),\n grant: runAccessGrantSchema.optional(),\n expiresIn: createDurationSchema('expiresIn must be whole seconds between 1s and realtime.maxTokenTTL.').optional(),\n})\n/** Minting inputs for one run. The app must check access before calling createToken. */\nexport type CreateRealtimeTokenOptions = Readonly<z.input<typeof createTokenOptionsSchema>> & {\n readonly expiresIn?: DurationString\n}\n\n/** Signs one run/environment/audience grant using an HMAC-SHA256 key of at least 256 bits. */\nexport async function signRunToken(\n environment: Environment,\n tokens: RunlaneRealtimeTokenOptions,\n input: CreateRealtimeTokenOptions,\n): Promise<string> {\n try {\n const options = createTokenOptionsSchema.parse(input)\n const header = headerSchema.parse({ alg: 'HS256', typ: 'JWT', kid: tokens.keyId })\n requireHmacKey(tokens.key, 'sign')\n const ttl = tokenLifetime(options.expiresIn?.milliseconds)\n const issuedAt = Math.floor(realtimeClock.now() / 1000)\n const claims = verifiedRunTokenSchema.parse({\n environment,\n runId: options.runId,\n grant: options.grant ?? { permissions: Object.values(RunReadPermission) },\n audience: tokens.audience,\n issuedAt,\n expiresAt: issuedAt + ttl / 1000,\n version: 1,\n })\n const token = await new CompactSign(encoder.encode(JSON.stringify(claims)))\n .setProtectedHeader(header)\n .sign(tokens.key)\n if (token.length > maximumTokenLength) throw invalidToken()\n return token\n } catch (cause) {\n if (cause instanceof RunlaneError) throw cause\n const message =\n cause instanceof z.ZodError\n ? `Token ${cause.issues[0]?.path.join('.') ?? 'expiresIn'} is invalid: ${cause.issues[0]?.message ?? 'Check the token options.'}`\n : 'Token signing failed; check key and claims.'\n const field = cause instanceof z.ZodError ? cause.issues[0]?.path[0] : undefined\n let code = ErrorCode.InternalError\n if (cause instanceof z.ZodError) {\n code =\n field === 'environment' || field === 'runId' || field === 'grant'\n ? ErrorCode.ValidationFailed\n : ErrorCode.ConfigurationInvalid\n }\n throw new RunlaneError({ code, message, retryable: false, cause })\n }\n}\n\nfunction tokenLifetime(ttl = realtimeTiming.tokenTTL): number {\n if (ttl < 1000 || ttl > realtimeTiming.maxTokenTTL || ttl % 1000 !== 0)\n throw new RunlaneError({\n code: ErrorCode.ConfigurationInvalid,\n message: 'expiresIn must be whole seconds between 1s and realtime.maxTokenTTL.',\n retryable: false,\n })\n return ttl\n}\n\n/** Verifies a scoped token and records only bounded rejection reasons through the supplied telemetry. */\nexport async function verifyRunToken(\n token: string,\n options: { readonly audience: string; readonly keys: Readonly<Record<string, CryptoKey>> },\n diagnostics: RunlaneTelemetryRecordingContext = {},\n operation = 'verify',\n): Promise<VerifiedRunToken> {\n let reason: TokenRejectionReason = TokenRejectionReason.Malformed\n try {\n if (token.length > maximumTokenLength) throw invalidToken()\n const [head, body, signature] = tokenPartsSchema.parse(token.split('.'))\n reason = TokenRejectionReason.Header\n const header = headerSchema.parse(JSON.parse(decoder.decode(decodeBase64(head))))\n reason = TokenRejectionReason.UnknownKey\n const key = Object.hasOwn(options.keys, header.kid) ? options.keys[header.kid] : undefined\n if (key === undefined) throw invalidToken()\n reason = TokenRejectionReason.Key\n requireHmacKey(key, 'verify')\n reason = TokenRejectionReason.Signature\n decodeBase64(signature)\n const verified = await compactVerify(token, key, { algorithms: ['HS256'] })\n reason = TokenRejectionReason.Claims\n decodeBase64(body)\n const claims = verifiedRunTokenSchema.parse(JSON.parse(decoder.decode(verified.payload)))\n const now = Math.floor(realtimeClock.now() / 1000)\n const rejection = tokenClaimRejection(claims, options.audience, now)\n if (rejection !== undefined) {\n reason = rejection\n throw invalidToken()\n }\n return claims\n } catch (cause) {\n recordRunlaneTelemetryMetric(diagnostics, {\n name: RunlaneMetricName.RealtimeTokenRejectedCount,\n value: 1,\n attributes: { [RunlaneMetricAttribute.Operation]: operation, [RunlaneMetricAttribute.Reason]: reason },\n })\n recordRunlaneTelemetryLog(diagnostics, {\n type: RunlaneLogEventType.RealtimeTokenRejected,\n level: RunlaneLogLevel.Warn,\n attributes: { [RunlaneLogAttribute.Operation]: operation, [RunlaneLogAttribute.Reason]: reason },\n })\n throw invalidToken(cause)\n }\n}\n\nfunction tokenClaimRejection(\n claims: VerifiedRunToken,\n audience: string,\n now: number,\n): TokenRejectionReason | undefined {\n if (claims.audience !== audience) return TokenRejectionReason.Audience\n if (claims.issuedAt > now + realtimeTiming.issuedAtLeeway / 1000) return TokenRejectionReason.IssuedAt\n if (claims.expiresAt <= now) return TokenRejectionReason.Expired\n if (claims.expiresAt <= claims.issuedAt || (claims.expiresAt - claims.issuedAt) * 1000 > realtimeTiming.maxTokenTTL)\n return TokenRejectionReason.Lifetime\n return undefined\n}\n\n/** Shared key policy for signing, verification, and handler startup checks. */\nexport function requireHmacKey(key: CryptoKey, usage: KeyUsage): void {\n if (\n !(key instanceof CryptoKey) ||\n key.type !== 'secret' ||\n !algorithmSchema.safeParse(key.algorithm).success ||\n !key.usages.includes(usage)\n )\n throw new RunlaneError({\n code: ErrorCode.ConfigurationInvalid,\n message: `key must be an HMAC-SHA256 key of at least 256 bits with ${usage} usage.`,\n retryable: false,\n })\n}\n\nfunction decodeBase64(value: string): Uint8Array {\n if (!/^[A-Za-z0-9_-]+$/.test(value)) throw invalidToken()\n const bytes = base64url.decode(value)\n if (base64url.encode(bytes) !== value) throw invalidToken()\n return bytes\n}\n\nfunction invalidToken(cause?: unknown): RunlaneError {\n return new RunlaneError({\n code: ErrorCode.AccessDenied,\n message: 'Run access denied.',\n retryable: false,\n cause,\n })\n}\n\nenum TokenRejectionReason {\n Malformed = 'malformed',\n Header = 'header',\n UnknownKey = 'unknown_key',\n Key = 'key',\n Signature = 'signature',\n Claims = 'claims',\n Audience = 'audience',\n IssuedAt = 'issued_at',\n Expired = 'expired',\n Lifetime = 'lifetime',\n}\n","import {\n contractDefaults,\n createDurationSchema,\n createRunlaneIdSchema,\n ErrorCode,\n realtimeDefaults,\n recordRunlaneTelemetryLog,\n recordRunlaneTelemetryMetric,\n runAccessGrantSchema,\n runCursorSchema,\n RunlaneError,\n RunlaneLogAttribute,\n RunlaneLogEventType,\n RunlaneLogLevel,\n RunlaneMetricAttribute,\n RunlaneMetricName,\n RunlaneSpanName,\n RunReadPermission,\n runRealtimeErrorCodeSchema,\n runStatusValues,\n runStreamNameSchema,\n runWithRunlaneTelemetrySpan,\n type RealtimeErrorData,\n type RunAccessGrant,\n type RunCursor,\n type RunId,\n type RunlaneTelemetryRecordingContext,\n type RunReadPage,\n type RunStreamRecord,\n type VerifiedRunToken,\n} from '@runlane/contracts/realtime'\nimport {\n createFunctionSchema,\n objectSurfaceSchema,\n waitForAbortableTimeout,\n type Awaitable,\n} from '@runlane/utilities/browser'\nimport { encode } from 'eventsource-encoder'\nimport * as z from 'zod'\n\nimport { intersectGrants, permitsStream, projectEvent } from './access.js'\nimport { invalidOptions } from './errors.js'\nimport { type RunlaneRealtimeSource } from './source.js'\nimport { realtimeClock, realtimeTiming } from './time.js'\nimport {\n realtimeTokenOptionsSchema,\n requireHmacKey,\n signRunToken,\n verifyRunToken,\n type CreateRealtimeTokenOptions,\n type RunlaneRealtimeTokenOptions,\n} from './tokens.js'\nimport { streamSelectionQuery } from './wire.js'\n\n/** Server options require authorize, tokens, or both. Configured authorization limits every valid connection. */\nexport interface RunlaneRealtimeOptions extends RunlaneTelemetryRecordingContext {\n readonly runlane: RunlaneRealtimeSource\n readonly authorize?: (input: {\n readonly request: Request\n readonly runId: RunId\n readonly token?: VerifiedRunToken\n }) => Awaitable<RunAccessGrant | undefined>\n readonly tokens?: RunlaneRealtimeTokenOptions\n}\n/** Authorization callback for a separately defined policy; undefined denies access to the run. */\nexport type RunlaneRealtimeAuthorize = NonNullable<RunlaneRealtimeOptions['authorize']>\n\n/** Server entry for authorized reads and request-independent token minting. */\nexport interface RunlaneRealtime {\n /** Serves SSE reads; authorize, when configured, limits every valid connection. */\n readonly handle: (request: Request) => Promise<Response>\n /** Mint after the app checks access. Does not call authorize or check run existence. */\n readonly createToken: (options: CreateRealtimeTokenOptions) => Promise<string>\n}\ninterface Route {\n readonly runId: RunId\n readonly name?: string\n readonly streams?: false\n readonly after?: RunCursor\n}\ninterface Frame {\n readonly event: string\n readonly cursor?: RunCursor\n readonly data: object\n}\nconst encoder = new TextEncoder()\nconst runIdSchema = createRunlaneIdSchema<'run'>('Run id')\nconst pollInterval = createDurationSchema().parse(contractDefaults.streams.pollInterval).milliseconds\n\nconst handlerOptionsSchema = z\n .strictObject({\n runlane: objectSurfaceSchema,\n authorize: createFunctionSchema<RunlaneRealtimeAuthorize>('authorize must be a function.').optional(),\n tokens: realtimeTokenOptionsSchema.optional(),\n telemetry: objectSurfaceSchema.optional(),\n onTelemetryError: createFunctionSchema<NonNullable<RunlaneRealtimeOptions['onTelemetryError']>>(\n 'onTelemetryError must be a function.',\n ).optional(),\n })\n .refine(\n (options) => options.authorize !== undefined || options.tokens !== undefined,\n 'Configure authorize for session access, tokens for bearer access, or both.',\n )\n\n/** Mounts authorized, bounded SSE reads without starting workers or adding runtime storage work. */\nexport function createRunlaneRealtime(options: RunlaneRealtimeOptions): RunlaneRealtime {\n const checked = handlerOptionsSchema.safeParse(options)\n if (!checked.success) throw invalidOptions(checked.error, 'handler')\n const tokens = checked.data.tokens\n if (tokens !== undefined) {\n requireHmacKey(tokens.key, 'sign')\n requireHmacKey(tokens.key, 'verify')\n for (const key of Object.values(tokens.verifyKeys ?? {})) requireHmacKey(key, 'verify')\n }\n const verification =\n tokens === undefined\n ? undefined\n : {\n audience: tokens.audience,\n keys: { ...tokens.verifyKeys, [tokens.keyId]: tokens.key },\n }\n return {\n async createToken(input) {\n if (tokens === undefined)\n throw new RunlaneError({\n code: ErrorCode.ConfigurationInvalid,\n message: 'Configure tokens before calling createToken.',\n })\n return signRunToken(options.runlane.environment, tokens, input)\n },\n async handle(request) {\n let operation = 'subscribe'\n try {\n const route = parseRoute(request)\n operation = route.name === undefined ? 'subscribe' : 'read'\n const token = await requestToken(request, route.runId, options, verification)\n const grant = await authorizeGrant(options, request, route, token, operation)\n return await openConnection(options, request, route, grant, token)\n } catch (cause) {\n const error = publicError(cause)\n if (error.code === ErrorCode.AccessDenied) recordDenial(options, cause, operation)\n return Response.json(\n { error },\n {\n status: request.method === 'GET' ? httpStatus(error.code) : 405,\n headers: { 'cache-control': 'no-store', ...(request.method === 'GET' ? {} : { allow: 'GET' }) },\n },\n )\n }\n },\n }\n}\n\nasync function authorizeGrant(\n options: RunlaneRealtimeOptions,\n request: Request,\n route: Route,\n token: VerifiedRunToken | undefined,\n operation: string,\n): Promise<RunAccessGrant> {\n let app: RunAccessGrant | undefined\n try {\n app =\n options.authorize === undefined\n ? token?.grant\n : await options.authorize({ request, runId: route.runId, ...(token === undefined ? {} : { token }) })\n } catch (cause) {\n recordRunlaneTelemetryMetric(options, {\n name: RunlaneMetricName.RealtimeAuthorizationErrorCount,\n value: 1,\n attributes: {\n [RunlaneMetricAttribute.Operation]: operation,\n [RunlaneMetricAttribute.Reason]: 'authorize_exception',\n },\n })\n recordRunlaneTelemetryLog(options, {\n type: RunlaneLogEventType.RealtimeAuthorizationFailed,\n level: RunlaneLogLevel.Error,\n attributes: {\n [RunlaneLogAttribute.Operation]: operation,\n [RunlaneLogAttribute.Reason]: 'authorize_exception',\n },\n })\n throw new RunlaneError({ code: ErrorCode.InternalError, message: 'Realtime authorization failed.', cause })\n }\n if (app === undefined) throw accessDenied()\n const parsed = runAccessGrantSchema.safeParse(app)\n if (!parsed.success) throw invalidRequest('Realtime grant is invalid.', parsed.error)\n const grant = intersectGrants(parsed.data, token?.grant)\n if (grant.permissions.length === 0 || (route.name !== undefined && !permitsStream(grant, route.name)))\n throw accessDenied()\n return grant\n}\n\nfunction recordDenial(options: RunlaneRealtimeOptions, cause: unknown, operation: string): void {\n const reason =\n accessDenialReasonSchema.safeParse(cause instanceof RunlaneError ? cause.meta?.reason : undefined).data ??\n 'token_rejected'\n if (reason !== 'token_rejected')\n recordRunlaneTelemetryLog(options, {\n type: RunlaneLogEventType.RealtimeAuthorizationDenied,\n level: RunlaneLogLevel.Warn,\n attributes: { [RunlaneLogAttribute.Operation]: operation, [RunlaneLogAttribute.Reason]: reason },\n })\n recordRunlaneTelemetryMetric(options, {\n name: RunlaneMetricName.RealtimeAuthorizationDeniedCount,\n value: 1,\n attributes: { [RunlaneMetricAttribute.Operation]: operation, [RunlaneMetricAttribute.Reason]: reason },\n })\n}\n\nfunction parseRoute(request: Request): Route {\n if (request.method !== 'GET')\n throw new RunlaneError({\n code: ErrorCode.ValidationFailed,\n message: 'Realtime routes require GET.',\n retryable: false,\n })\n const url = new URL(request.url)\n if (\n Array.from(url.searchParams.keys()).some((key) => key !== 'after' && key !== streamSelectionQuery.name) ||\n url.searchParams.getAll('after').length > 1\n )\n throw invalidRequest(\n 'Only one after and one streams query parameter are accepted; use Authorization for credentials.',\n )\n const match = /\\/runs\\/([^/]+)\\/(events|streams\\/([^/]+))$/.exec(url.pathname)\n if (match?.[1] === undefined)\n throw new RunlaneError({\n code: ErrorCode.RunNotFound,\n message: 'Realtime route was not found.',\n retryable: false,\n })\n let runId: RunId\n let name: string | undefined\n try {\n runId = runIdSchema.parse(decodeURIComponent(match[1]))\n name = match[3] === undefined ? undefined : runStreamNameSchema.parse(decodeURIComponent(match[3]))\n } catch (cause) {\n throw invalidRequest('Run id or stream name is invalid.', cause)\n }\n const selections = url.searchParams.getAll(streamSelectionQuery.name)\n if (\n selections.length > 1 ||\n (selections.length === 1 && (name !== undefined || selections[0] !== streamSelectionQuery.none))\n )\n throw invalidRequest('Stream selection requires one streams=none parameter on the events route.')\n return {\n runId,\n ...(name === undefined ? {} : { name }),\n ...(selections.length === 1 ? { streams: false } : {}),\n ...parseResumeCursor(request, url),\n }\n}\n\nfunction parseResumeCursor(request: Request, url: URL): Pick<Route, 'after'> {\n const header = request.headers.get('last-event-id')\n const query = url.searchParams.get('after')\n if (header !== null && query !== null && header !== query) throw invalidCursor()\n const raw = header ?? query\n const parsed = raw === null ? undefined : runCursorSchema.safeParse(raw)\n if (parsed !== undefined && !parsed.success) throw invalidCursor()\n return parsed?.success ? { after: parsed.data } : {}\n}\n\nasync function openConnection(\n options: RunlaneRealtimeOptions,\n request: Request,\n route: Route,\n grant: RunAccessGrant,\n token?: VerifiedRunToken,\n): Promise<Response> {\n const started = realtimeClock.now()\n const operation = route.name === undefined ? 'subscribe' : 'read'\n const control = new AbortController()\n const expires = Math.min(\n started + realtimeTiming.connectionDuration,\n token === undefined ? Infinity : token.expiresAt * 1000,\n )\n const stop = () => control.abort()\n request.signal.addEventListener('abort', stop, { once: true })\n if (request.signal.aborted) stop()\n const expiry = setTimeout(stop, Math.max(0, expires - realtimeClock.now()))\n const frames = sourceFrames(options.runlane, route, grant, control.signal)\n let pending: Promise<IteratorResult<Frame, void>> | undefined\n let cursor = route.after\n let closed = false\n const finish = () => {\n if (closed) return\n closed = true\n clearTimeout(expiry)\n request.signal.removeEventListener('abort', stop)\n control.abort()\n void frames.return().catch(() => undefined)\n recordRunlaneTelemetryMetric(options, {\n name: RunlaneMetricName.RealtimeConnectionDurationMs,\n value: Math.max(0, realtimeClock.now() - started),\n attributes: { [RunlaneMetricAttribute.Operation]: operation },\n })\n }\n const next = async (): Promise<Uint8Array | undefined> => {\n if (control.signal.aborted || realtimeClock.now() >= expires) return undefined\n pending ??= runWithRunlaneTelemetrySpan(\n options,\n { name: route.name === undefined ? RunlaneSpanName.RealtimeSubscribe : RunlaneSpanName.RealtimeRead },\n () => frames.next(),\n ).catch((cause: unknown) => {\n // Record the source failure before converting it to the public transport contract.\n const { cursor, ...error } = publicSourceError(cause)\n throw new RunlaneError({ ...error, cause, ...(cursor === undefined ? {} : { meta: { cursor } }) })\n })\n const timer = new AbortController()\n const abortTimer = () => timer.abort()\n control.signal.addEventListener('abort', abortTimer, { once: true })\n try {\n const result = await Promise.race([\n pending,\n waitForAbortableTimeout(realtimeTiming.heartbeatInterval, timer.signal).then(() => undefined),\n ])\n if (realtimeClock.now() >= expires) return undefined\n if (result === undefined) return encoder.encode(encode({ comment: 'heartbeat' }))\n pending = undefined\n if (result.done) return undefined\n const frame = result.value\n const bytes = encodeFrame(frame, cursor)\n cursor = frame.cursor ?? cursor\n return bytes\n } finally {\n timer.abort()\n control.signal.removeEventListener('abort', abortTimer)\n }\n }\n let first: Uint8Array | undefined\n try {\n first = await next()\n } catch (cause) {\n finish()\n throw cause\n }\n // No automatic prefetch: only a reader pull advances the core iterator.\n const body = new ReadableStream<Uint8Array>(\n {\n start(controller) {\n const end = () => {\n if (closed) return\n controller.close()\n finish()\n }\n control.signal.addEventListener('abort', end, { once: true })\n if (control.signal.aborted) end()\n },\n async pull(controller) {\n try {\n const bytes = control.signal.aborted || realtimeClock.now() >= expires ? undefined : (first ?? (await next()))\n if (closed) return\n first = undefined\n if (bytes === undefined) {\n controller.close()\n finish()\n return\n }\n controller.enqueue(bytes)\n } catch (cause) {\n if (closed) return\n controller.enqueue(\n encoder.encode(encode({ event: 'error', data: JSON.stringify(publicError(cause, cursor)) })),\n )\n controller.close()\n finish()\n }\n },\n cancel() {\n finish()\n },\n },\n { highWaterMark: 0 },\n )\n return new Response(body, {\n headers: {\n 'content-type': 'text/event-stream; charset=utf-8',\n 'cache-control': 'no-store',\n 'x-accel-buffering': 'no',\n },\n })\n}\n\nfunction encodeFrame(frame: Frame, cursor?: RunCursor): Uint8Array {\n const data = JSON.stringify(frame.data)\n const bytes = encoder.encode(\n encode({ event: frame.event, data, ...(frame.cursor === undefined ? {} : { id: frame.cursor }) }),\n )\n if (bytes.byteLength > realtimeDefaults.maxEventBytes)\n throw new RunlaneError({\n code: ErrorCode.EventTooLarge,\n message: 'Realtime event exceeds the serialized UTF-8 byte limit.',\n retryable: false,\n ...(cursor === undefined ? {} : { meta: { cursor } }),\n })\n return bytes\n}\n\nasync function* sourceFrames(\n source: RunlaneRealtimeSource,\n route: Route,\n grant: RunAccessGrant,\n signal: AbortSignal,\n): AsyncGenerator<Frame, void> {\n if (route.name === undefined) {\n for await (const event of source.runs.subscribe(route.runId, {\n after: route.after,\n signal,\n streams:\n route.streams === false || !grant.permissions.includes(RunReadPermission.Streams) ? false : grant.streams,\n })) {\n if (signal.aborted) return\n const projected = projectEvent(event, grant)\n yield projected === undefined\n ? { event: 'checkpoint', cursor: event.cursor, data: {} }\n : { event: projected.type, cursor: projected.cursor, data: projected }\n }\n if (!signal.aborted) yield { event: 'end', data: {} }\n return\n }\n yield* namedFrames(source, route.runId, route.name, route.after, signal)\n}\n\nasync function* namedFrames(\n source: RunlaneRealtimeSource,\n runId: RunId,\n name: string,\n initial: RunCursor | undefined,\n signal: AbortSignal,\n): AsyncGenerator<Frame, void> {\n let after = initial\n let terminal = false\n while (!signal.aborted) {\n const controller = new AbortController()\n const waiting = source.lane?.runSignal\n ?.wait({\n environment: source.environment,\n runId,\n signal: AbortSignal.any([signal, controller.signal]),\n timeoutMs: pollInterval,\n })\n .catch((cause: unknown) => {\n throw new RunlaneError({\n code: ErrorCode.AdapterContractViolation,\n message: 'Lane run signal wait must not reject.',\n cause,\n })\n })\n // A provider may reject before the page read finishes or while the consumer pauses.\n void waiting?.catch(() => undefined)\n try {\n const page = await source.runs.readStream(runId, name, { after, limit: contractDefaults.pagination.defaultLimit })\n yield* namedPageFrames(page, after)\n after = page.cursor\n if (page.hasMore) continue\n if (terminal && page.records.length === 0) {\n yield { event: 'end', data: {} }\n return\n }\n terminal = await readNamedRunTerminal(source, runId)\n if (terminal) continue\n if (page.records.length === 0) await (waiting ?? waitForAbortableTimeout(pollInterval, signal))\n } finally {\n controller.abort()\n await waiting\n }\n }\n}\n\nasync function readNamedRunTerminal(source: RunlaneRealtimeSource, runId: RunId): Promise<boolean> {\n const run = await source.runs.get(runId)\n if (run === undefined)\n throw new RunlaneError({\n code: ErrorCode.RunNotFound,\n message: 'Run was not found.',\n retryable: false,\n })\n return runStatusValues.isTerminal(run.status)\n}\n\nfunction* namedPageFrames(page: RunReadPage<RunStreamRecord>, after?: RunCursor): Generator<Frame, void> {\n for (const [index, record] of page.records.entries()) {\n const last = index === page.records.length - 1\n yield {\n event: 'stream',\n ...(last ? { cursor: page.cursor } : {}),\n data: { ...(last ? { cursor: page.cursor } : {}), record },\n }\n }\n if (page.records.length === 0 && page.cursor !== after) yield { event: 'checkpoint', cursor: page.cursor, data: {} }\n}\n\nfunction publicError(cause: unknown, cursor?: RunCursor): RealtimeErrorData {\n const checkpoint =\n cursor ?? (cause instanceof RunlaneError ? runCursorSchema.safeParse(cause.meta?.cursor).data : undefined)\n const resume = checkpoint === undefined ? {} : { cursor: checkpoint }\n if (cause instanceof RunlaneError) {\n const code = runRealtimeErrorCodeSchema.safeParse(cause.code)\n if (code.success && code.data !== ErrorCode.InternalError) {\n return { code: code.data, message: cause.message, retryable: cause.retryable, ...resume }\n }\n }\n return {\n code: ErrorCode.InternalError,\n message: 'Realtime request failed.',\n retryable: true,\n ...resume,\n }\n}\nfunction publicSourceError(cause: unknown): RealtimeErrorData {\n const error = publicError(cause)\n if (cause instanceof RunlaneError) {\n switch (cause.code) {\n case ErrorCode.ConfigurationInvalid:\n case ErrorCode.ValidationFailed:\n return { ...error, code: ErrorCode.ValidationFailed, message: 'Realtime request is invalid.', retryable: false }\n case ErrorCode.RunCursorInvalid:\n return { ...error, code: ErrorCode.RunCursorInvalid, message: 'Run cursor is invalid.', retryable: false }\n case ErrorCode.RunNotFound:\n return { ...error, code: ErrorCode.RunNotFound, message: 'Run was not found.', retryable: false }\n case ErrorCode.OperationCancelled:\n return {\n ...error,\n code: ErrorCode.Disconnected,\n message: 'Realtime runtime is closing; reconnect to resume.',\n retryable: true,\n }\n }\n }\n return error\n}\nfunction httpStatus(code: ErrorCode): number {\n if (code === ErrorCode.AccessDenied) return 403\n if (code === ErrorCode.RunNotFound) return 404\n if (code === ErrorCode.ValidationFailed || code === ErrorCode.RunCursorInvalid) return 400\n return 500\n}\nenum AccessDenialReason {\n ApplicationDenied = 'application_denied',\n AuthorizationHeader = 'authorization_header',\n VerificationUnconfigured = 'verification_unconfigured',\n TokenScope = 'token_scope',\n}\nconst accessDenialReasonSchema = z.enum(AccessDenialReason)\n\nfunction accessDenied(reason: AccessDenialReason = AccessDenialReason.ApplicationDenied): RunlaneError {\n return new RunlaneError({ code: ErrorCode.AccessDenied, message: 'Run access denied.', meta: { reason } })\n}\nfunction invalidRequest(message: string, cause?: unknown): RunlaneError {\n return new RunlaneError({ code: ErrorCode.ValidationFailed, message, retryable: false, cause })\n}\nfunction invalidCursor(): RunlaneError {\n return new RunlaneError({\n code: ErrorCode.RunCursorInvalid,\n message: 'Run cursor is invalid or conflicts with after.',\n retryable: false,\n })\n}\n\nasync function requestToken(\n request: Request,\n runId: RunId,\n options: RunlaneRealtimeOptions,\n verification: Parameters<typeof verifyRunToken>[1] | undefined,\n): Promise<VerifiedRunToken | undefined> {\n const supplied = request.headers.get('authorization')\n if (supplied === null) return undefined\n const match = /^Bearer ([a-z0-9_.-]+)$/i.exec(supplied)\n if (match?.[1] === undefined) throw accessDenied(AccessDenialReason.AuthorizationHeader)\n if (verification === undefined) throw accessDenied(AccessDenialReason.VerificationUnconfigured)\n const token = await verifyRunToken(\n match[1],\n verification,\n options,\n new URL(request.url).pathname.endsWith('/events') ? 'subscribe' : 'read',\n )\n if (token.runId !== runId || token.environment.name !== options.runlane.environment.name)\n throw accessDenied(AccessDenialReason.TokenScope)\n return token\n}\n"],"mappings":"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"}
@@ -32,6 +32,22 @@ const realtimeTiming = {
32
32
  clientReconnectDelay: createDurationSchema().parse(realtimeDefaults.clientReconnectDelay).milliseconds,
33
33
  clientMaxReconnectDelay: createDurationSchema().parse(realtimeDefaults.clientMaxReconnectDelay).milliseconds
34
34
  };
35
- export { wireInvalid as i, realtimeTiming as n, invalidOptions as r, realtimeClock as t };
35
+ // src/wire.ts
36
+ /** Events-route query that omits stream records; shared by the client and handler, documented in the realtime reference. */
37
+ const streamSelectionQuery = {
38
+ name: "streams",
39
+ none: "none"
40
+ };
41
+ const encoder = new TextEncoder();
42
+ /** Parses JSON within the serialized UTF-8 event bound. Storage owns application value validation. */
43
+ function parseWireJson(text) {
44
+ try {
45
+ if (encoder.encode(text).byteLength > realtimeDefaults.maxEventBytes) throw wireInvalid();
46
+ return JSON.parse(text);
47
+ } catch (cause) {
48
+ throw wireInvalid(cause);
49
+ }
50
+ }
51
+ export { invalidOptions as a, realtimeTiming as i, streamSelectionQuery as n, wireInvalid as o, realtimeClock as r, parseWireJson as t };
36
52
 
37
- //# sourceMappingURL=time-sHQYGDPD.mjs.map
53
+ //# sourceMappingURL=wire-BEevjo-K.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire-BEevjo-K.mjs","names":[],"sources":["../src/errors.ts","../src/time.ts","../src/wire.ts"],"sourcesContent":["import { ErrorCode, RunlaneError } from '@runlane/contracts/realtime'\nimport { getShallowestZodIssue, getZodIssueMessage } from '@runlane/utilities/browser'\nimport { type ZodError } from 'zod'\n\nexport function wireInvalid(cause?: unknown): RunlaneError {\n return new RunlaneError({\n code: ErrorCode.WireInvalid,\n message: 'Realtime response is malformed.',\n cause,\n })\n}\n\n/** Maps strict construction options to actionable local errors while retaining schema diagnostics. */\nexport function invalidOptions(cause: ZodError, owner: string): RunlaneError {\n const issue = getShallowestZodIssue(cause.issues)\n const message = getZodIssueMessage(issue, {\n fallbackMessage: `Realtime ${owner} options are invalid.`,\n unsupportedKeyMessage: (key) =>\n `Realtime ${owner} option \"${[...(issue?.path ?? []), key].join('.')}\" is not supported.`,\n })\n return new RunlaneError({\n code: ErrorCode.ConfigurationInvalid,\n message:\n issue?.path.length && issue.code !== 'custom' && issue.code !== 'unrecognized_keys'\n ? `${issue.path.join('.')}: ${message}`\n : message,\n cause,\n })\n}\n","import { createDurationSchema, realtimeDefaults } from '@runlane/contracts/realtime'\n\n// Time is an internal effect boundary, shared by signing, verification, and connection expiry.\nexport const realtimeClock = { now: () => Date.now() }\nexport const realtimeTiming = {\n tokenTTL: createDurationSchema().parse(realtimeDefaults.tokenTTL).milliseconds,\n issuedAtLeeway: createDurationSchema().parse(realtimeDefaults.issuedAtLeeway).milliseconds,\n maxTokenTTL: createDurationSchema().parse(realtimeDefaults.maxTokenTTL).milliseconds,\n connectionDuration: createDurationSchema().parse(realtimeDefaults.connectionDuration).milliseconds,\n heartbeatInterval: createDurationSchema().parse(realtimeDefaults.heartbeatInterval).milliseconds,\n clientReconnectDelay: createDurationSchema().parse(realtimeDefaults.clientReconnectDelay).milliseconds,\n clientMaxReconnectDelay: createDurationSchema().parse(realtimeDefaults.clientMaxReconnectDelay).milliseconds,\n}\n","import { realtimeDefaults } from '@runlane/contracts/realtime'\n\nimport { wireInvalid } from './errors.js'\n\n/** Events-route query that omits stream records; shared by the client and handler, documented in the realtime reference. */\nexport const streamSelectionQuery = { name: 'streams', none: 'none' }\n\nconst encoder = new TextEncoder()\n\n/** Parses JSON within the serialized UTF-8 event bound. Storage owns application value validation. */\nexport function parseWireJson(text: string): unknown {\n try {\n if (encoder.encode(text).byteLength > realtimeDefaults.maxEventBytes) throw wireInvalid()\n return JSON.parse(text)\n } catch (cause) {\n throw wireInvalid(cause)\n }\n}\n"],"mappings":";;;AAIA,SAAgB,YAAY,OAA+B;CACzD,OAAO,IAAI,aAAa;EACtB,MAAM,UAAU;EAChB,SAAS;EACT;CACF,CAAC;AACH;;AAGA,SAAgB,eAAe,OAAiB,OAA6B;CAC3E,MAAM,QAAQ,sBAAsB,MAAM,MAAM;CAChD,MAAM,UAAU,mBAAmB,OAAO;EACxC,iBAAiB,YAAY,MAAM;EACnC,wBAAwB,QACtB,YAAY,MAAM,WAAW,CAAC,GAAI,OAAO,QAAQ,CAAC,GAAI,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE;CACzE,CAAC;CACD,OAAO,IAAI,aAAa;EACtB,MAAM,UAAU;EAChB,SACE,OAAO,KAAK,UAAU,MAAM,SAAS,YAAY,MAAM,SAAS,sBAC5D,GAAG,MAAM,KAAK,KAAK,GAAG,EAAE,IAAI,YAC5B;EACN;CACF,CAAC;AACH;;ACzBA,MAAa,gBAAgB,EAAE,WAAW,KAAK,IAAI,EAAE;AACrD,MAAa,iBAAiB;CAC5B,UAAU,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,QAAQ,CAAC,CAAC;CAClE,gBAAgB,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,cAAc,CAAC,CAAC;CAC9E,aAAa,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,WAAW,CAAC,CAAC;CACxE,oBAAoB,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,kBAAkB,CAAC,CAAC;CACtF,mBAAmB,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,iBAAiB,CAAC,CAAC;CACpF,sBAAsB,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,oBAAoB,CAAC,CAAC;CAC1F,yBAAyB,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,uBAAuB,CAAC,CAAC;AAClG;;;ACPA,MAAa,uBAAuB;CAAE,MAAM;CAAW,MAAM;AAAO;AAEpE,MAAM,UAAU,IAAI,YAAY;;AAGhC,SAAgB,cAAc,MAAuB;CACnD,IAAI;EACF,IAAI,QAAQ,OAAO,IAAI,CAAC,CAAC,aAAa,iBAAiB,eAAe,MAAM,YAAY;EACxF,OAAO,KAAK,MAAM,IAAI;CACxB,SAAS,OAAO;EACd,MAAM,YAAY,KAAK;CACzB;AACF"}
@@ -53,6 +53,22 @@ const realtimeTiming = {
53
53
  clientReconnectDelay: (0, _runlane_contracts_realtime.createDurationSchema)().parse(_runlane_contracts_realtime.realtimeDefaults.clientReconnectDelay).milliseconds,
54
54
  clientMaxReconnectDelay: (0, _runlane_contracts_realtime.createDurationSchema)().parse(_runlane_contracts_realtime.realtimeDefaults.clientMaxReconnectDelay).milliseconds
55
55
  };
56
+ // src/wire.ts
57
+ /** Events-route query that omits stream records; shared by the client and handler, documented in the realtime reference. */
58
+ const streamSelectionQuery = {
59
+ name: "streams",
60
+ none: "none"
61
+ };
62
+ const encoder = new TextEncoder();
63
+ /** Parses JSON within the serialized UTF-8 event bound. Storage owns application value validation. */
64
+ function parseWireJson(text) {
65
+ try {
66
+ if (encoder.encode(text).byteLength > _runlane_contracts_realtime.realtimeDefaults.maxEventBytes) throw wireInvalid();
67
+ return JSON.parse(text);
68
+ } catch (cause) {
69
+ throw wireInvalid(cause);
70
+ }
71
+ }
56
72
  Object.defineProperty(exports, "__toESM", {
57
73
  enumerable: true,
58
74
  get: function() {
@@ -65,6 +81,12 @@ Object.defineProperty(exports, "invalidOptions", {
65
81
  return invalidOptions;
66
82
  }
67
83
  });
84
+ Object.defineProperty(exports, "parseWireJson", {
85
+ enumerable: true,
86
+ get: function() {
87
+ return parseWireJson;
88
+ }
89
+ });
68
90
  Object.defineProperty(exports, "realtimeClock", {
69
91
  enumerable: true,
70
92
  get: function() {
@@ -77,6 +99,12 @@ Object.defineProperty(exports, "realtimeTiming", {
77
99
  return realtimeTiming;
78
100
  }
79
101
  });
102
+ Object.defineProperty(exports, "streamSelectionQuery", {
103
+ enumerable: true,
104
+ get: function() {
105
+ return streamSelectionQuery;
106
+ }
107
+ });
80
108
  Object.defineProperty(exports, "wireInvalid", {
81
109
  enumerable: true,
82
110
  get: function() {
@@ -84,4 +112,4 @@ Object.defineProperty(exports, "wireInvalid", {
84
112
  }
85
113
  });
86
114
 
87
- //# sourceMappingURL=time-BhORZuav.cjs.map
115
+ //# sourceMappingURL=wire-xCr4QuVn.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire-xCr4QuVn.cjs","names":["RunlaneError","ErrorCode","getShallowestZodIssue","getZodIssueMessage","createDurationSchema","realtimeDefaults","realtimeDefaults"],"sources":["../src/errors.ts","../src/time.ts","../src/wire.ts"],"sourcesContent":["import { ErrorCode, RunlaneError } from '@runlane/contracts/realtime'\nimport { getShallowestZodIssue, getZodIssueMessage } from '@runlane/utilities/browser'\nimport { type ZodError } from 'zod'\n\nexport function wireInvalid(cause?: unknown): RunlaneError {\n return new RunlaneError({\n code: ErrorCode.WireInvalid,\n message: 'Realtime response is malformed.',\n cause,\n })\n}\n\n/** Maps strict construction options to actionable local errors while retaining schema diagnostics. */\nexport function invalidOptions(cause: ZodError, owner: string): RunlaneError {\n const issue = getShallowestZodIssue(cause.issues)\n const message = getZodIssueMessage(issue, {\n fallbackMessage: `Realtime ${owner} options are invalid.`,\n unsupportedKeyMessage: (key) =>\n `Realtime ${owner} option \"${[...(issue?.path ?? []), key].join('.')}\" is not supported.`,\n })\n return new RunlaneError({\n code: ErrorCode.ConfigurationInvalid,\n message:\n issue?.path.length && issue.code !== 'custom' && issue.code !== 'unrecognized_keys'\n ? `${issue.path.join('.')}: ${message}`\n : message,\n cause,\n })\n}\n","import { createDurationSchema, realtimeDefaults } from '@runlane/contracts/realtime'\n\n// Time is an internal effect boundary, shared by signing, verification, and connection expiry.\nexport const realtimeClock = { now: () => Date.now() }\nexport const realtimeTiming = {\n tokenTTL: createDurationSchema().parse(realtimeDefaults.tokenTTL).milliseconds,\n issuedAtLeeway: createDurationSchema().parse(realtimeDefaults.issuedAtLeeway).milliseconds,\n maxTokenTTL: createDurationSchema().parse(realtimeDefaults.maxTokenTTL).milliseconds,\n connectionDuration: createDurationSchema().parse(realtimeDefaults.connectionDuration).milliseconds,\n heartbeatInterval: createDurationSchema().parse(realtimeDefaults.heartbeatInterval).milliseconds,\n clientReconnectDelay: createDurationSchema().parse(realtimeDefaults.clientReconnectDelay).milliseconds,\n clientMaxReconnectDelay: createDurationSchema().parse(realtimeDefaults.clientMaxReconnectDelay).milliseconds,\n}\n","import { realtimeDefaults } from '@runlane/contracts/realtime'\n\nimport { wireInvalid } from './errors.js'\n\n/** Events-route query that omits stream records; shared by the client and handler, documented in the realtime reference. */\nexport const streamSelectionQuery = { name: 'streams', none: 'none' }\n\nconst encoder = new TextEncoder()\n\n/** Parses JSON within the serialized UTF-8 event bound. Storage owns application value validation. */\nexport function parseWireJson(text: string): unknown {\n try {\n if (encoder.encode(text).byteLength > realtimeDefaults.maxEventBytes) throw wireInvalid()\n return JSON.parse(text)\n } catch (cause) {\n throw wireInvalid(cause)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAIA,SAAgB,YAAY,OAA+B;CACzD,OAAO,IAAIA,4BAAAA,aAAa;EACtB,MAAMC,4BAAAA,UAAU;EAChB,SAAS;EACT;CACF,CAAC;AACH;;AAGA,SAAgB,eAAe,OAAiB,OAA6B;CAC3E,MAAM,SAAA,GAAQC,2BAAAA,sBAAAA,CAAsB,MAAM,MAAM;CAChD,MAAM,WAAA,GAAUC,2BAAAA,mBAAAA,CAAmB,OAAO;EACxC,iBAAiB,YAAY,MAAM;EACnC,wBAAwB,QACtB,YAAY,MAAM,WAAW,CAAC,GAAI,OAAO,QAAQ,CAAC,GAAI,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE;CACzE,CAAC;CACD,OAAO,IAAIH,4BAAAA,aAAa;EACtB,MAAMC,4BAAAA,UAAU;EAChB,SACE,OAAO,KAAK,UAAU,MAAM,SAAS,YAAY,MAAM,SAAS,sBAC5D,GAAG,MAAM,KAAK,KAAK,GAAG,EAAE,IAAI,YAC5B;EACN;CACF,CAAC;AACH;;ACzBA,MAAa,gBAAgB,EAAE,WAAW,KAAK,IAAI,EAAE;AACrD,MAAa,iBAAiB;CAC5B,WAAA,GAAUG,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,QAAQ,CAAC,CAAC;CAClE,iBAAA,GAAgBD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,cAAc,CAAC,CAAC;CAC9E,cAAA,GAAaD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,WAAW,CAAC,CAAC;CACxE,qBAAA,GAAoBD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,kBAAkB,CAAC,CAAC;CACtF,oBAAA,GAAmBD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,iBAAiB,CAAC,CAAC;CACpF,uBAAA,GAAsBD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,oBAAoB,CAAC,CAAC;CAC1F,0BAAA,GAAyBD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,uBAAuB,CAAC,CAAC;AAClG;;;ACPA,MAAa,uBAAuB;CAAE,MAAM;CAAW,MAAM;AAAO;AAEpE,MAAM,UAAU,IAAI,YAAY;;AAGhC,SAAgB,cAAc,MAAuB;CACnD,IAAI;EACF,IAAI,QAAQ,OAAO,IAAI,CAAC,CAAC,aAAaC,4BAAAA,iBAAiB,eAAe,MAAM,YAAY;EACxF,OAAO,KAAK,MAAM,IAAI;CACxB,SAAS,OAAO;EACd,MAAM,YAAY,KAAK;CACzB;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runlane/realtime",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Fetch realtime handler, scoped run tokens, and browser streaming client.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -58,8 +58,8 @@
58
58
  "eventsource-parser": "^4.1.2",
59
59
  "jose": "^6.2.13",
60
60
  "zod": "^4.5.4",
61
- "@runlane/contracts": "0.5.0",
62
- "@runlane/utilities": "0.5.0"
61
+ "@runlane/contracts": "0.5.1",
62
+ "@runlane/utilities": "0.5.1"
63
63
  },
64
64
  "devDependencies": {
65
65
  "typescript": "^6.0.3",
@@ -68,10 +68,10 @@
68
68
  "@repo/tsdown": "0.0.0",
69
69
  "@repo/typescript": "0.0.0",
70
70
  "@repo/vitest": "0.0.0",
71
- "@runlane/core": "0.5.0",
72
- "@runlane/lane-local": "0.5.0",
73
- "@runlane/lane-postgres-polling": "0.5.0",
74
- "@runlane/postgres-storage": "0.5.0"
71
+ "@runlane/core": "0.5.1",
72
+ "@runlane/lane-local": "0.5.1",
73
+ "@runlane/lane-postgres-polling": "0.5.1",
74
+ "@runlane/postgres-storage": "0.5.1"
75
75
  },
76
76
  "scripts": {
77
77
  "build": "tsdown",
@@ -1 +0,0 @@
1
- {"version":3,"file":"time-BhORZuav.cjs","names":["RunlaneError","ErrorCode","getShallowestZodIssue","getZodIssueMessage","createDurationSchema","realtimeDefaults"],"sources":["../src/errors.ts","../src/time.ts"],"sourcesContent":["import { ErrorCode, RunlaneError } from '@runlane/contracts/realtime'\nimport { getShallowestZodIssue, getZodIssueMessage } from '@runlane/utilities/browser'\nimport { type ZodError } from 'zod'\n\nexport function wireInvalid(cause?: unknown): RunlaneError {\n return new RunlaneError({\n code: ErrorCode.WireInvalid,\n message: 'Realtime response is malformed.',\n cause,\n })\n}\n\n/** Maps strict construction options to actionable local errors while retaining schema diagnostics. */\nexport function invalidOptions(cause: ZodError, owner: string): RunlaneError {\n const issue = getShallowestZodIssue(cause.issues)\n const message = getZodIssueMessage(issue, {\n fallbackMessage: `Realtime ${owner} options are invalid.`,\n unsupportedKeyMessage: (key) =>\n `Realtime ${owner} option \"${[...(issue?.path ?? []), key].join('.')}\" is not supported.`,\n })\n return new RunlaneError({\n code: ErrorCode.ConfigurationInvalid,\n message:\n issue?.path.length && issue.code !== 'custom' && issue.code !== 'unrecognized_keys'\n ? `${issue.path.join('.')}: ${message}`\n : message,\n cause,\n })\n}\n","import { createDurationSchema, realtimeDefaults } from '@runlane/contracts/realtime'\n\n// Time is an internal effect boundary, shared by signing, verification, and connection expiry.\nexport const realtimeClock = { now: () => Date.now() }\nexport const realtimeTiming = {\n tokenTTL: createDurationSchema().parse(realtimeDefaults.tokenTTL).milliseconds,\n issuedAtLeeway: createDurationSchema().parse(realtimeDefaults.issuedAtLeeway).milliseconds,\n maxTokenTTL: createDurationSchema().parse(realtimeDefaults.maxTokenTTL).milliseconds,\n connectionDuration: createDurationSchema().parse(realtimeDefaults.connectionDuration).milliseconds,\n heartbeatInterval: createDurationSchema().parse(realtimeDefaults.heartbeatInterval).milliseconds,\n clientReconnectDelay: createDurationSchema().parse(realtimeDefaults.clientReconnectDelay).milliseconds,\n clientMaxReconnectDelay: createDurationSchema().parse(realtimeDefaults.clientMaxReconnectDelay).milliseconds,\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAIA,SAAgB,YAAY,OAA+B;CACzD,OAAO,IAAIA,4BAAAA,aAAa;EACtB,MAAMC,4BAAAA,UAAU;EAChB,SAAS;EACT;CACF,CAAC;AACH;;AAGA,SAAgB,eAAe,OAAiB,OAA6B;CAC3E,MAAM,SAAA,GAAQC,2BAAAA,sBAAAA,CAAsB,MAAM,MAAM;CAChD,MAAM,WAAA,GAAUC,2BAAAA,mBAAAA,CAAmB,OAAO;EACxC,iBAAiB,YAAY,MAAM;EACnC,wBAAwB,QACtB,YAAY,MAAM,WAAW,CAAC,GAAI,OAAO,QAAQ,CAAC,GAAI,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE;CACzE,CAAC;CACD,OAAO,IAAIH,4BAAAA,aAAa;EACtB,MAAMC,4BAAAA,UAAU;EAChB,SACE,OAAO,KAAK,UAAU,MAAM,SAAS,YAAY,MAAM,SAAS,sBAC5D,GAAG,MAAM,KAAK,KAAK,GAAG,EAAE,IAAI,YAC5B;EACN;CACF,CAAC;AACH;;ACzBA,MAAa,gBAAgB,EAAE,WAAW,KAAK,IAAI,EAAE;AACrD,MAAa,iBAAiB;CAC5B,WAAA,GAAUG,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,QAAQ,CAAC,CAAC;CAClE,iBAAA,GAAgBD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,cAAc,CAAC,CAAC;CAC9E,cAAA,GAAaD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,WAAW,CAAC,CAAC;CACxE,qBAAA,GAAoBD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,kBAAkB,CAAC,CAAC;CACtF,oBAAA,GAAmBD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,iBAAiB,CAAC,CAAC;CACpF,uBAAA,GAAsBD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,oBAAoB,CAAC,CAAC;CAC1F,0BAAA,GAAyBD,4BAAAA,qBAAAA,CAAqB,CAAC,CAAC,MAAMC,4BAAAA,iBAAiB,uBAAuB,CAAC,CAAC;AAClG"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"time-sHQYGDPD.mjs","names":[],"sources":["../src/errors.ts","../src/time.ts"],"sourcesContent":["import { ErrorCode, RunlaneError } from '@runlane/contracts/realtime'\nimport { getShallowestZodIssue, getZodIssueMessage } from '@runlane/utilities/browser'\nimport { type ZodError } from 'zod'\n\nexport function wireInvalid(cause?: unknown): RunlaneError {\n return new RunlaneError({\n code: ErrorCode.WireInvalid,\n message: 'Realtime response is malformed.',\n cause,\n })\n}\n\n/** Maps strict construction options to actionable local errors while retaining schema diagnostics. */\nexport function invalidOptions(cause: ZodError, owner: string): RunlaneError {\n const issue = getShallowestZodIssue(cause.issues)\n const message = getZodIssueMessage(issue, {\n fallbackMessage: `Realtime ${owner} options are invalid.`,\n unsupportedKeyMessage: (key) =>\n `Realtime ${owner} option \"${[...(issue?.path ?? []), key].join('.')}\" is not supported.`,\n })\n return new RunlaneError({\n code: ErrorCode.ConfigurationInvalid,\n message:\n issue?.path.length && issue.code !== 'custom' && issue.code !== 'unrecognized_keys'\n ? `${issue.path.join('.')}: ${message}`\n : message,\n cause,\n })\n}\n","import { createDurationSchema, realtimeDefaults } from '@runlane/contracts/realtime'\n\n// Time is an internal effect boundary, shared by signing, verification, and connection expiry.\nexport const realtimeClock = { now: () => Date.now() }\nexport const realtimeTiming = {\n tokenTTL: createDurationSchema().parse(realtimeDefaults.tokenTTL).milliseconds,\n issuedAtLeeway: createDurationSchema().parse(realtimeDefaults.issuedAtLeeway).milliseconds,\n maxTokenTTL: createDurationSchema().parse(realtimeDefaults.maxTokenTTL).milliseconds,\n connectionDuration: createDurationSchema().parse(realtimeDefaults.connectionDuration).milliseconds,\n heartbeatInterval: createDurationSchema().parse(realtimeDefaults.heartbeatInterval).milliseconds,\n clientReconnectDelay: createDurationSchema().parse(realtimeDefaults.clientReconnectDelay).milliseconds,\n clientMaxReconnectDelay: createDurationSchema().parse(realtimeDefaults.clientMaxReconnectDelay).milliseconds,\n}\n"],"mappings":";;;AAIA,SAAgB,YAAY,OAA+B;CACzD,OAAO,IAAI,aAAa;EACtB,MAAM,UAAU;EAChB,SAAS;EACT;CACF,CAAC;AACH;;AAGA,SAAgB,eAAe,OAAiB,OAA6B;CAC3E,MAAM,QAAQ,sBAAsB,MAAM,MAAM;CAChD,MAAM,UAAU,mBAAmB,OAAO;EACxC,iBAAiB,YAAY,MAAM;EACnC,wBAAwB,QACtB,YAAY,MAAM,WAAW,CAAC,GAAI,OAAO,QAAQ,CAAC,GAAI,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE;CACzE,CAAC;CACD,OAAO,IAAI,aAAa;EACtB,MAAM,UAAU;EAChB,SACE,OAAO,KAAK,UAAU,MAAM,SAAS,YAAY,MAAM,SAAS,sBAC5D,GAAG,MAAM,KAAK,KAAK,GAAG,EAAE,IAAI,YAC5B;EACN;CACF,CAAC;AACH;;ACzBA,MAAa,gBAAgB,EAAE,WAAW,KAAK,IAAI,EAAE;AACrD,MAAa,iBAAiB;CAC5B,UAAU,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,QAAQ,CAAC,CAAC;CAClE,gBAAgB,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,cAAc,CAAC,CAAC;CAC9E,aAAa,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,WAAW,CAAC,CAAC;CACxE,oBAAoB,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,kBAAkB,CAAC,CAAC;CACtF,mBAAmB,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,iBAAiB,CAAC,CAAC;CACpF,sBAAsB,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,oBAAoB,CAAC,CAAC;CAC1F,yBAAyB,qBAAqB,CAAC,CAAC,MAAM,iBAAiB,uBAAuB,CAAC,CAAC;AAClG"}