@fluid-app/droplet-bridge 0.0.0-stage → 0.1.0
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/README.md +119 -2
- package/dist/index.cjs +1248 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +243 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +243 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1214 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +43 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["exactOrigin","abortable","supportsSdk","Errors.FluidBridgeConfigurationError","Errors.FluidBridgeHostUnavailableError","Errors.FluidBridgeHandshakeTimeoutError","Errors.FluidBridgeRequestTimeoutError","Errors.FluidBridgeIncompatibleVersionError","Errors.FluidBridgeInvalidContextError","Errors.FluidBridgeFailedAuthenticationError","Errors.FluidBridgeUnauthorizedError","Errors.FluidBridgeForbiddenOriginError","Errors.FluidBridgeTokenMintError"],"sources":["../src/errors.ts","../src/protocol.ts","../src/host.ts","../src/canonical-protocol.ts","../src/canonical-host.ts","../src/session-token-api.ts","../src/client-fetch.ts","../src/canonical-client.ts"],"sourcesContent":["export type FluidBridgeErrorCode =\n | \"configuration_error\"\n | \"host_unavailable\"\n | \"handshake_timeout\"\n | \"incompatible_version\"\n | \"token_mint_failed\"\n | \"unauthorized\"\n | \"forbidden_origin\"\n | \"invalid_context\"\n | \"request_timeout\"\n | \"fetch_target_not_allowed\"\n | \"network_error\"\n | \"failed_authentication\";\n\nexport class FluidBridgeError extends Error {\n readonly code: FluidBridgeErrorCode;\n readonly details?: unknown;\n\n constructor(code: FluidBridgeErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = \"FluidBridgeError\";\n this.code = code;\n this.details = details;\n }\n}\n\nexport class FluidBridgeConfigurationError extends FluidBridgeError {\n constructor(message: string, details?: unknown) {\n super(\"configuration_error\", message, details);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class FluidBridgeHostUnavailableError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host is unavailable\",\n details?: unknown,\n ) {\n super(\"host_unavailable\", message, details);\n this.name = \"HostUnavailableError\";\n }\n}\n\nexport class FluidBridgeHandshakeTimeoutError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host did not respond before the handshake timed out\",\n details?: unknown,\n ) {\n super(\"handshake_timeout\", message, details);\n this.name = \"HandshakeTimeoutError\";\n }\n}\n\nexport class FluidBridgeIncompatibleVersionError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge SDK is not compatible with the host\",\n details?: unknown,\n ) {\n super(\"incompatible_version\", message, details);\n this.name = \"IncompatibleVersionError\";\n }\n}\n\nexport class FluidBridgeTokenMintError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host could not mint a session token\",\n details?: unknown,\n ) {\n super(\"token_mint_failed\", message, details);\n this.name = \"TokenMintFailedError\";\n }\n}\n\nexport class FluidBridgeUnauthorizedError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge request is unauthorized\",\n details?: unknown,\n ) {\n super(\"unauthorized\", message, details);\n this.name = \"UnauthorizedError\";\n }\n}\n\nexport class FluidBridgeForbiddenOriginError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host origin is forbidden\",\n details?: unknown,\n ) {\n super(\"forbidden_origin\", message, details);\n this.name = \"ForbiddenOriginError\";\n }\n}\n\nexport class FluidBridgeInvalidContextError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge context is invalid\",\n details?: unknown,\n ) {\n super(\"invalid_context\", message, details);\n this.name = \"InvalidContextError\";\n }\n}\n\nexport class FluidBridgeRequestTimeoutError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge request timed out\",\n details?: unknown,\n ) {\n super(\"request_timeout\", message, details);\n this.name = \"RequestTimeoutError\";\n }\n}\n\nexport class FluidBridgeFetchTargetError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge fetch target is not allowed\",\n details?: unknown,\n ) {\n super(\"fetch_target_not_allowed\", message, details);\n this.name = \"FetchTargetNotAllowedError\";\n }\n}\n\nexport class FluidBridgeNetworkError extends FluidBridgeError {\n constructor(message = \"Fluid App Bridge fetch failed\", details?: unknown) {\n super(\"network_error\", message, details);\n this.name = \"NetworkError\";\n }\n}\n\nexport class FluidBridgeFailedAuthenticationError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge authentication failed\",\n details?: unknown,\n ) {\n super(\"failed_authentication\", message, details);\n this.name = \"FailedAuthenticationError\";\n }\n}\n","export const FLUID_BRIDGE_PROTOCOL_VERSION = \"2026-07\";\nexport const APP_BRIDGE_SDK_NAME = \"@fluid-app/droplet-bridge\";\nexport const APP_BRIDGE_SDK_VERSION = \"0.1.0\";\n\nexport const FluidBridgeMessageType = {\n SessionTokenRequest: \"FLUID::SESSION_TOKEN_REQUEST\",\n SessionTokenRespond: \"FLUID::SESSION_TOKEN_RESPOND\",\n ContextRequest: \"FLUID::CONTEXT_REQUEST\",\n ContextRespond: \"FLUID::CONTEXT_RESPOND\",\n FailedAuthentication: \"FLUID::ERROR::FAILED_AUTHENTICATION\",\n Unauthorized: \"FLUID::ERROR::UNAUTHORIZED\",\n IncompatibleVersion: \"FLUID::ERROR::INCOMPATIBLE_VERSION\",\n TokenMintFailed: \"FLUID::ERROR::TOKEN_MINT_FAILED\",\n InvalidContext: \"FLUID::ERROR::INVALID_CONTEXT\",\n} as const;\n\nexport type FluidBridgeMessageTypeValue =\n (typeof FluidBridgeMessageType)[keyof typeof FluidBridgeMessageType];\n\nexport type BridgeActorType = \"admin\" | \"member\" | \"customer\" | \"anonymous\";\nexport type BridgeEntryType =\n | \"droplet\"\n | \"drop_zone\"\n | \"mobile_embed\"\n | \"portal_embed\"\n | \"app_extension\";\n\nexport interface BridgeResource {\n type: string;\n id: string;\n}\n\nexport interface BridgeContext {\n protocol: typeof FLUID_BRIDGE_PROTOCOL_VERSION;\n app: { clientId: string };\n store: { subdomain: string; url: string; uuid?: string; name?: string };\n actor?: {\n type: BridgeActorType;\n uuid?: string;\n roles?: string[];\n permissions?: string[];\n memberType?: string;\n };\n entry: { type: BridgeEntryType; name?: string };\n resources: BridgeResource[];\n fetch: { allowedOrigins: string[] };\n sdk: { minVersion: string; recommendedVersion?: string };\n}\n\nexport interface BridgeEnvelope<TType extends string, TPayload> {\n id: string;\n type: TType;\n payload: TPayload;\n}\n","import {\n FLUID_BRIDGE_PROTOCOL_VERSION,\n FluidBridgeMessageType,\n type BridgeContext,\n type BridgeEnvelope,\n} from \"./protocol\";\nimport {\n FluidBridgeFailedAuthenticationError,\n FluidBridgeForbiddenOriginError,\n FluidBridgeIncompatibleVersionError,\n FluidBridgeInvalidContextError,\n FluidBridgeTokenMintError,\n FluidBridgeUnauthorizedError,\n type FluidBridgeErrorCode,\n} from \"./errors\";\n\ntype RequestPayload = {\n clientId: string;\n protocol: typeof FLUID_BRIDGE_PROTOCOL_VERSION;\n};\n\ntype HostErrorPayload = {\n code: FluidBridgeErrorCode;\n message: string;\n details?: unknown;\n};\n\nexport interface CreateFluidBridgeHostOptions {\n iframe: HTMLIFrameElement;\n appOrigin: string;\n clientId: string;\n getContext: () => BridgeContext | Promise<BridgeContext>;\n getSessionToken: (context: BridgeContext) => string | Promise<string>;\n targetWindow?: Window;\n}\n\nexport interface FluidBridgeHost {\n destroy: () => void;\n}\n\nexport function createFluidBridgeHost(\n options: CreateFluidBridgeHostOptions,\n): FluidBridgeHost {\n const targetWindow = options.targetWindow ?? window;\n const appOrigin = normalizeOrigin(options.appOrigin);\n\n const handleMessage = (event: MessageEvent<unknown>): void => {\n if (event.origin !== appOrigin) return;\n if (event.source !== options.iframe.contentWindow) return;\n if (!isBridgeEnvelope(event.data)) return;\n\n void respondToBridgeMessage(options, event.data, appOrigin);\n };\n\n targetWindow.addEventListener(\"message\", handleMessage);\n\n return {\n destroy: () => targetWindow.removeEventListener(\"message\", handleMessage),\n };\n}\n\nasync function respondToBridgeMessage(\n options: CreateFluidBridgeHostOptions,\n envelope: BridgeEnvelope<string, unknown>,\n appOrigin: string,\n): Promise<void> {\n const childWindow = options.iframe.contentWindow;\n if (!childWindow) return;\n\n try {\n validateRequestPayload(envelope.payload, options.clientId);\n\n switch (envelope.type) {\n case FluidBridgeMessageType.ContextRequest: {\n const context = await options.getContext();\n childWindow.postMessage(\n {\n id: envelope.id,\n type: FluidBridgeMessageType.ContextRespond,\n payload: context,\n } satisfies BridgeEnvelope<\n typeof FluidBridgeMessageType.ContextRespond,\n BridgeContext\n >,\n appOrigin,\n );\n return;\n }\n case FluidBridgeMessageType.SessionTokenRequest: {\n const context = await options.getContext();\n const sessionToken = await options.getSessionToken(context);\n if (sessionToken.length === 0) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge host returned an empty session token\",\n );\n }\n childWindow.postMessage(\n {\n id: envelope.id,\n type: FluidBridgeMessageType.SessionTokenRespond,\n payload: { sessionToken },\n } satisfies BridgeEnvelope<\n typeof FluidBridgeMessageType.SessionTokenRespond,\n { sessionToken: string }\n >,\n appOrigin,\n );\n return;\n }\n default:\n throw new FluidBridgeForbiddenOriginError(\n \"Fluid App Bridge host received an unsupported message type\",\n { type: envelope.type },\n );\n }\n } catch (error) {\n childWindow.postMessage(\n {\n id: envelope.id,\n type: errorTypeFor(error),\n payload: errorPayloadFor(error),\n } satisfies BridgeEnvelope<string, HostErrorPayload>,\n appOrigin,\n );\n }\n}\n\nfunction validateRequestPayload(\n value: unknown,\n clientId: string,\n): RequestPayload {\n if (typeof value !== \"object\" || value === null) {\n throw new FluidBridgeInvalidContextError(\n \"Fluid App Bridge request payload is invalid\",\n );\n }\n if (!(\"clientId\" in value) || value.clientId !== clientId) {\n throw new FluidBridgeFailedAuthenticationError(\n \"Fluid App Bridge request client ID does not match the host context\",\n );\n }\n if (\n !(\"protocol\" in value) ||\n value.protocol !== FLUID_BRIDGE_PROTOCOL_VERSION\n ) {\n throw new FluidBridgeIncompatibleVersionError();\n }\n return value as RequestPayload;\n}\n\nfunction isBridgeEnvelope(\n value: unknown,\n): value is BridgeEnvelope<string, unknown> {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n return (\n \"id\" in value &&\n \"type\" in value &&\n \"payload\" in value &&\n typeof value.id === \"string\" &&\n typeof value.type === \"string\"\n );\n}\n\nfunction errorTypeFor(error: unknown): string {\n if (error instanceof FluidBridgeFailedAuthenticationError) {\n return FluidBridgeMessageType.FailedAuthentication;\n }\n if (error instanceof FluidBridgeIncompatibleVersionError) {\n return FluidBridgeMessageType.IncompatibleVersion;\n }\n if (error instanceof FluidBridgeUnauthorizedError) {\n return FluidBridgeMessageType.Unauthorized;\n }\n if (error instanceof FluidBridgeTokenMintError) {\n return FluidBridgeMessageType.TokenMintFailed;\n }\n if (error instanceof FluidBridgeInvalidContextError) {\n return FluidBridgeMessageType.InvalidContext;\n }\n if (error instanceof FluidBridgeForbiddenOriginError) {\n return FluidBridgeMessageType.InvalidContext;\n }\n return FluidBridgeMessageType.TokenMintFailed;\n}\n\nfunction errorPayloadFor(error: unknown): HostErrorPayload {\n if (\n error instanceof Error &&\n \"code\" in error &&\n typeof error.code === \"string\"\n ) {\n return {\n code: error.code as FluidBridgeErrorCode,\n message: error.message,\n details: \"details\" in error ? error.details : undefined,\n };\n }\n return {\n code: \"token_mint_failed\",\n message: \"Fluid App Bridge host could not complete the request\",\n details: error,\n };\n}\n\nfunction normalizeOrigin(origin: string): string {\n return new URL(origin).origin;\n}\n","const protocolVersion = \"1\" as const;\n\nexport const BRIDGE_PROTOCOL_VERSION: typeof protocolVersion = protocolVersion;\n\nexport type BridgeMessageType =\n | \"bridge.ready\"\n | \"session_token.deliver\"\n | \"session_token.refresh_request\"\n | \"context.deliver\"\n | \"nav.request\"\n | \"nav.ack\"\n | \"nav.reject\"\n | \"modal.open\"\n | \"modal.close\"\n | \"toast.show\"\n | \"redirect.request\"\n | \"error\";\n\nexport type BridgeMessageDirection =\n | \"iframe-to-shell\"\n | \"shell-to-iframe\"\n | \"both\";\n\nexport type BridgeResponseExpectation =\n | false\n | {\n readonly messageTypes: readonly BridgeMessageType[];\n readonly correlation: \"request_id\" | \"lifecycle\";\n };\n\nexport type BridgePayloadShape =\n | { readonly kind: \"unknown\" }\n | { readonly kind: \"string\"; readonly nonEmpty?: boolean }\n | { readonly kind: \"string-array\" }\n | { readonly kind: \"absolute-origin-array\" }\n | {\n readonly kind: \"string-enum\";\n readonly values: readonly string[];\n }\n | {\n readonly kind: \"record\";\n readonly values: BridgePayloadShape;\n }\n | {\n readonly kind: \"array\";\n readonly items: BridgePayloadShape;\n }\n | {\n readonly kind: \"object\";\n readonly required?: Readonly<Record<string, BridgePayloadShape>>;\n readonly optional?: Readonly<Record<string, BridgePayloadShape>>;\n readonly additionalProperties?: boolean;\n };\n\nexport interface BridgeMessageCatalogEntry {\n readonly direction: BridgeMessageDirection;\n readonly expectsResponse: BridgeResponseExpectation;\n readonly payloadShape: BridgePayloadShape;\n}\n\nexport type BridgeMessageCatalog = Readonly<\n Record<BridgeMessageType, BridgeMessageCatalogEntry>\n>;\n\nexport type CanonicalBridgeActorType = \"store_admin\" | \"store_member\";\n\nexport type CanonicalBridgeEntryType =\n | \"droplet\"\n | \"drop_zone\"\n | \"mobile_embed\"\n | \"portal_embed\"\n | \"app_extension\";\n\nexport interface CanonicalBridgeResource {\n type: string;\n id: string;\n}\n\nexport interface CanonicalBridgeContext {\n protocolVersion: typeof BRIDGE_PROTOCOL_VERSION;\n app: { clientId: string };\n store: {\n subdomain: string;\n url: string;\n uuid?: string;\n name?: string;\n /** Authenticated viewer’s active language. Present when the host provides one. */\n locale?: string;\n };\n actor: {\n type: CanonicalBridgeActorType;\n uuid?: string;\n roles?: string[];\n permissions?: string[];\n memberType?: string;\n };\n entry: { type: CanonicalBridgeEntryType; name?: string };\n resources: CanonicalBridgeResource[];\n fetch: { allowedOrigins: string[] };\n sdk: {\n minVersion: string;\n recommendedVersion?: string;\n };\n}\n\nexport type EmptyBridgePayload = Readonly<Record<string, never>>;\n\nexport interface SessionTokenDeliverPayload {\n sessionToken: string;\n}\n\nexport interface SessionTokenRefreshRequestPayload {\n clientId: string;\n sdkVersion: string;\n protocolVersion: string;\n}\n\nexport interface NavigationRequestPayload {\n target: string;\n params: Record<string, unknown>;\n}\n\nexport interface NavigationRejectPayload {\n reason: string;\n}\n\nexport interface BridgeErrorPayload {\n code: string;\n message: string;\n details?: Record<string, unknown>;\n}\n\nexport interface BridgeMessagePayloads {\n readonly \"bridge.ready\": EmptyBridgePayload;\n readonly \"session_token.deliver\": SessionTokenDeliverPayload;\n readonly \"session_token.refresh_request\": SessionTokenRefreshRequestPayload;\n readonly \"context.deliver\": CanonicalBridgeContext;\n readonly \"nav.request\": NavigationRequestPayload;\n readonly \"nav.ack\": EmptyBridgePayload;\n readonly \"nav.reject\": NavigationRejectPayload;\n readonly \"modal.open\": Readonly<Record<string, unknown>>;\n readonly \"modal.close\": EmptyBridgePayload;\n readonly \"toast.show\": Readonly<Record<string, unknown>>;\n readonly \"redirect.request\": Readonly<Record<string, unknown>>;\n readonly error: BridgeErrorPayload;\n}\n\nexport type CanonicalBridgeEnvelope<\n TType extends BridgeMessageType = BridgeMessageType,\n> = TType extends BridgeMessageType\n ? {\n type: TType;\n payload: BridgeMessagePayloads[TType];\n request_id: string;\n version: typeof BRIDGE_PROTOCOL_VERSION;\n }\n : never;\n\nconst unknownShape: BridgePayloadShape = { kind: \"unknown\" };\nconst stringShape: BridgePayloadShape = { kind: \"string\" };\nconst nonEmptyStringShape: BridgePayloadShape = {\n kind: \"string\",\n nonEmpty: true,\n};\nconst emptyObjectShape: BridgePayloadShape = { kind: \"object\" };\nconst unspecifiedObjectShape: BridgePayloadShape = {\n kind: \"object\",\n additionalProperties: true,\n};\nconst stringArrayShape: BridgePayloadShape = { kind: \"string-array\" };\nconst absoluteOriginArrayShape: BridgePayloadShape = {\n kind: \"absolute-origin-array\",\n};\n\nconst bridgeContextShape: BridgePayloadShape = {\n kind: \"object\",\n required: {\n protocolVersion: {\n kind: \"string-enum\",\n values: [BRIDGE_PROTOCOL_VERSION],\n },\n app: {\n kind: \"object\",\n required: { clientId: nonEmptyStringShape },\n },\n store: {\n kind: \"object\",\n required: {\n subdomain: nonEmptyStringShape,\n url: nonEmptyStringShape,\n },\n optional: {\n uuid: stringShape,\n name: stringShape,\n locale: nonEmptyStringShape,\n },\n },\n actor: {\n kind: \"object\",\n required: {\n type: {\n kind: \"string-enum\",\n values: [\"store_admin\", \"store_member\"],\n },\n },\n optional: {\n uuid: stringShape,\n roles: stringArrayShape,\n permissions: stringArrayShape,\n memberType: stringShape,\n },\n },\n entry: {\n kind: \"object\",\n required: {\n type: {\n kind: \"string-enum\",\n values: [\n \"droplet\",\n \"drop_zone\",\n \"mobile_embed\",\n \"portal_embed\",\n \"app_extension\",\n ],\n },\n },\n optional: { name: stringShape },\n },\n resources: {\n kind: \"array\",\n items: {\n kind: \"object\",\n required: { type: nonEmptyStringShape, id: nonEmptyStringShape },\n },\n },\n fetch: {\n kind: \"object\",\n required: { allowedOrigins: absoluteOriginArrayShape },\n },\n sdk: {\n kind: \"object\",\n required: { minVersion: nonEmptyStringShape },\n optional: { recommendedVersion: stringShape },\n },\n },\n};\n\nexport const BRIDGE_MESSAGE_CATALOG: BridgeMessageCatalog = {\n \"bridge.ready\": {\n direction: \"iframe-to-shell\",\n expectsResponse: false,\n payloadShape: emptyObjectShape,\n },\n \"session_token.deliver\": {\n direction: \"shell-to-iframe\",\n expectsResponse: false,\n payloadShape: {\n kind: \"object\",\n required: { sessionToken: nonEmptyStringShape },\n },\n },\n \"session_token.refresh_request\": {\n direction: \"iframe-to-shell\",\n expectsResponse: {\n messageTypes: [\"session_token.deliver\"],\n correlation: \"request_id\",\n },\n payloadShape: {\n kind: \"object\",\n required: {\n clientId: nonEmptyStringShape,\n sdkVersion: nonEmptyStringShape,\n protocolVersion: nonEmptyStringShape,\n },\n },\n },\n \"context.deliver\": {\n direction: \"shell-to-iframe\",\n expectsResponse: false,\n payloadShape: bridgeContextShape,\n },\n \"nav.request\": {\n direction: \"iframe-to-shell\",\n expectsResponse: {\n messageTypes: [\"nav.ack\", \"nav.reject\"],\n correlation: \"request_id\",\n },\n payloadShape: {\n kind: \"object\",\n required: {\n target: nonEmptyStringShape,\n params: { kind: \"record\", values: unknownShape },\n },\n },\n },\n \"nav.ack\": {\n direction: \"shell-to-iframe\",\n expectsResponse: false,\n payloadShape: emptyObjectShape,\n },\n \"nav.reject\": {\n direction: \"shell-to-iframe\",\n expectsResponse: false,\n payloadShape: {\n kind: \"object\",\n required: { reason: nonEmptyStringShape },\n },\n },\n \"modal.open\": {\n direction: \"iframe-to-shell\",\n expectsResponse: {\n messageTypes: [\"modal.close\"],\n correlation: \"lifecycle\",\n },\n // Phase 004 defines the handler payload once the shell-owned UI contract lands.\n payloadShape: unspecifiedObjectShape,\n },\n \"modal.close\": {\n direction: \"shell-to-iframe\",\n expectsResponse: false,\n payloadShape: emptyObjectShape,\n },\n \"toast.show\": {\n direction: \"iframe-to-shell\",\n expectsResponse: false,\n // Phase 004 defines the handler payload once the shell-owned UI contract lands.\n payloadShape: unspecifiedObjectShape,\n },\n \"redirect.request\": {\n direction: \"iframe-to-shell\",\n expectsResponse: false,\n // Phase 004 defines the target shape and enforces its redirect allowlist.\n payloadShape: unspecifiedObjectShape,\n },\n error: {\n direction: \"both\",\n expectsResponse: false,\n payloadShape: {\n kind: \"object\",\n required: {\n code: nonEmptyStringShape,\n message: nonEmptyStringShape,\n },\n optional: {\n details: { kind: \"record\", values: unknownShape },\n },\n },\n },\n};\n\nexport interface ParseBridgeEnvelopeOptions {\n readonly receivedBy: \"shell\" | \"iframe\";\n}\n\nexport type BridgeEnvelopeParseFailureReason =\n | \"malformed\"\n | \"version_mismatch\"\n | \"unknown_type\"\n | \"invalid_payload\"\n | \"wrong_direction\";\n\nexport type BridgeEnvelopeParseResult =\n | { readonly ok: true; readonly envelope: CanonicalBridgeEnvelope }\n | {\n readonly ok: false;\n readonly reason: BridgeEnvelopeParseFailureReason;\n readonly requestId?: string;\n };\n\nexport function parseBridgeEnvelope(\n value: unknown,\n options: ParseBridgeEnvelopeOptions,\n): BridgeEnvelopeParseResult {\n try {\n if (!isRecord(value)) {\n return { ok: false, reason: \"malformed\" };\n }\n\n // Only a well-formed id is correlatable. Echoing an attacker-supplied string back in an\n // `error` envelope would produce a message the peer rejects as malformed, swallowing the\n // version-mismatch report the spec requires it to receive.\n const requestId =\n typeof value.request_id === \"string\" &&\n uuidV7Pattern.test(value.request_id)\n ? value.request_id\n : undefined;\n\n if (!hasExactKeys(value, envelopeKeys)) {\n return parseFailure(\"malformed\", requestId);\n }\n\n if (value.version !== BRIDGE_PROTOCOL_VERSION) {\n return parseFailure(\"version_mismatch\", requestId);\n }\n\n if (\n typeof value.type !== \"string\" ||\n typeof value.request_id !== \"string\" ||\n !uuidV7Pattern.test(value.request_id)\n ) {\n return parseFailure(\"malformed\", requestId);\n }\n\n if (!isBridgeMessageType(value.type)) {\n return parseFailure(\"unknown_type\", requestId);\n }\n\n const catalogEntry = BRIDGE_MESSAGE_CATALOG[value.type];\n if (!isDirectionAllowed(catalogEntry.direction, options.receivedBy)) {\n return parseFailure(\"wrong_direction\", requestId);\n }\n\n if (!matchesPayloadShape(value.payload, catalogEntry.payloadShape)) {\n return parseFailure(\"invalid_payload\", requestId);\n }\n\n return { ok: true, envelope: value as CanonicalBridgeEnvelope };\n } catch {\n return { ok: false, reason: \"malformed\" };\n }\n}\n\nexport function isBridgeEnvelope(\n value: unknown,\n options: ParseBridgeEnvelopeOptions,\n): value is CanonicalBridgeEnvelope {\n return parseBridgeEnvelope(value, options).ok;\n}\n\nexport function isTimedRequest(type: BridgeMessageType): boolean {\n const expectation = BRIDGE_MESSAGE_CATALOG[type].expectsResponse;\n return expectation !== false && expectation.correlation === \"request_id\";\n}\n\nconst envelopeKeys: readonly string[] = [\n \"type\",\n \"payload\",\n \"request_id\",\n \"version\",\n];\n\nconst uuidV7Pattern: RegExp =\n /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return false;\n }\n\n // Structured clone carries Date, Map, Set and other exotic objects across\n // postMessage intact, and every one of them is `typeof \"object\"`. Only a\n // plain or null-prototype object is a record for payload purposes.\n const prototype: unknown = Object.getPrototypeOf(value);\n\n return prototype === Object.prototype || prototype === null;\n}\n\n// Internal: True when every index in an array is actually present and the array carries\n// nothing else. `Array.prototype.every` skips holes, so a sparse array like `Array(1)`\n// satisfies any per-item predicate while yielding `undefined` to a consumer that the\n// validated type promised a value. Counting keys alone is not enough: structured clone\n// keeps named properties, so `Array(1)` plus `extra` has as many keys as it has length.\n// The key count is checked first so the index scan is bounded by what the sender\n// actually cloned, never by a claimed length like `Array(1e9)`.\nfunction isDenseArray(value: unknown): value is unknown[] {\n if (!Array.isArray(value)) return false;\n if (Object.keys(value).length !== value.length) return false;\n\n for (let index = 0; index < value.length; index += 1) {\n if (!Object.hasOwn(value, index)) return false;\n }\n\n return true;\n}\n\nfunction hasExactKeys(\n value: Readonly<Record<string, unknown>>,\n expectedKeys: readonly string[],\n): boolean {\n const actualKeys = Object.keys(value);\n return (\n actualKeys.length === expectedKeys.length &&\n expectedKeys.every((key) => Object.hasOwn(value, key))\n );\n}\n\nfunction isBridgeMessageType(value: string): value is BridgeMessageType {\n return Object.hasOwn(BRIDGE_MESSAGE_CATALOG, value);\n}\n\nfunction parseFailure(\n reason: BridgeEnvelopeParseFailureReason,\n requestId: string | undefined,\n): BridgeEnvelopeParseResult {\n return requestId === undefined\n ? { ok: false, reason }\n : { ok: false, reason, requestId };\n}\n\nfunction isDirectionAllowed(\n direction: BridgeMessageDirection,\n receivedBy: ParseBridgeEnvelopeOptions[\"receivedBy\"],\n): boolean {\n return (\n direction === \"both\" ||\n (direction === \"iframe-to-shell\" && receivedBy === \"shell\") ||\n (direction === \"shell-to-iframe\" && receivedBy === \"iframe\")\n );\n}\n\nfunction matchesPayloadShape(\n value: unknown,\n shape: BridgePayloadShape,\n): boolean {\n if (shape.kind === \"unknown\") {\n return true;\n }\n\n if (shape.kind === \"string\") {\n return (\n typeof value === \"string\" && (shape.nonEmpty !== true || value.length > 0)\n );\n }\n\n if (shape.kind === \"string-array\") {\n return (\n isDenseArray(value) && value.every((item) => typeof item === \"string\")\n );\n }\n\n if (shape.kind === \"absolute-origin-array\") {\n return isDenseArray(value) && value.every(isAbsoluteOrigin);\n }\n\n if (shape.kind === \"string-enum\") {\n return typeof value === \"string\" && shape.values.includes(value);\n }\n\n if (shape.kind === \"array\") {\n return (\n isDenseArray(value) &&\n value.every((item) => matchesPayloadShape(item, shape.items))\n );\n }\n\n if (shape.kind === \"record\") {\n return (\n isRecord(value) &&\n Object.values(value).every((item) =>\n matchesPayloadShape(item, shape.values),\n )\n );\n }\n\n if (!isRecord(value)) {\n return false;\n }\n\n const required = shape.required ?? {};\n const optional = shape.optional ?? {};\n const knownKeys = new Set([\n ...Object.keys(required),\n ...Object.keys(optional),\n ]);\n\n if (\n !Object.entries(required).every(\n ([key, fieldShape]) =>\n Object.hasOwn(value, key) &&\n matchesPayloadShape(value[key], fieldShape),\n )\n ) {\n return false;\n }\n\n if (\n !Object.entries(optional).every(\n ([key, fieldShape]) =>\n !Object.hasOwn(value, key) ||\n matchesPayloadShape(value[key], fieldShape),\n )\n ) {\n return false;\n }\n\n return (\n shape.additionalProperties === true ||\n Object.keys(value).every((key) => knownKeys.has(key))\n );\n}\n\nfunction isAbsoluteOrigin(value: unknown): boolean {\n if (typeof value !== \"string\" || value === \"*\") {\n return false;\n }\n\n try {\n const url = new URL(value);\n return (\n (url.protocol === \"https:\" || url.protocol === \"http:\") &&\n url.origin !== \"null\" &&\n url.origin === value\n );\n } catch {\n return false;\n }\n}\n","import {\n BRIDGE_PROTOCOL_VERSION,\n parseBridgeEnvelope,\n type BridgeErrorPayload,\n type CanonicalBridgeContext,\n type CanonicalBridgeEnvelope,\n type SessionTokenRefreshRequestPayload,\n} from \"./canonical-protocol\";\nimport {\n FluidBridgeConfigurationError,\n FluidBridgeError,\n FluidBridgeInvalidContextError,\n FluidBridgeRequestTimeoutError,\n FluidBridgeTokenMintError,\n} from \"./errors\";\n\n/** Trusted host inputs, fixed for one document load. Never populate from iframe messages. */\nexport interface BridgeMount {\n clientId: string;\n storeUuid: string;\n actor: { type: CanonicalBridgeContext[\"actor\"][\"type\"]; uuid: string };\n /**\n * Advisory/informational only. Required so the shell cannot omit it, but\n * the host never compares it against anything — it is not an\n * authorization input. Carry it for logging/telemetry only.\n */\n installationId: string;\n entry: { type: CanonicalBridgeContext[\"entry\"][\"type\"]; name: string };\n /** Generated once by the shell, shared with the URL-bootstrap mint. */\n sid: string;\n}\n\nexport interface CanonicalHostOptions {\n iframe: HTMLIFrameElement;\n /** Exact origin derived by the shell from the server's registered embed URL. */\n appOrigin: string;\n mount: BridgeMount;\n /** Endpoint adapter for the context request. Returns the inner bridge_context unchanged. */\n getContext: (signal: AbortSignal) => Promise<unknown>;\n /** Endpoint adapter for the session-token request. Uses host auth; returns the compact token. */\n getSessionToken: (\n mount: Readonly<BridgeMount>,\n signal: AbortSignal,\n ) => Promise<string>;\n targetWindow?: Window;\n}\n\nexport interface CanonicalBridgeHost {\n /** Unmount or identity/context change must destroy this host before mounting another. */\n destroy: () => void;\n}\n\nconst REQUEST_TIMEOUT_MS = 5_000;\nconst MAX_PENDING_REQUESTS = 16;\nconst CONTEXT_VALIDATION_ID = \"00000000-0000-7000-8000-000000000000\";\n\n/** Push handshake and correlated refresh on the single canonical envelope. */\nexport function createCanonicalBridgeHost(\n options: CanonicalHostOptions,\n): CanonicalBridgeHost {\n const targetWindow = options.targetWindow ?? window;\n const appOrigin = exactOrigin(options.appOrigin);\n // Snapshot nested values too: changing store/actor/installation is a new host, never a re-key.\n const mount: Readonly<BridgeMount> = Object.freeze({\n ...options.mount,\n actor: Object.freeze({ ...options.mount.actor }),\n entry: Object.freeze({ ...options.mount.entry }),\n });\n if (\n !mount.clientId.trim() ||\n !mount.storeUuid.trim() ||\n !mount.actor.uuid.trim() ||\n !mount.installationId.trim() ||\n !mount.entry.name.trim() ||\n !mount.sid.trim()\n ) {\n throw new FluidBridgeConfigurationError(\n \"Host mount identifiers must be present\",\n );\n }\n const iframe = options.iframe;\n const frameWindow = iframe.contentWindow;\n if (!frameWindow)\n throw new FluidBridgeConfigurationError(\"Host requires a mounted iframe\");\n const frameSrc = iframe.src;\n if (new URL(frameSrc).origin !== appOrigin) {\n throw new FluidBridgeConfigurationError(\n \"Iframe does not match its registered origin\",\n );\n }\n\n let destroyed = false;\n let context: CanonicalBridgeContext | undefined;\n // The union of every allowedOrigins set ever delivered on this host mount,\n // via deliver(). Monotonic for the lifetime of the mount: a later deliver()\n // only adds to it, never resets it, and only destroy() (a genuine remount)\n // clears it. The host cannot reliably tell a new document's bridge.ready\n // from a duplicate/retried one from the SAME document (an SDK retry race,\n // or a bfcache pageshow resend) — resetting the baseline on every deliver()\n // would let a duplicate ready silently erase a prior origin removal and let\n // refresh() mint again for an origin that was already revoked.\n let originBaseline: Set<string> | undefined;\n let ready = false;\n // Readiness and refresh each get their own bounded pool. A storm of refreshes from an\n // old document must never cost a new document's bridge.ready a host_unavailable — the\n // host answers every valid bridge.ready for the current mount (Q8).\n const pendingReady = new Map<string, AbortController>();\n const pendingRefresh = new Map<string, AbortController>();\n\n const isCurrent = (): boolean =>\n !destroyed &&\n iframe.contentWindow === frameWindow &&\n iframe.src === frameSrc;\n const post = (envelope: CanonicalBridgeEnvelope): void => {\n if (isCurrent()) frameWindow.postMessage(envelope, appOrigin);\n };\n const fail = (requestId: string, payload: BridgeErrorPayload): void => {\n post({\n type: \"error\",\n payload,\n request_id: requestId,\n version: BRIDGE_PROTOCOL_VERSION,\n });\n };\n\n const run = async (\n requestId: string,\n operation: (signal: AbortSignal) => Promise<void>,\n initial: boolean,\n ): Promise<void> => {\n const pool = initial ? pendingReady : pendingRefresh;\n if (pool.has(requestId)) return;\n if (pool.size >= MAX_PENDING_REQUESTS) {\n fail(requestId, {\n code: \"host_unavailable\",\n message: \"Host request capacity exceeded\",\n });\n return;\n }\n const controller = new AbortController();\n pool.set(requestId, controller);\n const timer = setTimeout(\n () => controller.abort(new FluidBridgeRequestTimeoutError()),\n REQUEST_TIMEOUT_MS,\n );\n try {\n // Abort must also settle callbacks that ignore their AbortSignal. Late work never posts.\n await abortable(operation(controller.signal), controller.signal);\n } catch (error) {\n if (isCurrent()) fail(requestId, safeError(error, initial));\n } finally {\n clearTimeout(timer);\n pool.delete(requestId);\n }\n };\n\n const mint = async (signal: AbortSignal): Promise<string> => {\n const token = await options.getSessionToken(mount, signal);\n if (signal.aborted) throw signal.reason;\n if (typeof token !== \"string\" || !tokenMatchesMount(token, mount)) {\n throw new FluidBridgeTokenMintError();\n }\n return token;\n };\n\n const fetchContext = async (\n signal: AbortSignal,\n ): Promise<CanonicalBridgeContext> => {\n let candidate: unknown;\n try {\n candidate = await options.getContext(signal);\n } catch (error) {\n if (signal.aborted || error instanceof FluidBridgeError) throw error;\n throw new FluidBridgeInvalidContextError();\n }\n if (signal.aborted) throw signal.reason;\n return boundContext(candidate, mount, appOrigin);\n };\n\n const deliver = async (\n requestId: string,\n signal: AbortSignal,\n ): Promise<void> => {\n // Keep this request's own fetched context in a local const. Two overlapping\n // deliveries can resolve their fetchContext/mint calls in any order; posting\n // from the shared `context` variable here would let a slower request's post\n // carry a faster (or slower) sibling's context under the wrong request_id.\n const deliveredContext = await fetchContext(signal);\n const token = await mint(signal);\n if (signal.aborted) throw signal.reason;\n if (!isCurrent()) return;\n context = deliveredContext;\n originBaseline = originBaseline\n ? new Set([...originBaseline, ...deliveredContext.fetch.allowedOrigins])\n : new Set(deliveredContext.fetch.allowedOrigins);\n post({\n type: \"context.deliver\",\n payload: deliveredContext,\n request_id: requestId,\n version: BRIDGE_PROTOCOL_VERSION,\n });\n post({\n type: \"session_token.deliver\",\n payload: { sessionToken: token },\n request_id: requestId,\n version: BRIDGE_PROTOCOL_VERSION,\n });\n ready = true;\n };\n\n const refresh = async (\n requestId: string,\n payload: SessionTokenRefreshRequestPayload,\n signal: AbortSignal,\n ): Promise<void> => {\n if (!ready || !context) {\n fail(requestId, {\n code: \"host_unavailable\",\n message: \"Complete the handshake before refreshing\",\n });\n return;\n }\n if (payload.clientId !== mount.clientId) {\n fail(requestId, {\n code: \"failed_authentication\",\n message: \"Request does not match the mounted app\",\n });\n return;\n }\n if (\n payload.protocolVersion !== BRIDGE_PROTOCOL_VERSION ||\n !supportsSdk(payload.sdkVersion, context.sdk.minVersion)\n ) {\n fail(requestId, {\n code: \"incompatible_version\",\n message: \"SDK or protocol version is incompatible\",\n details: {\n received: {\n sdkVersion: payload.sdkVersion.slice(0, 32),\n protocolVersion: payload.protocolVersion.slice(0, 32),\n },\n required: {\n sdkVersion: context.sdk.minVersion,\n protocolVersion: BRIDGE_PROTOCOL_VERSION,\n },\n },\n });\n return;\n }\n const authorizedContext = await fetchContext(signal);\n if (!supportsSdk(payload.sdkVersion, authorizedContext.sdk.minVersion)) {\n fail(requestId, {\n code: \"incompatible_version\",\n message: \"SDK version is incompatible with the current context\",\n });\n return;\n }\n // An origin removed server-side since it was ever delivered on this mount must\n // never receive a freshly minted token, even though the iframe stays mounted.\n // Compare against originBaseline (the monotonic union of every deliver()'s\n // allowedOrigins), never against `context`, which a prior successful refresh\n // may have already advanced — that would let an earlier removal hide behind a\n // later, unrelated addition.\n if (\n originBaseline &&\n [...originBaseline].some(\n (origin) => !authorizedContext.fetch.allowedOrigins.includes(origin),\n )\n ) {\n fail(requestId, {\n code: \"unauthorized\",\n message: \"Authorized fetch origins changed for the current document\",\n });\n return;\n }\n context = authorizedContext;\n const token = await mint(signal);\n if (signal.aborted) throw signal.reason;\n post({\n type: \"session_token.deliver\",\n payload: { sessionToken: token },\n request_id: requestId,\n version: BRIDGE_PROTOCOL_VERSION,\n });\n };\n\n const handleMessage = (event: MessageEvent<unknown>): void => {\n if (\n !isCurrent() ||\n event.origin !== appOrigin ||\n event.source !== frameWindow\n )\n return;\n const parsed = parseBridgeEnvelope(event.data, { receivedBy: \"shell\" });\n if (!parsed.ok) {\n if (parsed.reason === \"version_mismatch\" && parsed.requestId) {\n fail(parsed.requestId, {\n code: \"version_mismatch\",\n message: \"Unsupported bridge protocol version\",\n });\n } else if (\n parsed.reason === \"invalid_payload\" &&\n parsed.requestId &&\n typeof event.data === \"object\" &&\n event.data !== null &&\n \"type\" in event.data &&\n event.data.type === \"session_token.refresh_request\"\n ) {\n fail(parsed.requestId, {\n code: \"incompatible_version\",\n message: \"Refresh requires client, SDK and protocol metadata\",\n });\n }\n return;\n }\n const envelope = parsed.envelope;\n if (envelope.type === \"bridge.ready\") {\n // Every document uses its own readiness id; coalesce only a retry of\n // the same in-flight request. A new document must not lose readiness\n // behind the old document’s pending context/mint work.\n if (pendingReady.has(envelope.request_id)) return;\n void run(\n envelope.request_id,\n (signal) => deliver(envelope.request_id, signal),\n true,\n );\n } else if (envelope.type === \"session_token.refresh_request\") {\n void run(\n envelope.request_id,\n (signal) => refresh(envelope.request_id, envelope.payload, signal),\n false,\n );\n }\n };\n targetWindow.addEventListener(\"message\", handleMessage);\n return {\n destroy: () => {\n destroyed = true;\n targetWindow.removeEventListener(\"message\", handleMessage);\n for (const controller of pendingReady.values()) controller.abort();\n for (const controller of pendingRefresh.values()) controller.abort();\n pendingReady.clear();\n pendingRefresh.clear();\n context = undefined;\n originBaseline = undefined;\n ready = false;\n },\n };\n}\n\n// This is a delivery binding check on a trusted mint response, never signature verification.\n// A changed host auth session must not pair its new actor token with an old immutable context.\n// `exp` is checked for shape only (a present integer) — expiry itself is the droplet verifier's\n// job. Comparing it here against the host's own clock would reject a freshly minted short-lived\n// token outright for any admin whose clock runs a little fast.\nfunction tokenMatchesMount(token: string, mount: BridgeMount): boolean {\n try {\n if (!/^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/.test(token))\n return false;\n const encoded = token.split(\".\")[1];\n if (!encoded) return false;\n const claims: unknown = JSON.parse(\n new TextDecoder(\"utf-8\", { fatal: true }).decode(\n Uint8Array.from(\n atob(encoded.replace(/-/g, \"+\").replace(/_/g, \"/\")),\n (character) => character.charCodeAt(0),\n ),\n ),\n );\n if (typeof claims !== \"object\" || claims === null || Array.isArray(claims))\n return false;\n const payload = claims as Record<string, unknown>;\n const entry = payload.entry;\n return (\n payload.aud === mount.clientId &&\n payload.dest === `urn:fluid:store:${mount.storeUuid}` &&\n payload.sub === `urn:fluid:${mount.actor.type}:${mount.actor.uuid}` &&\n payload.sid === mount.sid &&\n typeof payload.exp === \"number\" &&\n Number.isInteger(payload.exp) &&\n typeof entry === \"object\" &&\n entry !== null &&\n \"type\" in entry &&\n entry.type === mount.entry.type &&\n \"name\" in entry &&\n entry.name === mount.entry.name\n );\n } catch {\n return false;\n }\n}\n\nfunction exactOrigin(value: string): string {\n try {\n const url = new URL(value);\n if (\n (url.protocol === \"https:\" || url.protocol === \"http:\") &&\n url.origin === value\n )\n return value;\n } catch {\n /* Invalid origins fail closed below. */\n }\n throw new FluidBridgeConfigurationError(\n \"Host requires an exact HTTP(S) app origin\",\n );\n}\n\nfunction boundContext(\n value: unknown,\n mount: BridgeMount,\n appOrigin: string,\n): CanonicalBridgeContext {\n const parsed = parseBridgeEnvelope(\n {\n type: \"context.deliver\",\n payload: value,\n request_id: CONTEXT_VALIDATION_ID,\n version: BRIDGE_PROTOCOL_VERSION,\n },\n { receivedBy: \"iframe\" },\n );\n if (!parsed.ok || parsed.envelope.type !== \"context.deliver\")\n throw new FluidBridgeInvalidContextError();\n const context = parsed.envelope.payload;\n if (\n context.app.clientId !== mount.clientId ||\n context.store.uuid !== mount.storeUuid ||\n context.actor.type !== mount.actor.type ||\n context.actor.uuid !== mount.actor.uuid ||\n context.entry.type !== mount.entry.type ||\n context.entry.name !== mount.entry.name ||\n !context.fetch.allowedOrigins.includes(appOrigin) ||\n !supportsSdk(context.sdk.minVersion, context.sdk.minVersion)\n )\n throw new FluidBridgeInvalidContextError();\n return context;\n}\n\n// Stable numeric semver only: malformed/prerelease versions must not bypass the minimum.\nfunction supportsSdk(received: string, minimum: string): boolean {\n const pattern = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$/;\n if (!pattern.test(received) || !pattern.test(minimum)) return false;\n const current = received.split(\".\").map(Number);\n const required = minimum.split(\".\").map(Number);\n if (![...current, ...required].every(Number.isSafeInteger)) return false;\n for (const index of [0, 1, 2]) {\n const left = current[index];\n const right = required[index];\n if (left === undefined || right === undefined) return false;\n if (left !== right) return left > right;\n }\n return true;\n}\n\nfunction safeError(error: unknown, initial: boolean): BridgeErrorPayload {\n if (error instanceof FluidBridgeRequestTimeoutError) {\n return {\n code: initial ? \"handshake_timeout\" : \"request_timeout\",\n message: \"Host request timed out\",\n };\n }\n if (error instanceof FluidBridgeError) {\n const code = error.code;\n if (\n code === \"unauthorized\" ||\n code === \"failed_authentication\" ||\n code === \"invalid_context\" ||\n code === \"incompatible_version\" ||\n code === \"host_unavailable\"\n ) {\n return { code, message: \"Host could not complete the bridge request\" };\n }\n }\n // Exception messages/details can contain request URLs, credentials or response bodies.\n return {\n code: \"token_mint_failed\",\n message: \"Host could not obtain a session token\",\n };\n}\n\nfunction abortable<T>(operation: Promise<T>, signal: AbortSignal): Promise<T> {\n return new Promise((resolve, reject) => {\n const abort = (): void => reject(signal.reason);\n if (signal.aborted) {\n abort();\n return;\n }\n signal.addEventListener(\"abort\", abort, { once: true });\n operation\n .then(resolve, reject)\n .finally(() => signal.removeEventListener(\"abort\", abort));\n });\n}\n","import {\n APP_BRIDGE_SDK_NAME,\n APP_BRIDGE_SDK_VERSION,\n FLUID_BRIDGE_PROTOCOL_VERSION,\n type BridgeContext,\n} from \"./protocol\";\nimport {\n FluidBridgeFailedAuthenticationError,\n FluidBridgeIncompatibleVersionError,\n FluidBridgeTokenMintError,\n FluidBridgeUnauthorizedError,\n} from \"./errors\";\n\nexport interface AppBridgeSessionTokenRequest {\n clientId: string;\n entry: BridgeContext[\"entry\"];\n resources?: BridgeContext[\"resources\"];\n allowedOrigins?: string[];\n sessionId?: string;\n}\n\nexport interface MintAppBridgeSessionTokenOptions {\n request: AppBridgeSessionTokenRequest;\n apiBaseUrl?: string;\n authToken?: string;\n fetch?: typeof fetch;\n}\n\ninterface SessionTokenSuccessResponse {\n session_token: string;\n}\n\ninterface LegacyErrorResponse {\n error?: {\n message?: string;\n details?: unknown;\n };\n}\n\nconst DEFAULT_SESSION_TOKEN_PATH = \"api/v2025-06/app_bridge/session_token\";\n\nexport async function mintAppBridgeSessionToken({\n request,\n apiBaseUrl,\n authToken,\n fetch: fetchImplementation = globalThis.fetch?.bind(globalThis),\n}: MintAppBridgeSessionTokenOptions): Promise<string> {\n if (!fetchImplementation) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge host requires a fetch implementation to mint session tokens\",\n );\n }\n\n const response = await fetchImplementation(\n resolveSessionTokenUrl(apiBaseUrl),\n {\n method: \"POST\",\n headers: sessionTokenHeaders(authToken),\n body: JSON.stringify(sessionTokenRequestBody(request)),\n },\n );\n\n const body: unknown = await response.json().catch(() => null);\n\n if (!response.ok) {\n throw errorForTokenResponse(response.status, body);\n }\n\n if (!isSessionTokenSuccessResponse(body) || body.session_token.length === 0) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge backend returned an invalid session token response\",\n { body },\n );\n }\n\n return body.session_token;\n}\n\nexport function sessionTokenRequestFromContext(\n context: BridgeContext,\n sessionId?: string,\n): AppBridgeSessionTokenRequest {\n return {\n clientId: context.app.clientId,\n entry: context.entry,\n resources: context.resources,\n allowedOrigins: context.fetch.allowedOrigins,\n ...(sessionId ? { sessionId } : {}),\n };\n}\n\nfunction sessionTokenHeaders(authToken: string | undefined): Headers {\n const headers = new Headers({\n \"Content-Type\": \"application/json\",\n \"X-Fluid-App-Bridge-Protocol\": FLUID_BRIDGE_PROTOCOL_VERSION,\n \"X-Fluid-App-Bridge-Version\": APP_BRIDGE_SDK_VERSION,\n \"X-Fluid-App-Bridge-Sdk\": APP_BRIDGE_SDK_NAME,\n });\n\n if (authToken) {\n headers.set(\"Authorization\", `Bearer ${authToken}`);\n }\n\n return headers;\n}\n\nfunction sessionTokenRequestBody(\n request: AppBridgeSessionTokenRequest,\n): Record<string, unknown> {\n return {\n client_id: request.clientId,\n entry: request.entry,\n resources: request.resources ?? [],\n allowed_origins: request.allowedOrigins ?? [],\n ...(request.sessionId ? { session_id: request.sessionId } : {}),\n };\n}\n\nfunction resolveSessionTokenUrl(apiBaseUrl: string | undefined): string {\n if (!apiBaseUrl) {\n return `/${DEFAULT_SESSION_TOKEN_PATH}`;\n }\n return new URL(\n DEFAULT_SESSION_TOKEN_PATH,\n ensureTrailingSlash(apiBaseUrl),\n ).toString();\n}\n\nfunction ensureTrailingSlash(url: string): string {\n return url.endsWith(\"/\") ? url : `${url}/`;\n}\n\nfunction isSessionTokenSuccessResponse(\n value: unknown,\n): value is SessionTokenSuccessResponse {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"session_token\" in value &&\n typeof value.session_token === \"string\"\n );\n}\n\nfunction errorForTokenResponse(status: number, body: unknown): Error {\n const errorBody = isLegacyErrorResponse(body) ? body.error : undefined;\n const message =\n errorBody?.message ??\n \"Fluid App Bridge backend rejected the session-token request\";\n const details = errorBody?.details ?? body;\n\n if (status === 401) {\n return new FluidBridgeUnauthorizedError(message, details);\n }\n if (status === 403) {\n return new FluidBridgeFailedAuthenticationError(message, details);\n }\n if (status === 422) {\n return new FluidBridgeIncompatibleVersionError(message, details);\n }\n return new FluidBridgeTokenMintError(message, details);\n}\n\nfunction isLegacyErrorResponse(value: unknown): value is LegacyErrorResponse {\n return typeof value === \"object\" && value !== null && \"error\" in value;\n}\n","import type { CanonicalBridgeContext } from \"./canonical-protocol\";\nimport {\n FluidBridgeFetchTargetError,\n FluidBridgeInvalidContextError,\n FluidBridgeNetworkError,\n FluidBridgeFailedAuthenticationError,\n} from \"./errors\";\n\n/** Snapshot of the handshake at call time; never awaited for the ambient decision below. */\nexport type FluidBridgeHandshakeState =\n | \"pending\"\n | \"resolved\"\n | \"failed\"\n | \"destroyed\";\n\ninterface AuthenticatedFetchOptions {\n nativeFetch: typeof fetch;\n getContext(): Promise<CanonicalBridgeContext>;\n getSessionToken(): Promise<string>;\n /** Read live (e.g. location.href) so an in-document route change resolves relative URLs correctly. */\n getBaseUrl(): string;\n getHandshakeState(): FluidBridgeHandshakeState;\n /** Synchronous peek at a context already delivered this document, without waiting on the token. */\n getDeliveredContext(): CanonicalBridgeContext | undefined;\n ambient: boolean;\n}\n/** Both explicit and ambient fetch use only server-delivered exact origins. */\nexport function createAuthenticatedFetch(\n options: AuthenticatedFetchOptions,\n): typeof fetch {\n return async (input, init) => {\n const baseUrl = options.getBaseUrl();\n let url: URL;\n try {\n url = new URL(\n input instanceof Request ? input.url : input.toString(),\n baseUrl,\n );\n } catch {\n throw new FluidBridgeFetchTargetError();\n }\n const fluidApi =\n url.hostname === \"api.fluid.app\" ||\n url.hostname.endsWith(\".api.fluid.app\");\n if (fluidApi) {\n if (options.ambient) return options.nativeFetch(input, init);\n throw new FluidBridgeFetchTargetError();\n }\n if (options.ambient) {\n // A patched window.fetch must never stall or reject ordinary document traffic\n // (Sentry, analytics, same-origin requests) on a handshake that failed or has\n // not resolved yet, or on one retained after teardown. Only requests to the\n // document's own origin wait for a pending handshake — they are the likely\n // authenticated ones. Explicit bridge fetch is unaffected: it always awaits\n // and fails closed below.\n const state = options.getHandshakeState();\n if (state === \"failed\") return options.nativeFetch(input, init);\n // A reference to this ambient wrapper can outlive destroy() (e.g. a telemetry\n // wrapper that captured window.fetch before teardown). Cross-origin traffic\n // through it is never the authenticated kind, so it still passes through; a\n // same-origin request keeps failing closed below, including one already\n // waiting on the handshake when teardown happened.\n if (state === \"destroyed\" && url.origin !== documentOrigin(baseUrl)) {\n return options.nativeFetch(input, init);\n }\n // Once a context has actually been delivered this document, decide\n // pass-through from its real allowed-origin list instead of the coarser\n // pending/resolved state — `resolved` fires as soon as context arrives, which\n // is before the token (session_token.deliver) and would otherwise make a\n // request to a never-allowed origin wait on a mint it will never need.\n const delivered = options.getDeliveredContext();\n if (delivered) {\n if (!delivered.fetch.allowedOrigins.includes(url.origin)) {\n return options.nativeFetch(input, init);\n }\n } else if (url.origin !== documentOrigin(baseUrl)) {\n return options.nativeFetch(input, init);\n }\n }\n const signal = resolveSignal(input, init);\n if (signal?.aborted) throw signal.reason;\n let context: CanonicalBridgeContext;\n try {\n context = signal\n ? await abortable(options.getContext(), signal)\n : await options.getContext();\n } catch (error) {\n // The snapshot above can still race a handshake that fails while this\n // same-origin ambient request was waiting; fall back the same way. A\n // destroyed client is not a failed handshake: the waiting request rejects\n // rather than leaving unauthenticated after teardown.\n if (options.ambient && options.getHandshakeState() === \"failed\")\n return options.nativeFetch(input, init);\n throw error;\n }\n if (!context.fetch.allowedOrigins.includes(url.origin)) {\n if (options.ambient) return options.nativeFetch(input, init);\n throw new FluidBridgeFetchTargetError();\n }\n const locale = context.store.locale;\n if (!locale || !/^[a-z]{2,3}(?:[-_][a-z0-9]{2,8})*$/i.test(locale))\n throw new FluidBridgeInvalidContextError();\n let request: Request;\n try {\n request = new Request(input instanceof Request ? input : url, init);\n } catch {\n throw new FluidBridgeNetworkError();\n }\n request.signal.throwIfAborted();\n const token = await abortable(options.getSessionToken(), request.signal);\n const headers = new Headers(request.headers);\n headers.set(\"Authorization\", `Bearer ${token}`);\n headers.set(\"Accept-Language\", locale.replaceAll(\"_\", \"-\"));\n let authenticated: Request;\n try {\n // Browsers strip the Authorization header on a cross-origin redirect per the\n // Fetch spec, so forwarding it across a redirect would be silently insecure —\n // explicit bridge fetch refuses outright. Ambient fetch keeps the caller's own\n // redirect semantics instead (same-origin pages routinely rely on normal\n // redirect following) and is not held to that fail-closed bar.\n authenticated = new Request(request, {\n headers,\n ...(options.ambient ? {} : { redirect: \"error\" }),\n });\n } catch {\n throw new FluidBridgeNetworkError();\n }\n let response: Response;\n try {\n response = await options.nativeFetch(authenticated);\n } catch {\n if (request.signal.aborted) throw request.signal.reason;\n throw new FluidBridgeNetworkError();\n }\n // Only explicit bridge fetch converts 401/403 into a typed throw. Ambient callers\n // (same-origin app code) expect to see and handle their own response statuses.\n if (\n !options.ambient &&\n (response.status === 401 || response.status === 403)\n )\n throw new FluidBridgeFailedAuthenticationError();\n return response;\n };\n}\nfunction documentOrigin(baseUrl: string): string | undefined {\n try {\n return new URL(baseUrl).origin;\n } catch {\n return undefined;\n }\n}\n// `signal: null` is Fetch's explicit \"use no signal\". An omitted or `undefined` signal\n// is \"not present\" (WebIDL dictionary semantics) and inherits the input Request's own\n// signal, exactly as `new Request(input, init)` does. `??` cannot tell null apart.\nfunction resolveSignal(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n): AbortSignal | undefined {\n if (init?.signal !== undefined) return init.signal ?? undefined;\n return input instanceof Request ? input.signal : undefined;\n}\nfunction abortable<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n return new Promise((resolve, reject) => {\n const abort = () => reject(signal.reason);\n if (signal.aborted) {\n abort();\n return;\n }\n signal.addEventListener(\"abort\", abort, { once: true });\n promise\n .then(resolve, reject)\n .finally(() => signal.removeEventListener(\"abort\", abort));\n });\n}\n","import {\n BRIDGE_PROTOCOL_VERSION,\n parseBridgeEnvelope,\n type CanonicalBridgeContext,\n type CanonicalBridgeEnvelope,\n type BridgeErrorPayload,\n} from \"./canonical-protocol\";\nimport { APP_BRIDGE_SDK_VERSION } from \"./protocol\";\nimport * as Errors from \"./errors\";\nimport {\n createAuthenticatedFetch,\n type FluidBridgeHandshakeState,\n} from \"./client-fetch\";\n\nexport interface CreateFluidBridgeOptions {\n clientId: string;\n /** Exact host-shell origin, supplied by the shell. Never inferred from referrer. */\n hostOrigin: string;\n disableFetchPatch?: boolean;\n timeoutMs?: number;\n /** Document window; parent remains the only permitted sender. Primarily for testing. */\n targetWindow?: Window;\n fetch?: typeof fetch;\n}\nexport interface FluidBridge {\n getContext(): Promise<CanonicalBridgeContext>;\n getSessionToken(): Promise<string>;\n fetch: typeof fetch;\n destroy(): void;\n}\ninterface PendingToken {\n resolve(token: string): void;\n reject(error: Errors.FluidBridgeError): void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nconst activeDocuments = new WeakSet<Window>();\n\n/** One canonical client per iframe document. Tokens are decoded for delivery binding only. */\nexport function createFluidBridge(\n options: CreateFluidBridgeOptions,\n): FluidBridge {\n if (\n !options ||\n typeof options.clientId !== \"string\" ||\n !options.clientId.trim() ||\n \"appOrigins\" in options\n ) {\n throw new Errors.FluidBridgeConfigurationError(\n \"Use clientId and the server-delivered origin list\",\n );\n }\n const hostOrigin = exactOrigin(options.hostOrigin);\n const current = options.targetWindow ?? globalThis.window;\n if (!current || current.parent === current)\n throw new Errors.FluidBridgeHostUnavailableError();\n const parent = current.parent;\n const nativeFetch = options.fetch ?? current.fetch?.bind(current);\n const timeout = options.timeoutMs ?? 10_000;\n if (\n typeof nativeFetch !== \"function\" ||\n !Number.isFinite(timeout) ||\n timeout < 1 ||\n timeout > 60_000\n ) {\n throw new Errors.FluidBridgeConfigurationError(\n \"A fetch implementation and bounded timeout are required\",\n );\n }\n if (activeDocuments.has(current))\n throw new Errors.FluidBridgeConfigurationError(\n \"Destroy the existing bridge before initializing another\",\n );\n const bootstrap = new URL(current.location.href);\n if (bootstrap.searchParams.has(\"session_token\")) {\n bootstrap.searchParams.delete(\"session_token\");\n current.history.replaceState(current.history.state, \"\", bootstrap.href);\n }\n activeDocuments.add(current);\n const readyId = uuidV7();\n const pending = new Map<string, PendingToken>();\n let context: CanonicalBridgeContext | undefined;\n let sid: string | undefined;\n let destroyed = false;\n let settled = false;\n let handshakeFailed = false;\n let refreshInFlight: Promise<string> | undefined;\n let attempts = 0;\n let retryTimer: ReturnType<typeof setTimeout> | undefined;\n let refreshTimer: ReturnType<typeof setTimeout> | undefined;\n let resolveHandshake!: (context: CanonicalBridgeContext) => void;\n let rejectHandshake!: (error: Errors.FluidBridgeError) => void;\n const handshake = new Promise<CanonicalBridgeContext>((resolve, reject) => {\n resolveHandshake = resolve;\n rejectHandshake = reject;\n });\n // Initialization starts before callers attach handlers; keep terminal failures handled.\n void handshake.catch(() => undefined);\n const startHandshakeTimer = () =>\n setTimeout(\n () => failHandshake(new Errors.FluidBridgeHandshakeTimeoutError()),\n timeout,\n );\n let handshakeTimer = startHandshakeTimer();\n function handshakeState(): FluidBridgeHandshakeState {\n if (destroyed) return \"destroyed\";\n if (handshakeFailed) return \"failed\";\n return context ? \"resolved\" : \"pending\";\n }\n\n function post(envelope: CanonicalBridgeEnvelope): void {\n if (destroyed) return;\n try {\n parent.postMessage(envelope, hostOrigin);\n } catch {\n rejectRequest(\n envelope.request_id,\n new Errors.FluidBridgeHostUnavailableError(),\n );\n }\n }\n function failHandshake(error: Errors.FluidBridgeError): void {\n if (settled) return;\n settled = true;\n handshakeFailed = true;\n clearTimeout(handshakeTimer);\n clearTimeout(retryTimer);\n rejectHandshake(error);\n }\n // `force` is for a bfcache restore only: a persisted pageshow with an\n // unsettled handshake may be resuming a document whose context.deliver\n // landed before the freeze but whose session_token.deliver never did (lost\n // to the freeze in transit). Without a resend, nothing ever re-triggers the\n // host, so the handshake would hang forever. A normal retry (no `force`)\n // still stops once context is set — in the non-restore case the host posts\n // context.deliver and session_token.deliver together, so there is nothing\n // left to wait on.\n function sendReady(force = false): void {\n if (destroyed || settled || attempts >= 8) return;\n if (context && !force) return;\n post({\n type: \"bridge.ready\",\n payload: {},\n request_id: readyId,\n version: BRIDGE_PROTOCOL_VERSION,\n });\n attempts += 1;\n if (!context && !settled)\n retryTimer = setTimeout(\n sendReady,\n Math.min(100 * 2 ** (attempts - 1), 1_600),\n );\n }\n async function getSessionToken(): Promise<string> {\n await handshake;\n if (destroyed) throw new Errors.FluidBridgeHostUnavailableError();\n // Coalesce concurrent callers (e.g. several ambient fetches at once) onto one\n // in-flight refresh_request instead of flooding the host's refresh pool. A call\n // made after this one settles starts a fresh request of its own.\n if (refreshInFlight) return refreshInFlight;\n const requestId = uuidV7();\n const request = new Promise<string>((resolve, reject) => {\n const timer = setTimeout(() => {\n pending.delete(requestId);\n reject(new Errors.FluidBridgeRequestTimeoutError());\n }, timeout);\n pending.set(requestId, { resolve, reject, timer });\n post({\n type: \"session_token.refresh_request\",\n payload: {\n clientId: options.clientId,\n sdkVersion: APP_BRIDGE_SDK_VERSION,\n protocolVersion: BRIDGE_PROTOCOL_VERSION,\n },\n request_id: requestId,\n version: BRIDGE_PROTOCOL_VERSION,\n });\n });\n refreshInFlight = request.finally(() => {\n refreshInFlight = undefined;\n });\n return refreshInFlight;\n }\n // No iat on the token: assume the documented default lifetime rather than guessing\n // from the local clock.\n const DEFAULT_TOKEN_LIFETIME_MS = 60_000;\n function scheduleRefresh(claims: { exp: number; iat?: number }): void {\n clearTimeout(refreshTimer);\n // Both exp and iat are the host's own clock, so their difference is immune to\n // local clock skew. Schedule the timer's relative delay from here (receipt) —\n // never by comparing exp against this client's Date.now(), which is exactly the\n // comparison boundToken deliberately no longer makes (see below): an admin clock\n // running fast relative to the host would otherwise make every fresh token look\n // already due, producing a refresh every ~1s instead of once per lifetime.\n const lifetimeMs =\n typeof claims.iat === \"number\" &&\n Number.isSafeInteger(claims.iat) &&\n claims.iat < claims.exp\n ? (claims.exp - claims.iat) * 1_000\n : DEFAULT_TOKEN_LIFETIME_MS;\n const delay = Math.max(1_000, lifetimeMs / 2, lifetimeMs - 10_000);\n refreshTimer = setTimeout(\n () => {\n // A failed refresh is surfaced to subsequent explicit calls, never an unhandled rejection.\n void getSessionToken().catch(() => undefined);\n },\n Math.min(2_147_483_647, delay),\n );\n }\n function onMessage(event: MessageEvent<unknown>): void {\n if (destroyed || event.source !== parent || event.origin !== hostOrigin)\n return;\n const parsed = parseBridgeEnvelope(event.data, { receivedBy: \"iframe\" });\n const id = parsed.ok ? parsed.envelope.request_id : parsed.requestId;\n if (!id || (id !== readyId && !pending.has(id))) return;\n if (id === readyId && settled) return;\n if (!parsed.ok) {\n const error =\n parsed.reason === \"version_mismatch\"\n ? new Errors.FluidBridgeIncompatibleVersionError()\n : new Errors.FluidBridgeInvalidContextError();\n rejectRequest(id, error);\n return;\n }\n const envelope = parsed.envelope;\n if (envelope.type === \"error\") {\n rejectRequest(id, errorFromHost(envelope.payload));\n } else if (\n envelope.type === \"context.deliver\" &&\n id === readyId &&\n !context\n ) {\n const candidate = envelope.payload;\n if (\n candidate.app.clientId !== options.clientId ||\n !candidate.store.uuid ||\n !candidate.actor.uuid ||\n !candidate.entry.name ||\n !candidate.fetch.allowedOrigins.includes(current.location.origin)\n ) {\n failHandshake(new Errors.FluidBridgeInvalidContextError());\n return;\n }\n if (!supportsSdk(APP_BRIDGE_SDK_VERSION, candidate.sdk.minVersion)) {\n failHandshake(\n new Errors.FluidBridgeIncompatibleVersionError(undefined, {\n received: APP_BRIDGE_SDK_VERSION,\n required: candidate.sdk.minVersion,\n }),\n );\n return;\n }\n context = freezeContext(candidate);\n clearTimeout(retryTimer);\n } else if (envelope.type === \"session_token.deliver\") {\n const claims = boundToken(envelope.payload.sessionToken, context, sid);\n if (!claims) {\n rejectRequest(id, new Errors.FluidBridgeFailedAuthenticationError());\n return;\n }\n sid ??= claims.sid;\n scheduleRefresh(claims);\n if (id === readyId && context) {\n settled = true;\n clearTimeout(handshakeTimer);\n resolveHandshake(context);\n } else {\n const request = pending.get(id);\n if (request) {\n clearTimeout(request.timer);\n pending.delete(id);\n request.resolve(envelope.payload.sessionToken);\n }\n }\n }\n }\n function rejectRequest(id: string, error: Errors.FluidBridgeError): void {\n if (id === readyId) failHandshake(error);\n const request = pending.get(id);\n if (request) {\n clearTimeout(request.timer);\n pending.delete(id);\n request.reject(error);\n }\n }\n const getContext = async (): Promise<CanonicalBridgeContext> => {\n if (destroyed) throw new Errors.FluidBridgeHostUnavailableError();\n return handshake;\n };\n const getBaseUrl = (): string => current.location.href;\n // Synchronous peek at a context already delivered this document, even before the\n // handshake has fully resolved (session_token.deliver still pending) or after\n // teardown. Lets ambient fetch decide pass-through from the real allowed-origin\n // list instead of the coarse pending/resolved/destroyed state alone.\n const getDeliveredContext = (): CanonicalBridgeContext | undefined => context;\n const authenticatedFetch = createAuthenticatedFetch({\n nativeFetch,\n getContext,\n getSessionToken,\n getBaseUrl,\n getHandshakeState: handshakeState,\n getDeliveredContext,\n ambient: false,\n });\n const ambientFetch = createAuthenticatedFetch({\n nativeFetch,\n getContext,\n getSessionToken,\n getBaseUrl,\n getHandshakeState: handshakeState,\n getDeliveredContext,\n ambient: true,\n });\n const previousFetch = current.fetch;\n if (!options.disableFetchPatch) current.fetch = ambientFetch;\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n activeDocuments.delete(current);\n current.removeEventListener(\"message\", onMessage);\n current.removeEventListener(\"pagehide\", onPageHide);\n current.removeEventListener(\"pageshow\", onPageShow);\n current.removeEventListener(\"unload\", destroy);\n clearTimeout(retryTimer);\n clearTimeout(refreshTimer);\n failHandshake(new Errors.FluidBridgeHostUnavailableError());\n for (const request of pending.values()) {\n clearTimeout(request.timer);\n request.reject(new Errors.FluidBridgeHostUnavailableError());\n }\n pending.clear();\n context = undefined;\n sid = undefined;\n if (current.fetch === ambientFetch) current.fetch = previousFetch;\n }\n // The page entering the back/forward cache fires `pagehide` with\n // `persisted: true`: the document is frozen, not torn down, and may return via\n // `pageshow`. Destroying here would leave a restored page permanently dead\n // (host_unavailable, fetch unpatched). Only a real navigation (`persisted: false`)\n // or `unload` destroys the bridge.\n function onPageHide(event: PageTransitionEvent): void {\n if (event.persisted) return;\n destroy();\n }\n // On restore, a handshake that already resolved keeps working unchanged — tokens\n // keep flowing over `refresh_request` against the same host mount. Only a\n // handshake that had not yet resolved needs help: its retry timer may have been\n // frozen mid-flight, so resume readiness from a fresh attempt budget. Force the\n // resend even if `context` is already set — a context.deliver can land just\n // before the freeze with its paired session_token.deliver lost in transit,\n // and sendReady's normal guard would otherwise never retry once context is set.\n function onPageShow(event: PageTransitionEvent): void {\n if (!event.persisted || destroyed || settled) return;\n // The handshake window is measured from restoration: a long cache stay must\n // not let the original deadline reject the resent readiness before it is answered.\n clearTimeout(handshakeTimer);\n handshakeTimer = startHandshakeTimer();\n clearTimeout(retryTimer);\n attempts = 0;\n sendReady(true);\n }\n current.addEventListener(\"message\", onMessage);\n current.addEventListener(\"pagehide\", onPageHide);\n current.addEventListener(\"pageshow\", onPageShow);\n current.addEventListener(\"unload\", destroy);\n sendReady();\n return { getContext, getSessionToken, fetch: authenticatedFetch, destroy };\n}\n\nfunction exactOrigin(origin: string): string {\n try {\n const url = new URL(origin);\n if (\n (url.protocol === \"http:\" || url.protocol === \"https:\") &&\n url.origin === origin\n )\n return origin;\n } catch {\n /* Fail closed. */\n }\n throw new Errors.FluidBridgeConfigurationError(\n \"hostOrigin must be an exact HTTP(S) origin\",\n );\n}\nfunction uuidV7(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n let timestamp = BigInt(Date.now());\n for (let index = 5; index >= 0; index -= 1) {\n bytes[index] = Number(timestamp & 255n);\n timestamp >>= 8n;\n }\n bytes[6] = (bytes[6]! & 15) | 112;\n bytes[8] = (bytes[8]! & 63) | 128;\n const hex = Array.from(bytes, (byte) =>\n byte.toString(16).padStart(2, \"0\"),\n ).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\nfunction supportsSdk(received: string, minimum: string): boolean {\n const semver = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$/;\n if (!semver.test(received) || !semver.test(minimum)) return false;\n const left = received.split(\".\").map(Number),\n right = minimum.split(\".\").map(Number);\n if (![...left, ...right].every(Number.isSafeInteger)) return false;\n for (let index = 0; index < 3; index += 1)\n if (left[index] !== right[index]) return left[index]! > right[index]!;\n return true;\n}\nfunction boundToken(\n token: string,\n context: CanonicalBridgeContext | undefined,\n sid: string | undefined,\n): { sid: string; exp: number; iat?: number } | undefined {\n try {\n if (\n !context ||\n !/^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/.test(token)\n )\n return;\n const encoded = token.split(\".\")[1]!;\n const claims: unknown = JSON.parse(\n new TextDecoder(\"utf-8\", { fatal: true }).decode(\n Uint8Array.from(\n atob(encoded.replace(/-/g, \"+\").replace(/_/g, \"/\")),\n (c) => c.charCodeAt(0),\n ),\n ),\n );\n if (!claims || typeof claims !== \"object\" || Array.isArray(claims)) return;\n const payload = claims as Record<string, unknown>;\n const entry = payload.entry;\n if (\n payload.aud !== context.app.clientId ||\n payload.dest !== `urn:fluid:store:${context.store.uuid}` ||\n payload.sub !== `urn:fluid:${context.actor.type}:${context.actor.uuid}` ||\n typeof payload.sid !== \"string\" ||\n !payload.sid ||\n (sid !== undefined && payload.sid !== sid) ||\n typeof payload.exp !== \"number\" ||\n !Number.isSafeInteger(payload.exp) ||\n // `exp` is checked for shape only. The host deliberately does not check it\n // against its own clock either (see tokenMatchesMount in canonical-host.ts) —\n // comparing it here against this client's clock would reject a freshly minted\n // short-lived token outright for any admin whose clock runs a little fast.\n // Expiry itself is the droplet verifier's job.\n typeof entry !== \"object\" ||\n !entry ||\n !(\"type\" in entry) ||\n !(\"name\" in entry) ||\n entry.type !== context.entry.type ||\n entry.name !== context.entry.name\n )\n return;\n const iat =\n typeof payload.iat === \"number\" && Number.isSafeInteger(payload.iat)\n ? payload.iat\n : undefined;\n return iat === undefined\n ? { sid: payload.sid, exp: payload.exp }\n : { sid: payload.sid, exp: payload.exp, iat };\n } catch {\n return;\n }\n}\nfunction freezeContext(\n context: CanonicalBridgeContext,\n): CanonicalBridgeContext {\n Object.freeze(context.store);\n Object.freeze(context.app);\n Object.freeze(context.entry);\n if (context.actor.roles) Object.freeze(context.actor.roles);\n if (context.actor.permissions) Object.freeze(context.actor.permissions);\n Object.freeze(context.actor);\n context.resources.forEach(Object.freeze);\n Object.freeze(context.resources);\n Object.freeze(context.fetch.allowedOrigins);\n Object.freeze(context.fetch);\n Object.freeze(context.sdk);\n return Object.freeze(context);\n}\nfunction errorFromHost(payload: BridgeErrorPayload): Errors.FluidBridgeError {\n // Do not relay host exception text or arbitrary details into app errors.\n switch (payload.code) {\n case \"version_mismatch\":\n case \"incompatible_version\":\n return new Errors.FluidBridgeIncompatibleVersionError(\n undefined,\n versionDetails(payload.details),\n );\n case \"unauthorized\":\n return new Errors.FluidBridgeUnauthorizedError();\n case \"failed_authentication\":\n return new Errors.FluidBridgeFailedAuthenticationError();\n case \"invalid_context\":\n return new Errors.FluidBridgeInvalidContextError();\n case \"request_timeout\":\n return new Errors.FluidBridgeRequestTimeoutError();\n case \"handshake_timeout\":\n return new Errors.FluidBridgeHandshakeTimeoutError();\n case \"host_unavailable\":\n return new Errors.FluidBridgeHostUnavailableError();\n case \"forbidden_origin\":\n return new Errors.FluidBridgeForbiddenOriginError();\n default:\n return new Errors.FluidBridgeTokenMintError();\n }\n}\n\nfunction versionDetails(details: Record<string, unknown> | undefined): unknown {\n if (!details) return undefined;\n const sanitize = (value: unknown): Record<string, string> | undefined => {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return undefined;\n const record = value as Record<string, unknown>;\n return Object.fromEntries(\n [\"sdkVersion\", \"protocolVersion\"].flatMap((key) =>\n typeof record[key] === \"string\"\n ? [[key, record[key].slice(0, 32)]]\n : [],\n ),\n );\n };\n return {\n received: sanitize(details.received),\n required: sanitize(details.required),\n };\n}\n"],"mappings":";AAcA,IAAa,mBAAb,cAAsC,MAAM;CAC1C;CACA;CAEA,YAAY,MAA4B,SAAiB,SAAmB;AAC1E,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,OAAO;AACZ,OAAK,UAAU;;;AAInB,IAAa,gCAAb,cAAmD,iBAAiB;CAClE,YAAY,SAAiB,SAAmB;AAC9C,QAAM,uBAAuB,SAAS,QAAQ;AAC9C,OAAK,OAAO;;;AAIhB,IAAa,kCAAb,cAAqD,iBAAiB;CACpE,YACE,UAAU,wCACV,SACA;AACA,QAAM,oBAAoB,SAAS,QAAQ;AAC3C,OAAK,OAAO;;;AAIhB,IAAa,mCAAb,cAAsD,iBAAiB;CACrE,YACE,UAAU,wEACV,SACA;AACA,QAAM,qBAAqB,SAAS,QAAQ;AAC5C,OAAK,OAAO;;;AAIhB,IAAa,sCAAb,cAAyD,iBAAiB;CACxE,YACE,UAAU,wDACV,SACA;AACA,QAAM,wBAAwB,SAAS,QAAQ;AAC/C,OAAK,OAAO;;;AAIhB,IAAa,4BAAb,cAA+C,iBAAiB;CAC9D,YACE,UAAU,wDACV,SACA;AACA,QAAM,qBAAqB,SAAS,QAAQ;AAC5C,OAAK,OAAO;;;AAIhB,IAAa,+BAAb,cAAkD,iBAAiB;CACjE,YACE,UAAU,4CACV,SACA;AACA,QAAM,gBAAgB,SAAS,QAAQ;AACvC,OAAK,OAAO;;;AAIhB,IAAa,kCAAb,cAAqD,iBAAiB;CACpE,YACE,UAAU,6CACV,SACA;AACA,QAAM,oBAAoB,SAAS,QAAQ;AAC3C,OAAK,OAAO;;;AAIhB,IAAa,iCAAb,cAAoD,iBAAiB;CACnE,YACE,UAAU,uCACV,SACA;AACA,QAAM,mBAAmB,SAAS,QAAQ;AAC1C,OAAK,OAAO;;;AAIhB,IAAa,iCAAb,cAAoD,iBAAiB;CACnE,YACE,UAAU,sCACV,SACA;AACA,QAAM,mBAAmB,SAAS,QAAQ;AAC1C,OAAK,OAAO;;;AAIhB,IAAa,8BAAb,cAAiD,iBAAiB;CAChE,YACE,UAAU,gDACV,SACA;AACA,QAAM,4BAA4B,SAAS,QAAQ;AACnD,OAAK,OAAO;;;AAIhB,IAAa,0BAAb,cAA6C,iBAAiB;CAC5D,YAAY,UAAU,iCAAiC,SAAmB;AACxE,QAAM,iBAAiB,SAAS,QAAQ;AACxC,OAAK,OAAO;;;AAIhB,IAAa,uCAAb,cAA0D,iBAAiB;CACzE,YACE,UAAU,0CACV,SACA;AACA,QAAM,yBAAyB,SAAS,QAAQ;AAChD,OAAK,OAAO;;;;;ACxIhB,MAAa,gCAAgC;AAC7C,MAAa,sBAAsB;AACnC,MAAa,yBAAyB;AAEtC,MAAa,yBAAyB;CACpC,qBAAqB;CACrB,qBAAqB;CACrB,gBAAgB;CAChB,gBAAgB;CAChB,sBAAsB;CACtB,cAAc;CACd,qBAAqB;CACrB,iBAAiB;CACjB,gBAAgB;CACjB;;;AC0BD,SAAgB,sBACd,SACiB;CACjB,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,YAAY,gBAAgB,QAAQ,UAAU;CAEpD,MAAM,iBAAiB,UAAuC;AAC5D,MAAI,MAAM,WAAW,UAAW;AAChC,MAAI,MAAM,WAAW,QAAQ,OAAO,cAAe;AACnD,MAAI,CAAC,iBAAiB,MAAM,KAAK,CAAE;AAE9B,yBAAuB,SAAS,MAAM,MAAM,UAAU;;AAG7D,cAAa,iBAAiB,WAAW,cAAc;AAEvD,QAAO,EACL,eAAe,aAAa,oBAAoB,WAAW,cAAc,EAC1E;;AAGH,eAAe,uBACb,SACA,UACA,WACe;CACf,MAAM,cAAc,QAAQ,OAAO;AACnC,KAAI,CAAC,YAAa;AAElB,KAAI;AACF,yBAAuB,SAAS,SAAS,QAAQ,SAAS;AAE1D,UAAQ,SAAS,MAAjB;GACE,KAAK,uBAAuB,gBAAgB;IAC1C,MAAM,UAAU,MAAM,QAAQ,YAAY;AAC1C,gBAAY,YACV;KACE,IAAI,SAAS;KACb,MAAM,uBAAuB;KAC7B,SAAS;KACV,EAID,UACD;AACD;;GAEF,KAAK,uBAAuB,qBAAqB;IAC/C,MAAM,UAAU,MAAM,QAAQ,YAAY;IAC1C,MAAM,eAAe,MAAM,QAAQ,gBAAgB,QAAQ;AAC3D,QAAI,aAAa,WAAW,EAC1B,OAAM,IAAI,0BACR,wDACD;AAEH,gBAAY,YACV;KACE,IAAI,SAAS;KACb,MAAM,uBAAuB;KAC7B,SAAS,EAAE,cAAc;KAC1B,EAID,UACD;AACD;;GAEF,QACE,OAAM,IAAI,gCACR,8DACA,EAAE,MAAM,SAAS,MAAM,CACxB;;UAEE,OAAO;AACd,cAAY,YACV;GACE,IAAI,SAAS;GACb,MAAM,aAAa,MAAM;GACzB,SAAS,gBAAgB,MAAM;GAChC,EACD,UACD;;;AAIL,SAAS,uBACP,OACA,UACgB;AAChB,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,OAAM,IAAI,+BACR,8CACD;AAEH,KAAI,EAAE,cAAc,UAAU,MAAM,aAAa,SAC/C,OAAM,IAAI,qCACR,qEACD;AAEH,KACE,EAAE,cAAc,UAChB,MAAM,aAAA,UAEN,OAAM,IAAI,qCAAqC;AAEjD,QAAO;;AAGT,SAAS,iBACP,OAC0C;AAC1C,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,QAAO;AAET,QACE,QAAQ,SACR,UAAU,SACV,aAAa,SACb,OAAO,MAAM,OAAO,YACpB,OAAO,MAAM,SAAS;;AAI1B,SAAS,aAAa,OAAwB;AAC5C,KAAI,iBAAiB,qCACnB,QAAO,uBAAuB;AAEhC,KAAI,iBAAiB,oCACnB,QAAO,uBAAuB;AAEhC,KAAI,iBAAiB,6BACnB,QAAO,uBAAuB;AAEhC,KAAI,iBAAiB,0BACnB,QAAO,uBAAuB;AAEhC,KAAI,iBAAiB,+BACnB,QAAO,uBAAuB;AAEhC,KAAI,iBAAiB,gCACnB,QAAO,uBAAuB;AAEhC,QAAO,uBAAuB;;AAGhC,SAAS,gBAAgB,OAAkC;AACzD,KACE,iBAAiB,SACjB,UAAU,SACV,OAAO,MAAM,SAAS,SAEtB,QAAO;EACL,MAAM,MAAM;EACZ,SAAS,MAAM;EACf,SAAS,aAAa,QAAQ,MAAM,UAAU,KAAA;EAC/C;AAEH,QAAO;EACL,MAAM;EACN,SAAS;EACT,SAAS;EACV;;AAGH,SAAS,gBAAgB,QAAwB;AAC/C,QAAO,IAAI,IAAI,OAAO,CAAC;;ACjDzB,MAAM,eAAmC,EAAE,MAAM,WAAW;AAC5D,MAAM,cAAkC,EAAE,MAAM,UAAU;AAC1D,MAAM,sBAA0C;CAC9C,MAAM;CACN,UAAU;CACX;AACD,MAAM,mBAAuC,EAAE,MAAM,UAAU;AAC/D,MAAM,yBAA6C;CACjD,MAAM;CACN,sBAAsB;CACvB;AACD,MAAM,mBAAuC,EAAE,MAAM,gBAAgB;AAKrE,MAAM,qBAAyC;CAC7C,MAAM;CACN,UAAU;EACR,iBAAiB;GACf,MAAM;GACN,QAAQ,CAAA,IAAyB;GAClC;EACD,KAAK;GACH,MAAM;GACN,UAAU,EAAE,UAAU,qBAAqB;GAC5C;EACD,OAAO;GACL,MAAM;GACN,UAAU;IACR,WAAW;IACX,KAAK;IACN;GACD,UAAU;IACR,MAAM;IACN,MAAM;IACN,QAAQ;IACT;GACF;EACD,OAAO;GACL,MAAM;GACN,UAAU,EACR,MAAM;IACJ,MAAM;IACN,QAAQ,CAAC,eAAe,eAAe;IACxC,EACF;GACD,UAAU;IACR,MAAM;IACN,OAAO;IACP,aAAa;IACb,YAAY;IACb;GACF;EACD,OAAO;GACL,MAAM;GACN,UAAU,EACR,MAAM;IACJ,MAAM;IACN,QAAQ;KACN;KACA;KACA;KACA;KACA;KACD;IACF,EACF;GACD,UAAU,EAAE,MAAM,aAAa;GAChC;EACD,WAAW;GACT,MAAM;GACN,OAAO;IACL,MAAM;IACN,UAAU;KAAE,MAAM;KAAqB,IAAI;KAAqB;IACjE;GACF;EACD,OAAO;GACL,MAAM;GACN,UAAU,EAAE,gBAnEmC,EACnD,MAAM,yBACP,EAiE2D;GACvD;EACD,KAAK;GACH,MAAM;GACN,UAAU,EAAE,YAAY,qBAAqB;GAC7C,UAAU,EAAE,oBAAoB,aAAa;GAC9C;EACF;CACF;AAED,MAAa,yBAA+C;CAC1D,gBAAgB;EACd,WAAW;EACX,iBAAiB;EACjB,cAAc;EACf;CACD,yBAAyB;EACvB,WAAW;EACX,iBAAiB;EACjB,cAAc;GACZ,MAAM;GACN,UAAU,EAAE,cAAc,qBAAqB;GAChD;EACF;CACD,iCAAiC;EAC/B,WAAW;EACX,iBAAiB;GACf,cAAc,CAAC,wBAAwB;GACvC,aAAa;GACd;EACD,cAAc;GACZ,MAAM;GACN,UAAU;IACR,UAAU;IACV,YAAY;IACZ,iBAAiB;IAClB;GACF;EACF;CACD,mBAAmB;EACjB,WAAW;EACX,iBAAiB;EACjB,cAAc;EACf;CACD,eAAe;EACb,WAAW;EACX,iBAAiB;GACf,cAAc,CAAC,WAAW,aAAa;GACvC,aAAa;GACd;EACD,cAAc;GACZ,MAAM;GACN,UAAU;IACR,QAAQ;IACR,QAAQ;KAAE,MAAM;KAAU,QAAQ;KAAc;IACjD;GACF;EACF;CACD,WAAW;EACT,WAAW;EACX,iBAAiB;EACjB,cAAc;EACf;CACD,cAAc;EACZ,WAAW;EACX,iBAAiB;EACjB,cAAc;GACZ,MAAM;GACN,UAAU,EAAE,QAAQ,qBAAqB;GAC1C;EACF;CACD,cAAc;EACZ,WAAW;EACX,iBAAiB;GACf,cAAc,CAAC,cAAc;GAC7B,aAAa;GACd;EAED,cAAc;EACf;CACD,eAAe;EACb,WAAW;EACX,iBAAiB;EACjB,cAAc;EACf;CACD,cAAc;EACZ,WAAW;EACX,iBAAiB;EAEjB,cAAc;EACf;CACD,oBAAoB;EAClB,WAAW;EACX,iBAAiB;EAEjB,cAAc;EACf;CACD,OAAO;EACL,WAAW;EACX,iBAAiB;EACjB,cAAc;GACZ,MAAM;GACN,UAAU;IACR,MAAM;IACN,SAAS;IACV;GACD,UAAU,EACR,SAAS;IAAE,MAAM;IAAU,QAAQ;IAAc,EAClD;GACF;EACF;CACF;AAqBD,SAAgB,oBACd,OACA,SAC2B;AAC3B,KAAI;AACF,MAAI,CAAC,SAAS,MAAM,CAClB,QAAO;GAAE,IAAI;GAAO,QAAQ;GAAa;EAM3C,MAAM,YACJ,OAAO,MAAM,eAAe,YAC5B,cAAc,KAAK,MAAM,WAAW,GAChC,MAAM,aACN,KAAA;AAEN,MAAI,CAAC,aAAa,OAAO,aAAa,CACpC,QAAO,aAAa,aAAa,UAAU;AAG7C,MAAI,MAAM,YAAA,IACR,QAAO,aAAa,oBAAoB,UAAU;AAGpD,MACE,OAAO,MAAM,SAAS,YACtB,OAAO,MAAM,eAAe,YAC5B,CAAC,cAAc,KAAK,MAAM,WAAW,CAErC,QAAO,aAAa,aAAa,UAAU;AAG7C,MAAI,CAAC,oBAAoB,MAAM,KAAK,CAClC,QAAO,aAAa,gBAAgB,UAAU;EAGhD,MAAM,eAAe,uBAAuB,MAAM;AAClD,MAAI,CAAC,mBAAmB,aAAa,WAAW,QAAQ,WAAW,CACjE,QAAO,aAAa,mBAAmB,UAAU;AAGnD,MAAI,CAAC,oBAAoB,MAAM,SAAS,aAAa,aAAa,CAChE,QAAO,aAAa,mBAAmB,UAAU;AAGnD,SAAO;GAAE,IAAI;GAAM,UAAU;GAAkC;SACzD;AACN,SAAO;GAAE,IAAI;GAAO,QAAQ;GAAa;;;AAgB7C,MAAM,eAAkC;CACtC;CACA;CACA;CACA;CACD;AAED,MAAM,gBACJ;AAEF,SAAS,SAAS,OAAkD;AAClE,KAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,MAAM,CACrE,QAAO;CAMT,MAAM,YAAqB,OAAO,eAAe,MAAM;AAEvD,QAAO,cAAc,OAAO,aAAa,cAAc;;AAUzD,SAAS,aAAa,OAAoC;AACxD,KAAI,CAAC,MAAM,QAAQ,MAAM,CAAE,QAAO;AAClC,KAAI,OAAO,KAAK,MAAM,CAAC,WAAW,MAAM,OAAQ,QAAO;AAEvD,MAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,EACjD,KAAI,CAAC,OAAO,OAAO,OAAO,MAAM,CAAE,QAAO;AAG3C,QAAO;;AAGT,SAAS,aACP,OACA,cACS;AAET,QADmB,OAAO,KAAK,MAAM,CAExB,WAAW,aAAa,UACnC,aAAa,OAAO,QAAQ,OAAO,OAAO,OAAO,IAAI,CAAC;;AAI1D,SAAS,oBAAoB,OAA2C;AACtE,QAAO,OAAO,OAAO,wBAAwB,MAAM;;AAGrD,SAAS,aACP,QACA,WAC2B;AAC3B,QAAO,cAAc,KAAA,IACjB;EAAE,IAAI;EAAO;EAAQ,GACrB;EAAE,IAAI;EAAO;EAAQ;EAAW;;AAGtC,SAAS,mBACP,WACA,YACS;AACT,QACE,cAAc,UACb,cAAc,qBAAqB,eAAe,WAClD,cAAc,qBAAqB,eAAe;;AAIvD,SAAS,oBACP,OACA,OACS;AACT,KAAI,MAAM,SAAS,UACjB,QAAO;AAGT,KAAI,MAAM,SAAS,SACjB,QACE,OAAO,UAAU,aAAa,MAAM,aAAa,QAAQ,MAAM,SAAS;AAI5E,KAAI,MAAM,SAAS,eACjB,QACE,aAAa,MAAM,IAAI,MAAM,OAAO,SAAS,OAAO,SAAS,SAAS;AAI1E,KAAI,MAAM,SAAS,wBACjB,QAAO,aAAa,MAAM,IAAI,MAAM,MAAM,iBAAiB;AAG7D,KAAI,MAAM,SAAS,cACjB,QAAO,OAAO,UAAU,YAAY,MAAM,OAAO,SAAS,MAAM;AAGlE,KAAI,MAAM,SAAS,QACjB,QACE,aAAa,MAAM,IACnB,MAAM,OAAO,SAAS,oBAAoB,MAAM,MAAM,MAAM,CAAC;AAIjE,KAAI,MAAM,SAAS,SACjB,QACE,SAAS,MAAM,IACf,OAAO,OAAO,MAAM,CAAC,OAAO,SAC1B,oBAAoB,MAAM,MAAM,OAAO,CACxC;AAIL,KAAI,CAAC,SAAS,MAAM,CAClB,QAAO;CAGT,MAAM,WAAW,MAAM,YAAY,EAAE;CACrC,MAAM,WAAW,MAAM,YAAY,EAAE;CACrC,MAAM,YAAY,IAAI,IAAI,CACxB,GAAG,OAAO,KAAK,SAAS,EACxB,GAAG,OAAO,KAAK,SAAS,CACzB,CAAC;AAEF,KACE,CAAC,OAAO,QAAQ,SAAS,CAAC,OACvB,CAAC,KAAK,gBACL,OAAO,OAAO,OAAO,IAAI,IACzB,oBAAoB,MAAM,MAAM,WAAW,CAC9C,CAED,QAAO;AAGT,KACE,CAAC,OAAO,QAAQ,SAAS,CAAC,OACvB,CAAC,KAAK,gBACL,CAAC,OAAO,OAAO,OAAO,IAAI,IAC1B,oBAAoB,MAAM,MAAM,WAAW,CAC9C,CAED,QAAO;AAGT,QACE,MAAM,yBAAyB,QAC/B,OAAO,KAAK,MAAM,CAAC,OAAO,QAAQ,UAAU,IAAI,IAAI,CAAC;;AAIzD,SAAS,iBAAiB,OAAyB;AACjD,KAAI,OAAO,UAAU,YAAY,UAAU,IACzC,QAAO;AAGT,KAAI;EACF,MAAM,MAAM,IAAI,IAAI,MAAM;AAC1B,UACG,IAAI,aAAa,YAAY,IAAI,aAAa,YAC/C,IAAI,WAAW,UACf,IAAI,WAAW;SAEX;AACN,SAAO;;;;;ACxiBX,MAAM,qBAAqB;AAC3B,MAAM,uBAAuB;AAC7B,MAAM,wBAAwB;;AAG9B,SAAgB,0BACd,SACqB;CACrB,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,YAAYA,cAAY,QAAQ,UAAU;CAEhD,MAAM,QAA+B,OAAO,OAAO;EACjD,GAAG,QAAQ;EACX,OAAO,OAAO,OAAO,EAAE,GAAG,QAAQ,MAAM,OAAO,CAAC;EAChD,OAAO,OAAO,OAAO,EAAE,GAAG,QAAQ,MAAM,OAAO,CAAC;EACjD,CAAC;AACF,KACE,CAAC,MAAM,SAAS,MAAM,IACtB,CAAC,MAAM,UAAU,MAAM,IACvB,CAAC,MAAM,MAAM,KAAK,MAAM,IACxB,CAAC,MAAM,eAAe,MAAM,IAC5B,CAAC,MAAM,MAAM,KAAK,MAAM,IACxB,CAAC,MAAM,IAAI,MAAM,CAEjB,OAAM,IAAI,8BACR,yCACD;CAEH,MAAM,SAAS,QAAQ;CACvB,MAAM,cAAc,OAAO;AAC3B,KAAI,CAAC,YACH,OAAM,IAAI,8BAA8B,iCAAiC;CAC3E,MAAM,WAAW,OAAO;AACxB,KAAI,IAAI,IAAI,SAAS,CAAC,WAAW,UAC/B,OAAM,IAAI,8BACR,8CACD;CAGH,IAAI,YAAY;CAChB,IAAI;CASJ,IAAI;CACJ,IAAI,QAAQ;CAIZ,MAAM,+BAAe,IAAI,KAA8B;CACvD,MAAM,iCAAiB,IAAI,KAA8B;CAEzD,MAAM,kBACJ,CAAC,aACD,OAAO,kBAAkB,eACzB,OAAO,QAAQ;CACjB,MAAM,QAAQ,aAA4C;AACxD,MAAI,WAAW,CAAE,aAAY,YAAY,UAAU,UAAU;;CAE/D,MAAM,QAAQ,WAAmB,YAAsC;AACrE,OAAK;GACH,MAAM;GACN;GACA,YAAY;GACZ,SAAA;GACD,CAAC;;CAGJ,MAAM,MAAM,OACV,WACA,WACA,YACkB;EAClB,MAAM,OAAO,UAAU,eAAe;AACtC,MAAI,KAAK,IAAI,UAAU,CAAE;AACzB,MAAI,KAAK,QAAQ,sBAAsB;AACrC,QAAK,WAAW;IACd,MAAM;IACN,SAAS;IACV,CAAC;AACF;;EAEF,MAAM,aAAa,IAAI,iBAAiB;AACxC,OAAK,IAAI,WAAW,WAAW;EAC/B,MAAM,QAAQ,iBACN,WAAW,MAAM,IAAI,gCAAgC,CAAC,EAC5D,mBACD;AACD,MAAI;AAEF,SAAMC,YAAU,UAAU,WAAW,OAAO,EAAE,WAAW,OAAO;WACzD,OAAO;AACd,OAAI,WAAW,CAAE,MAAK,WAAW,UAAU,OAAO,QAAQ,CAAC;YACnD;AACR,gBAAa,MAAM;AACnB,QAAK,OAAO,UAAU;;;CAI1B,MAAM,OAAO,OAAO,WAAyC;EAC3D,MAAM,QAAQ,MAAM,QAAQ,gBAAgB,OAAO,OAAO;AAC1D,MAAI,OAAO,QAAS,OAAM,OAAO;AACjC,MAAI,OAAO,UAAU,YAAY,CAAC,kBAAkB,OAAO,MAAM,CAC/D,OAAM,IAAI,2BAA2B;AAEvC,SAAO;;CAGT,MAAM,eAAe,OACnB,WACoC;EACpC,IAAI;AACJ,MAAI;AACF,eAAY,MAAM,QAAQ,WAAW,OAAO;WACrC,OAAO;AACd,OAAI,OAAO,WAAW,iBAAiB,iBAAkB,OAAM;AAC/D,SAAM,IAAI,gCAAgC;;AAE5C,MAAI,OAAO,QAAS,OAAM,OAAO;AACjC,SAAO,aAAa,WAAW,OAAO,UAAU;;CAGlD,MAAM,UAAU,OACd,WACA,WACkB;EAKlB,MAAM,mBAAmB,MAAM,aAAa,OAAO;EACnD,MAAM,QAAQ,MAAM,KAAK,OAAO;AAChC,MAAI,OAAO,QAAS,OAAM,OAAO;AACjC,MAAI,CAAC,WAAW,CAAE;AAClB,YAAU;AACV,mBAAiB,iBACb,IAAI,IAAI,CAAC,GAAG,gBAAgB,GAAG,iBAAiB,MAAM,eAAe,CAAC,GACtE,IAAI,IAAI,iBAAiB,MAAM,eAAe;AAClD,OAAK;GACH,MAAM;GACN,SAAS;GACT,YAAY;GACZ,SAAA;GACD,CAAC;AACF,OAAK;GACH,MAAM;GACN,SAAS,EAAE,cAAc,OAAO;GAChC,YAAY;GACZ,SAAA;GACD,CAAC;AACF,UAAQ;;CAGV,MAAM,UAAU,OACd,WACA,SACA,WACkB;AAClB,MAAI,CAAC,SAAS,CAAC,SAAS;AACtB,QAAK,WAAW;IACd,MAAM;IACN,SAAS;IACV,CAAC;AACF;;AAEF,MAAI,QAAQ,aAAa,MAAM,UAAU;AACvC,QAAK,WAAW;IACd,MAAM;IACN,SAAS;IACV,CAAC;AACF;;AAEF,MACE,QAAQ,oBAAA,OACR,CAACC,cAAY,QAAQ,YAAY,QAAQ,IAAI,WAAW,EACxD;AACA,QAAK,WAAW;IACd,MAAM;IACN,SAAS;IACT,SAAS;KACP,UAAU;MACR,YAAY,QAAQ,WAAW,MAAM,GAAG,GAAG;MAC3C,iBAAiB,QAAQ,gBAAgB,MAAM,GAAG,GAAG;MACtD;KACD,UAAU;MACR,YAAY,QAAQ,IAAI;MACxB,iBAAA;MACD;KACF;IACF,CAAC;AACF;;EAEF,MAAM,oBAAoB,MAAM,aAAa,OAAO;AACpD,MAAI,CAACA,cAAY,QAAQ,YAAY,kBAAkB,IAAI,WAAW,EAAE;AACtE,QAAK,WAAW;IACd,MAAM;IACN,SAAS;IACV,CAAC;AACF;;AAQF,MACE,kBACA,CAAC,GAAG,eAAe,CAAC,MACjB,WAAW,CAAC,kBAAkB,MAAM,eAAe,SAAS,OAAO,CACrE,EACD;AACA,QAAK,WAAW;IACd,MAAM;IACN,SAAS;IACV,CAAC;AACF;;AAEF,YAAU;EACV,MAAM,QAAQ,MAAM,KAAK,OAAO;AAChC,MAAI,OAAO,QAAS,OAAM,OAAO;AACjC,OAAK;GACH,MAAM;GACN,SAAS,EAAE,cAAc,OAAO;GAChC,YAAY;GACZ,SAAA;GACD,CAAC;;CAGJ,MAAM,iBAAiB,UAAuC;AAC5D,MACE,CAAC,WAAW,IACZ,MAAM,WAAW,aACjB,MAAM,WAAW,YAEjB;EACF,MAAM,SAAS,oBAAoB,MAAM,MAAM,EAAE,YAAY,SAAS,CAAC;AACvE,MAAI,CAAC,OAAO,IAAI;AACd,OAAI,OAAO,WAAW,sBAAsB,OAAO,UACjD,MAAK,OAAO,WAAW;IACrB,MAAM;IACN,SAAS;IACV,CAAC;YAEF,OAAO,WAAW,qBAClB,OAAO,aACP,OAAO,MAAM,SAAS,YACtB,MAAM,SAAS,QACf,UAAU,MAAM,QAChB,MAAM,KAAK,SAAS,gCAEpB,MAAK,OAAO,WAAW;IACrB,MAAM;IACN,SAAS;IACV,CAAC;AAEJ;;EAEF,MAAM,WAAW,OAAO;AACxB,MAAI,SAAS,SAAS,gBAAgB;AAIpC,OAAI,aAAa,IAAI,SAAS,WAAW,CAAE;AACtC,OACH,SAAS,aACR,WAAW,QAAQ,SAAS,YAAY,OAAO,EAChD,KACD;aACQ,SAAS,SAAS,gCACtB,KACH,SAAS,aACR,WAAW,QAAQ,SAAS,YAAY,SAAS,SAAS,OAAO,EAClE,MACD;;AAGL,cAAa,iBAAiB,WAAW,cAAc;AACvD,QAAO,EACL,eAAe;AACb,cAAY;AACZ,eAAa,oBAAoB,WAAW,cAAc;AAC1D,OAAK,MAAM,cAAc,aAAa,QAAQ,CAAE,YAAW,OAAO;AAClE,OAAK,MAAM,cAAc,eAAe,QAAQ,CAAE,YAAW,OAAO;AACpE,eAAa,OAAO;AACpB,iBAAe,OAAO;AACtB,YAAU,KAAA;AACV,mBAAiB,KAAA;AACjB,UAAQ;IAEX;;AAQH,SAAS,kBAAkB,OAAe,OAA6B;AACrE,KAAI;AACF,MAAI,CAAC,mDAAmD,KAAK,MAAM,CACjE,QAAO;EACT,MAAM,UAAU,MAAM,MAAM,IAAI,CAAC;AACjC,MAAI,CAAC,QAAS,QAAO;EACrB,MAAM,SAAkB,KAAK,MAC3B,IAAI,YAAY,SAAS,EAAE,OAAO,MAAM,CAAC,CAAC,OACxC,WAAW,KACT,KAAK,QAAQ,QAAQ,MAAM,IAAI,CAAC,QAAQ,MAAM,IAAI,CAAC,GAClD,cAAc,UAAU,WAAW,EAAE,CACvC,CACF,CACF;AACD,MAAI,OAAO,WAAW,YAAY,WAAW,QAAQ,MAAM,QAAQ,OAAO,CACxE,QAAO;EACT,MAAM,UAAU;EAChB,MAAM,QAAQ,QAAQ;AACtB,SACE,QAAQ,QAAQ,MAAM,YACtB,QAAQ,SAAS,mBAAmB,MAAM,eAC1C,QAAQ,QAAQ,aAAa,MAAM,MAAM,KAAK,GAAG,MAAM,MAAM,UAC7D,QAAQ,QAAQ,MAAM,OACtB,OAAO,QAAQ,QAAQ,YACvB,OAAO,UAAU,QAAQ,IAAI,IAC7B,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,MAAM,SAAS,MAAM,MAAM,QAC3B,UAAU,SACV,MAAM,SAAS,MAAM,MAAM;SAEvB;AACN,SAAO;;;AAIX,SAASF,cAAY,OAAuB;AAC1C,KAAI;EACF,MAAM,MAAM,IAAI,IAAI,MAAM;AAC1B,OACG,IAAI,aAAa,YAAY,IAAI,aAAa,YAC/C,IAAI,WAAW,MAEf,QAAO;SACH;AAGR,OAAM,IAAI,8BACR,4CACD;;AAGH,SAAS,aACP,OACA,OACA,WACwB;CACxB,MAAM,SAAS,oBACb;EACE,MAAM;EACN,SAAS;EACT,YAAY;EACZ,SAAA;EACD,EACD,EAAE,YAAY,UAAU,CACzB;AACD,KAAI,CAAC,OAAO,MAAM,OAAO,SAAS,SAAS,kBACzC,OAAM,IAAI,gCAAgC;CAC5C,MAAM,UAAU,OAAO,SAAS;AAChC,KACE,QAAQ,IAAI,aAAa,MAAM,YAC/B,QAAQ,MAAM,SAAS,MAAM,aAC7B,QAAQ,MAAM,SAAS,MAAM,MAAM,QACnC,QAAQ,MAAM,SAAS,MAAM,MAAM,QACnC,QAAQ,MAAM,SAAS,MAAM,MAAM,QACnC,QAAQ,MAAM,SAAS,MAAM,MAAM,QACnC,CAAC,QAAQ,MAAM,eAAe,SAAS,UAAU,IACjD,CAACE,cAAY,QAAQ,IAAI,YAAY,QAAQ,IAAI,WAAW,CAE5D,OAAM,IAAI,gCAAgC;AAC5C,QAAO;;AAIT,SAASA,cAAY,UAAkB,SAA0B;CAC/D,MAAM,UAAU;AAChB,KAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAE,QAAO;CAC9D,MAAM,UAAU,SAAS,MAAM,IAAI,CAAC,IAAI,OAAO;CAC/C,MAAM,WAAW,QAAQ,MAAM,IAAI,CAAC,IAAI,OAAO;AAC/C,KAAI,CAAC,CAAC,GAAG,SAAS,GAAG,SAAS,CAAC,MAAM,OAAO,cAAc,CAAE,QAAO;AACnE,MAAK,MAAM,SAAS;EAAC;EAAG;EAAG;EAAE,EAAE;EAC7B,MAAM,OAAO,QAAQ;EACrB,MAAM,QAAQ,SAAS;AACvB,MAAI,SAAS,KAAA,KAAa,UAAU,KAAA,EAAW,QAAO;AACtD,MAAI,SAAS,MAAO,QAAO,OAAO;;AAEpC,QAAO;;AAGT,SAAS,UAAU,OAAgB,SAAsC;AACvE,KAAI,iBAAiB,+BACnB,QAAO;EACL,MAAM,UAAU,sBAAsB;EACtC,SAAS;EACV;AAEH,KAAI,iBAAiB,kBAAkB;EACrC,MAAM,OAAO,MAAM;AACnB,MACE,SAAS,kBACT,SAAS,2BACT,SAAS,qBACT,SAAS,0BACT,SAAS,mBAET,QAAO;GAAE;GAAM,SAAS;GAA8C;;AAI1E,QAAO;EACL,MAAM;EACN,SAAS;EACV;;AAGH,SAASD,YAAa,WAAuB,QAAiC;AAC5E,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,cAAoB,OAAO,OAAO,OAAO;AAC/C,MAAI,OAAO,SAAS;AAClB,UAAO;AACP;;AAEF,SAAO,iBAAiB,SAAS,OAAO,EAAE,MAAM,MAAM,CAAC;AACvD,YACG,KAAK,SAAS,OAAO,CACrB,cAAc,OAAO,oBAAoB,SAAS,MAAM,CAAC;GAC5D;;;;ACrcJ,MAAM,6BAA6B;AAEnC,eAAsB,0BAA0B,EAC9C,SACA,YACA,WACA,OAAO,sBAAsB,WAAW,OAAO,KAAK,WAAW,IACX;AACpD,KAAI,CAAC,oBACH,OAAM,IAAI,0BACR,+EACD;CAGH,MAAM,WAAW,MAAM,oBACrB,uBAAuB,WAAW,EAClC;EACE,QAAQ;EACR,SAAS,oBAAoB,UAAU;EACvC,MAAM,KAAK,UAAU,wBAAwB,QAAQ,CAAC;EACvD,CACF;CAED,MAAM,OAAgB,MAAM,SAAS,MAAM,CAAC,YAAY,KAAK;AAE7D,KAAI,CAAC,SAAS,GACZ,OAAM,sBAAsB,SAAS,QAAQ,KAAK;AAGpD,KAAI,CAAC,8BAA8B,KAAK,IAAI,KAAK,cAAc,WAAW,EACxE,OAAM,IAAI,0BACR,uEACA,EAAE,MAAM,CACT;AAGH,QAAO,KAAK;;AAGd,SAAgB,+BACd,SACA,WAC8B;AAC9B,QAAO;EACL,UAAU,QAAQ,IAAI;EACtB,OAAO,QAAQ;EACf,WAAW,QAAQ;EACnB,gBAAgB,QAAQ,MAAM;EAC9B,GAAI,YAAY,EAAE,WAAW,GAAG,EAAE;EACnC;;AAGH,SAAS,oBAAoB,WAAwC;CACnE,MAAM,UAAU,IAAI,QAAQ;EAC1B,gBAAgB;EAChB,+BAA+B;EAC/B,8BAA8B;EAC9B,0BAA0B;EAC3B,CAAC;AAEF,KAAI,UACF,SAAQ,IAAI,iBAAiB,UAAU,YAAY;AAGrD,QAAO;;AAGT,SAAS,wBACP,SACyB;AACzB,QAAO;EACL,WAAW,QAAQ;EACnB,OAAO,QAAQ;EACf,WAAW,QAAQ,aAAa,EAAE;EAClC,iBAAiB,QAAQ,kBAAkB,EAAE;EAC7C,GAAI,QAAQ,YAAY,EAAE,YAAY,QAAQ,WAAW,GAAG,EAAE;EAC/D;;AAGH,SAAS,uBAAuB,YAAwC;AACtE,KAAI,CAAC,WACH,QAAO,IAAI;AAEb,QAAO,IAAI,IACT,4BACA,oBAAoB,WAAW,CAChC,CAAC,UAAU;;AAGd,SAAS,oBAAoB,KAAqB;AAChD,QAAO,IAAI,SAAS,IAAI,GAAG,MAAM,GAAG,IAAI;;AAG1C,SAAS,8BACP,OACsC;AACtC,QACE,OAAO,UAAU,YACjB,UAAU,QACV,mBAAmB,SACnB,OAAO,MAAM,kBAAkB;;AAInC,SAAS,sBAAsB,QAAgB,MAAsB;CACnE,MAAM,YAAY,sBAAsB,KAAK,GAAG,KAAK,QAAQ,KAAA;CAC7D,MAAM,UACJ,WAAW,WACX;CACF,MAAM,UAAU,WAAW,WAAW;AAEtC,KAAI,WAAW,IACb,QAAO,IAAI,6BAA6B,SAAS,QAAQ;AAE3D,KAAI,WAAW,IACb,QAAO,IAAI,qCAAqC,SAAS,QAAQ;AAEnE,KAAI,WAAW,IACb,QAAO,IAAI,oCAAoC,SAAS,QAAQ;AAElE,QAAO,IAAI,0BAA0B,SAAS,QAAQ;;AAGxD,SAAS,sBAAsB,OAA8C;AAC3E,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,WAAW;;;;;ACxInE,SAAgB,yBACd,SACc;AACd,QAAO,OAAO,OAAO,SAAS;EAC5B,MAAM,UAAU,QAAQ,YAAY;EACpC,IAAI;AACJ,MAAI;AACF,SAAM,IAAI,IACR,iBAAiB,UAAU,MAAM,MAAM,MAAM,UAAU,EACvD,QACD;UACK;AACN,SAAM,IAAI,6BAA6B;;AAKzC,MAFE,IAAI,aAAa,mBACjB,IAAI,SAAS,SAAS,iBAAiB,EAC3B;AACZ,OAAI,QAAQ,QAAS,QAAO,QAAQ,YAAY,OAAO,KAAK;AAC5D,SAAM,IAAI,6BAA6B;;AAEzC,MAAI,QAAQ,SAAS;GAOnB,MAAM,QAAQ,QAAQ,mBAAmB;AACzC,OAAI,UAAU,SAAU,QAAO,QAAQ,YAAY,OAAO,KAAK;AAM/D,OAAI,UAAU,eAAe,IAAI,WAAW,eAAe,QAAQ,CACjE,QAAO,QAAQ,YAAY,OAAO,KAAK;GAOzC,MAAM,YAAY,QAAQ,qBAAqB;AAC/C,OAAI;QACE,CAAC,UAAU,MAAM,eAAe,SAAS,IAAI,OAAO,CACtD,QAAO,QAAQ,YAAY,OAAO,KAAK;cAEhC,IAAI,WAAW,eAAe,QAAQ,CAC/C,QAAO,QAAQ,YAAY,OAAO,KAAK;;EAG3C,MAAM,SAAS,cAAc,OAAO,KAAK;AACzC,MAAI,QAAQ,QAAS,OAAM,OAAO;EAClC,IAAI;AACJ,MAAI;AACF,aAAU,SACN,MAAM,UAAU,QAAQ,YAAY,EAAE,OAAO,GAC7C,MAAM,QAAQ,YAAY;WACvB,OAAO;AAKd,OAAI,QAAQ,WAAW,QAAQ,mBAAmB,KAAK,SACrD,QAAO,QAAQ,YAAY,OAAO,KAAK;AACzC,SAAM;;AAER,MAAI,CAAC,QAAQ,MAAM,eAAe,SAAS,IAAI,OAAO,EAAE;AACtD,OAAI,QAAQ,QAAS,QAAO,QAAQ,YAAY,OAAO,KAAK;AAC5D,SAAM,IAAI,6BAA6B;;EAEzC,MAAM,SAAS,QAAQ,MAAM;AAC7B,MAAI,CAAC,UAAU,CAAC,sCAAsC,KAAK,OAAO,CAChE,OAAM,IAAI,gCAAgC;EAC5C,IAAI;AACJ,MAAI;AACF,aAAU,IAAI,QAAQ,iBAAiB,UAAU,QAAQ,KAAK,KAAK;UAC7D;AACN,SAAM,IAAI,yBAAyB;;AAErC,UAAQ,OAAO,gBAAgB;EAC/B,MAAM,QAAQ,MAAM,UAAU,QAAQ,iBAAiB,EAAE,QAAQ,OAAO;EACxE,MAAM,UAAU,IAAI,QAAQ,QAAQ,QAAQ;AAC5C,UAAQ,IAAI,iBAAiB,UAAU,QAAQ;AAC/C,UAAQ,IAAI,mBAAmB,OAAO,WAAW,KAAK,IAAI,CAAC;EAC3D,IAAI;AACJ,MAAI;AAMF,mBAAgB,IAAI,QAAQ,SAAS;IACnC;IACA,GAAI,QAAQ,UAAU,EAAE,GAAG,EAAE,UAAU,SAAS;IACjD,CAAC;UACI;AACN,SAAM,IAAI,yBAAyB;;EAErC,IAAI;AACJ,MAAI;AACF,cAAW,MAAM,QAAQ,YAAY,cAAc;UAC7C;AACN,OAAI,QAAQ,OAAO,QAAS,OAAM,QAAQ,OAAO;AACjD,SAAM,IAAI,yBAAyB;;AAIrC,MACE,CAAC,QAAQ,YACR,SAAS,WAAW,OAAO,SAAS,WAAW,KAEhD,OAAM,IAAI,sCAAsC;AAClD,SAAO;;;AAGX,SAAS,eAAe,SAAqC;AAC3D,KAAI;AACF,SAAO,IAAI,IAAI,QAAQ,CAAC;SAClB;AACN;;;AAMJ,SAAS,cACP,OACA,MACyB;AACzB,KAAI,MAAM,WAAW,KAAA,EAAW,QAAO,KAAK,UAAU,KAAA;AACtD,QAAO,iBAAiB,UAAU,MAAM,SAAS,KAAA;;AAEnD,SAAS,UAAa,SAAqB,QAAiC;AAC1E,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,cAAc,OAAO,OAAO,OAAO;AACzC,MAAI,OAAO,SAAS;AAClB,UAAO;AACP;;AAEF,SAAO,iBAAiB,SAAS,OAAO,EAAE,MAAM,MAAM,CAAC;AACvD,UACG,KAAK,SAAS,OAAO,CACrB,cAAc,OAAO,oBAAoB,SAAS,MAAM,CAAC;GAC5D;;;;ACxIJ,MAAM,kCAAkB,IAAI,SAAiB;;AAG7C,SAAgB,kBACd,SACa;AACb,KACE,CAAC,WACD,OAAO,QAAQ,aAAa,YAC5B,CAAC,QAAQ,SAAS,MAAM,IACxB,gBAAgB,QAEhB,OAAM,IAAIE,8BACR,oDACD;CAEH,MAAM,aAAa,YAAY,QAAQ,WAAW;CAClD,MAAM,UAAU,QAAQ,gBAAgB,WAAW;AACnD,KAAI,CAAC,WAAW,QAAQ,WAAW,QACjC,OAAM,IAAIC,iCAAwC;CACpD,MAAM,SAAS,QAAQ;CACvB,MAAM,cAAc,QAAQ,SAAS,QAAQ,OAAO,KAAK,QAAQ;CACjE,MAAM,UAAU,QAAQ,aAAa;AACrC,KACE,OAAO,gBAAgB,cACvB,CAAC,OAAO,SAAS,QAAQ,IACzB,UAAU,KACV,UAAU,IAEV,OAAM,IAAID,8BACR,0DACD;AAEH,KAAI,gBAAgB,IAAI,QAAQ,CAC9B,OAAM,IAAIA,8BACR,0DACD;CACH,MAAM,YAAY,IAAI,IAAI,QAAQ,SAAS,KAAK;AAChD,KAAI,UAAU,aAAa,IAAI,gBAAgB,EAAE;AAC/C,YAAU,aAAa,OAAO,gBAAgB;AAC9C,UAAQ,QAAQ,aAAa,QAAQ,QAAQ,OAAO,IAAI,UAAU,KAAK;;AAEzE,iBAAgB,IAAI,QAAQ;CAC5B,MAAM,UAAU,QAAQ;CACxB,MAAM,0BAAU,IAAI,KAA2B;CAC/C,IAAI;CACJ,IAAI;CACJ,IAAI,YAAY;CAChB,IAAI,UAAU;CACd,IAAI,kBAAkB;CACtB,IAAI;CACJ,IAAI,WAAW;CACf,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM,YAAY,IAAI,SAAiC,SAAS,WAAW;AACzE,qBAAmB;AACnB,oBAAkB;GAClB;AAEG,WAAU,YAAY,KAAA,EAAU;CACrC,MAAM,4BACJ,iBACQ,cAAc,IAAIE,kCAAyC,CAAC,EAClE,QACD;CACH,IAAI,iBAAiB,qBAAqB;CAC1C,SAAS,iBAA4C;AACnD,MAAI,UAAW,QAAO;AACtB,MAAI,gBAAiB,QAAO;AAC5B,SAAO,UAAU,aAAa;;CAGhC,SAAS,KAAK,UAAyC;AACrD,MAAI,UAAW;AACf,MAAI;AACF,UAAO,YAAY,UAAU,WAAW;UAClC;AACN,iBACE,SAAS,YACT,IAAID,iCAAwC,CAC7C;;;CAGL,SAAS,cAAc,OAAsC;AAC3D,MAAI,QAAS;AACb,YAAU;AACV,oBAAkB;AAClB,eAAa,eAAe;AAC5B,eAAa,WAAW;AACxB,kBAAgB,MAAM;;CAUxB,SAAS,UAAU,QAAQ,OAAa;AACtC,MAAI,aAAa,WAAW,YAAY,EAAG;AAC3C,MAAI,WAAW,CAAC,MAAO;AACvB,OAAK;GACH,MAAM;GACN,SAAS,EAAE;GACX,YAAY;GACZ,SAAA;GACD,CAAC;AACF,cAAY;AACZ,MAAI,CAAC,WAAW,CAAC,QACf,cAAa,WACX,WACA,KAAK,IAAI,MAAM,MAAM,WAAW,IAAI,KAAM,CAC3C;;CAEL,eAAe,kBAAmC;AAChD,QAAM;AACN,MAAI,UAAW,OAAM,IAAIA,iCAAwC;AAIjE,MAAI,gBAAiB,QAAO;EAC5B,MAAM,YAAY,QAAQ;AAkB1B,oBAjBgB,IAAI,SAAiB,SAAS,WAAW;GACvD,MAAM,QAAQ,iBAAiB;AAC7B,YAAQ,OAAO,UAAU;AACzB,WAAO,IAAIE,gCAAuC,CAAC;MAClD,QAAQ;AACX,WAAQ,IAAI,WAAW;IAAE;IAAS;IAAQ;IAAO,CAAC;AAClD,QAAK;IACH,MAAM;IACN,SAAS;KACP,UAAU,QAAQ;KAClB,YAAY;KACZ,iBAAA;KACD;IACD,YAAY;IACZ,SAAA;IACD,CAAC;IACF,CACwB,cAAc;AACtC,qBAAkB,KAAA;IAClB;AACF,SAAO;;CAIT,MAAM,4BAA4B;CAClC,SAAS,gBAAgB,QAA6C;AACpE,eAAa,aAAa;EAO1B,MAAM,aACJ,OAAO,OAAO,QAAQ,YACtB,OAAO,cAAc,OAAO,IAAI,IAChC,OAAO,MAAM,OAAO,OACf,OAAO,MAAM,OAAO,OAAO,MAC5B;EACN,MAAM,QAAQ,KAAK,IAAI,KAAO,aAAa,GAAG,aAAa,IAAO;AAClE,iBAAe,iBACP;AAEC,oBAAiB,CAAC,YAAY,KAAA,EAAU;KAE/C,KAAK,IAAI,YAAe,MAAM,CAC/B;;CAEH,SAAS,UAAU,OAAoC;AACrD,MAAI,aAAa,MAAM,WAAW,UAAU,MAAM,WAAW,WAC3D;EACF,MAAM,SAAS,oBAAoB,MAAM,MAAM,EAAE,YAAY,UAAU,CAAC;EACxE,MAAM,KAAK,OAAO,KAAK,OAAO,SAAS,aAAa,OAAO;AAC3D,MAAI,CAAC,MAAO,OAAO,WAAW,CAAC,QAAQ,IAAI,GAAG,CAAG;AACjD,MAAI,OAAO,WAAW,QAAS;AAC/B,MAAI,CAAC,OAAO,IAAI;AAKd,iBAAc,IAHZ,OAAO,WAAW,qBACd,IAAIC,qCAA4C,GAChD,IAAIC,gCAAuC,CACzB;AACxB;;EAEF,MAAM,WAAW,OAAO;AACxB,MAAI,SAAS,SAAS,QACpB,eAAc,IAAI,cAAc,SAAS,QAAQ,CAAC;WAElD,SAAS,SAAS,qBAClB,OAAO,WACP,CAAC,SACD;GACA,MAAM,YAAY,SAAS;AAC3B,OACE,UAAU,IAAI,aAAa,QAAQ,YACnC,CAAC,UAAU,MAAM,QACjB,CAAC,UAAU,MAAM,QACjB,CAAC,UAAU,MAAM,QACjB,CAAC,UAAU,MAAM,eAAe,SAAS,QAAQ,SAAS,OAAO,EACjE;AACA,kBAAc,IAAIA,gCAAuC,CAAC;AAC1D;;AAEF,OAAI,CAAC,YAAA,SAAoC,UAAU,IAAI,WAAW,EAAE;AAClE,kBACE,IAAID,oCAA2C,KAAA,GAAW;KACxD,UAAU;KACV,UAAU,UAAU,IAAI;KACzB,CAAC,CACH;AACD;;AAEF,aAAU,cAAc,UAAU;AAClC,gBAAa,WAAW;aACf,SAAS,SAAS,yBAAyB;GACpD,MAAM,SAAS,WAAW,SAAS,QAAQ,cAAc,SAAS,IAAI;AACtE,OAAI,CAAC,QAAQ;AACX,kBAAc,IAAI,IAAIE,sCAA6C,CAAC;AACpE;;AAEF,WAAQ,OAAO;AACf,mBAAgB,OAAO;AACvB,OAAI,OAAO,WAAW,SAAS;AAC7B,cAAU;AACV,iBAAa,eAAe;AAC5B,qBAAiB,QAAQ;UACpB;IACL,MAAM,UAAU,QAAQ,IAAI,GAAG;AAC/B,QAAI,SAAS;AACX,kBAAa,QAAQ,MAAM;AAC3B,aAAQ,OAAO,GAAG;AAClB,aAAQ,QAAQ,SAAS,QAAQ,aAAa;;;;;CAKtD,SAAS,cAAc,IAAY,OAAsC;AACvE,MAAI,OAAO,QAAS,eAAc,MAAM;EACxC,MAAM,UAAU,QAAQ,IAAI,GAAG;AAC/B,MAAI,SAAS;AACX,gBAAa,QAAQ,MAAM;AAC3B,WAAQ,OAAO,GAAG;AAClB,WAAQ,OAAO,MAAM;;;CAGzB,MAAM,aAAa,YAA6C;AAC9D,MAAI,UAAW,OAAM,IAAIL,iCAAwC;AACjE,SAAO;;CAET,MAAM,mBAA2B,QAAQ,SAAS;CAKlD,MAAM,4BAAgE;CACtE,MAAM,qBAAqB,yBAAyB;EAClD;EACA;EACA;EACA;EACA,mBAAmB;EACnB;EACA,SAAS;EACV,CAAC;CACF,MAAM,eAAe,yBAAyB;EAC5C;EACA;EACA;EACA;EACA,mBAAmB;EACnB;EACA,SAAS;EACV,CAAC;CACF,MAAM,gBAAgB,QAAQ;AAC9B,KAAI,CAAC,QAAQ,kBAAmB,SAAQ,QAAQ;CAChD,SAAS,UAAgB;AACvB,MAAI,UAAW;AACf,cAAY;AACZ,kBAAgB,OAAO,QAAQ;AAC/B,UAAQ,oBAAoB,WAAW,UAAU;AACjD,UAAQ,oBAAoB,YAAY,WAAW;AACnD,UAAQ,oBAAoB,YAAY,WAAW;AACnD,UAAQ,oBAAoB,UAAU,QAAQ;AAC9C,eAAa,WAAW;AACxB,eAAa,aAAa;AAC1B,gBAAc,IAAIA,iCAAwC,CAAC;AAC3D,OAAK,MAAM,WAAW,QAAQ,QAAQ,EAAE;AACtC,gBAAa,QAAQ,MAAM;AAC3B,WAAQ,OAAO,IAAIA,iCAAwC,CAAC;;AAE9D,UAAQ,OAAO;AACf,YAAU,KAAA;AACV,QAAM,KAAA;AACN,MAAI,QAAQ,UAAU,aAAc,SAAQ,QAAQ;;CAOtD,SAAS,WAAW,OAAkC;AACpD,MAAI,MAAM,UAAW;AACrB,WAAS;;CASX,SAAS,WAAW,OAAkC;AACpD,MAAI,CAAC,MAAM,aAAa,aAAa,QAAS;AAG9C,eAAa,eAAe;AAC5B,mBAAiB,qBAAqB;AACtC,eAAa,WAAW;AACxB,aAAW;AACX,YAAU,KAAK;;AAEjB,SAAQ,iBAAiB,WAAW,UAAU;AAC9C,SAAQ,iBAAiB,YAAY,WAAW;AAChD,SAAQ,iBAAiB,YAAY,WAAW;AAChD,SAAQ,iBAAiB,UAAU,QAAQ;AAC3C,YAAW;AACX,QAAO;EAAE;EAAY;EAAiB,OAAO;EAAoB;EAAS;;AAG5E,SAAS,YAAY,QAAwB;AAC3C,KAAI;EACF,MAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,OACG,IAAI,aAAa,WAAW,IAAI,aAAa,aAC9C,IAAI,WAAW,OAEf,QAAO;SACH;AAGR,OAAM,IAAID,8BACR,6CACD;;AAEH,SAAS,SAAiB;CACxB,MAAM,QAAQ,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;CACxD,IAAI,YAAY,OAAO,KAAK,KAAK,CAAC;AAClC,MAAK,IAAI,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG;AAC1C,QAAM,SAAS,OAAO,YAAY,KAAK;AACvC,gBAAc;;AAEhB,OAAM,KAAM,MAAM,KAAM,KAAM;AAC9B,OAAM,KAAM,MAAM,KAAM,KAAM;CAC9B,MAAM,MAAM,MAAM,KAAK,QAAQ,SAC7B,KAAK,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CACnC,CAAC,KAAK,GAAG;AACV,QAAO,GAAG,IAAI,MAAM,GAAG,EAAE,CAAC,GAAG,IAAI,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,MAAM,GAAG;;AAE1G,SAAS,YAAY,UAAkB,SAA0B;CAC/D,MAAM,SAAS;AACf,KAAI,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAE,QAAO;CAC5D,MAAM,OAAO,SAAS,MAAM,IAAI,CAAC,IAAI,OAAO,EAC1C,QAAQ,QAAQ,MAAM,IAAI,CAAC,IAAI,OAAO;AACxC,KAAI,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,OAAO,cAAc,CAAE,QAAO;AAC7D,MAAK,IAAI,QAAQ,GAAG,QAAQ,GAAG,SAAS,EACtC,KAAI,KAAK,WAAW,MAAM,OAAQ,QAAO,KAAK,SAAU,MAAM;AAChE,QAAO;;AAET,SAAS,WACP,OACA,SACA,KACwD;AACxD,KAAI;AACF,MACE,CAAC,WACD,CAAC,mDAAmD,KAAK,MAAM,CAE/D;EACF,MAAM,UAAU,MAAM,MAAM,IAAI,CAAC;EACjC,MAAM,SAAkB,KAAK,MAC3B,IAAI,YAAY,SAAS,EAAE,OAAO,MAAM,CAAC,CAAC,OACxC,WAAW,KACT,KAAK,QAAQ,QAAQ,MAAM,IAAI,CAAC,QAAQ,MAAM,IAAI,CAAC,GAClD,MAAM,EAAE,WAAW,EAAE,CACvB,CACF,CACF;AACD,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,CAAE;EACpE,MAAM,UAAU;EAChB,MAAM,QAAQ,QAAQ;AACtB,MACE,QAAQ,QAAQ,QAAQ,IAAI,YAC5B,QAAQ,SAAS,mBAAmB,QAAQ,MAAM,UAClD,QAAQ,QAAQ,aAAa,QAAQ,MAAM,KAAK,GAAG,QAAQ,MAAM,UACjE,OAAO,QAAQ,QAAQ,YACvB,CAAC,QAAQ,OACR,QAAQ,KAAA,KAAa,QAAQ,QAAQ,OACtC,OAAO,QAAQ,QAAQ,YACvB,CAAC,OAAO,cAAc,QAAQ,IAAI,IAMlC,OAAO,UAAU,YACjB,CAAC,SACD,EAAE,UAAU,UACZ,EAAE,UAAU,UACZ,MAAM,SAAS,QAAQ,MAAM,QAC7B,MAAM,SAAS,QAAQ,MAAM,KAE7B;EACF,MAAM,MACJ,OAAO,QAAQ,QAAQ,YAAY,OAAO,cAAc,QAAQ,IAAI,GAChE,QAAQ,MACR,KAAA;AACN,SAAO,QAAQ,KAAA,IACX;GAAE,KAAK,QAAQ;GAAK,KAAK,QAAQ;GAAK,GACtC;GAAE,KAAK,QAAQ;GAAK,KAAK,QAAQ;GAAK;GAAK;SACzC;AACN;;;AAGJ,SAAS,cACP,SACwB;AACxB,QAAO,OAAO,QAAQ,MAAM;AAC5B,QAAO,OAAO,QAAQ,IAAI;AAC1B,QAAO,OAAO,QAAQ,MAAM;AAC5B,KAAI,QAAQ,MAAM,MAAO,QAAO,OAAO,QAAQ,MAAM,MAAM;AAC3D,KAAI,QAAQ,MAAM,YAAa,QAAO,OAAO,QAAQ,MAAM,YAAY;AACvE,QAAO,OAAO,QAAQ,MAAM;AAC5B,SAAQ,UAAU,QAAQ,OAAO,OAAO;AACxC,QAAO,OAAO,QAAQ,UAAU;AAChC,QAAO,OAAO,QAAQ,MAAM,eAAe;AAC3C,QAAO,OAAO,QAAQ,MAAM;AAC5B,QAAO,OAAO,QAAQ,IAAI;AAC1B,QAAO,OAAO,OAAO,QAAQ;;AAE/B,SAAS,cAAc,SAAsD;AAE3E,SAAQ,QAAQ,MAAhB;EACE,KAAK;EACL,KAAK,uBACH,QAAO,IAAII,oCACT,KAAA,GACA,eAAe,QAAQ,QAAQ,CAChC;EACH,KAAK,eACH,QAAO,IAAIG,8BAAqC;EAClD,KAAK,wBACH,QAAO,IAAID,sCAA6C;EAC1D,KAAK,kBACH,QAAO,IAAID,gCAAuC;EACpD,KAAK,kBACH,QAAO,IAAIF,gCAAuC;EACpD,KAAK,oBACH,QAAO,IAAID,kCAAyC;EACtD,KAAK,mBACH,QAAO,IAAID,iCAAwC;EACrD,KAAK,mBACH,QAAO,IAAIO,iCAAwC;EACrD,QACE,QAAO,IAAIC,2BAAkC;;;AAInD,SAAS,eAAe,SAAuD;AAC7E,KAAI,CAAC,QAAS,QAAO,KAAA;CACrB,MAAM,YAAY,UAAuD;AACvE,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,MAAM,CAC7D,QAAO,KAAA;EACT,MAAM,SAAS;AACf,SAAO,OAAO,YACZ,CAAC,cAAc,kBAAkB,CAAC,SAAS,QACzC,OAAO,OAAO,SAAS,WACnB,CAAC,CAAC,KAAK,OAAO,KAAK,MAAM,GAAG,GAAG,CAAC,CAAC,GACjC,EAAE,CACP,CACF;;AAEH,QAAO;EACL,UAAU,SAAS,QAAQ,SAAS;EACpC,UAAU,SAAS,QAAQ,SAAS;EACrC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluid-app/droplet-bridge",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Browser SDK for Fluid embedded app session tokens and context.",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"type": "module",
|
|
9
|
+
"sideEffects": false,
|
|
10
|
+
"main": "./dist/index.cjs",
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": {
|
|
15
|
+
"types": "./dist/index.d.mts",
|
|
16
|
+
"default": "./dist/index.mjs"
|
|
17
|
+
},
|
|
18
|
+
"require": {
|
|
19
|
+
"types": "./dist/index.d.cts",
|
|
20
|
+
"default": "./dist/index.cjs"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@fluid-app/typescript-config": "0.0.0",
|
|
29
|
+
"@swc/core": "^1.15.18",
|
|
30
|
+
"@swc/jest": "^0.2.39",
|
|
31
|
+
"@types/jest": "^29.5.14",
|
|
32
|
+
"jest": "^29.7.0",
|
|
33
|
+
"tsdown": "^0.21.0",
|
|
34
|
+
"typescript": "^5"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsdown",
|
|
38
|
+
"dev": "tsdown --watch",
|
|
39
|
+
"transit": "tsgo --emitDeclarationOnly",
|
|
40
|
+
"typecheck": "tsgo --noEmit",
|
|
41
|
+
"lint": "oxlint --deny-warnings",
|
|
42
|
+
"lint:fix": "oxlint --fix --deny-warnings",
|
|
43
|
+
"test": "jest"
|
|
44
|
+
},
|
|
45
|
+
"module": "./dist/index.mjs"
|
|
6
46
|
}
|