osra 0.3.2 → 0.3.3
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/build/index.js +243 -229
- package/build/index.js.map +1 -1
- package/package.json +1 -1
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/types.ts","../src/utils/type-guards.ts","../src/utils/transport.ts","../src/revivables/utils.ts","../src/revivables/array-buffer.ts","../src/revivables/date.ts","../src/revivables/headers.ts","../src/revivables/error.ts","../src/revivables/typed-array.ts","../src/utils/event-channel.ts","../src/revivables/message-port.ts","../src/revivables/promise.ts","../src/revivables/function.ts","../src/revivables/readable-stream.ts","../src/revivables/abort-signal.ts","../src/revivables/response.ts","../src/revivables/request.ts","../src/revivables/identity.ts","../src/revivables/transfer.ts","../src/revivables/map.ts","../src/revivables/set.ts","../src/revivables/bigint.ts","../src/revivables/event-target.ts","../src/revivables/index.ts","../src/connections/bidirectional.ts","../src/utils/typed-event-target.ts","../src/utils/transferable.ts","../src/connections/utils.ts","../src/connections/index.ts","../src/index.ts"],"sourcesContent":["import type { ConnectionMessage } from './connections'\nimport type { TypedEventTarget } from './utils'\nimport type {\n DefaultRevivableModules, RevivableModule,\n InferMessages, InferRevivables\n} from './revivables'\n\nexport const OSRA_KEY = '__OSRA_KEY__' as const\nexport const OSRA_DEFAULT_KEY = '__OSRA_DEFAULT_KEY__' as const\nexport const OSRA_BOX = '__OSRA_BOX__' as const\n\nexport type Uuid = `${string}-${string}-${string}-${string}-${string}`\n\nexport type Jsonable =\n | boolean\n | null\n | number\n | string\n | { [key: string]: Jsonable }\n | Array<Jsonable>\n\nexport type Structurable =\n | Jsonable\n /** not really structureable but here for convenience */\n | void\n | undefined\n | bigint\n | Date\n | RegExp\n | Blob\n | File\n | FileList\n | ArrayBuffer\n | ArrayBufferView\n | ImageBitmap\n | ImageData\n | { [key: string]: Structurable }\n | Array<Structurable>\n | Map<Structurable, Structurable>\n | Set<Structurable>\n\nexport type StructurableTransferable =\n | Structurable\n | Transferable\n | { [key: string]: StructurableTransferable }\n | Array<StructurableTransferable>\n | Map<StructurableTransferable, StructurableTransferable>\n | Set<StructurableTransferable>\n\nexport type Capable<TModules extends readonly RevivableModule[] = DefaultRevivableModules> =\n | StructurableTransferable\n | InferRevivables<TModules>\n | { [key: string]: Capable<TModules> }\n | Array<Capable<TModules>>\n | Map<Capable<TModules>, Capable<TModules>>\n | Set<Capable<TModules>>\n\nexport type MessageFields = {\n type: string\n remoteUuid: Uuid\n}\n\nexport type MessageBase = {\n [OSRA_KEY]: string\n /** UUID of the client that sent the message */\n uuid: Uuid\n name?: string\n}\n\nexport type ProtocolMessage =\n | {\n type: 'announce'\n /** Only set when acknowledging a remote announcement */\n remoteUuid?: Uuid\n }\n | {\n type: 'close'\n remoteUuid: Uuid\n }\n\nexport type MessageVariant<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> =\n | ProtocolMessage\n | ConnectionMessage<TModules>\n | InferMessages<TModules>\n\nexport type Message<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> =\n & MessageBase\n & MessageVariant<TModules>\n\nexport type MessageEventMap<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n message: CustomEvent<Message<TModules>>\n}\n\nexport type MessageEventTarget<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n > = TypedEventTarget<MessageEventMap<TModules>>\n","import type { Runtime } from 'webextension-polyfill'\nimport type { Message } from '../types'\nimport type {\n CustomEmitTransport, CustomReceiveTransport,\n CustomTransport, EmitJsonPlatformTransport,\n EmitTransport, JsonPlatformTransport,\n ReceiveJsonPlatformTransport,\n ReceiveTransport, Transport\n} from './transport'\n\nimport { OSRA_KEY } from '../types'\nimport { getWebExtensionRuntime } from './transport'\n\nconst typedArrayConstructorsByName = {\n Int8Array,\n Uint8Array,\n Uint8ClampedArray,\n Int16Array,\n Uint16Array,\n Int32Array,\n Uint32Array,\n Float16Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n BigUint64Array,\n} as const\n\nexport type TypedArrayType = keyof typeof typedArrayConstructorsByName\nexport type TypedArrayConstructor = (typeof typedArrayConstructorsByName)[TypedArrayType]\nexport type TypedArray = InstanceType<TypedArrayConstructor>\n\nconst typedArrayConstructors = Object.values(typedArrayConstructorsByName)\n\nexport const typedArrayToType = (value: TypedArray): TypedArrayType => {\n const name = value.constructor.name as TypedArrayType\n if (!(name in typedArrayConstructorsByName)) throw new Error('Unknown typed array type')\n return name\n}\n\nexport const typedArrayTypeToTypedArrayConstructor = (value: TypedArrayType): TypedArrayConstructor => {\n const ctor = typedArrayConstructorsByName[value]\n if (!ctor) throw new Error('Unknown typed array type')\n return ctor\n}\n\nexport const isTypedArray = (value: unknown): value is TypedArray =>\n typedArrayConstructors.some(ctor => value instanceof ctor)\nexport const isWebSocket = (value: unknown): value is WebSocket => value instanceof WebSocket\nexport const isServiceWorkerContainer = (value: unknown): value is ServiceWorkerContainer => !!globalThis.ServiceWorkerContainer && value instanceof ServiceWorkerContainer\nexport const isWorker = (value: unknown): value is Worker => !!globalThis.Worker && value instanceof Worker\n// @ts-expect-error DedicatedWorkerGlobalScope is only present in worker scopes\nexport const isDedicatedWorker = (value: unknown): value is DedicatedWorkerGlobalScope => !!globalThis.DedicatedWorkerGlobalScope && value instanceof DedicatedWorkerGlobalScope\nexport const isSharedWorker = (value: unknown): value is SharedWorker => !!globalThis.SharedWorker && value instanceof SharedWorker\nconst isMessagePort = (value: unknown): value is MessagePort => value instanceof MessagePort\n\nexport const isOsraMessage = (value: unknown): value is Message =>\n !!value\n && typeof value === 'object'\n && OSRA_KEY in value\n && !!value[OSRA_KEY]\n\ntype AnyConstructor = abstract new (...args: any[]) => unknown\n\n/** True if `value` is an instance of any of the given (possibly undefined-on-this-platform)\n * constructors. Tolerates missing globals so callers don't have to guard each one. */\nexport const instanceOfAny = (value: unknown, ctors: readonly (AnyConstructor | undefined)[]): boolean => {\n for (const ctor of ctors) if (ctor && value instanceof ctor) return true\n return false\n}\n\nexport const isClonable = (value: unknown): boolean =>\n instanceOfAny(value, [globalThis.SharedArrayBuffer])\n\nexport const isTransferable = (value: unknown): value is Transferable =>\n instanceOfAny(value, [\n globalThis.ArrayBuffer,\n globalThis.MessagePort,\n globalThis.ReadableStream,\n globalThis.WritableStream,\n globalThis.TransformStream,\n globalThis.ImageBitmap,\n ])\n\nexport type WebExtRuntime = typeof browser.runtime\nexport const isWebExtensionRuntime = (value: unknown): value is WebExtRuntime => {\n const runtime = getWebExtensionRuntime()\n if (!runtime) return false\n return value === runtime\n}\n\nexport type WebExtPort = ReturnType<WebExtRuntime['connect']> | Runtime.Port\nexport const isWebExtensionPort = (value: unknown, connectPort: boolean = false): value is WebExtPort => {\n if (!value || typeof value !== 'object') return false\n // Prevent SecurityError when `value` is a cross-origin window.\n if (isWindow(value)) return false\n if (!('name' in value) || !('disconnect' in value) || !('postMessage' in value)) return false\n // these properties are only present on WebExtPorts created through runtime.connect()\n if (!connectPort) return true\n return 'sender' in value && 'onMessage' in value && 'onDisconnect' in value\n}\n\nexport type WebExtSender = NonNullable<WebExtPort['sender']>\n\n// Structural guard for any `addListener` / `hasListener` / `removeListener` event.\n// Not enough on its own to tell onConnect from onMessage — they have identical shapes.\nconst hasListenerApi = (value: unknown): boolean =>\n !!value\n && typeof value === 'object'\n // Prevent SecurityError when `value` is a cross-origin window.\n && !isWindow(value)\n && 'addListener' in value\n && 'hasListener' in value\n && 'removeListener' in value\n\n// Identity-compare against the runtime's onConnect events: structural checks\n// can't distinguish onConnect from onMessage, and misclassifying onMessage as\n// onConnect makes us treat each incoming message as a port and crash on\n// `message.onMessage.addListener`.\nexport type WebExtOnConnect = WebExtRuntime['onConnect']\nexport const isWebExtensionOnConnect = (value: unknown): value is WebExtOnConnect => {\n const runtime = getWebExtensionRuntime()\n if (!runtime) return false\n return value === runtime.onConnect || value === runtime.onConnectExternal\n}\n\nexport type WebExtOnMessage = WebExtRuntime['onMessage']\nexport const isWebExtensionOnMessage = (value: unknown): value is WebExtOnMessage =>\n hasListenerApi(value)\n\nexport const isWindow = (value: unknown): value is Window => {\n if (!value || typeof value !== 'object') return false\n try {\n return 'window' in value && value.window === value\n } catch {\n // Cross-origin Window access can throw SecurityError; fall back to a\n // no-read shape probe that tolerates protected properties.\n try {\n return 'closed' in value\n && typeof value.closed === 'boolean'\n && 'close' in value\n && typeof value.close === 'function'\n } catch {\n return false\n }\n }\n}\n\nexport const isEmitJsonOnlyTransport = (value: unknown): value is EmitJsonPlatformTransport =>\n isWebSocket(value)\n || isWebExtensionPort(value)\n || isWebExtensionRuntime(value)\n\nexport const isReceiveJsonOnlyTransport = (value: unknown): value is ReceiveJsonPlatformTransport =>\n isWebSocket(value)\n || isWebExtensionPort(value)\n || isWebExtensionOnConnect(value)\n || isWebExtensionOnMessage(value)\n || isWebExtensionRuntime(value)\n\nexport type IsJsonOnlyTransport<T extends Transport> = T extends JsonPlatformTransport ? true : false\nexport const isJsonOnlyTransport = (value: unknown): value is Extract<Transport, JsonPlatformTransport> =>\n (!!value && typeof value === 'object' && 'isJson' in value && value.isJson === true)\n || isEmitJsonOnlyTransport(value)\n || isReceiveJsonOnlyTransport(value)\n\nexport const isEmitTransport = (value: unknown): value is EmitTransport =>\n isWindow(value)\n || isEmitJsonOnlyTransport(value)\n || isServiceWorkerContainer(value)\n || isWorker(value)\n || isDedicatedWorker(value)\n || isSharedWorker(value)\n || isMessagePort(value)\n || isCustomEmitTransport(value)\n\nexport function assertEmitTransport(transport: Transport): asserts transport is EmitTransport {\n if (!isEmitTransport(transport)) throw new Error('Transport is not emitable')\n}\n\nexport const isReceiveTransport = (value: unknown): value is ReceiveTransport =>\n isWindow(value)\n || isReceiveJsonOnlyTransport(value)\n || isServiceWorkerContainer(value)\n || isWorker(value)\n || isDedicatedWorker(value)\n || isSharedWorker(value)\n || isMessagePort(value)\n || isCustomReceiveTransport(value)\n\nexport function assertReceiveTransport(transport: Transport): asserts transport is ReceiveTransport {\n if (!isReceiveTransport(transport)) throw new Error('Transport is not receiveable')\n}\n\nexport const isCustomEmitTransport = (value: unknown): value is CustomEmitTransport => {\n if (!value || typeof value !== 'object') return false\n // Prevent SecurityError when `value` is a cross-origin window.\n if (isWindow(value)) return false\n if (!('emit' in value)) return false\n return isEmitTransport(value.emit) || typeof value.emit === 'function'\n}\n\nexport const isCustomReceiveTransport = (value: unknown): value is CustomReceiveTransport => {\n if (!value || typeof value !== 'object') return false\n // Prevent SecurityError when `value` is a cross-origin window.\n if (isWindow(value)) return false\n if (!('receive' in value)) return false\n return isReceiveTransport(value.receive) || typeof value.receive === 'function'\n}\n\nexport const isCustomTransport = (value: unknown): value is CustomTransport =>\n isCustomEmitTransport(value)\n || isCustomReceiveTransport(value)\n\nexport const isTransport = (value: unknown): value is Transport =>\n isEmitTransport(value)\n || isReceiveTransport(value)\n || isCustomTransport(value)\n || isJsonOnlyTransport(value)\n","import type { Message} from '../types'\nimport type {\n WebExtOnConnect, WebExtOnMessage,\n WebExtPort, WebExtRuntime, WebExtSender\n} from './type-guards'\n\nimport { OSRA_KEY } from '../types'\nimport {\n isOsraMessage, isCustomTransport,\n isWebExtensionOnConnect, isWebExtensionOnMessage,\n isWebExtensionPort, isWebExtensionRuntime, isWebSocket, isWindow, isSharedWorker\n} from './type-guards'\n\nexport type MessageContext = {\n port?: MessagePort | WebExtPort // WebExtension\n sender?: WebExtSender // WebExtension\n receiveTransport?: ReceivePlatformTransport\n source?: MessageEventSource | null // Window, Worker, WebSocket, ect...\n}\n\nexport type ReceiveHandler = (listener: (event: Message, messageContext: MessageContext) => void) => void\nexport type EmitHandler = (message: Message, transferables?: Transferable[]) => void\n\ntype CustomReceive = ReceivePlatformTransport | ReceiveHandler\ntype CustomEmit = EmitPlatformTransport | EmitHandler\n\nexport type CustomTransport =\n { isJson?: boolean }\n & (\n | { receive: CustomReceive, emit: CustomEmit }\n | { receive: CustomReceive }\n | { emit: CustomEmit }\n )\n\nexport type CustomEmitTransport = Extract<CustomTransport, { emit: any }>\nexport type CustomReceiveTransport = Extract<CustomTransport, { receive: any }>\n\nexport type EmitJsonPlatformTransport =\n | WebSocket\n | WebExtPort\n | WebExtRuntime\n\nexport type ReceiveJsonPlatformTransport =\n | WebSocket\n | WebExtPort\n | WebExtOnConnect\n | WebExtOnMessage\n | WebExtRuntime\n\nexport type JsonPlatformTransport =\n | { isJson: true }\n | EmitJsonPlatformTransport\n | ReceiveJsonPlatformTransport\n\ntype StructuredClonePlatformTransport =\n | Window\n | ServiceWorker\n | Worker\n | SharedWorker\n | MessagePort\n\nexport type EmitPlatformTransport =\n | EmitJsonPlatformTransport\n | StructuredClonePlatformTransport\n\nexport type ReceivePlatformTransport =\n | ReceiveJsonPlatformTransport\n | StructuredClonePlatformTransport\n\nexport type PlatformTransport =\n | EmitPlatformTransport\n | ReceivePlatformTransport\n\nexport type EmitTransport = EmitPlatformTransport & Extract<CustomTransport, { emit: any }>\nexport type ReceiveTransport = ReceivePlatformTransport & Extract<CustomTransport, { receive: any }>\n\nexport type Transport =\n | PlatformTransport\n | CustomTransport\n\nexport const getWebExtensionGlobal = () => globalThis.browser ?? globalThis.chrome\nexport const getWebExtensionRuntime = () => getWebExtensionGlobal()?.runtime\n\nexport const checkOsraMessageKey = (message: any, key: string): message is Message =>\n isOsraMessage(message)\n && message[OSRA_KEY] === key\n\nconst onAbort = (signal: AbortSignal | undefined, fn: () => void) =>\n signal?.addEventListener('abort', fn, { once: true })\n\nexport const registerOsraMessageListener = (\n { listener, transport, remoteName, key = OSRA_KEY, unregisterSignal }:\n {\n listener: (message: Message, messageContext: MessageContext) => void\n transport: ReceiveTransport\n remoteName?: string\n key?: string\n unregisterSignal?: AbortSignal\n }\n) => {\n const receiveTransport: Extract<CustomTransport, { receive: any }>['receive'] =\n isCustomTransport(transport) ? transport.receive : transport\n\n // Custom function handler\n if (typeof receiveTransport === 'function') {\n receiveTransport((message, ctx) => {\n if (!checkOsraMessageKey(message, key)) return\n if (remoteName && message.name !== remoteName) return\n listener(message, ctx)\n })\n return\n }\n\n // WebExtension family — subscribe to an `onMessage`-style listener API.\n if (\n isWebExtensionRuntime(receiveTransport)\n || isWebExtensionPort(receiveTransport)\n || isWebExtensionOnConnect(receiveTransport)\n || isWebExtensionOnMessage(receiveTransport)\n ) {\n const listenOnWebExtOnMessage = (onMessage: WebExtOnMessage, port?: WebExtPort) => {\n const _listener = (message: object, sender?: WebExtSender) => {\n if (!checkOsraMessageKey(message, key)) return\n if (remoteName && message.name !== remoteName) return\n listener(message, { port, sender })\n }\n onMessage.addListener(_listener)\n onAbort(unregisterSignal, () => onMessage.removeListener(_listener))\n }\n\n if (isWebExtensionRuntime(receiveTransport)) {\n listenOnWebExtOnMessage(receiveTransport.onMessage)\n } else if (isWebExtensionOnConnect(receiveTransport)) {\n // Port.onMessage has a narrower (message, port) shape than the shared\n // (message, sender) Runtime.onMessage — but our listener only reads\n // `message` so the runtime shape covers both.\n const _listener = (port: WebExtPort) =>\n listenOnWebExtOnMessage(port.onMessage as WebExtOnMessage, port)\n receiveTransport.addListener(_listener)\n onAbort(unregisterSignal, () => receiveTransport.removeListener(_listener))\n } else if (isWebExtensionOnMessage(receiveTransport)) {\n listenOnWebExtOnMessage(receiveTransport)\n } else { // WebExtPort\n listenOnWebExtOnMessage(receiveTransport.onMessage as WebExtOnMessage)\n }\n return\n }\n\n // Window, Worker, WebSocket, ServiceWorker, MessagePort, …\n const messageListener = (event: MessageEvent<Message>) => {\n if (!checkOsraMessageKey(event.data, key)) return\n if (remoteName && event.data.name !== remoteName) return\n listener(event.data, { receiveTransport, source: event.source })\n }\n receiveTransport.addEventListener('message', messageListener as EventListener)\n onAbort(unregisterSignal, () =>\n receiveTransport.removeEventListener('message', messageListener as EventListener),\n )\n}\n\nexport const sendOsraMessage = (\n transport: EmitTransport,\n message: Message,\n origin = '*',\n transferables: Transferable[] = []\n) => {\n const emitTransport: Extract<EmitTransport, { emit: any }>['emit'] =\n isCustomTransport(transport) ? transport.emit : transport\n\n if (typeof emitTransport === 'function') {\n emitTransport(message, transferables)\n } else if (isWindow(emitTransport)) {\n // Must be checked first: cross-origin windows throw on other property access.\n emitTransport.postMessage(message, origin, transferables)\n } else if (isWebExtensionPort(emitTransport)) {\n emitTransport.postMessage(message)\n } else if (isWebExtensionRuntime(emitTransport)) {\n emitTransport.sendMessage(message)\n } else if (isWebSocket(emitTransport)) {\n emitTransport.send(JSON.stringify(message))\n } else if (isSharedWorker(emitTransport)) {\n emitTransport.port.postMessage(message, transferables)\n } else { // MessagePort | ServiceWorker | Worker\n emitTransport.postMessage(message, transferables)\n }\n}\n","import type { DefaultRevivableModules, RevivableModule } from '.'\nimport type {\n MessageEventTarget,\n MessageFields,\n Uuid,\n} from '../types'\nimport type { Transport } from '../utils/transport'\nimport type { IsJsonOnlyTransport } from '../utils/type-guards'\n\nimport { OSRA_BOX } from '../types'\nimport { isJsonOnlyTransport } from '../utils/type-guards'\n\nexport type { UnderlyingType } from '../utils/type'\n\nexport const BoxBase = {\n [OSRA_BOX]: 'revivable',\n} as const\n\nexport type BoxBase<T extends string = string> =\n & typeof BoxBase\n & { type: T }\n\nexport type RevivableContext<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n transport: Transport\n remoteUuid: Uuid\n unregisterSignal?: AbortSignal\n /** Typed as a broad dispatcher so revivables can post their own message\n * variants without triggering contravariant function-parameter mismatches\n * across modules. The shape is enforced structurally via `MessageFields`. */\n sendMessage: (message: MessageFields & Record<string, unknown>) => void\n revivableModules: TModules\n eventTarget: MessageEventTarget<TModules>\n}\n\nexport type ExtractType<T> =\n T extends { isType: (value: unknown) => value is infer S }\n ? S\n : never\n\nexport type ExtractBox<T> =\n T extends { box: (...args: any[]) => infer B }\n ? B\n : never\n\nexport type ExtractMessages<T> =\n T extends { Messages?: infer B }\n ? B extends { type: string }\n ? string extends B['type'] ? never : B\n : never\n : never\n\nexport type InferMessages<TModules extends readonly unknown[]> =\n ExtractMessages<TModules[number]>\n\nexport type InferRevivables<TModules extends readonly unknown[]> =\n ExtractType<TModules[number]>\n\nexport type InferRevivableBox<TModules extends readonly unknown[]> =\n ExtractBox<TModules[number]>\n\nexport const isRevivableBox = (value: unknown): value is BoxBase =>\n !!value\n && typeof value === 'object'\n && OSRA_BOX in value\n && value[OSRA_BOX] === 'revivable'\n\n/** Stable string form for an unknown rejection value. Errors keep their stack;\n * everything else gets coerced via `String()`. Used wherever a Promise/Function\n * rejection has to cross the wire as a serialisable string. */\nexport const serializeError = (error: unknown): string =>\n error instanceof Error ? (error.stack ?? String(error)) : String(error)\n\n/** Wire shape for an ArrayBuffer carried by a JSON or clone transport. JSON\n * paths emit a base64 string (so the buffer survives JSON.stringify); clone\n * paths pass the buffer through structured-clone unchanged. */\nexport type BoxedBuffer<TCtx extends RevivableContext = RevivableContext> =\n IsJsonOnlyTransport<TCtx['transport']> extends true ? { base64Buffer: string }\n : IsJsonOnlyTransport<TCtx['transport']> extends false ? { arrayBuffer: ArrayBuffer }\n : { base64Buffer: string } | { arrayBuffer: ArrayBuffer }\n\nexport const boxBuffer = <TCtx extends RevivableContext>(\n buffer: ArrayBuffer,\n context: TCtx,\n): BoxedBuffer<TCtx> =>\n (isJsonOnlyTransport(context.transport)\n ? { base64Buffer: new Uint8Array(buffer).toBase64() }\n : { arrayBuffer: buffer }\n ) as BoxedBuffer<TCtx>\n\nexport const reviveBuffer = (boxed: { arrayBuffer: ArrayBuffer } | { base64Buffer: string }): ArrayBuffer =>\n 'arrayBuffer' in boxed\n ? boxed.arrayBuffer\n : Uint8Array.fromBase64(boxed.base64Buffer).buffer\n","import type { RevivableContext, UnderlyingType, BoxedBuffer } from './utils'\n\nimport { BoxBase, boxBuffer, reviveBuffer } from './utils'\n\nexport const type = 'arrayBuffer' as const\n\ntype BoxedArrayBuffer<T extends ArrayBuffer, T2 extends RevivableContext> =\n & typeof BoxBase\n & { type: typeof type }\n & BoxedBuffer<T2>\n & { [UnderlyingType]: T }\n\nexport const isType = (value: unknown): value is ArrayBuffer =>\n value instanceof ArrayBuffer\n\nexport const box = <T extends ArrayBuffer, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): BoxedArrayBuffer<T, T2> =>\n ({ ...BoxBase, type, ...boxBuffer(value, context) }) as unknown as BoxedArrayBuffer<T, T2>\n\nexport const revive = <T extends BoxedArrayBuffer<ArrayBuffer, RevivableContext>>(\n value: T,\n _context: RevivableContext,\n): T[UnderlyingType] =>\n reviveBuffer(value) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const boxed = box(new ArrayBuffer(10), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: ArrayBuffer = revived\n // @ts-expect-error - not an ArrayBuffer\n const notArrayBuffer: string = revived\n // @ts-expect-error - cannot box non-ArrayBuffer\n box('not an array buffer', {} as RevivableContext)\n}\n","import type { RevivableContext } from './utils'\n\nimport { BoxBase } from './utils'\n\nexport const type = 'date' as const\n\nexport const isType = (value: unknown): value is Date =>\n value instanceof Date\n\nexport const box = <T extends Date, T2 extends RevivableContext>(\n value: T,\n _context: T2\n) => ({\n ...BoxBase,\n type,\n ISOString: value.toISOString()\n})\n\nexport const revive = <T extends ReturnType<typeof box>, T2 extends RevivableContext>(\n value: T,\n _context: T2\n): Date => {\n return new Date(value.ISOString)\n}\n\nconst typeCheck = () => {\n const boxed = box(new Date(), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Date = revived\n // @ts-expect-error - not a Date\n const notDate: string = revived\n // @ts-expect-error - cannot box non-Date\n box('not a date', {} as RevivableContext)\n}\n","import type { RevivableContext } from './utils'\n\nimport { BoxBase } from './utils'\n\nexport const type = 'headers' as const\n\nexport const isType = (value: unknown): value is Headers =>\n value instanceof Headers\n\nexport const box = <T extends Headers, T2 extends RevivableContext>(\n value: T,\n _context: T2\n) => ({\n ...BoxBase,\n type,\n entries: [...value.entries()]\n})\n\nexport const revive = <T extends ReturnType<typeof box>, T2 extends RevivableContext>(\n value: T,\n _context: T2\n): Headers => {\n return new Headers(value.entries)\n}\n\nconst typeCheck = () => {\n const boxed = box(new Headers(), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Headers = revived\n // @ts-expect-error - not a Headers\n const notHeaders: string = revived\n // @ts-expect-error - cannot box non-Headers\n box('not a header', {} as RevivableContext)\n}\n","import type { RevivableContext } from './utils'\n\nimport { BoxBase } from './utils'\n\nexport const type = 'error' as const\n\nexport const isType = (value: unknown): value is Error =>\n value instanceof Error\n\nexport const box = <T extends Error, T2 extends RevivableContext>(\n value: T,\n _context: T2\n) => ({\n ...BoxBase,\n type,\n message: value.message,\n stack: value.stack || value.toString()\n})\n\nexport const revive = <T extends ReturnType<typeof box>, T2 extends RevivableContext>(\n value: T,\n _context: T2\n) => new Error(value.message, { cause: value.stack })\n\nconst typeCheck = () => {\n const boxed = box(new Error('test'), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Error = revived\n // @ts-expect-error - not an Error\n const notError: string = revived\n // @ts-expect-error - cannot box non-Error\n box('not an error', {} as RevivableContext)\n}\n","import type { RevivableContext, UnderlyingType, BoxedBuffer } from './utils'\nimport type { TypedArray, TypedArrayType } from '../utils/type-guards'\n\nimport { BoxBase, boxBuffer, reviveBuffer } from './utils'\nimport {\n isTypedArray,\n typedArrayToType,\n typedArrayTypeToTypedArrayConstructor,\n} from '../utils/type-guards'\n\nexport const type = 'typedArray' as const\n\ntype BoxedTypedArray<T extends TypedArray, T2 extends RevivableContext> =\n & typeof BoxBase\n & { type: typeof type }\n & { typedArrayType: TypedArrayType }\n & BoxedBuffer<T2>\n & { [UnderlyingType]: T }\n\nexport const isType = isTypedArray\n\nexport const box = <T extends TypedArray, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): BoxedTypedArray<T, T2> =>\n ({\n ...BoxBase,\n type,\n typedArrayType: typedArrayToType(value),\n ...boxBuffer(value.buffer as ArrayBuffer, context),\n }) as unknown as BoxedTypedArray<T, T2>\n\nexport const revive = <T extends BoxedTypedArray<TypedArray, RevivableContext>>(\n value: T,\n _context: RevivableContext,\n): T[UnderlyingType] =>\n new (typedArrayTypeToTypedArrayConstructor(value.typedArrayType))(reviveBuffer(value)) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const uint8Boxed = box(new Uint8Array(10), {} as RevivableContext)\n const uint8Revived = revive(uint8Boxed, {} as RevivableContext)\n const expectedUint8: Uint8Array = uint8Revived\n // @ts-expect-error - wrong typed array type\n const wrongType: Int32Array = uint8Revived\n\n const float32Boxed = box(new Float32Array(10), {} as RevivableContext)\n const float32Revived = revive(float32Boxed, {} as RevivableContext)\n const expectedFloat32: Float32Array = float32Revived\n // @ts-expect-error - wrong typed array type\n const wrongFloat: Uint8Array = float32Revived\n\n // @ts-expect-error - cannot box non-TypedArray\n box('not a typed array', {} as RevivableContext)\n}\n","import type { TypedMessagePort, TypedMessagePortEventMap } from './typed-message-channel'\n\nexport class EventPort<T> extends EventTarget {\n addEventListener<K extends keyof TypedMessagePortEventMap<T> & string>(\n type: K,\n listener: ((event: TypedMessagePortEventMap<T>[K]) => void) | null,\n options?: boolean | AddEventListenerOptions\n ): void\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | AddEventListenerOptions\n ): void\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | AddEventListenerOptions\n ): void {\n super.addEventListener(type, listener, options)\n }\n\n removeEventListener<K extends keyof TypedMessagePortEventMap<T> & string>(\n type: K,\n listener: ((event: TypedMessagePortEventMap<T>[K]) => void) | null,\n options?: boolean | EventListenerOptions\n ): void\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | EventListenerOptions\n ): void\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | EventListenerOptions\n ): void {\n super.removeEventListener(type, listener, options)\n }\n\n _peer: EventPort<any> | undefined\n _queue: MessageEvent<T>[] = []\n _started = false\n _closed = false\n _onClose: (() => void) | undefined\n\n private _onmessage: ((this: MessagePort, ev: MessageEvent<T>) => unknown) | null = null\n\n get onmessage(): ((this: MessagePort, ev: MessageEvent<T>) => unknown) | null {\n return this._onmessage\n }\n set onmessage(value: ((this: MessagePort, ev: MessageEvent<T>) => unknown) | null) {\n this._onmessage = value\n if (value !== null) this.start()\n }\n\n onmessageerror: ((this: MessagePort, ev: MessageEvent) => unknown) | null = null\n\n dispatchEvent(event: Event): boolean {\n if (event.type === 'message') {\n this._onmessage?.call(this, event as MessageEvent<T>)\n } else if (event.type === 'messageerror') {\n this.onmessageerror?.call(this, event as MessageEvent)\n }\n return super.dispatchEvent(event)\n }\n\n postMessage(message: T, _options?: Transferable[] | StructuredSerializeOptions): void {\n const peer = this._peer\n if (!peer || peer._closed) return\n queueMicrotask(() => {\n if (peer._closed) return\n const event = new MessageEvent('message', { data: message })\n if (peer._started) {\n peer.dispatchEvent(event)\n } else {\n peer._queue.push(event)\n }\n })\n }\n\n start(): void {\n if (this._started) return\n this._started = true\n for (const event of this._queue.splice(0)) {\n this.dispatchEvent(event)\n }\n }\n\n close(): void {\n if (this._closed) return\n this._closed = true\n this._queue.length = 0\n this._onClose?.()\n }\n}\n\nexport interface EventPort<T>\n extends Omit<\n TypedMessagePort<T>,\n 'addEventListener' | 'removeEventListener'\n > {}\n\nexport class EventChannel<T1 = unknown, T2 = unknown> {\n readonly port1: EventPort<T1>\n readonly port2: EventPort<T2>\n\n constructor() {\n const port1 = new EventPort<T1>()\n const port2 = new EventPort<T2>()\n port1._peer = port2\n port2._peer = port1\n this.port1 = port1\n this.port2 = port2\n }\n}\n","import type { Capable, StructurableTransferable, Uuid } from '../types'\nimport type { TypedMessagePort } from '../utils/typed-message-channel'\nimport type { RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { UnderlyingType } from '../utils/type'\nimport type {\n BadFieldValue, BadFieldPath, BadFieldParent,\n ErrorMessage, BadValue, Path, ParentObject\n} from '../utils/capable-check'\n\nimport { BoxBase } from './utils'\nimport { recursiveBox, recursiveRevive } from '.'\nimport { getTransferableObjects, isJsonOnlyTransport } from '../utils'\nimport { EventChannel, EventPort } from '../utils/event-channel'\n\n/**\n * FinalizationRegistry for automatically cleaning up ports when they are garbage collected.\n * In JSON-only mode we can't transfer ports on the wire, so we track them via\n * portId and tell the remote side to close when the local handle is collected.\n */\ntype PortCleanupInfo = {\n sendMessage: (message: Messages) => void\n remoteUuid: Uuid\n portId: Uuid\n cleanup: () => void\n}\n\nconst messagePortRegistry = new FinalizationRegistry<PortCleanupInfo>((info) => {\n // Send close message to remote side\n info.sendMessage({\n type: 'message-port-close',\n remoteUuid: info.remoteUuid,\n portId: info.portId\n })\n // Perform local cleanup\n info.cleanup()\n})\n\nexport const type = 'messagePort' as const\n\nexport type Messages =\n | {\n type: 'message'\n remoteUuid: Uuid\n data: Capable\n /** uuid of the messagePort that the message was sent through */\n portId: Uuid\n }\n | {\n type: 'message-port-close'\n remoteUuid: Uuid\n /** uuid of the messagePort that closed */\n portId: Uuid\n }\n\nexport declare const Messages: Messages\n\n/** Any port-shape the message-port revivable is happy to accept. Real\n * MessagePorts (from `new MessageChannel()`) and synthetic EventPorts\n * (from `new EventChannel()`) both flow through here. Messages can be any\n * Capable value — message-port boxes/revives as they cross the transport,\n * and the in-realm side uses pass-by-reference via EventChannel. */\nexport type AnyPort<T = Capable> =\n | TypedMessagePort<T>\n | EventPort<T>\n\nexport type BoxedMessagePort<T = Capable> =\n & BoxBaseType<typeof type>\n & (\n /** The origin was a synthetic EventPort — revive must reproduce an\n * EventPort on the other side so live (non-clonable) Promises/Functions\n * etc. can flow through by reference. */\n | { portId: Uuid, synthetic: true }\n /** The origin was a real MessagePort but the transport can't carry\n * ports (JSON-only) — revive produces a real MessagePort proxy so the\n * receiver sees it as if it had been transferred. Payloads must be\n * structured-clonable; live (non-clonable) values nested in a\n * user-level MessagePort aren't supported in this mode. */\n | { portId: Uuid, synthetic: false }\n /** The origin was a real MessagePort and the transport supports\n * structured clone — the port is transferred on the wire. When\n * `autoBox` is true, the revive side wraps it in a `ProtocolPort`\n * that auto-boxes outgoing / auto-revives incoming payloads so\n * live values (Promises/Functions) flow through unchanged. When\n * `autoBox` is absent/false, the receiver gets the raw MessagePort\n * with structured-clone semantics (used for user-owned ports). */\n | { port: AnyPort<T>, autoBox?: boolean }\n )\n & { [UnderlyingType]: TypedMessagePort<T> }\n\n// `[T] extends [Capable]` disables distributive conditionals so unions like\n// `A | B` give back `AnyPort<A | B>`, not `AnyPort<A> | AnyPort<B>`.\n// The error branch intersects with AnyPort<T> so the user's port-shaped keys\n// are present on the target — otherwise TS's excess-property check flags a\n// port key instead of reporting the failure against the whole argument.\ntype StructurableTransferablePort<T> = [T] extends [Capable]\n ? AnyPort<T>\n : AnyPort<T> & {\n [ErrorMessage]: 'Message type must extend Capable'\n [BadValue]: BadFieldValue<T, Capable>\n [Path]: BadFieldPath<T, Capable>\n [ParentObject]: BadFieldParent<T, Capable>\n }\n\n// -------------------------------------------------------------------------\n// Per-connection state\n//\n// The WeakMap ties per-connection message-port state to the connection's\n// RevivableContext — when the context is collected, the state goes with it.\n// State lives only here; no sibling revivable has to know about it.\n// -------------------------------------------------------------------------\n\ntype ConnectionMessagePortState = {\n /** Direct per-portId dispatch — O(1) lookup avoids the O(N) addEventListener\n * scan that was the bottleneck for tight-loop RPC traffic. */\n portHandlers: Map<string, (message: Messages) => void>\n}\n\nconst connectionStateMap = new WeakMap<RevivableContext, ConnectionMessagePortState>()\n\nconst getState = (context: RevivableContext): ConnectionMessagePortState => {\n const state = connectionStateMap.get(context)\n if (!state) {\n throw new Error('osra message-port: connection state missing; did init() run?')\n }\n return state\n}\n\n// -------------------------------------------------------------------------\n// init hook\n//\n// Called once per connection by the bidirectional connection bootstrap.\n// Sets up the per-connection port-handler map and installs the event-target\n// listener that routes incoming 'message' envelopes to the correct local\n// handler.\n// -------------------------------------------------------------------------\n\nexport const init = (context: RevivableContext): void => {\n const state: ConnectionMessagePortState = {\n portHandlers: new Map()\n }\n connectionStateMap.set(context, state)\n\n context.eventTarget.addEventListener('message', ({ detail }) => {\n if (detail.type !== 'message' && detail.type !== 'message-port-close') return\n state.portHandlers.get(detail.portId)?.(detail)\n })\n}\n\nexport const isType = (value: unknown): value is MessagePort | EventPort<StructurableTransferable> =>\n value instanceof MessagePort || value instanceof EventPort\n\nexport const box = <T, T2 extends RevivableContext = RevivableContext>(\n value: StructurableTransferablePort<T>,\n context: T2,\n options?: { autoBox?: boolean },\n): BoxedMessagePort<T> => {\n // Synthetic EventPorts are not structured-clonable, so even when the\n // transport supports cloning we have to route them via portId — otherwise\n // sending the wrapping message would crash with DataCloneError.\n const synthetic = value instanceof EventPort\n if (synthetic || isJsonOnlyTransport(context.transport)) {\n const { portHandlers } = getState(context)\n const liveRef: AnyPort<T> = value\n const portId: Uuid = globalThis.crypto.randomUUID()\n\n let cleanedUp = false\n const performCleanup = () => {\n if (cleanedUp) return\n cleanedUp = true\n portHandlers.delete(portId)\n messagePortRegistry.unregister(liveRef)\n liveRef.removeEventListener('message', messagePortListener as EventListener)\n }\n\n // Incoming: remote side wrote to its revived port — deliver the payload\n // on our local port after reviving it back into a live value.\n const handler = (message: Messages) => {\n if (message.type === 'message-port-close') {\n performCleanup()\n liveRef.close()\n return\n }\n const revivedData = recursiveRevive(message.data, context) as T\n liveRef.postMessage(revivedData, getTransferableObjects(revivedData))\n }\n\n // Outgoing: whatever was written into our side of the user's channel gets\n // boxed and shipped over the main transport.\n function messagePortListener({ data }: MessageEvent<Capable>) {\n context.sendMessage({\n type: 'message',\n remoteUuid: context.remoteUuid,\n data: recursiveBox(data, context),\n portId,\n })\n }\n\n // Register for automatic cleanup when garbage collected. Note the handler\n // (stored in portHandlers) holds `liveRef` strongly via closure, so GC\n // will only fire once the Map entry is deleted (in performCleanup).\n messagePortRegistry.register(liveRef, {\n sendMessage: context.sendMessage,\n remoteUuid: context.remoteUuid,\n portId,\n cleanup: performCleanup,\n }, liveRef)\n\n liveRef.addEventListener('message', messagePortListener as EventListener)\n liveRef.start()\n\n // For synthetic EventPorts, close() is how the owning side signals it's\n // done — wire it up so we tear down listeners and notify the remote.\n if (liveRef instanceof EventPort) {\n liveRef._onClose = () => {\n if (cleanedUp) return\n context.sendMessage({\n type: 'message-port-close',\n remoteUuid: context.remoteUuid,\n portId,\n })\n performCleanup()\n }\n }\n\n portHandlers.set(portId, handler)\n\n return { ...BoxBase, type, portId, synthetic } as BoxedMessagePort<T>\n }\n return {\n ...BoxBase,\n type,\n port: value,\n ...(options?.autoBox ? { autoBox: true } : {}),\n } as BoxedMessagePort<T>\n}\n\nexport const revive = <T extends Capable, T2 extends RevivableContext>(\n value: BoxedMessagePort<T>,\n context: T2,\n): TypedMessagePort<T> => {\n if ('port' in value) {\n // autoBox: box side was an internal protocol channel — wrap the\n // transferred MessagePort so outgoing/incoming payloads auto-box/revive\n // and live values (Promises/Functions) flow through unchanged.\n if (value.autoBox) {\n return createProtocolPort<T>(value.port as TypedMessagePort<Capable>, context)\n }\n return value.port\n }\n // portId path: origin was either a synthetic EventPort (pass-by-ref for\n // live values) or a real MessagePort we couldn't clone (JSON-only\n // transport). EventPorts must revive as EventPorts so that live values\n // pass through unchanged; MessagePorts must revive as MessagePorts so\n // the receiver sees the same shape they'd get from a real `transfer`.\n return reviveViaPortId<T>(value.portId, context, value.synthetic)\n}\n\n/**\n * Thin wrapper around a real MessagePort: auto-boxes outgoing messages and\n * auto-revives incoming ones. Lets revivables treat it like an EventTarget\n * (addEventListener / postMessage / start / close) that transparently\n * carries live values (Promises, Functions, …) over a clone-only transport.\n */\nconst createProtocolPort = <T>(\n port: TypedMessagePort<Capable>,\n ctx: RevivableContext,\n): TypedMessagePort<T> => {\n const target = new EventTarget() as TypedMessagePort<T>\n const onMessage = ({ data }: MessageEvent<Capable>): void => {\n target.dispatchEvent(new MessageEvent('message', {\n data: recursiveRevive(data, ctx),\n }))\n }\n port.addEventListener('message', onMessage)\n target.postMessage = (data: T, opt?: Transferable[] | StructuredSerializeOptions) => {\n const boxed = recursiveBox(data as Capable, ctx)\n const transferables = getTransferableObjects(boxed)\n const extra = Array.isArray(opt) ? opt : []\n port.postMessage(boxed, extra.length ? [...transferables, ...extra] : transferables)\n }\n target.start = () => port.start()\n target.close = () => {\n port.removeEventListener('message', onMessage)\n port.close()\n }\n return target\n}\n\n/**\n * Factory for revivable-internal channels. Returns a local port used by the\n * revivable and a pre-boxed remote port ready to embed in the revivable's\n * Boxed* structure. The local port auto-boxes/revives on clone transports\n * (via ProtocolPort over a MessageChannel) and passes by reference on JSON\n * transports (via EventChannel → portId routing).\n *\n * Revivables can post live values (Promises/Functions/…) on `localPort`\n * without caring about the transport mode.\n */\nexport const createRevivableChannel = <T extends Capable>(\n context: RevivableContext,\n): { localPort: AnyPort<T>, boxedRemote: BoxedMessagePort<T> } => {\n if (isJsonOnlyTransport(context.transport)) {\n const { port1, port2 } = new EventChannel<T, T>()\n return {\n localPort: port1,\n boxedRemote: box(port2 as StructurableTransferablePort<T>, context),\n }\n }\n const { port1, port2 } = new MessageChannel() as unknown as {\n port1: TypedMessagePort<Capable>\n port2: TypedMessagePort<Capable>\n }\n return {\n localPort: createProtocolPort<T>(port1, context) as unknown as AnyPort<T>,\n boxedRemote: box(port2 as unknown as StructurableTransferablePort<T>, context, { autoBox: true }),\n }\n}\n\n/**\n * Revive a port that was routed via portId. Covers both the synthetic\n * (EventChannel, pass-by-reference) and proxy (real MessageChannel,\n * structured-clone) paths — they share all cleanup/routing logic, only\n * differing in which channel type is instantiated, whether transferables\n * are listed on internal postMessage, and whether userPort exposes an\n * explicit close hook.\n */\nconst reviveViaPortId = <T extends Capable>(\n portId: Uuid,\n context: RevivableContext,\n synthetic: boolean,\n): TypedMessagePort<T> => {\n const { portHandlers } = getState(context)\n const { port1: userPort, port2: internalPort } =\n synthetic\n ? new EventChannel<T, T>()\n : new MessageChannel() as { port1: TypedMessagePort<T>, port2: TypedMessagePort<T> }\n const userPortRef = new WeakRef(userPort)\n\n let cleanedUp = false\n const performCleanup = () => {\n if (cleanedUp) return\n cleanedUp = true\n portHandlers.delete(portId)\n internalPort.removeEventListener('message', internalPortListener as EventListener)\n internalPort.close()\n const port = userPortRef.deref()\n if (port) messagePortRegistry.unregister(port)\n }\n\n const handler = (message: Messages) => {\n if (message.type === 'message-port-close') {\n performCleanup()\n userPortRef.deref()?.close()\n return\n }\n const port = userPortRef.deref()\n if (!port) {\n performCleanup()\n return\n }\n const revivedData = recursiveRevive(message.data, context) as T\n // Real MessagePorts need must-transfer items on the transfer list;\n // EventPorts pass by reference so no transferable list applies.\n if (synthetic) internalPort.postMessage(revivedData)\n else internalPort.postMessage(revivedData, getTransferableObjects(revivedData))\n }\n\n const internalPortListener = ({ data }: MessageEvent<T>) => {\n context.sendMessage({\n type: 'message',\n remoteUuid: context.remoteUuid,\n data: recursiveBox(data, context),\n portId,\n })\n }\n\n messagePortRegistry.register(userPort, {\n sendMessage: context.sendMessage,\n remoteUuid: context.remoteUuid,\n portId,\n cleanup: performCleanup,\n }, userPort)\n\n // EventPort exposes an explicit close hook — wire it so user.close() tears\n // down listeners locally and notifies the remote side. Real MessagePorts\n // have no equivalent; they rely on the FinalizationRegistry to notify.\n if (userPort instanceof EventPort) {\n userPort._onClose = () => {\n if (cleanedUp) return\n context.sendMessage({\n type: 'message-port-close',\n remoteUuid: context.remoteUuid,\n portId,\n })\n performCleanup()\n }\n }\n\n internalPort.addEventListener('message', internalPortListener as EventListener)\n internalPort.start()\n\n portHandlers.set(portId, handler)\n\n return userPort\n}\n\nconst typeCheck = () => {\n const port = {} as TypedMessagePort<{ foo: string }>\n const boxed = box(port, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: AnyPort<{ foo: string }> = revived\n // @ts-expect-error - wrong message type\n const wrongType: AnyPort<{ bar: number }> = revived\n // Promise-valued messages are fine now — EventChannel pass-by-reference\n // means we don't need StructurableTransferable here.\n box({} as TypedMessagePort<Promise<string>>, {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { UnderlyingType } from '.'\nimport type {\n BadFieldValue, BadFieldPath, BadFieldParent,\n ErrorMessage, BadValue, Path, ParentObject\n} from '../utils/capable-check'\n\nimport { BoxBase, serializeError } from './utils'\nimport {\n createRevivableChannel,\n revive as reviveMessagePort,\n BoxedMessagePort,\n AnyPort,\n} from './message-port'\n\nexport const type = 'promise' as const\n\nexport type Context =\n | { type: 'resolve', data: Capable }\n | { type: 'reject', error: string }\n\n// Error branches intersect with T so the user's own keys are present on the\n// target — otherwise TS's excess-property check flags the first user key\n// (e.g. `foo`) instead of reporting the failure against the whole argument.\ntype CapablePromise<T> = T extends Promise<infer U>\n ? U extends Capable\n ? T\n : T & {\n [ErrorMessage]: 'Value type must extend a Promise that resolves to a Capable'\n [BadValue]: BadFieldValue<U, Capable>\n [Path]: BadFieldPath<U, Capable>\n [ParentObject]: BadFieldParent<U, Capable>\n }\n : T & {\n [ErrorMessage]: 'Value type must extend a Promise that resolves to a Capable'\n [BadValue]: T\n [Path]: ''\n [ParentObject]: T\n }\n\ntype ExtractCapable<T> = T extends Promise<infer U>\n ? U extends Capable ? U : never\n : never\n\nconst isCapablePromise = <T, U extends Capable = ExtractCapable<T>>(value: T): value is T & Promise<U> =>\n value instanceof Promise\n\nexport type BoxedPromise<T extends Capable = Capable> =\n & BoxBaseType<typeof type>\n & { port: BoxedMessagePort<Context> }\n & { [UnderlyingType]: T }\n\n// Pins the revived port between executor return and result arrival. The\n// port↔listener cycle has no external anchor — the caller only holds the\n// returned Promise, which references its native resolvers, not the port.\n// Without this Set, GC under memory pressure can collect the cycle before\n// the result arrives and the Promise hangs forever. Mirrors the\n// inFlightReturnPorts pattern in function.ts.\nconst inFlightPromisePorts = new Set<AnyPort<Context>>()\n\nexport const isType = (value: unknown): value is Promise<any> =>\n value instanceof Promise\n\nexport const box = <T, T2 extends RevivableContext>(\n value: CapablePromise<T>,\n context: T2\n): BoxedPromise<ExtractCapable<T>> => {\n if (!isCapablePromise(value)) throw new TypeError('Expected Promise')\n const promise = value\n // Revivable-internal channel: localPort auto-boxes on send regardless of\n // transport (ProtocolPort over MessageChannel on clone, EventChannel +\n // portId on JSON). We just post the result and let it take care of boxing.\n const { localPort, boxedRemote } = createRevivableChannel<Context>(context)\n\n const sendResult = (result: Context) => {\n localPort.postMessage(result)\n localPort.close()\n }\n\n promise\n .then((data: ExtractCapable<T>) => sendResult({ type: 'resolve', data }))\n .catch((error: unknown) => sendResult({\n type: 'reject',\n error: serializeError(error),\n }))\n\n return { ...BoxBase, type, port: boxedRemote } as BoxedPromise<ExtractCapable<T>>\n}\n\nexport const revive = <T extends BoxedPromise, T2 extends RevivableContext>(\n value: T,\n context: T2\n) => {\n const port = reviveMessagePort(value.port, context)\n inFlightPromisePorts.add(port)\n return new Promise<T[UnderlyingType]>((resolve, reject) => {\n port.addEventListener('message', ({ data: result }) => {\n if (result.type === 'resolve') {\n resolve(result.data as T[UnderlyingType])\n } else {\n reject(result.error)\n }\n port.close()\n inFlightPromisePorts.delete(port)\n }, { once: true })\n port.start()\n })\n}\n\nconst typeCheck = () => {\n const boxed = box(Promise.resolve(1 as const), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Promise<1> = revived\n // @ts-expect-error\n const notExpected: Promise<string> = revived\n // @ts-expect-error\n box(1 as const, {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { UnderlyingType, RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { TypedMessagePort } from '../utils/typed-message-channel'\nimport type { AnyPort } from './message-port'\n\nimport { BoxBase, serializeError } from './utils'\nimport {\n createRevivableChannel,\n revive as reviveMessagePort,\n BoxedMessagePort,\n} from './message-port'\n\nexport const type = 'function' as const\n\ntype ResultMessage =\n | { __osra_ok__: true, value: Capable }\n | { __osra_err__: true, error: string }\n\ntype CallMessage = CallContext | { __osra_close__: true }\n\n// Per-call record so the FinalizationRegistry callback (and the synchronous\n// postMessage-failed path) can reject the right Promise and tear down the\n// matching return port. Each record is owned by a single in-flight call.\ntype CallRecord = {\n returnLocal: AnyPort<ResultMessage>\n reject: (error: unknown) => void\n}\n\n/**\n * FinalizationRegistry for automatically cleaning up function ports when the\n * revived function is garbage collected. Also rejects any in-flight calls that\n * were initiated through this function — without this, a caller that drops\n * `func` while awaiting its result would leak the return port and leave the\n * Promise hung forever.\n */\ntype FunctionCleanupInfo = {\n port: TypedMessagePort<CallMessage>\n inFlight: Set<CallRecord>\n}\n\nconst functionRegistry = new FinalizationRegistry<FunctionCleanupInfo>((info) => {\n try {\n info.port.postMessage({ __osra_close__: true })\n } catch { /* Port may already be closed */ }\n try {\n info.port.close()\n } catch { /* Port may already be closed */ }\n for (const { returnLocal, reject } of info.inFlight) {\n try { reject(new Error('osra function was garbage collected before result arrived')) } catch { /* listener gone */ }\n inFlightReturnPorts.delete(returnLocal)\n try { returnLocal.close() } catch { /* port may already be closed */ }\n }\n info.inFlight.clear()\n})\n\n// Pins caller-side return-value ports between send and result arriving. The\n// cycle (localPort↔listener↔remotePort) has no external anchor after the\n// Promise executor returns, so under memory pressure GC can collect it before\n// the result arrives — the Promise hangs forever. We remove the entries in\n// the once-listener and in every terminal-state cleanup path below.\nconst inFlightReturnPorts = new Set<AnyPort<any>>()\n\n/** Call-site payload (sent over the wire): the return port is pre-boxed by\n * createRevivableChannel; args are passed live and boxed by the channel. */\ntype SentCallContext = [BoxedMessagePort<ResultMessage>, Capable[]]\n\n/** Call-site payload as received by the callee, after box-side revival: the\n * return port is now a live AnyPort<ResultMessage> (ProtocolPort on clone,\n * EventPort on JSON); args are revived. */\nexport type CallContext = [AnyPort<ResultMessage>, Capable[]]\n\nexport type BoxedFunction<T extends (...args: any[]) => any = (...args: any[]) => any> =\n & BoxBaseType<typeof type>\n & { port: BoxedMessagePort<CallMessage> }\n & { [UnderlyingType]: (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>> }\n\ntype CapableFunction<T> = T extends (...args: infer P) => infer R\n ? P extends Capable[]\n ? R extends Capable ? T : never\n : never\n : never\n\nexport const isType = (value: unknown): value is (...args: any[]) => any =>\n typeof value === 'function'\n\nexport const box = <T extends (...args: any[]) => any, T2 extends RevivableContext>(\n value: T & CapableFunction<T>,\n context: T2\n): BoxedFunction<T> => {\n const { localPort, boxedRemote } = createRevivableChannel<CallMessage>(context)\n\n const cleanup = () => {\n localPort.close()\n }\n\n localPort.addEventListener('message', ({ data }) => {\n if (!Array.isArray(data)) {\n // __osra_close__ sentinel — only non-array message on this channel\n cleanup()\n return\n }\n const [returnPort, args] = data\n ;(async () => value(...(args as Parameters<T>)))()\n .then(\n (resolved) => {\n try {\n returnPort.postMessage({ __osra_ok__: true, value: resolved })\n } catch (postErr) {\n // Result wasn't clonable / boxable — surface as a remote error\n // instead of letting the caller hang waiting for a message that\n // can never be sent.\n try {\n returnPort.postMessage({\n __osra_err__: true,\n error: serializeError(postErr),\n })\n } catch { /* error itself failed to serialise; caller cleanup will reject */ }\n }\n },\n (error: unknown) => {\n try {\n returnPort.postMessage({\n __osra_err__: true,\n error: serializeError(error),\n })\n } catch { /* serialised error failed to post; caller cleanup will reject */ }\n },\n )\n .finally(() => {\n // Close after the message has flushed through the microtask queue so\n // the result actually dispatches before we tear the channel down.\n queueMicrotask(() => returnPort.close())\n })\n })\n localPort.start()\n\n return { ...BoxBase, type, port: boxedRemote } as BoxedFunction<T>\n}\n\nexport const revive = <T extends BoxedFunction, T2 extends RevivableContext>(\n value: T,\n context: T2\n): T[UnderlyingType] => {\n const port = reviveMessagePort(value.port, context)\n // Per-function bag of in-flight calls — captured by both the FinalizationRegistry\n // callback (rejects on func GC) and each call's once-listener (removes on settle).\n const inFlight = new Set<CallRecord>()\n\n const func = (...args: Capable[]) =>\n new Promise((resolve, reject) => {\n const { localPort: returnLocal, boxedRemote: returnBoxedRemote } =\n createRevivableChannel<ResultMessage>(context)\n // Pin ports to a module-level Set so GC can't collect the\n // port↔listener cycle while the call is in flight. Without this,\n // under memory pressure the listener (and thus `resolve`) can be\n // collected before the result arrives — the Promise hangs forever.\n inFlightReturnPorts.add(returnLocal)\n const record: CallRecord = { returnLocal, reject }\n inFlight.add(record)\n\n returnLocal.addEventListener('message', ({ data: result }) => {\n if ('__osra_ok__' in result) resolve(result.value)\n else reject(result.error)\n returnLocal.close()\n inFlightReturnPorts.delete(returnLocal)\n inFlight.delete(record)\n }, { once: true })\n returnLocal.start()\n\n // Boxing the args may throw synchronously (DataCloneError on a clone\n // transport, JSON cycle on a JSON transport). Without this catch, the\n // pin and the in-flight record would leak forever even though the\n // Promise itself rejects via the executor's implicit try/catch.\n try {\n port.postMessage([returnBoxedRemote, args] as SentCallContext as unknown as CallMessage)\n } catch (sendErr) {\n inFlightReturnPorts.delete(returnLocal)\n inFlight.delete(record)\n try { returnLocal.close() } catch { /* may already be closed */ }\n reject(sendErr)\n }\n })\n\n // Register the function for automatic cleanup when garbage collected. The\n // callback also rejects every in-flight call so abandoned awaits stop hanging.\n functionRegistry.register(func, { port, inFlight }, func)\n\n return func\n}\n\nconst typeCheck = () => {\n const boxed = box((a: number, b: string) => a + b.length, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: (a: number, b: string) => Promise<number> = revived\n // @ts-expect-error - wrong return type\n const wrongReturn: (a: number, b: string) => Promise<string> = revived\n // @ts-expect-error - wrong parameter types\n const wrongParams: (a: string, b: number) => Promise<number> = revived\n // @ts-expect-error - non-Capable parameter type (Set is not directly Capable as parameter)\n box((a: WeakMap<object, string>) => a, {} as RevivableContext)\n // @ts-expect-error - non-Capable return type\n box(() => new WeakMap(), {} as RevivableContext)\n}\n","import type { RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { UnderlyingType } from '.'\n\nimport { BoxBase } from './utils'\nimport {\n createRevivableChannel,\n revive as reviveMessagePort,\n BoxedMessagePort\n} from './message-port'\n\nexport const type = 'readableStream' as const\n\nexport type PullContext = {\n type: 'pull' | 'cancel'\n}\n\ntype ChunkMessage<T = unknown> = Promise<ReadableStreamReadResult<T>>\n\ntype Msg = PullContext | ChunkMessage\n\nexport type BoxedReadableStream<T extends ReadableStream = ReadableStream> =\n & BoxBaseType<typeof type>\n & { port: BoxedMessagePort<Msg> }\n & { [UnderlyingType]: T }\n\nexport const isType = (value: unknown): value is ReadableStream =>\n value instanceof ReadableStream\n\nexport const box = <T extends ReadableStream, T2 extends RevivableContext>(\n value: T,\n context: T2\n): BoxedReadableStream<T> => {\n const { localPort, boxedRemote } = createRevivableChannel<Msg>(context)\n const reader = value.getReader()\n\n localPort.addEventListener('message', ({ data }) => {\n if ('type' in data && data.type === 'pull') {\n // reader.read() is a Promise — posting it live works because localPort\n // (ProtocolPort or EventPort) boxes it internally for the transport.\n localPort.postMessage(reader.read())\n } else {\n reader.cancel()\n localPort.close()\n }\n })\n localPort.start()\n\n return { ...BoxBase, type, port: boxedRemote } as BoxedReadableStream<T>\n}\n\nexport const revive = <T extends BoxedReadableStream, T2 extends RevivableContext>(\n value: T,\n context: T2\n): T[UnderlyingType] => {\n const port = reviveMessagePort(value.port, context)\n port.start()\n\n return new ReadableStream({\n pull: (controller) => new Promise<void>((resolve, reject) => {\n port.addEventListener('message', ({ data }) => {\n if (!(data instanceof Promise)) return\n data\n .then(result => {\n if (result.done) controller.close()\n else controller.enqueue(result.value)\n resolve()\n })\n .catch(reject)\n }, { once: true })\n port.postMessage({ type: 'pull' })\n }),\n cancel: () => {\n port.postMessage({ type: 'cancel' })\n // Defer close so the cancel message dispatches before tear-down — same\n // pattern function.ts uses for return-port cleanup.\n queueMicrotask(() => port.close())\n },\n }) as T[UnderlyingType]\n}\n\nconst typeCheck = () => {\n const stream = new ReadableStream<number>()\n const boxed = box(stream, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: ReadableStream<number> = revived\n // @ts-expect-error - wrong stream type\n const wrongType: ReadableStream<string> = revived\n // @ts-expect-error - not a ReadableStream\n box('not a stream', {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { UnderlyingType } from '../utils/type'\nimport type { BoxedMessagePort } from './message-port'\n\nimport { BoxBase } from './utils'\nimport { recursiveBox, recursiveRevive } from '.'\nimport {\n createRevivableChannel,\n revive as reviveMessagePort\n} from './message-port'\n\nexport const type = 'abortSignal' as const\n\ntype AbortMessage = {\n type: 'abort'\n reason?: Capable\n}\n\nexport type BoxedAbortSignal<T extends AbortSignal = AbortSignal> =\n & BoxBaseType<typeof type>\n & {\n aborted: boolean\n reason?: Capable\n port: BoxedMessagePort<AbortMessage>\n }\n & { [UnderlyingType]: T }\n\nexport const isType = (value: unknown): value is AbortSignal =>\n value instanceof AbortSignal\n\nexport const box = <T extends AbortSignal, T2 extends RevivableContext>(\n value: T,\n context: T2\n): BoxedAbortSignal<T> => {\n const { localPort, boxedRemote } = createRevivableChannel<AbortMessage>(context)\n\n if (!value.aborted) {\n value.addEventListener('abort', () => {\n localPort.postMessage({ type: 'abort', reason: value.reason as Capable })\n localPort.close()\n }, { once: true })\n } else {\n localPort.close()\n }\n\n // Eagerly-aborted reason rides the wrapper instead of the channel, so it\n // has to go through recursiveBox here — the outer recursiveBox will see\n // OSRA_BOX on this object and short-circuit before descending into `reason`.\n // Without this, a reason carrying live values (Function/Promise/EventTarget/…)\n // throws DataCloneError on clone transports and silently loses fields on\n // JSON transports.\n return {\n ...BoxBase,\n type,\n aborted: value.aborted,\n reason: value.aborted ? recursiveBox(value.reason as Capable, context) as Capable : undefined,\n port: boxedRemote,\n } as BoxedAbortSignal<T>\n}\n\nexport const revive = <T extends BoxedAbortSignal, T2 extends RevivableContext>(\n value: T,\n context: T2\n): AbortSignal => {\n const controller = new AbortController()\n\n if (value.aborted) {\n controller.abort(recursiveRevive(value.reason as Capable, context))\n return controller.signal\n }\n\n const port = reviveMessagePort(value.port, context)\n port.start()\n\n port.addEventListener('message', ({ data: message }) => {\n if (message.type === 'abort') {\n controller.abort(recursiveRevive(message.reason as Capable, context))\n port.close()\n }\n })\n\n return controller.signal\n}\n\nconst typeCheck = () => {\n const boxed = box(new AbortController().signal, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: AbortSignal = revived\n // @ts-expect-error - not an AbortSignal\n const notAbortSignal: string = revived\n // @ts-expect-error - cannot box non-AbortSignal\n box('not an abort signal', {} as RevivableContext)\n}\n","import type { RevivableContext } from './utils'\n\nimport { BoxBase } from './utils'\nimport { box as boxHeaders, revive as reviveHeaders } from './headers'\nimport { box as boxReadableStream, revive as reviveReadableStream } from './readable-stream'\n\nexport const type = 'response' as const\n\nexport const isType = (value: unknown): value is Response =>\n value instanceof Response\n\nexport const box = <T extends Response, T2 extends RevivableContext>(\n value: T,\n context: T2\n) => ({\n ...BoxBase,\n type,\n status: value.status,\n statusText: value.statusText,\n headers: boxHeaders(value.headers, context),\n body: value.body ? boxReadableStream(value.body, context) : null,\n url: value.url,\n redirected: value.redirected\n})\n\nexport const revive = <T extends ReturnType<typeof box>, T2 extends RevivableContext>(\n value: T,\n context: T2\n): Response => {\n const headers = reviveHeaders(value.headers, context)\n const body = value.body ? reviveReadableStream(value.body, context) : null\n\n return new Response(body, {\n status: value.status,\n statusText: value.statusText,\n headers\n })\n}\n\nconst typeCheck = () => {\n const boxed = box(new Response('body', { status: 200 }), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Response = revived\n // @ts-expect-error - not a Response\n const notResponse: string = revived\n // @ts-expect-error - cannot box non-Response\n box('not a response', {} as RevivableContext)\n}\n","import type { RevivableContext } from './utils'\n\nimport { BoxBase } from './utils'\nimport { box as boxHeaders, revive as reviveHeaders } from './headers'\nimport { box as boxReadableStream, revive as reviveReadableStream } from './readable-stream'\n\nexport const type = 'request' as const\n\nexport const isType = (value: unknown): value is Request =>\n value instanceof Request\n\nexport const box = <T extends Request, T2 extends RevivableContext>(\n value: T,\n context: T2\n) => ({\n ...BoxBase,\n type,\n method: value.method,\n url: value.url,\n headers: boxHeaders(value.headers, context),\n body: value.body ? boxReadableStream(value.body, context) : null,\n credentials: value.credentials,\n cache: value.cache,\n redirect: value.redirect,\n referrer: value.referrer,\n referrerPolicy: value.referrerPolicy,\n integrity: value.integrity,\n keepalive: value.keepalive\n})\n\nexport const revive = <T extends ReturnType<typeof box>, T2 extends RevivableContext>(\n value: T,\n context: T2\n): Request => {\n const headers = reviveHeaders(value.headers, context)\n const body = value.body ? reviveReadableStream(value.body, context) : null\n\n return new Request(value.url, {\n method: value.method,\n headers,\n body,\n credentials: value.credentials,\n cache: value.cache,\n redirect: value.redirect,\n referrer: value.referrer,\n referrerPolicy: value.referrerPolicy,\n integrity: value.integrity,\n keepalive: value.keepalive,\n // @ts-expect-error - duplex is needed for streaming bodies\n duplex: 'half',\n })\n}\n\nconst typeCheck = () => {\n const boxed = box(new Request('https://example.com'), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Request = revived\n // @ts-expect-error - not a Request\n const notRequest: string = revived\n // @ts-expect-error - cannot box non-Request\n box('not a request', {} as RevivableContext)\n}\n","import type { Capable, Message, Uuid } from '../types'\nimport type { RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { UnderlyingType } from '../utils/type'\n\nimport { BoxBase } from './utils'\nimport { recursiveBox, recursiveRevive } from '.'\n\nexport const type = 'identity' as const\n\nexport type Messages = {\n type: 'identity-dispose'\n remoteUuid: Uuid\n /** id of the identity-wrapped value that was collected */\n id: string\n}\n\nexport declare const Messages: Messages\n\nconst IDENTITY_MARKER: unique symbol = Symbol.for('osra.identity')\n\ntype IdentityWrapper<T = unknown> = {\n readonly [IDENTITY_MARKER]: true\n readonly value: T\n}\n\nexport type BoxedIdentity<T extends Capable = Capable> = BoxBaseType<typeof type> & {\n id: string\n inner?: Capable\n [UnderlyingType]: T\n}\n\nconst isObjectOrFunction = (value: unknown): value is object =>\n value !== null && (typeof value === 'object' || typeof value === 'function')\n\nconst isIdentityWrapper = (value: unknown): value is IdentityWrapper =>\n isObjectOrFunction(value) && IDENTITY_MARKER in value && value[IDENTITY_MARKER] === true\n\nconst wrapperMemo = new WeakMap<object, IdentityWrapper>()\n\nconst wrap = (value: object): IdentityWrapper => {\n if (isIdentityWrapper(value)) return value\n const cached = wrapperMemo.get(value)\n if (cached) return cached\n const wrapper: IdentityWrapper = { [IDENTITY_MARKER]: true, value }\n wrapperMemo.set(value, wrapper)\n return wrapper\n}\n\n/**\n * Wrap a value so that osra preserves its reference identity across the\n * RPC boundary, per connection. Calling identity(X) twice on the same\n * value produces the same wrapper, and both wrapper sends resolve to the\n * same revived reference on the remote side.\n *\n * - Primitives pass through unchanged (there is no identity to preserve).\n * - Already-wrapped values pass through unchanged (idempotent).\n *\n * NOTE: This lies at the type level — the runtime value for object/function\n * inputs is an IdentityWrapper<T>, typed as T so the user's surrounding\n * code stays unchanged. The box-site unwraps it.\n */\nexport const identity = <T>(value: T): T =>\n (isObjectOrFunction(value) ? wrap(value) : value) as T\n\n/**\n * Per-connection state for the identity revivable. Stored in a module-level\n * WeakMap so the connection's RevivableContext acts as the key — when the\n * connection ends and the context is collected, the state goes with it.\n */\ntype IdentityState = {\n /** Send side: inner value → stable id for this connection. */\n readonly sendIds: WeakMap<object, string>\n /** Send side: FinalizationRegistry firing when an inner value is GC'd. */\n readonly sendRegistry: FinalizationRegistry<string>\n /** Receive side: id → revived value (strong ref, explicit cleanup). */\n readonly receiveCache: Map<string, unknown>\n /** True once the eventTarget listener has been installed. */\n listenerInstalled: boolean\n}\n\nconst connectionStates = new WeakMap<RevivableContext, IdentityState>()\n\nconst getOrCreateState = (context: RevivableContext): IdentityState => {\n const existing = connectionStates.get(context)\n if (existing) return existing\n const state: IdentityState = {\n sendIds: new WeakMap(),\n sendRegistry: new FinalizationRegistry<string>((id) => {\n // Sender-side inner value was collected. Tell the receiver to drop\n // its cached revived value so both sides converge. If the transport\n // has already been torn down, swallow the error.\n try {\n context.sendMessage({\n type: 'identity-dispose',\n remoteUuid: context.remoteUuid,\n id,\n })\n } catch { /* connection already closed */ }\n }),\n receiveCache: new Map(),\n listenerInstalled: false,\n }\n connectionStates.set(context, state)\n installReceiveListener(context, state)\n return state\n}\n\nconst installReceiveListener = (context: RevivableContext, state: IdentityState) => {\n if (state.listenerInstalled) return\n state.listenerInstalled = true\n context.eventTarget.addEventListener('message', ({ detail }) => {\n if (detail?.type === 'identity-dispose') {\n state.receiveCache.delete(detail.id)\n }\n })\n}\n\nexport const isType = (value: unknown): value is IdentityWrapper =>\n isIdentityWrapper(value)\n\nexport const box = <T extends Capable, TContext extends RevivableContext>(\n wrapper: IdentityWrapper<T>,\n context: TContext,\n): BoxedIdentity<T> => {\n const state = getOrCreateState(context)\n const inner = wrapper.value\n const key = isObjectOrFunction(inner) ? inner : undefined\n if (key !== undefined) {\n const existingId = state.sendIds.get(key)\n if (existingId !== undefined) {\n // Subsequent send for this value on this connection: skip the inner\n // box entirely so the receiver resolves through its cache.\n return {\n ...BoxBase,\n type,\n id: existingId,\n } as BoxedIdentity<T>\n }\n }\n const id = globalThis.crypto.randomUUID()\n const innerBox = recursiveBox(inner, context)\n if (key !== undefined) {\n state.sendIds.set(key, id)\n state.sendRegistry.register(key, id)\n }\n return {\n ...BoxBase,\n type,\n id,\n inner: innerBox,\n } as BoxedIdentity<T>\n}\n\nexport const revive = <T extends BoxedIdentity, TContext extends RevivableContext>(\n value: T,\n context: TContext,\n): T[UnderlyingType] => {\n const state = getOrCreateState(context)\n const cached = state.receiveCache.get(value.id)\n if (cached !== undefined) return cached as T[UnderlyingType]\n if (!('inner' in value) || value.inner === undefined) {\n throw new Error(\n `osra identity: received id=${value.id} with no inner payload and no cached value`,\n )\n }\n const revived = recursiveRevive(value.inner, context)\n state.receiveCache.set(value.id, revived)\n return revived as T[UnderlyingType]\n}\n\nconst typeCheck = () => {\n const fn = () => 42\n const wrapper = { [IDENTITY_MARKER]: true, value: fn } as IdentityWrapper<typeof fn>\n const boxed = box(wrapper, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n // Revive recovers the original function type via the UnderlyingType phantom.\n const expected: typeof fn = revived\n // @ts-expect-error - revived is the original function type, not string\n const notExpected: string = revived\n // @ts-expect-error - cannot box a non-Capable wrapper (Symbol not assignable)\n box({ [IDENTITY_MARKER]: true, value: Symbol() } as IdentityWrapper<symbol>, {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { BoxBase as BoxBaseType, RevivableContext, UnderlyingType } from './utils'\n\nimport { BoxBase } from './utils'\nimport { instanceOfAny, isJsonOnlyTransport } from '../utils'\nimport { recursiveBox, recursiveRevive } from '.'\n\nexport const type = 'transfer' as const\n\nconst TRANSFER_MARKER: unique symbol = Symbol.for('osra.transfer')\n\ntype TransferWrapper<T = unknown> = {\n readonly [TRANSFER_MARKER]: true\n readonly value: T\n}\n\nexport type BoxedTransfer<T extends Capable = Capable> = BoxBaseType<typeof type> & {\n inner: Capable\n degraded: boolean\n [UnderlyingType]: T\n}\n\nconst isObject = (value: unknown): value is object =>\n value !== null && typeof value === 'object'\n\nconst isTransferWrapper = (value: unknown): value is TransferWrapper =>\n isObject(value) && TRANSFER_MARKER in value && value[TRANSFER_MARKER] === true\n\n// The set of types `transfer()` accepts. Anything else — primitives, nullish,\n// plain objects, Dates, Errors, Promises, etc. — is returned unchanged so\n// normal payloads don't blow up if someone wraps the wrong thing.\nconst isWrappableTransferable = (value: unknown): boolean => {\n if (!isObject(value)) return false\n if (ArrayBuffer.isView(value)) return true\n return instanceOfAny(value, [\n globalThis.ArrayBuffer,\n globalThis.MessagePort,\n globalThis.ReadableStream,\n globalThis.WritableStream,\n globalThis.TransformStream,\n globalThis.ImageBitmap,\n globalThis.OffscreenCanvas,\n ])\n}\n\n/**\n * Opt into transfer semantics for a transferable value. Without this wrapper\n * osra sends transferables as structured clones (copies) — the sender-side\n * reference stays usable after the RPC. Wrapping hands the underlying storage\n * off to the receiver and neuters the sender-side reference, matching what\n * you'd get by listing it in the transfer list of `postMessage(msg, [buf])`.\n *\n * - Primitives, null, undefined, plain objects, Promises, Dates, etc. are\n * returned unchanged.\n * - Typed array views (`Uint8Array`, `DataView`, …) are accepted as a\n * convenience — their underlying `.buffer` is what actually gets moved.\n * - `transfer(transfer(x))` returns the same wrapper as `transfer(x)`.\n * - If the current platform cannot transfer the given type, the wrapper\n * silently degrades to a copy — nothing throws.\n *\n * NOTE: This lies at the type level — the runtime value for transferable\n * inputs is a TransferWrapper<T>, typed as T so the user's surrounding\n * code stays unchanged. The box-site unwraps it.\n */\nexport const transfer = <T>(value: T): T =>\n (isWrappableTransferable(value)\n ? { [TRANSFER_MARKER]: true, value }\n : value\n ) as T\n\n// -------------------------------------------------------------------------\n// Revivable module interface\n// -------------------------------------------------------------------------\n\nexport const isType = (value: unknown): value is TransferWrapper =>\n isTransferWrapper(value)\n\nexport const box = <T extends Capable, TContext extends RevivableContext>(\n wrapper: TransferWrapper<T>,\n context: TContext,\n): BoxedTransfer<T> => {\n const inner = wrapper.value\n const innerBoxed = recursiveBox(inner, context)\n // The `degraded` flag carries the transport mode to the send-time walker\n // in getTransferableObjects. When true, the walker treats this box as if\n // it weren't a transfer box at all — no mode flip, no transferables on\n // the transfer list — and the wrapper silently degrades to a copy. JSON\n // transports can't move ownership over the wire, so transfer semantics\n // don't apply and we degrade.\n return {\n ...BoxBase,\n type,\n inner: innerBoxed,\n degraded: isJsonOnlyTransport(context.transport),\n } as BoxedTransfer<T>\n}\n\nexport const revive = <T extends BoxedTransfer, TContext extends RevivableContext>(\n value: T,\n context: TContext,\n): T[UnderlyingType] =>\n recursiveRevive(value.inner, context) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const ab = new ArrayBuffer(10)\n const wrapper = { [TRANSFER_MARKER]: true, value: ab } as TransferWrapper<ArrayBuffer>\n const boxed = box(wrapper, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n // Revive recovers the original ArrayBuffer type via the UnderlyingType phantom.\n const expected: ArrayBuffer = revived\n // @ts-expect-error - revived is ArrayBuffer, not string\n const notExpected: string = revived\n // @ts-expect-error - cannot box a non-Capable wrapper (Symbol not assignable)\n box({ [TRANSFER_MARKER]: true, value: Symbol() } as TransferWrapper<symbol>, {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { RevivableContext, UnderlyingType, BoxBase as BoxBaseType } from './utils'\n\nimport { BoxBase } from './utils'\nimport { recursiveBox, recursiveRevive } from '.'\n\nexport const type = 'map' as const\n\nexport type BoxedMap<T extends Map<Capable, Capable> = Map<Capable, Capable>> =\n & BoxBaseType<typeof type>\n & { entries: Array<[Capable, Capable]> }\n & { [UnderlyingType]: T }\n\n// `Map<unknown, unknown>` rather than `Map<Capable, Capable>` here breaks\n// the Capable ↔ defaultRevivableModules ↔ this module type cycle.\n// box() narrows to Map<Capable, Capable> so misuse is still caught at the\n// box site.\nexport const isType = (value: unknown): value is Map<unknown, unknown> =>\n value instanceof Map\n\nexport const box = <T extends Map<Capable, Capable>, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): BoxedMap<T> => ({\n ...BoxBase,\n type,\n entries: Array.from(value, ([k, v]): [Capable, Capable] =>\n [recursiveBox(k, context) as Capable, recursiveBox(v, context) as Capable]),\n}) as BoxedMap<T>\n\nexport const revive = <T extends BoxedMap, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): T[UnderlyingType] =>\n new Map(value.entries.map(([k, v]) => [\n recursiveRevive(k, context),\n recursiveRevive(v, context),\n ])) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const m = new Map<string, number>([['a', 1]])\n const boxed = box(m, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Map<string, number> = revived\n // @ts-expect-error - wrong value type\n const wrongValue: Map<string, string> = revived\n // @ts-expect-error - cannot box non-Map\n box('not a map', {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { RevivableContext, UnderlyingType, BoxBase as BoxBaseType } from './utils'\n\nimport { BoxBase } from './utils'\nimport { recursiveBox, recursiveRevive } from '.'\n\nexport const type = 'set' as const\n\nexport type BoxedSet<T extends Set<Capable> = Set<Capable>> =\n & BoxBaseType<typeof type>\n & { values: Array<Capable> }\n & { [UnderlyingType]: T }\n\n// `Set<unknown>` rather than `Set<Capable>` here breaks the Capable ↔\n// defaultRevivableModules ↔ this module type cycle. box() narrows to\n// Set<Capable> so misuse is still caught at the box site.\nexport const isType = (value: unknown): value is Set<unknown> =>\n value instanceof Set\n\nexport const box = <T extends Set<Capable>, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): BoxedSet<T> => ({\n ...BoxBase,\n type,\n values: Array.from(value, v => recursiveBox(v, context) as Capable),\n}) as BoxedSet<T>\n\nexport const revive = <T extends BoxedSet, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): T[UnderlyingType] =>\n new Set(value.values.map(v => recursiveRevive(v, context))) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const s = new Set<number>([1, 2, 3])\n const boxed = box(s, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Set<number> = revived\n // @ts-expect-error - wrong value type\n const wrongValue: Set<string> = revived\n // @ts-expect-error - cannot box non-Set\n box('not a set', {} as RevivableContext)\n}\n","import type { RevivableContext, UnderlyingType } from './utils'\n\nimport { BoxBase } from './utils'\n\nexport const type = 'bigint' as const\n\ntype BoxedBigInt<T extends bigint> =\n & typeof BoxBase\n & { type: typeof type }\n & { value: string }\n & { [UnderlyingType]: T }\n\nexport const isType = (value: unknown): value is bigint =>\n typeof value === 'bigint'\n\nexport const box = <T extends bigint, T2 extends RevivableContext>(\n value: T,\n _context: T2,\n): BoxedBigInt<T> =>\n ({ ...BoxBase, type, value: value.toString() }) as BoxedBigInt<T>\n\nexport const revive = <T extends BoxedBigInt<bigint>>(\n value: T,\n _context: RevivableContext,\n): T[UnderlyingType] =>\n BigInt(value.value) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const boxed = box(123n, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: bigint = revived\n // @ts-expect-error - not a string\n const notString: string = revived\n // @ts-expect-error - cannot box non-bigint\n box('not a bigint', {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { RevivableContext, BoxBase as BoxBaseType, UnderlyingType } from './utils'\nimport type { AnyPort, BoxedMessagePort } from './message-port'\n\nimport { BoxBase } from './utils'\nimport {\n createRevivableChannel,\n revive as reviveMessagePort,\n} from './message-port'\n\nexport const type = 'eventTarget' as const\n\n// Wire protocol — receiver tells source which event types to forward (so we\n// don't broadcast every dispatch); source pushes a serialised event when its\n// EventTarget fires a matching type. The `close` sentinel lets the revive\n// side notify the box side that the revived target is gone so it can tear\n// down its forwarder listeners.\ntype EventTargetMessage =\n | { kind: 'subscribe', eventType: string }\n | { kind: 'unsubscribe', eventType: string }\n | { kind: 'close' }\n | {\n kind: 'event'\n eventType: string\n bubbles: boolean\n cancelable: boolean\n composed: boolean\n // Present iff the source dispatched a CustomEvent — preserves `detail`\n // (boxed via the surrounding revivable graph so live values flow).\n detail?: Capable\n }\n\nexport type BoxedEventTarget<T extends EventTarget = EventTarget> =\n & BoxBaseType<typeof type>\n & { port: BoxedMessagePort<EventTargetMessage> }\n & { [UnderlyingType]: T }\n\n// FinalizationRegistry — when the revived EventTarget is collected the box\n// side needs to remove the forwarder listeners it installed on the user's\n// source EventTarget; otherwise long-lived sources (window, document, …)\n// retain the forwarder forever and keep posting into a dead channel on\n// every dispatch. We post a `close` sentinel through the revive-side port\n// but deliberately do NOT call .close() on the port here: on synthetic\n// EventPort channels (JSON transport) close() synchronously sends a\n// `message-port-close` to the box side via _onClose, which races ahead of\n// our queued sentinel and tears the box-side portHandlers entry down\n// before the sentinel arrives — so the sentinel gets dropped and tearDown\n// never runs. Leaving the port open lets messagePortRegistry clean it up\n// a GC cycle later, by which time the sentinel has already flushed.\ntype EventTargetCleanupInfo = {\n port: AnyPort<EventTargetMessage>\n}\n\nconst eventTargetRegistry = new FinalizationRegistry<EventTargetCleanupInfo>((info) => {\n try {\n info.port.postMessage({ kind: 'close' })\n } catch { /* Port may already be closed */ }\n})\n\nexport const isType = (value: unknown): value is EventTarget =>\n value instanceof EventTarget\n\nexport const box = <T extends EventTarget, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): BoxedEventTarget<T> => {\n const { localPort, boxedRemote } = createRevivableChannel<EventTargetMessage>(context)\n\n // One forwarder per event type, installed on demand and torn down when the\n // remote unsubscribes. Keyed by eventType so duplicate subscribes are no-ops.\n const sourceListeners = new Map<string, EventListener>()\n\n const tearDown = () => {\n for (const [eventType, listener] of sourceListeners) {\n value.removeEventListener(eventType, listener)\n }\n sourceListeners.clear()\n localPort.removeEventListener('message', messageListener as EventListener)\n localPort.close()\n }\n\n const messageListener = ({ data }: MessageEvent<EventTargetMessage>) => {\n if (data.kind === 'close') {\n tearDown()\n return\n }\n if (data.kind === 'subscribe') {\n if (sourceListeners.has(data.eventType)) return\n const listener: EventListener = (event) => {\n const message: EventTargetMessage = {\n kind: 'event',\n eventType: data.eventType,\n bubbles: event.bubbles,\n cancelable: event.cancelable,\n composed: event.composed,\n }\n if (event instanceof CustomEvent) {\n message.detail = event.detail as Capable\n }\n localPort.postMessage(message)\n }\n value.addEventListener(data.eventType, listener)\n sourceListeners.set(data.eventType, listener)\n return\n }\n if (data.kind === 'unsubscribe') {\n const existing = sourceListeners.get(data.eventType)\n if (!existing) return\n value.removeEventListener(data.eventType, existing)\n sourceListeners.delete(data.eventType)\n }\n }\n\n localPort.addEventListener('message', messageListener as EventListener)\n localPort.start()\n\n return { ...BoxBase, type, port: boxedRemote } as BoxedEventTarget<T>\n}\n\nconst extractCapture = (\n options?: boolean | EventListenerOptions | AddEventListenerOptions,\n): boolean => typeof options === 'boolean' ? options : !!options?.capture\n\nconst extractOnce = (options?: boolean | AddEventListenerOptions): boolean =>\n typeof options === 'object' && options !== null && !!options.once\n\ntype Subscriptions =\n Map<string, Map<EventListenerOrEventListenerObject, Map<boolean, EventListenerOrEventListenerObject>>>\n\n// Removes one (listener, capture) registration; returns true iff the\n// event type went from non-empty to empty so the caller can post unsubscribe.\nconst removeFromTracking = (\n subscriptions: Subscriptions,\n eventType: string,\n listener: EventListenerOrEventListenerObject,\n capture: boolean,\n): boolean => {\n const byListener = subscriptions.get(eventType)\n if (!byListener) return false\n const byCapture = byListener.get(listener)\n if (!byCapture) return false\n if (!byCapture.delete(capture)) return false\n if (byCapture.size === 0) byListener.delete(listener)\n if (byListener.size > 0) return false\n subscriptions.delete(eventType)\n return true\n}\n\n// Attaches the port-dispatch listener inside a helper so V8's closure scope\n// record for the listener contains only `targetRef` + `port` — not the outer\n// revive frame (which has a strong `target` binding that would pin the\n// revived EventTarget and defeat the FinalizationRegistry-based cleanup).\nconst wireMessageListener = (\n port: AnyPort<EventTargetMessage>,\n targetRef: WeakRef<EventTarget>,\n): void => {\n port.addEventListener('message', ({ data }: MessageEvent<EventTargetMessage>) => {\n if (data.kind !== 'event') return\n const t = targetRef.deref()\n if (!t) return\n const eventInit = {\n bubbles: data.bubbles,\n cancelable: data.cancelable,\n composed: data.composed,\n }\n const event = 'detail' in data\n ? new CustomEvent(data.eventType, { ...eventInit, detail: data.detail })\n : new Event(data.eventType, eventInit)\n t.dispatchEvent(event)\n })\n}\n\n// Builds the addEventListener/removeEventListener overrides inside a helper\n// so the closures they produce capture only the listed params — not `target`\n// from revive's scope (V8 retains whole context slots per closure, so leaving\n// `target` in the enclosing lexical scope would pin it alive indefinitely).\nconst installOverrides = (\n target: EventTarget,\n port: AnyPort<EventTargetMessage>,\n subscriptions: Subscriptions,\n): void => {\n const nativeAdd = EventTarget.prototype.addEventListener.bind(target)\n const nativeRemove = EventTarget.prototype.removeEventListener.bind(target)\n\n Object.defineProperty(target, 'addEventListener', {\n value: (\n eventType: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | AddEventListenerOptions,\n ) => {\n if (listener === null) return\n const capture = extractCapture(options)\n const once = extractOnce(options)\n\n let byListener = subscriptions.get(eventType)\n const isFirstForType = !byListener\n if (!byListener) {\n byListener = new Map()\n subscriptions.set(eventType, byListener)\n }\n let byCapture = byListener.get(listener)\n if (!byCapture) {\n byCapture = new Map()\n byListener.set(listener, byCapture)\n }\n if (byCapture.has(capture)) return\n\n // `{ once: true }` auto-removes the native registration after first\n // dispatch, but the DOM doesn't notify our override — so without a\n // wrapper, our tracking would diverge and we'd never send unsubscribe.\n const effective: EventListenerOrEventListenerObject = once\n ? (event: Event) => {\n const becameEmpty = removeFromTracking(subscriptions, eventType, listener, capture)\n if (becameEmpty) port.postMessage({ kind: 'unsubscribe', eventType })\n if (typeof listener === 'function') listener(event)\n else listener.handleEvent(event)\n }\n : listener\n\n byCapture.set(capture, effective)\n if (isFirstForType) port.postMessage({ kind: 'subscribe', eventType })\n nativeAdd(eventType, effective, options)\n },\n })\n\n Object.defineProperty(target, 'removeEventListener', {\n value: (\n eventType: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | EventListenerOptions,\n ) => {\n if (listener === null) return\n const capture = extractCapture(options)\n const effective = subscriptions.get(eventType)?.get(listener)?.get(capture)\n if (!effective) return\n nativeRemove(eventType, effective, options)\n const becameEmpty = removeFromTracking(subscriptions, eventType, listener, capture)\n if (becameEmpty) port.postMessage({ kind: 'unsubscribe', eventType })\n },\n })\n}\n\nexport const revive = <T extends BoxedEventTarget, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): T[UnderlyingType] => {\n const port = reviveMessagePort(value.port, context)\n port.start()\n\n const target = new EventTarget()\n // Per-type registrations keyed by `(listener, capture)` because the DOM\n // uniques on that tuple: the same listener with capture=true and capture=false\n // are two distinct registrations and must be tracked independently. Tracking\n // on listener identity alone would silently drop one registration when the\n // other is removed, and miss `{ once: true }` self-removal.\n const subscriptions: Subscriptions = new Map()\n\n // WeakRef wrapping + helpers-with-tight-scope pattern: closures created\n // inside wireMessageListener / installOverrides only capture their params,\n // not `target` from this frame. That's what lets the FinalizationRegistry\n // fire when the user drops their revived-target reference.\n wireMessageListener(port, new WeakRef(target))\n installOverrides(target, port, subscriptions)\n\n eventTargetRegistry.register(target, { port }, target)\n\n return target as T[UnderlyingType]\n}\n\nconst typeCheck = () => {\n const et = new EventTarget()\n const boxed = box(et, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: EventTarget = revived\n // @ts-expect-error - not a string\n const notString: string = revived\n // @ts-expect-error - cannot box non-EventTarget\n box('not an event target', {} as RevivableContext)\n}\n","import type { BoxBase, RevivableContext } from './utils'\nimport type { DeepReplaceWithBox, DeepReplaceWithRevive, ReplaceWithBox, ReplaceWithRevive } from '../utils/replace'\nimport type { MessageFields, Capable } from '../types'\n\nimport { isRevivableBox } from './utils'\nimport * as arrayBuffer from './array-buffer'\nimport * as date from './date'\nimport * as headers from './headers'\nimport * as error from './error'\nimport * as typedArray from './typed-array'\nimport * as promise from './promise'\nimport * as func from './function'\nimport * as messagePort from './message-port'\nimport * as readableStream from './readable-stream'\nimport * as abortSignal from './abort-signal'\nimport * as response from './response'\nimport * as request from './request'\nimport * as identity from './identity'\nimport * as transfer from './transfer'\nimport * as map from './map'\nimport * as set from './set'\nimport * as bigInt from './bigint'\nimport * as eventTarget from './event-target'\n\nexport { identity } from './identity'\nexport { transfer } from './transfer'\n\nexport * from './utils'\n\n// Module-level signatures intentionally widen to `any` on the box/revive/init\n// parameters: each module's concrete box takes a narrower input than the\n// shared interface can express, and TS treats `readonly`-property function\n// types contravariantly. The `any`s here are the bivariance escape hatch that\n// lets concrete modules be assigned to `RevivableModule[]` at all.\nexport type RevivableModule<\n T extends string = string,\n T2 = any,\n T3 extends BoxBase<T> = any,\n T4 extends MessageFields = MessageFields,\n> = {\n readonly type: T\n readonly isType: (value: unknown) => value is T2\n readonly box: ((value: T2, context: RevivableContext<any>) => T3) | ((...args: any[]) => any)\n readonly revive: (value: T3, context: RevivableContext<any>) => T2\n readonly init?: (context: RevivableContext<any>) => void\n readonly Messages?: T4\n}\n\nexport const defaultRevivableModules = [\n transfer,\n identity,\n arrayBuffer,\n date,\n headers,\n error,\n typedArray,\n promise,\n func,\n messagePort,\n readableStream,\n abortSignal,\n response,\n request,\n map,\n set,\n bigInt,\n // eventTarget MUST be last among instanceof-EventTarget revivables —\n // MessagePort, AbortSignal, EventPort, Window, Worker, etc. all extend\n // EventTarget; the more specific revivables (messagePort/abortSignal) need\n // first dibs via findBoxModule's iteration order.\n eventTarget,\n] as const\n\nexport type DefaultRevivableModules = typeof defaultRevivableModules\nexport type DefaultRevivableModule = DefaultRevivableModules[number]\n\nconst findBoxModule = (\n value: unknown,\n modules: readonly RevivableModule[]\n): RevivableModule | undefined =>\n modules.find(module => module.isType(value))\n\nconst findReviveModule = (\n value: BoxBase,\n modules: readonly RevivableModule[],\n): RevivableModule | undefined =>\n modules.find(module => module.type === value.type)\n\nconst isPlainObject = (value: unknown): value is Record<string, Capable> =>\n !!value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype\n\nconst descend = <TOut>(value: unknown, transform: (v: Capable) => unknown): TOut => {\n if (Array.isArray(value)) {\n return value.map(v => transform(v)) as TOut\n }\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries<Capable>(value).map(([k, v]) => [k, transform(v)]),\n ) as TOut\n }\n return value as TOut\n}\n\nexport const box = <\n T extends Capable,\n TModules extends readonly RevivableModule[]\n>(\n value: T,\n context: RevivableContext<TModules>\n): ReplaceWithBox<T, TModules[number]> => {\n const handledByModule = findBoxModule(value, context.revivableModules)\n if (handledByModule) {\n return handledByModule.box(value, context) as ReplaceWithBox<T, TModules[number]>\n }\n return value as ReplaceWithBox<T, TModules[number]>\n}\n\nexport const recursiveBox = <\n T extends Capable,\n TModules extends readonly RevivableModule[]\n>(\n value: T,\n context: RevivableContext<TModules>\n): DeepReplaceWithBox<T, TModules[number]> => {\n type ReturnCastType = DeepReplaceWithBox<T, TModules[number]>\n // Already-boxed values pass through — revivables (e.g. createRevivableChannel)\n // may embed a pre-built BoxedX in their outgoing payload; descending into it\n // would re-box raw ports nested inside.\n if (isRevivableBox(value)) return value as ReturnCastType\n const handledByModule = findBoxModule(value, context.revivableModules)\n if (handledByModule) {\n return handledByModule.box(value, context) as ReturnCastType\n }\n return descend<ReturnCastType>(value, v => recursiveBox(v, context))\n}\n\nexport const revive = <\n T extends ReturnType<typeof box>,\n TModules extends readonly RevivableModule[]\n>(\n value: T,\n context: RevivableContext<TModules>\n): ReplaceWithRevive<T, TModules[number]> => {\n if (!isRevivableBox(value)) return value as ReplaceWithRevive<T, TModules[number]>\n const handledByModule = findReviveModule(value, context.revivableModules)\n if (handledByModule) {\n return handledByModule.revive(value, context) as ReplaceWithRevive<T, TModules[number]>\n }\n return value as ReplaceWithRevive<T, TModules[number]>\n}\n\nexport const recursiveRevive = <\n T extends Capable,\n TModules extends readonly RevivableModule[]\n>(\n value: T,\n context: RevivableContext<TModules>\n): DeepReplaceWithRevive<T, TModules[number]> => {\n type ReturnCastType = DeepReplaceWithRevive<T, TModules[number]>\n if (isRevivableBox(value)) {\n const handledByModule = findReviveModule(value, context.revivableModules)\n if (handledByModule) {\n return handledByModule.revive(value, context) as ReturnCastType\n }\n }\n return descend<ReturnCastType>(value, v => recursiveRevive(v, context))\n}","import type { Transport } from '../utils/transport'\nimport type { DefaultRevivableModules, RevivableModule } from '../revivables'\nimport type { DeepReplaceWithBox } from '../utils/replace'\nimport type { ProtocolContext } from './utils'\nimport type {\n Capable, MessageEventTarget, MessageFields,\n MessageVariant, Uuid,\n} from '../types'\n\nimport { recursiveBox, recursiveRevive } from '../revivables'\nimport { isEmitTransport, isReceiveTransport } from '../utils/type-guards'\n\nexport const type = 'bidirectional' as const\n\nexport type InitMessage<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules,\n T extends Capable<TModules> = Capable<TModules>\n> = {\n type: 'init'\n remoteUuid: Uuid\n data: DeepReplaceWithBox<T, TModules[number]>\n}\n\nexport declare const Messages: <\n TModules extends readonly RevivableModule[] = DefaultRevivableModules,\n T extends Capable<TModules> = Capable<TModules>\n>(modules: TModules, value: T) =>\n | InitMessage<TModules, T>\n\nexport type Messages<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules,\n T extends Capable<TModules> = Capable<TModules>\n> = ReturnType<typeof Messages<TModules, T>>\n\nexport type ConnectionContext<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n type: 'bidirectional'\n eventTarget: MessageEventTarget<TModules>\n connection: BidirectionalConnection<TModules>\n}\n\nexport type ConnectionRevivableContext<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n transport: Transport\n remoteUuid: Uuid\n sendMessage: (message: MessageFields & Record<string, unknown>) => void\n revivableModules: TModules\n eventTarget: MessageEventTarget<TModules>\n}\n\nexport const startBidirectionalConnection = <\n TModules extends readonly RevivableModule[] = DefaultRevivableModules,\n>(\n { transport, value, remoteUuid, eventTarget, send, revivableModules }:\n {\n transport: Transport\n value: Capable<TModules>\n remoteUuid: Uuid\n eventTarget: MessageEventTarget<TModules>\n send: (message: MessageFields & Record<string, unknown>) => void\n revivableModules: TModules\n },\n) => {\n const revivableContext = {\n transport,\n remoteUuid,\n sendMessage: send,\n eventTarget,\n revivableModules\n } satisfies ConnectionRevivableContext<TModules>\n\n for (const module of revivableModules) {\n module.init?.(revivableContext)\n }\n\n const { promise, resolve } = Promise.withResolvers<InitMessage<TModules>['data']>()\n\n eventTarget.addEventListener('message', function listener ({ detail }) {\n if (detail.type === 'init') {\n resolve(detail.data)\n eventTarget.removeEventListener('message', listener)\n }\n })\n\n send({\n type: 'init',\n remoteUuid,\n data: recursiveBox(value, revivableContext)\n })\n\n return {\n revivableContext,\n remoteValue:\n promise\n .then(initData => recursiveRevive(initData, revivableContext) as Capable),\n }\n}\n\nexport type BidirectionalConnection<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n revivableContext: ConnectionRevivableContext<TModules>\n remoteValue: Promise<Capable>\n}\n\n/**\n * init() — mounts the bidirectional mode on the shared protocol context.\n * Only activates when the transport can both emit and receive. Owns the\n * announce / close handshake and routes per-connection messages (init /\n * message / message-port-close) to the right connection's eventTarget.\n */\nexport const init = <TModules extends readonly RevivableModule[]>(\n ctx: ProtocolContext<TModules>\n): void => {\n if (!(isEmitTransport(ctx.transport) && isReceiveTransport(ctx.transport))) return\n\n ctx.protocolEventTarget.addEventListener('message', ({ detail: message }) => {\n if (message.type === 'announce') {\n if (!message.remoteUuid) {\n ctx.sendMessage({ type: 'announce', remoteUuid: message.uuid })\n return\n }\n if (message.remoteUuid !== ctx.getUuid()) return\n // Already-tracked uuid is the normal handshake-echo case (the peer\n // re-announcing back at us after we replied to its initial announce),\n // not a uuid collision — silently drop it so we don't double-set up\n // the same connection.\n if (ctx.connectionContexts.has(message.uuid)) return\n // Send announce back so the other side can also create a connection\n // (in case they missed our initial announce due to timing)\n ctx.sendMessage({ type: 'announce', remoteUuid: message.uuid })\n const eventTarget = ctx.createConnectionEventTarget()\n const connectionContext = {\n type: 'bidirectional',\n eventTarget,\n connection:\n startBidirectionalConnection<TModules>({\n transport: ctx.transport,\n value: ctx.value,\n remoteUuid: message.uuid,\n eventTarget,\n send: (m) => ctx.sendMessage(m as MessageVariant),\n revivableModules: ctx.revivableModules\n })\n } satisfies ConnectionContext<TModules>\n ctx.connectionContexts.set(message.uuid, connectionContext)\n connectionContext.connection.remoteValue.then((remoteValue) =>\n ctx.resolveRemoteValue(remoteValue)\n )\n return\n }\n if (message.type === 'close') {\n if (message.remoteUuid !== ctx.getUuid()) return\n ctx.connectionContexts.delete(message.uuid)\n return\n }\n // \"init\" | \"message\" | \"message-port-close\"\n if (message.remoteUuid !== ctx.getUuid()) return\n const connection = ctx.connectionContexts.get(message.uuid)\n // drop messages that arrive before the remote has announced itself,\n // or after its connection has been torn down\n if (!connection) return\n connection.eventTarget.dispatchEvent(\n new CustomEvent('message', { detail: message })\n )\n })\n\n if (ctx.presetRemoteUuid !== undefined) {\n const eventTarget = ctx.createConnectionEventTarget()\n const connectionContext = {\n type: 'bidirectional',\n eventTarget,\n connection:\n startBidirectionalConnection<TModules>({\n transport: ctx.transport,\n value: ctx.value,\n remoteUuid: ctx.presetRemoteUuid,\n eventTarget,\n send: (m) => ctx.sendMessage(m as MessageVariant),\n revivableModules: ctx.revivableModules\n })\n } satisfies ConnectionContext<TModules>\n ctx.connectionContexts.set(ctx.presetRemoteUuid, connectionContext)\n connectionContext.connection.remoteValue.then((remoteValue) =>\n ctx.resolveRemoteValue(remoteValue)\n )\n return\n }\n\n ctx.sendMessage({ type: 'announce' })\n}\n","import type { UnderlyingType } from './type'\n\nexport type EventMap = Record<string, Event>\n\nexport interface TypedEventTarget<T extends EventMap> extends EventTarget {\n [UnderlyingType]?: T\n\n addEventListener<K extends keyof T & string>(\n type: K,\n listener: ((event: T[K]) => void) | null,\n options?: boolean | AddEventListenerOptions\n ): void\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | AddEventListenerOptions\n ): void\n\n removeEventListener<K extends keyof T & string>(\n type: K,\n listener: ((event: T[K]) => void) | null,\n options?: boolean | EventListenerOptions\n ): void\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | EventListenerOptions\n ): void\n}\n\n/**\n * Create a new `TypedEventTarget<T>` for a given event map. Centralises the\n * `EventTarget` → `TypedEventTarget<T>` cast so individual call sites don't\n * each need their own (`EventTarget` lacks the generic event map at the type\n * level, but the runtime behaviour is identical).\n */\nexport const createTypedEventTarget = <T extends EventMap>(): TypedEventTarget<T> =>\n new EventTarget() as TypedEventTarget<T>\n","import { transfer } from '../revivables/transfer'\nimport { isRevivableBox } from '../revivables/utils'\nimport { instanceOfAny, isClonable, isTransferable } from './type-guards'\n\nexport { transfer }\n\n// \"Must-transfer\" types: structured clone cannot copy these, so any occurrence\n// in the outgoing message has to go on the transfer list regardless of whether\n// the user opted in with `transfer()`. MessagePort is the canonical case —\n// cloning one would leave the remote side unable to respond.\nconst isMustTransfer = (value: unknown): value is Transferable =>\n instanceOfAny(value, [\n globalThis.MessagePort,\n globalThis.ReadableStream,\n globalThis.WritableStream,\n globalThis.TransformStream,\n globalThis.OffscreenCanvas,\n ])\n\n// Structural check for a transfer revivable box. Uses the 'transfer' string\n// literal rather than importing the module's exported `type` constant, so the\n// walker stays decoupled from the module's full graph.\n// The `degraded` flag is set by transfer.box() when the platform can't\n// actually transfer — a degraded box is a no-op for the walker.\nconst isTransferBox = (value: unknown): value is { inner: unknown, degraded: boolean } =>\n isRevivableBox(value) && value.type === 'transfer'\n\n/**\n * Walk a boxed message and collect the list of Transferable references that\n * should be moved (rather than cloned) when calling postMessage.\n *\n * The rules are:\n * 1. Must-transfer types (MessagePort, streams, OffscreenCanvas) are always\n * included — structured clone cannot represent them.\n * 2. Clonable types (SharedArrayBuffer) are skipped entirely.\n * 3. Other Transferable types (ArrayBuffer, ImageBitmap) are included only\n * when the walker is inside a non-degraded transfer box — i.e. when the\n * user explicitly opted into move semantics at the send site via\n * transfer() AND the platform supports transferring.\n *\n * The transfer intent is carried on the wire by the transfer revivable box;\n * recognising it structurally here (without importing the module) is all the\n * coupling this file needs.\n */\nexport const getTransferableObjects = (value: unknown): Transferable[] => {\n const transferables: Transferable[] = []\n const seen = new WeakSet<object>()\n\n const recurse = (value: unknown, inTransferBox: boolean): void => {\n if (!value || typeof value !== 'object') return\n if (seen.has(value)) return\n seen.add(value)\n\n if (isClonable(value)) return\n\n if (isTransferBox(value)) {\n // Non-degraded box: flip into transfer mode — every Transferable found\n // below this point on this branch of the walk gets added to the\n // transfer list. Degraded box (platform can't transfer): keep whatever\n // mode we were in, so the wrapper becomes a no-op and the inner gets\n // walked as a normal copy payload.\n recurse(value.inner, inTransferBox || !value.degraded)\n return\n }\n\n if (isMustTransfer(value)) {\n transferables.push(value)\n return\n }\n\n if (isTransferable(value)) {\n if (inTransferBox) {\n transferables.push(value)\n }\n return\n }\n\n // TypedArray / DataView expose every numeric index as an own key — iterating\n // `Object.keys` of a 100 KB buffer touches 100 K entries for no useful\n // result. The underlying buffer is the only thing we could transfer, and\n // that happens via the transfer box / typed-array revivable path anyway.\n if (ArrayBuffer.isView(value)) return\n\n if (Array.isArray(value)) {\n for (const item of value) recurse(item, inTransferBox)\n return\n }\n\n for (const item of Object.values(value)) recurse(item, inTransferBox)\n }\n\n recurse(value, false)\n return transferables\n}\n","import type {\n Message, MessageVariant, Uuid,\n Capable, MessageEventMap\n} from '../types'\nimport type { DefaultRevivableModules, RevivableModule } from '../revivables'\nimport type { Transport } from '../utils/transport'\nimport type { ConnectionContext } from '.'\nimport type { TypedEventTarget } from '../utils/typed-event-target'\n\nimport { defaultRevivableModules } from '../revivables'\nimport { isJsonOnlyTransport, isCustomTransport } from '../utils/type-guards'\n\nexport const normalizeTransport = (transport: Transport): Transport => {\n const isJson =\n 'isJson' in transport && transport.isJson !== undefined\n ? transport.isJson\n : isJsonOnlyTransport(transport)\n const ports =\n isCustomTransport(transport)\n ? transport\n : { emit: transport, receive: transport }\n return { isJson, ...ports } satisfies Transport\n}\n\nexport const mergeRevivableModules = <\n TUserModules extends readonly RevivableModule[]\n>(userModules: TUserModules | undefined) => [\n ...defaultRevivableModules.filter(\n d => !(userModules ?? []).some(u => u.type === d.type),\n ),\n ...(userModules ?? []),\n] as const\n\nexport type ProtocolEventMap<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n message: CustomEvent<Message<TModules>>\n}\n\nexport type ProtocolEventTarget<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = TypedEventTarget<ProtocolEventMap<TModules>>\n\nexport type ProtocolContext<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n transport: Transport\n value: Capable<TModules>\n revivableModules: TModules\n connectionContexts: Map<string, ConnectionContext<TModules>>\n getUuid: () => Uuid\n presetRemoteUuid?: Uuid\n sendMessage: (message: MessageVariant) => void\n protocolEventTarget: ProtocolEventTarget<TModules>\n resolveRemoteValue: (value: Capable<TModules>) => void\n createConnectionEventTarget: () => TypedEventTarget<MessageEventMap<TModules>>\n}\n\nexport type StartConnectionsOptions<\n TUserModules extends readonly RevivableModule[] = readonly []\n> = {\n transport: Transport\n name?: string\n remoteName?: string\n key?: string\n origin?: string\n unregisterSignal?: AbortSignal\n revivableModules?: TUserModules\n uuid?: Uuid\n remoteUuid?: Uuid\n}\n","import type { DefaultRevivableModules, RevivableModule } from '../revivables'\nimport type { ConnectionContext as BidirectionalConnectionContext } from './bidirectional'\nimport type {\n ProtocolContext,\n StartConnectionsOptions,\n} from '../utils'\nimport type {\n Message, MessageVariant, Uuid,\n Capable,\n} from '../types'\nimport type { MessageContext } from '../utils/transport'\n\nimport { OSRA_DEFAULT_KEY, OSRA_KEY } from '../types'\nimport * as bidirectional from './bidirectional'\nimport {\n isEmitTransport,\n isReceiveTransport,\n} from '../utils/type-guards'\nimport { createTypedEventTarget } from '../utils/typed-event-target'\nimport { getTransferableObjects } from '../utils/transferable'\nimport { registerOsraMessageListener, sendOsraMessage } from '../utils/transport'\nimport { mergeRevivableModules, normalizeTransport } from './utils'\n\nexport * from './bidirectional'\nexport * from './utils'\n\nexport type ConnectionModule<T> = {\n readonly type: string\n // ProtocolContext<any> rather than ProtocolContext<readonly RevivableModule[]>\n // for the same bivariance reason as RevivableModule.box — concrete modules\n // declare narrower context generics than the shared interface can express.\n readonly init: (ctx: ProtocolContext<any>) => void\n readonly Messages?: T\n}\n\nexport const connections = [\n bidirectional\n] as const\n\nexport type DefaultConnectionModules = typeof connections\nexport type DefaultConnectionModule = DefaultConnectionModules[number]\n\nexport type ConnectionMessage<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules,\n T extends Capable<TModules> = Capable<TModules>\n> =\n DefaultConnectionModule extends {\n Messages: (modules: TModules, value: T) => infer R\n }\n ? R\n : never\n\nexport type ConnectionContext<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> =\n | BidirectionalConnectionContext<TModules>\n\nexport const startConnections = <\n T = unknown,\n const TUserModules extends readonly RevivableModule[] = readonly []\n>(\n value: Capable<[...DefaultRevivableModules, ...TUserModules]>,\n {\n transport: _transport,\n name,\n remoteName,\n key = OSRA_DEFAULT_KEY,\n origin = '*',\n unregisterSignal,\n revivableModules: _userRevivableModules,\n uuid: _uuid,\n remoteUuid: presetRemoteUuid,\n }: StartConnectionsOptions<TUserModules>\n): Promise<T> => {\n const transport = normalizeTransport(_transport)\n const mergedRevivableModules = mergeRevivableModules(_userRevivableModules)\n type MergedModules = typeof mergedRevivableModules\n const connectionContexts = new Map<string, ConnectionContext<MergedModules>>()\n\n const { promise: remoteValuePromise, resolve: resolveRemoteValue } =\n Promise.withResolvers<Capable<MergedModules>>()\n\n const uuid: Uuid = _uuid ?? globalThis.crypto.randomUUID()\n\n const sendMessage = (message: MessageVariant) => {\n if (unregisterSignal?.aborted) return\n if (!isEmitTransport(transport)) return\n const envelope = { [OSRA_KEY]: key, name, uuid, ...message }\n sendOsraMessage(transport, envelope, origin, getTransferableObjects(envelope))\n }\n\n const protocolEventTarget = createTypedEventTarget<{ message: CustomEvent<Message<MergedModules>> }>()\n\n const ctx: ProtocolContext<MergedModules> = {\n transport,\n value: value as Capable<MergedModules>,\n revivableModules: mergedRevivableModules,\n connectionContexts,\n getUuid: () => uuid,\n presetRemoteUuid,\n sendMessage,\n protocolEventTarget,\n resolveRemoteValue,\n createConnectionEventTarget: createTypedEventTarget,\n }\n\n const listener = (message: Message<MergedModules>, _: MessageContext) => {\n // own message looped back on the channel\n if (message.uuid === uuid) return\n protocolEventTarget.dispatchEvent(\n new CustomEvent('message', { detail: message }),\n )\n }\n\n if (isReceiveTransport(transport)) {\n registerOsraMessageListener({\n listener,\n transport,\n remoteName,\n key,\n unregisterSignal\n })\n }\n\n for (const connectionModule of connections) {\n connectionModule.init(ctx)\n }\n\n return remoteValuePromise as Promise<T>\n}\n","import type { Capable } from './types'\nimport type { DefaultRevivableModules } from './revivables'\nimport type { RevivableModule } from './revivables'\nimport type { StartConnectionsOptions } from './connections/utils'\nimport type {\n BadFieldValue, BadFieldPath, BadFieldParent,\n ErrorMessage, BadValue, Path, ParentObject\n} from './utils/capable-check'\n\nimport { startConnections } from './utils'\n\nexport * from './types'\nexport * from './revivables'\nexport * from './connections'\nexport * from './utils'\n\ntype CapableCheck<\n T,\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> =\n T extends Capable<TModules>\n ? T\n : T & {\n [ErrorMessage]: 'Value type must resolve to a Capable'\n [BadValue]: BadFieldValue<T, Capable<TModules>>\n [Path]: BadFieldPath<T, Capable<TModules>>\n [ParentObject]: BadFieldParent<T, Capable<TModules>>\n }\n\nexport const expose = async <\n T = unknown,\n const TUserModules extends readonly RevivableModule[] = readonly [],\n const TValue = Capable<[...DefaultRevivableModules, ...TUserModules]>\n>(\n value: CapableCheck<TValue, [...DefaultRevivableModules, ...TUserModules]>,\n options: StartConnectionsOptions<TUserModules>\n): Promise<T> =>\n startConnections<T, TUserModules>(\n value as Capable<[...DefaultRevivableModules, ...TUserModules]>,\n options\n )\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/types.ts","../src/utils/type-guards.ts","../src/utils/transport.ts","../src/revivables/utils.ts","../src/revivables/array-buffer.ts","../src/revivables/date.ts","../src/revivables/headers.ts","../src/revivables/error.ts","../src/revivables/typed-array.ts","../src/utils/event-channel.ts","../src/revivables/message-port.ts","../src/revivables/promise.ts","../src/revivables/function.ts","../src/revivables/readable-stream.ts","../src/revivables/abort-signal.ts","../src/revivables/response.ts","../src/revivables/request.ts","../src/revivables/identity.ts","../src/revivables/transfer.ts","../src/revivables/map.ts","../src/revivables/set.ts","../src/revivables/bigint.ts","../src/revivables/event-target.ts","../src/revivables/index.ts","../src/connections/bidirectional.ts","../src/utils/typed-event-target.ts","../src/utils/transferable.ts","../src/connections/utils.ts","../src/connections/index.ts","../src/index.ts"],"sourcesContent":["import type { ConnectionMessage } from './connections'\nimport type { TypedEventTarget } from './utils'\nimport type {\n DefaultRevivableModules, RevivableModule,\n InferMessages, InferRevivables\n} from './revivables'\n\nexport const OSRA_KEY = '__OSRA_KEY__' as const\nexport const OSRA_DEFAULT_KEY = '__OSRA_DEFAULT_KEY__' as const\nexport const OSRA_BOX = '__OSRA_BOX__' as const\n\nexport type Uuid = `${string}-${string}-${string}-${string}-${string}`\n\nexport type Jsonable =\n | boolean\n | null\n | number\n | string\n | { [key: string]: Jsonable }\n | Array<Jsonable>\n\nexport type Structurable =\n | Jsonable\n /** not really structureable but here for convenience */\n | void\n | undefined\n | bigint\n | Date\n | RegExp\n | Blob\n | File\n | FileList\n | ArrayBuffer\n | ArrayBufferView\n | ImageBitmap\n | ImageData\n | { [key: string]: Structurable }\n | Array<Structurable>\n | Map<Structurable, Structurable>\n | Set<Structurable>\n\nexport type StructurableTransferable =\n | Structurable\n | Transferable\n | { [key: string]: StructurableTransferable }\n | Array<StructurableTransferable>\n | Map<StructurableTransferable, StructurableTransferable>\n | Set<StructurableTransferable>\n\nexport type Capable<TModules extends readonly RevivableModule[] = DefaultRevivableModules> =\n | StructurableTransferable\n | InferRevivables<TModules>\n | { [key: string]: Capable<TModules> }\n | Array<Capable<TModules>>\n | Map<Capable<TModules>, Capable<TModules>>\n | Set<Capable<TModules>>\n\nexport type MessageFields = {\n type: string\n remoteUuid: Uuid\n}\n\nexport type MessageBase = {\n [OSRA_KEY]: string\n /** UUID of the client that sent the message */\n uuid: Uuid\n name?: string\n}\n\nexport type ProtocolMessage =\n | {\n type: 'announce'\n /** Only set when acknowledging a remote announcement */\n remoteUuid?: Uuid\n }\n | {\n type: 'close'\n remoteUuid: Uuid\n }\n\nexport type MessageVariant<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> =\n | ProtocolMessage\n | ConnectionMessage<TModules>\n | InferMessages<TModules>\n\nexport type Message<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> =\n & MessageBase\n & MessageVariant<TModules>\n\nexport type MessageEventMap<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n message: CustomEvent<Message<TModules>>\n}\n\nexport type MessageEventTarget<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n > = TypedEventTarget<MessageEventMap<TModules>>\n","import type { Runtime } from 'webextension-polyfill'\nimport type { Message } from '../types'\nimport type {\n CustomEmitTransport, CustomReceiveTransport,\n CustomTransport, EmitJsonPlatformTransport,\n EmitTransport, JsonPlatformTransport,\n ReceiveJsonPlatformTransport,\n ReceiveTransport, Transport\n} from './transport'\n\nimport { OSRA_KEY } from '../types'\nimport { getWebExtensionRuntime } from './transport'\n\nconst typedArrayConstructorsByName = {\n Int8Array,\n Uint8Array,\n Uint8ClampedArray,\n Int16Array,\n Uint16Array,\n Int32Array,\n Uint32Array,\n Float16Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n BigUint64Array,\n} as const\n\nexport type TypedArrayType = keyof typeof typedArrayConstructorsByName\nexport type TypedArrayConstructor = (typeof typedArrayConstructorsByName)[TypedArrayType]\nexport type TypedArray = InstanceType<TypedArrayConstructor>\n\nconst typedArrayConstructors = Object.values(typedArrayConstructorsByName)\n\nexport const typedArrayToType = (value: TypedArray): TypedArrayType => {\n const name = value.constructor.name as TypedArrayType\n if (!(name in typedArrayConstructorsByName)) throw new Error('Unknown typed array type')\n return name\n}\n\nexport const typedArrayTypeToTypedArrayConstructor = (value: TypedArrayType): TypedArrayConstructor => {\n const ctor = typedArrayConstructorsByName[value]\n if (!ctor) throw new Error('Unknown typed array type')\n return ctor\n}\n\nexport const isTypedArray = (value: unknown): value is TypedArray =>\n typedArrayConstructors.some(ctor => value instanceof ctor)\nexport const isWebSocket = (value: unknown): value is WebSocket => value instanceof WebSocket\nexport const isServiceWorkerContainer = (value: unknown): value is ServiceWorkerContainer => !!globalThis.ServiceWorkerContainer && value instanceof ServiceWorkerContainer\nexport const isWorker = (value: unknown): value is Worker => !!globalThis.Worker && value instanceof Worker\n// @ts-expect-error DedicatedWorkerGlobalScope is only present in worker scopes\nexport const isDedicatedWorker = (value: unknown): value is DedicatedWorkerGlobalScope => !!globalThis.DedicatedWorkerGlobalScope && value instanceof DedicatedWorkerGlobalScope\nexport const isSharedWorker = (value: unknown): value is SharedWorker => !!globalThis.SharedWorker && value instanceof SharedWorker\nconst isMessagePort = (value: unknown): value is MessagePort => value instanceof MessagePort\n\nexport const isOsraMessage = (value: unknown): value is Message =>\n !!value\n && typeof value === 'object'\n && OSRA_KEY in value\n && !!value[OSRA_KEY]\n\ntype AnyConstructor = abstract new (...args: any[]) => unknown\n\n/** True if `value` is an instance of any of the given (possibly undefined-on-this-platform)\n * constructors. Tolerates missing globals so callers don't have to guard each one. */\nexport const instanceOfAny = (value: unknown, ctors: readonly (AnyConstructor | undefined)[]): boolean => {\n for (const ctor of ctors) if (ctor && value instanceof ctor) return true\n return false\n}\n\nexport const isClonable = (value: unknown): boolean =>\n instanceOfAny(value, [globalThis.SharedArrayBuffer])\n\nexport const isTransferable = (value: unknown): value is Transferable =>\n instanceOfAny(value, [\n globalThis.ArrayBuffer,\n globalThis.MessagePort,\n globalThis.ReadableStream,\n globalThis.WritableStream,\n globalThis.TransformStream,\n globalThis.ImageBitmap,\n ])\n\nexport type WebExtRuntime = typeof browser.runtime\nexport const isWebExtensionRuntime = (value: unknown): value is WebExtRuntime => {\n const runtime = getWebExtensionRuntime()\n if (!runtime) return false\n return value === runtime\n}\n\nexport type WebExtPort = ReturnType<WebExtRuntime['connect']> | Runtime.Port\nexport const isWebExtensionPort = (value: unknown, connectPort: boolean = false): value is WebExtPort => {\n if (!value || typeof value !== 'object') return false\n // Prevent SecurityError when `value` is a cross-origin window.\n if (isWindow(value)) return false\n if (!('name' in value) || !('disconnect' in value) || !('postMessage' in value)) return false\n // these properties are only present on WebExtPorts created through runtime.connect()\n if (!connectPort) return true\n return 'sender' in value && 'onMessage' in value && 'onDisconnect' in value\n}\n\nexport type WebExtSender = NonNullable<WebExtPort['sender']>\n\n// Structural guard for any `addListener` / `hasListener` / `removeListener` event.\n// Not enough on its own to tell onConnect from onMessage — they have identical shapes.\nconst hasListenerApi = (value: unknown): boolean =>\n !!value\n && typeof value === 'object'\n // Prevent SecurityError when `value` is a cross-origin window.\n && !isWindow(value)\n && 'addListener' in value\n && 'hasListener' in value\n && 'removeListener' in value\n\n// Identity-compare against the runtime's onConnect events: structural checks\n// can't distinguish onConnect from onMessage, and misclassifying onMessage as\n// onConnect makes us treat each incoming message as a port and crash on\n// `message.onMessage.addListener`.\nexport type WebExtOnConnect = WebExtRuntime['onConnect']\nexport const isWebExtensionOnConnect = (value: unknown): value is WebExtOnConnect => {\n const runtime = getWebExtensionRuntime()\n if (!runtime) return false\n return value === runtime.onConnect || value === runtime.onConnectExternal\n}\n\nexport type WebExtOnMessage = WebExtRuntime['onMessage']\nexport const isWebExtensionOnMessage = (value: unknown): value is WebExtOnMessage =>\n hasListenerApi(value)\n\nexport const isWindow = (value: unknown): value is Window => {\n if (!value || typeof value !== 'object') return false\n try {\n return 'window' in value && value.window === value\n } catch {\n // Cross-origin Window access can throw SecurityError; fall back to a\n // no-read shape probe that tolerates protected properties.\n try {\n return 'closed' in value\n && typeof value.closed === 'boolean'\n && 'close' in value\n && typeof value.close === 'function'\n } catch {\n return false\n }\n }\n}\n\nexport const isEmitJsonOnlyTransport = (value: unknown): value is EmitJsonPlatformTransport =>\n isWebSocket(value)\n || isWebExtensionPort(value)\n || isWebExtensionRuntime(value)\n\nexport const isReceiveJsonOnlyTransport = (value: unknown): value is ReceiveJsonPlatformTransport =>\n isWebSocket(value)\n || isWebExtensionPort(value)\n || isWebExtensionOnConnect(value)\n || isWebExtensionOnMessage(value)\n || isWebExtensionRuntime(value)\n\nexport type IsJsonOnlyTransport<T extends Transport> = T extends JsonPlatformTransport ? true : false\nexport const isJsonOnlyTransport = (value: unknown): value is Extract<Transport, JsonPlatformTransport> =>\n (!!value && typeof value === 'object' && 'isJson' in value && value.isJson === true)\n || isEmitJsonOnlyTransport(value)\n || isReceiveJsonOnlyTransport(value)\n\nexport const isEmitTransport = (value: unknown): value is EmitTransport =>\n isWindow(value)\n || isEmitJsonOnlyTransport(value)\n || isServiceWorkerContainer(value)\n || isWorker(value)\n || isDedicatedWorker(value)\n || isSharedWorker(value)\n || isMessagePort(value)\n || isCustomEmitTransport(value)\n\nexport function assertEmitTransport(transport: Transport): asserts transport is EmitTransport {\n if (!isEmitTransport(transport)) throw new Error('Transport is not emitable')\n}\n\nexport const isReceiveTransport = (value: unknown): value is ReceiveTransport =>\n isWindow(value)\n || isReceiveJsonOnlyTransport(value)\n || isServiceWorkerContainer(value)\n || isWorker(value)\n || isDedicatedWorker(value)\n || isSharedWorker(value)\n || isMessagePort(value)\n || isCustomReceiveTransport(value)\n\nexport function assertReceiveTransport(transport: Transport): asserts transport is ReceiveTransport {\n if (!isReceiveTransport(transport)) throw new Error('Transport is not receiveable')\n}\n\nexport const isCustomEmitTransport = (value: unknown): value is CustomEmitTransport => {\n if (!value || typeof value !== 'object') return false\n // Prevent SecurityError when `value` is a cross-origin window.\n if (isWindow(value)) return false\n if (!('emit' in value)) return false\n return isEmitTransport(value.emit) || typeof value.emit === 'function'\n}\n\nexport const isCustomReceiveTransport = (value: unknown): value is CustomReceiveTransport => {\n if (!value || typeof value !== 'object') return false\n // Prevent SecurityError when `value` is a cross-origin window.\n if (isWindow(value)) return false\n if (!('receive' in value)) return false\n return isReceiveTransport(value.receive) || typeof value.receive === 'function'\n}\n\nexport const isCustomTransport = (value: unknown): value is CustomTransport =>\n isCustomEmitTransport(value)\n || isCustomReceiveTransport(value)\n\nexport const isTransport = (value: unknown): value is Transport =>\n isEmitTransport(value)\n || isReceiveTransport(value)\n || isCustomTransport(value)\n || isJsonOnlyTransport(value)\n","import type { Message} from '../types'\nimport type {\n WebExtOnConnect, WebExtOnMessage,\n WebExtPort, WebExtRuntime, WebExtSender\n} from './type-guards'\n\nimport { OSRA_KEY } from '../types'\nimport {\n isOsraMessage, isCustomTransport,\n isWebExtensionOnConnect, isWebExtensionOnMessage,\n isWebExtensionPort, isWebExtensionRuntime, isWebSocket, isWindow, isSharedWorker\n} from './type-guards'\n\nexport type MessageContext = {\n port?: MessagePort | WebExtPort // WebExtension\n sender?: WebExtSender // WebExtension\n receiveTransport?: ReceivePlatformTransport\n source?: MessageEventSource | null // Window, Worker, WebSocket, ect...\n}\n\nexport type ReceiveHandler = (listener: (event: Message, messageContext: MessageContext) => void) => void\nexport type EmitHandler = (message: Message, transferables?: Transferable[]) => void\n\ntype CustomReceive = ReceivePlatformTransport | ReceiveHandler\ntype CustomEmit = EmitPlatformTransport | EmitHandler\n\nexport type CustomTransport =\n { isJson?: boolean }\n & (\n | { receive: CustomReceive, emit: CustomEmit }\n | { receive: CustomReceive }\n | { emit: CustomEmit }\n )\n\nexport type CustomEmitTransport = Extract<CustomTransport, { emit: any }>\nexport type CustomReceiveTransport = Extract<CustomTransport, { receive: any }>\n\nexport type EmitJsonPlatformTransport =\n | WebSocket\n | WebExtPort\n | WebExtRuntime\n\nexport type ReceiveJsonPlatformTransport =\n | WebSocket\n | WebExtPort\n | WebExtOnConnect\n | WebExtOnMessage\n | WebExtRuntime\n\nexport type JsonPlatformTransport =\n | { isJson: true }\n | EmitJsonPlatformTransport\n | ReceiveJsonPlatformTransport\n\ntype StructuredClonePlatformTransport =\n | Window\n | ServiceWorker\n | Worker\n | SharedWorker\n | MessagePort\n\nexport type EmitPlatformTransport =\n | EmitJsonPlatformTransport\n | StructuredClonePlatformTransport\n\nexport type ReceivePlatformTransport =\n | ReceiveJsonPlatformTransport\n | StructuredClonePlatformTransport\n\nexport type PlatformTransport =\n | EmitPlatformTransport\n | ReceivePlatformTransport\n\nexport type EmitTransport = EmitPlatformTransport & Extract<CustomTransport, { emit: any }>\nexport type ReceiveTransport = ReceivePlatformTransport & Extract<CustomTransport, { receive: any }>\n\nexport type Transport =\n | PlatformTransport\n | CustomTransport\n\nexport const getWebExtensionGlobal = () => globalThis.browser ?? globalThis.chrome\nexport const getWebExtensionRuntime = () => getWebExtensionGlobal()?.runtime\n\nexport const checkOsraMessageKey = (message: any, key: string): message is Message =>\n isOsraMessage(message)\n && message[OSRA_KEY] === key\n\nconst onAbort = (signal: AbortSignal | undefined, fn: () => void) =>\n signal?.addEventListener('abort', fn, { once: true })\n\nexport const registerOsraMessageListener = (\n { listener, transport, remoteName, key = OSRA_KEY, unregisterSignal }:\n {\n listener: (message: Message, messageContext: MessageContext) => void\n transport: ReceiveTransport\n remoteName?: string\n key?: string\n unregisterSignal?: AbortSignal\n }\n) => {\n const receiveTransport: Extract<CustomTransport, { receive: any }>['receive'] =\n isCustomTransport(transport) ? transport.receive : transport\n\n // Custom function handler\n if (typeof receiveTransport === 'function') {\n receiveTransport((message, ctx) => {\n if (!checkOsraMessageKey(message, key)) return\n if (remoteName && message.name !== remoteName) return\n listener(message, ctx)\n })\n return\n }\n\n // WebExtension family — subscribe to an `onMessage`-style listener API.\n if (\n isWebExtensionRuntime(receiveTransport)\n || isWebExtensionPort(receiveTransport)\n || isWebExtensionOnConnect(receiveTransport)\n || isWebExtensionOnMessage(receiveTransport)\n ) {\n const listenOnWebExtOnMessage = (onMessage: WebExtOnMessage, port?: WebExtPort) => {\n const _listener = (message: object, sender?: WebExtSender) => {\n if (!checkOsraMessageKey(message, key)) return\n if (remoteName && message.name !== remoteName) return\n listener(message, { port, sender })\n }\n onMessage.addListener(_listener)\n onAbort(unregisterSignal, () => onMessage.removeListener(_listener))\n }\n\n if (isWebExtensionRuntime(receiveTransport)) {\n listenOnWebExtOnMessage(receiveTransport.onMessage)\n } else if (isWebExtensionOnConnect(receiveTransport)) {\n // Port.onMessage has a narrower (message, port) shape than the shared\n // (message, sender) Runtime.onMessage — but our listener only reads\n // `message` so the runtime shape covers both.\n const _listener = (port: WebExtPort) =>\n listenOnWebExtOnMessage(port.onMessage as WebExtOnMessage, port)\n receiveTransport.addListener(_listener)\n onAbort(unregisterSignal, () => receiveTransport.removeListener(_listener))\n } else if (isWebExtensionOnMessage(receiveTransport)) {\n listenOnWebExtOnMessage(receiveTransport)\n } else { // WebExtPort\n listenOnWebExtOnMessage(receiveTransport.onMessage as WebExtOnMessage)\n }\n return\n }\n\n // Window, Worker, WebSocket, ServiceWorker, MessagePort, …\n const messageListener = (event: MessageEvent<Message>) => {\n if (!checkOsraMessageKey(event.data, key)) return\n if (remoteName && event.data.name !== remoteName) return\n listener(event.data, { receiveTransport, source: event.source })\n }\n receiveTransport.addEventListener('message', messageListener as EventListener)\n onAbort(unregisterSignal, () =>\n receiveTransport.removeEventListener('message', messageListener as EventListener),\n )\n}\n\nexport const sendOsraMessage = (\n transport: EmitTransport,\n message: Message,\n origin = '*',\n transferables: Transferable[] = []\n) => {\n const emitTransport: Extract<EmitTransport, { emit: any }>['emit'] =\n isCustomTransport(transport) ? transport.emit : transport\n\n if (typeof emitTransport === 'function') {\n emitTransport(message, transferables)\n } else if (isWindow(emitTransport)) {\n // Must be checked first: cross-origin windows throw on other property access.\n emitTransport.postMessage(message, origin, transferables)\n } else if (isWebExtensionPort(emitTransport)) {\n emitTransport.postMessage(message)\n } else if (isWebExtensionRuntime(emitTransport)) {\n emitTransport.sendMessage(message)\n } else if (isWebSocket(emitTransport)) {\n emitTransport.send(JSON.stringify(message))\n } else if (isSharedWorker(emitTransport)) {\n emitTransport.port.postMessage(message, transferables)\n } else { // MessagePort | ServiceWorker | Worker\n emitTransport.postMessage(message, transferables)\n }\n}\n","import type { DefaultRevivableModules, RevivableModule } from '.'\nimport type {\n MessageEventTarget,\n MessageFields,\n Uuid,\n} from '../types'\nimport type { Transport } from '../utils/transport'\nimport type { IsJsonOnlyTransport } from '../utils/type-guards'\n\nimport { OSRA_BOX } from '../types'\nimport { isJsonOnlyTransport } from '../utils/type-guards'\n\nexport type { UnderlyingType } from '../utils/type'\n\nexport const BoxBase = {\n [OSRA_BOX]: 'revivable',\n} as const\n\nexport type BoxBase<T extends string = string> =\n & typeof BoxBase\n & { type: T }\n\nexport type RevivableContext<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n transport: Transport\n remoteUuid: Uuid\n unregisterSignal?: AbortSignal\n /** Typed as a broad dispatcher so revivables can post their own message\n * variants without triggering contravariant function-parameter mismatches\n * across modules. The shape is enforced structurally via `MessageFields`. */\n sendMessage: (message: MessageFields & Record<string, unknown>) => void\n revivableModules: TModules\n eventTarget: MessageEventTarget<TModules>\n}\n\nexport type ExtractType<T> =\n T extends { isType: (value: unknown) => value is infer S }\n ? S\n : never\n\nexport type ExtractBox<T> =\n T extends { box: (...args: any[]) => infer B }\n ? B\n : never\n\nexport type ExtractMessages<T> =\n T extends { Messages?: infer B }\n ? B extends { type: string }\n ? string extends B['type'] ? never : B\n : never\n : never\n\nexport type InferMessages<TModules extends readonly unknown[]> =\n ExtractMessages<TModules[number]>\n\nexport type InferRevivables<TModules extends readonly unknown[]> =\n ExtractType<TModules[number]>\n\nexport type InferRevivableBox<TModules extends readonly unknown[]> =\n ExtractBox<TModules[number]>\n\nexport const isRevivableBox = (value: unknown): value is BoxBase =>\n !!value\n && typeof value === 'object'\n && OSRA_BOX in value\n && value[OSRA_BOX] === 'revivable'\n\n/** Stable string form for an unknown rejection value. Errors keep their stack;\n * everything else gets coerced via `String()`. Used wherever a Promise/Function\n * rejection has to cross the wire as a serialisable string. */\nexport const serializeError = (error: unknown): string =>\n error instanceof Error ? (error.stack ?? String(error)) : String(error)\n\n/** Wire shape for an ArrayBuffer carried by a JSON or clone transport. JSON\n * paths emit a base64 string (so the buffer survives JSON.stringify); clone\n * paths pass the buffer through structured-clone unchanged. */\nexport type BoxedBuffer<TCtx extends RevivableContext = RevivableContext> =\n IsJsonOnlyTransport<TCtx['transport']> extends true ? { base64Buffer: string }\n : IsJsonOnlyTransport<TCtx['transport']> extends false ? { arrayBuffer: ArrayBuffer }\n : { base64Buffer: string } | { arrayBuffer: ArrayBuffer }\n\nexport const boxBuffer = <TCtx extends RevivableContext>(\n buffer: ArrayBuffer,\n context: TCtx,\n): BoxedBuffer<TCtx> =>\n (isJsonOnlyTransport(context.transport)\n ? { base64Buffer: new Uint8Array(buffer).toBase64() }\n : { arrayBuffer: buffer }\n ) as BoxedBuffer<TCtx>\n\nexport const reviveBuffer = (boxed: { arrayBuffer: ArrayBuffer } | { base64Buffer: string }): ArrayBuffer =>\n 'arrayBuffer' in boxed\n ? boxed.arrayBuffer\n : Uint8Array.fromBase64(boxed.base64Buffer).buffer\n","import type { RevivableContext, UnderlyingType, BoxedBuffer } from './utils'\n\nimport { BoxBase, boxBuffer, reviveBuffer } from './utils'\n\nexport const type = 'arrayBuffer' as const\n\ntype BoxedArrayBuffer<T extends ArrayBuffer, T2 extends RevivableContext> =\n & typeof BoxBase\n & { type: typeof type }\n & BoxedBuffer<T2>\n & { [UnderlyingType]: T }\n\nexport const isType = (value: unknown): value is ArrayBuffer =>\n value instanceof ArrayBuffer\n\nexport const box = <T extends ArrayBuffer, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): BoxedArrayBuffer<T, T2> =>\n ({ ...BoxBase, type, ...boxBuffer(value, context) }) as unknown as BoxedArrayBuffer<T, T2>\n\nexport const revive = <T extends BoxedArrayBuffer<ArrayBuffer, RevivableContext>>(\n value: T,\n _context: RevivableContext,\n): T[UnderlyingType] =>\n reviveBuffer(value) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const boxed = box(new ArrayBuffer(10), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: ArrayBuffer = revived\n // @ts-expect-error - not an ArrayBuffer\n const notArrayBuffer: string = revived\n // @ts-expect-error - cannot box non-ArrayBuffer\n box('not an array buffer', {} as RevivableContext)\n}\n","import type { RevivableContext } from './utils'\n\nimport { BoxBase } from './utils'\n\nexport const type = 'date' as const\n\nexport const isType = (value: unknown): value is Date =>\n value instanceof Date\n\nexport const box = <T extends Date, T2 extends RevivableContext>(\n value: T,\n _context: T2\n) => ({\n ...BoxBase,\n type,\n ISOString: value.toISOString()\n})\n\nexport const revive = <T extends ReturnType<typeof box>, T2 extends RevivableContext>(\n value: T,\n _context: T2\n): Date => {\n return new Date(value.ISOString)\n}\n\nconst typeCheck = () => {\n const boxed = box(new Date(), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Date = revived\n // @ts-expect-error - not a Date\n const notDate: string = revived\n // @ts-expect-error - cannot box non-Date\n box('not a date', {} as RevivableContext)\n}\n","import type { RevivableContext } from './utils'\n\nimport { BoxBase } from './utils'\n\nexport const type = 'headers' as const\n\nexport const isType = (value: unknown): value is Headers =>\n value instanceof Headers\n\nexport const box = <T extends Headers, T2 extends RevivableContext>(\n value: T,\n _context: T2\n) => ({\n ...BoxBase,\n type,\n entries: [...value.entries()]\n})\n\nexport const revive = <T extends ReturnType<typeof box>, T2 extends RevivableContext>(\n value: T,\n _context: T2\n): Headers => {\n return new Headers(value.entries)\n}\n\nconst typeCheck = () => {\n const boxed = box(new Headers(), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Headers = revived\n // @ts-expect-error - not a Headers\n const notHeaders: string = revived\n // @ts-expect-error - cannot box non-Headers\n box('not a header', {} as RevivableContext)\n}\n","import type { RevivableContext } from './utils'\n\nimport { BoxBase } from './utils'\n\nexport const type = 'error' as const\n\nexport const isType = (value: unknown): value is Error =>\n value instanceof Error\n\nexport const box = <T extends Error, T2 extends RevivableContext>(\n value: T,\n _context: T2\n) => ({\n ...BoxBase,\n type,\n message: value.message,\n stack: value.stack || value.toString()\n})\n\nexport const revive = <T extends ReturnType<typeof box>, T2 extends RevivableContext>(\n value: T,\n _context: T2\n) => new Error(value.message, { cause: value.stack })\n\nconst typeCheck = () => {\n const boxed = box(new Error('test'), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Error = revived\n // @ts-expect-error - not an Error\n const notError: string = revived\n // @ts-expect-error - cannot box non-Error\n box('not an error', {} as RevivableContext)\n}\n","import type { RevivableContext, UnderlyingType, BoxedBuffer } from './utils'\nimport type { TypedArray, TypedArrayType } from '../utils/type-guards'\n\nimport { BoxBase, boxBuffer, reviveBuffer } from './utils'\nimport {\n isTypedArray,\n typedArrayToType,\n typedArrayTypeToTypedArrayConstructor,\n} from '../utils/type-guards'\n\nexport const type = 'typedArray' as const\n\ntype BoxedTypedArray<T extends TypedArray, T2 extends RevivableContext> =\n & typeof BoxBase\n & { type: typeof type }\n & { typedArrayType: TypedArrayType }\n & BoxedBuffer<T2>\n & { [UnderlyingType]: T }\n\nexport const isType = isTypedArray\n\nexport const box = <T extends TypedArray, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): BoxedTypedArray<T, T2> =>\n ({\n ...BoxBase,\n type,\n typedArrayType: typedArrayToType(value),\n ...boxBuffer(value.buffer as ArrayBuffer, context),\n }) as unknown as BoxedTypedArray<T, T2>\n\nexport const revive = <T extends BoxedTypedArray<TypedArray, RevivableContext>>(\n value: T,\n _context: RevivableContext,\n): T[UnderlyingType] =>\n new (typedArrayTypeToTypedArrayConstructor(value.typedArrayType))(reviveBuffer(value)) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const uint8Boxed = box(new Uint8Array(10), {} as RevivableContext)\n const uint8Revived = revive(uint8Boxed, {} as RevivableContext)\n const expectedUint8: Uint8Array = uint8Revived\n // @ts-expect-error - wrong typed array type\n const wrongType: Int32Array = uint8Revived\n\n const float32Boxed = box(new Float32Array(10), {} as RevivableContext)\n const float32Revived = revive(float32Boxed, {} as RevivableContext)\n const expectedFloat32: Float32Array = float32Revived\n // @ts-expect-error - wrong typed array type\n const wrongFloat: Uint8Array = float32Revived\n\n // @ts-expect-error - cannot box non-TypedArray\n box('not a typed array', {} as RevivableContext)\n}\n","import type { TypedMessagePort, TypedMessagePortEventMap } from './typed-message-channel'\n\nexport class EventPort<T> extends EventTarget {\n addEventListener<K extends keyof TypedMessagePortEventMap<T> & string>(\n type: K,\n listener: ((event: TypedMessagePortEventMap<T>[K]) => void) | null,\n options?: boolean | AddEventListenerOptions\n ): void\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | AddEventListenerOptions\n ): void\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | AddEventListenerOptions\n ): void {\n super.addEventListener(type, listener, options)\n }\n\n removeEventListener<K extends keyof TypedMessagePortEventMap<T> & string>(\n type: K,\n listener: ((event: TypedMessagePortEventMap<T>[K]) => void) | null,\n options?: boolean | EventListenerOptions\n ): void\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | EventListenerOptions\n ): void\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | EventListenerOptions\n ): void {\n super.removeEventListener(type, listener, options)\n }\n\n _peer: EventPort<any> | undefined\n _queue: MessageEvent<T>[] = []\n _started = false\n _closed = false\n _onClose: (() => void) | undefined\n\n private _onmessage: ((this: MessagePort, ev: MessageEvent<T>) => unknown) | null = null\n\n get onmessage(): ((this: MessagePort, ev: MessageEvent<T>) => unknown) | null {\n return this._onmessage\n }\n set onmessage(value: ((this: MessagePort, ev: MessageEvent<T>) => unknown) | null) {\n this._onmessage = value\n if (value !== null) this.start()\n }\n\n onmessageerror: ((this: MessagePort, ev: MessageEvent) => unknown) | null = null\n\n dispatchEvent(event: Event): boolean {\n if (event.type === 'message') {\n this._onmessage?.call(this, event as MessageEvent<T>)\n } else if (event.type === 'messageerror') {\n this.onmessageerror?.call(this, event as MessageEvent)\n }\n return super.dispatchEvent(event)\n }\n\n postMessage(message: T, _options?: Transferable[] | StructuredSerializeOptions): void {\n const peer = this._peer\n if (!peer || peer._closed) return\n queueMicrotask(() => {\n if (peer._closed) return\n const event = new MessageEvent('message', { data: message })\n if (peer._started) {\n peer.dispatchEvent(event)\n } else {\n peer._queue.push(event)\n }\n })\n }\n\n start(): void {\n if (this._started) return\n this._started = true\n for (const event of this._queue.splice(0)) {\n this.dispatchEvent(event)\n }\n }\n\n close(): void {\n if (this._closed) return\n this._closed = true\n this._queue.length = 0\n this._onClose?.()\n }\n}\n\nexport interface EventPort<T>\n extends Omit<\n TypedMessagePort<T>,\n 'addEventListener' | 'removeEventListener'\n > {}\n\nexport class EventChannel<T1 = unknown, T2 = unknown> {\n readonly port1: EventPort<T1>\n readonly port2: EventPort<T2>\n\n constructor() {\n const port1 = new EventPort<T1>()\n const port2 = new EventPort<T2>()\n port1._peer = port2\n port2._peer = port1\n this.port1 = port1\n this.port2 = port2\n }\n}\n","import type { Capable, StructurableTransferable, Uuid } from '../types'\nimport type { TypedMessagePort } from '../utils/typed-message-channel'\nimport type { RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { UnderlyingType } from '../utils/type'\nimport type {\n BadFieldValue, BadFieldPath, BadFieldParent,\n ErrorMessage, BadValue, Path, ParentObject\n} from '../utils/capable-check'\n\nimport { BoxBase } from './utils'\nimport { recursiveBox, recursiveRevive } from '.'\nimport { getTransferableObjects, isJsonOnlyTransport } from '../utils'\nimport { EventChannel, EventPort } from '../utils/event-channel'\n\n/**\n * FinalizationRegistry for automatically cleaning up ports when they are garbage collected.\n * In JSON-only mode we can't transfer ports on the wire, so we track them via\n * portId and tell the remote side to close when the local handle is collected.\n */\ntype PortCleanupInfo = {\n sendMessage: (message: Messages) => void\n remoteUuid: Uuid\n portId: Uuid\n cleanup: () => void\n}\n\nconst messagePortRegistry = new FinalizationRegistry<PortCleanupInfo>((info) => {\n // Send close message to remote side\n info.sendMessage({\n type: 'message-port-close',\n remoteUuid: info.remoteUuid,\n portId: info.portId\n })\n // Perform local cleanup\n info.cleanup()\n})\n\nexport const type = 'messagePort' as const\n\nexport type Messages =\n | {\n type: 'message'\n remoteUuid: Uuid\n data: Capable\n /** uuid of the messagePort that the message was sent through */\n portId: Uuid\n }\n | {\n type: 'message-port-close'\n remoteUuid: Uuid\n /** uuid of the messagePort that closed */\n portId: Uuid\n }\n\nexport declare const Messages: Messages\n\n/** Any port-shape the message-port revivable is happy to accept. Real\n * MessagePorts (from `new MessageChannel()`) and synthetic EventPorts\n * (from `new EventChannel()`) both flow through here. Messages can be any\n * Capable value — message-port boxes/revives as they cross the transport,\n * and the in-realm side uses pass-by-reference via EventChannel. */\nexport type AnyPort<T = Capable> =\n | TypedMessagePort<T>\n | EventPort<T>\n\nexport type BoxedMessagePort<T = Capable> =\n & BoxBaseType<typeof type>\n & (\n /** The origin was a synthetic EventPort — revive must reproduce an\n * EventPort on the other side so live (non-clonable) Promises/Functions\n * etc. can flow through by reference. */\n | { portId: Uuid, synthetic: true }\n /** The origin was a real MessagePort but the transport can't carry\n * ports (JSON-only) — revive produces a real MessagePort proxy so the\n * receiver sees it as if it had been transferred. Payloads must be\n * structured-clonable; live (non-clonable) values nested in a\n * user-level MessagePort aren't supported in this mode. */\n | { portId: Uuid, synthetic: false }\n /** The origin was a real MessagePort and the transport supports\n * structured clone — the port is transferred on the wire. When\n * `autoBox` is true, the revive side wraps it in a `ProtocolPort`\n * that auto-boxes outgoing / auto-revives incoming payloads so\n * live values (Promises/Functions) flow through unchanged. When\n * `autoBox` is absent/false, the receiver gets the raw MessagePort\n * with structured-clone semantics (used for user-owned ports). */\n | { port: AnyPort<T>, autoBox?: boolean }\n )\n & { [UnderlyingType]: TypedMessagePort<T> }\n\n// `[T] extends [Capable]` disables distributive conditionals so unions like\n// `A | B` give back `AnyPort<A | B>`, not `AnyPort<A> | AnyPort<B>`.\n// The error branch intersects with AnyPort<T> so the user's port-shaped keys\n// are present on the target — otherwise TS's excess-property check flags a\n// port key instead of reporting the failure against the whole argument.\ntype StructurableTransferablePort<T> = [T] extends [Capable]\n ? AnyPort<T>\n : AnyPort<T> & {\n [ErrorMessage]: 'Message type must extend Capable'\n [BadValue]: BadFieldValue<T, Capable>\n [Path]: BadFieldPath<T, Capable>\n [ParentObject]: BadFieldParent<T, Capable>\n }\n\n// -------------------------------------------------------------------------\n// Per-connection state\n//\n// The WeakMap ties per-connection message-port state to the connection's\n// RevivableContext — when the context is collected, the state goes with it.\n// State lives only here; no sibling revivable has to know about it.\n// -------------------------------------------------------------------------\n\ntype ConnectionMessagePortState = {\n /** Direct per-portId dispatch — O(1) lookup avoids the O(N) addEventListener\n * scan that was the bottleneck for tight-loop RPC traffic. */\n portHandlers: Map<string, (message: Messages) => void>\n}\n\nconst connectionStateMap = new WeakMap<RevivableContext, ConnectionMessagePortState>()\n\nconst getState = (context: RevivableContext): ConnectionMessagePortState => {\n const state = connectionStateMap.get(context)\n if (!state) {\n throw new Error('osra message-port: connection state missing; did init() run?')\n }\n return state\n}\n\n// -------------------------------------------------------------------------\n// init hook\n//\n// Called once per connection by the bidirectional connection bootstrap.\n// Sets up the per-connection port-handler map and installs the event-target\n// listener that routes incoming 'message' envelopes to the correct local\n// handler.\n// -------------------------------------------------------------------------\n\nexport const init = (context: RevivableContext): void => {\n const state: ConnectionMessagePortState = {\n portHandlers: new Map()\n }\n connectionStateMap.set(context, state)\n\n context.eventTarget.addEventListener('message', ({ detail }) => {\n if (detail.type !== 'message' && detail.type !== 'message-port-close') return\n state.portHandlers.get(detail.portId)?.(detail)\n })\n}\n\nexport const isType = (value: unknown): value is MessagePort | EventPort<StructurableTransferable> =>\n value instanceof MessagePort || value instanceof EventPort\n\nexport const box = <T, T2 extends RevivableContext = RevivableContext>(\n value: StructurableTransferablePort<T>,\n context: T2,\n options?: { autoBox?: boolean },\n): BoxedMessagePort<T> => {\n // Synthetic EventPorts are not structured-clonable, so even when the\n // transport supports cloning we have to route them via portId — otherwise\n // sending the wrapping message would crash with DataCloneError.\n const synthetic = value instanceof EventPort\n if (synthetic || isJsonOnlyTransport(context.transport)) {\n const { portHandlers } = getState(context)\n const liveRef: AnyPort<T> = value\n const portId: Uuid = globalThis.crypto.randomUUID()\n\n let cleanedUp = false\n const performCleanup = () => {\n if (cleanedUp) return\n cleanedUp = true\n portHandlers.delete(portId)\n messagePortRegistry.unregister(liveRef)\n liveRef.removeEventListener('message', messagePortListener as EventListener)\n }\n\n // Incoming: remote side wrote to its revived port — deliver the payload\n // on our local port after reviving it back into a live value.\n const handler = (message: Messages) => {\n if (message.type === 'message-port-close') {\n performCleanup()\n liveRef.close()\n return\n }\n const revivedData = recursiveRevive(message.data, context) as T\n liveRef.postMessage(revivedData, getTransferableObjects(revivedData))\n }\n\n // Outgoing: whatever was written into our side of the user's channel gets\n // boxed and shipped over the main transport.\n function messagePortListener({ data }: MessageEvent<Capable>) {\n context.sendMessage({\n type: 'message',\n remoteUuid: context.remoteUuid,\n data: recursiveBox(data, context),\n portId,\n })\n }\n\n // Register for automatic cleanup when garbage collected. Note the handler\n // (stored in portHandlers) holds `liveRef` strongly via closure, so GC\n // will only fire once the Map entry is deleted (in performCleanup).\n messagePortRegistry.register(liveRef, {\n sendMessage: context.sendMessage,\n remoteUuid: context.remoteUuid,\n portId,\n cleanup: performCleanup,\n }, liveRef)\n\n liveRef.addEventListener('message', messagePortListener as EventListener)\n liveRef.start()\n\n // For synthetic EventPorts, close() is how the owning side signals it's\n // done — wire it up so we tear down listeners and notify the remote.\n if (liveRef instanceof EventPort) {\n liveRef._onClose = () => {\n if (cleanedUp) return\n context.sendMessage({\n type: 'message-port-close',\n remoteUuid: context.remoteUuid,\n portId,\n })\n performCleanup()\n }\n }\n\n portHandlers.set(portId, handler)\n\n return { ...BoxBase, type, portId, synthetic } as BoxedMessagePort<T>\n }\n return {\n ...BoxBase,\n type,\n port: value,\n ...(options?.autoBox ? { autoBox: true } : {}),\n } as BoxedMessagePort<T>\n}\n\nexport const revive = <T extends Capable, T2 extends RevivableContext>(\n value: BoxedMessagePort<T>,\n context: T2,\n): TypedMessagePort<T> => {\n if ('port' in value) {\n // autoBox: box side was an internal protocol channel — wrap the\n // transferred MessagePort so outgoing/incoming payloads auto-box/revive\n // and live values (Promises/Functions) flow through unchanged.\n if (value.autoBox) {\n return createProtocolPort<T>(value.port as TypedMessagePort<Capable>, context)\n }\n return value.port\n }\n // portId path: origin was either a synthetic EventPort (pass-by-ref for\n // live values) or a real MessagePort we couldn't clone (JSON-only\n // transport). EventPorts must revive as EventPorts so that live values\n // pass through unchanged; MessagePorts must revive as MessagePorts so\n // the receiver sees the same shape they'd get from a real `transfer`.\n return reviveViaPortId<T>(value.portId, context, value.synthetic)\n}\n\n/**\n * Thin wrapper around a real MessagePort: auto-boxes outgoing messages and\n * auto-revives incoming ones. Lets revivables treat it like an EventTarget\n * (addEventListener / postMessage / start / close) that transparently\n * carries live values (Promises, Functions, …) over a clone-only transport.\n */\nconst createProtocolPort = <T>(\n port: TypedMessagePort<Capable>,\n ctx: RevivableContext,\n): TypedMessagePort<T> => {\n const target = new EventTarget() as TypedMessagePort<T>\n const onMessage = ({ data }: MessageEvent<Capable>): void => {\n target.dispatchEvent(new MessageEvent('message', {\n data: recursiveRevive(data, ctx),\n }))\n }\n port.addEventListener('message', onMessage)\n target.postMessage = (data: T, opt?: Transferable[] | StructuredSerializeOptions) => {\n const boxed = recursiveBox(data as Capable, ctx)\n const transferables = getTransferableObjects(boxed)\n const extra = Array.isArray(opt) ? opt : []\n port.postMessage(boxed, extra.length ? [...transferables, ...extra] : transferables)\n }\n target.start = () => port.start()\n target.close = () => {\n port.removeEventListener('message', onMessage)\n port.close()\n }\n return target\n}\n\n/**\n * Factory for revivable-internal channels. Returns a local port used by the\n * revivable and a pre-boxed remote port ready to embed in the revivable's\n * Boxed* structure. The local port auto-boxes/revives on clone transports\n * (via ProtocolPort over a MessageChannel) and passes by reference on JSON\n * transports (via EventChannel → portId routing).\n *\n * Revivables can post live values (Promises/Functions/…) on `localPort`\n * without caring about the transport mode.\n */\nexport const createRevivableChannel = <T extends Capable>(\n context: RevivableContext,\n): { localPort: AnyPort<T>, boxedRemote: BoxedMessagePort<T> } => {\n if (isJsonOnlyTransport(context.transport)) {\n const { port1, port2 } = new EventChannel<T, T>()\n return {\n localPort: port1,\n boxedRemote: box(port2 as StructurableTransferablePort<T>, context),\n }\n }\n const { port1, port2 } = new MessageChannel() as unknown as {\n port1: TypedMessagePort<Capable>\n port2: TypedMessagePort<Capable>\n }\n return {\n localPort: createProtocolPort<T>(port1, context) as unknown as AnyPort<T>,\n boxedRemote: box(port2 as unknown as StructurableTransferablePort<T>, context, { autoBox: true }),\n }\n}\n\n/**\n * Revive a port that was routed via portId. Covers both the synthetic\n * (EventChannel, pass-by-reference) and proxy (real MessageChannel,\n * structured-clone) paths — they share all cleanup/routing logic, only\n * differing in which channel type is instantiated, whether transferables\n * are listed on internal postMessage, and whether userPort exposes an\n * explicit close hook.\n */\nconst reviveViaPortId = <T extends Capable>(\n portId: Uuid,\n context: RevivableContext,\n synthetic: boolean,\n): TypedMessagePort<T> => {\n const { portHandlers } = getState(context)\n const { port1: userPort, port2: internalPort } =\n synthetic\n ? new EventChannel<T, T>()\n : new MessageChannel() as { port1: TypedMessagePort<T>, port2: TypedMessagePort<T> }\n const userPortRef = new WeakRef(userPort)\n\n let cleanedUp = false\n const performCleanup = () => {\n if (cleanedUp) return\n cleanedUp = true\n portHandlers.delete(portId)\n internalPort.removeEventListener('message', internalPortListener as EventListener)\n internalPort.close()\n const port = userPortRef.deref()\n if (port) messagePortRegistry.unregister(port)\n }\n\n const handler = (message: Messages) => {\n if (message.type === 'message-port-close') {\n performCleanup()\n userPortRef.deref()?.close()\n return\n }\n const port = userPortRef.deref()\n if (!port) {\n performCleanup()\n return\n }\n const revivedData = recursiveRevive(message.data, context) as T\n // Real MessagePorts need must-transfer items on the transfer list;\n // EventPorts pass by reference so no transferable list applies.\n if (synthetic) internalPort.postMessage(revivedData)\n else internalPort.postMessage(revivedData, getTransferableObjects(revivedData))\n }\n\n const internalPortListener = ({ data }: MessageEvent<T>) => {\n context.sendMessage({\n type: 'message',\n remoteUuid: context.remoteUuid,\n data: recursiveBox(data, context),\n portId,\n })\n }\n\n messagePortRegistry.register(userPort, {\n sendMessage: context.sendMessage,\n remoteUuid: context.remoteUuid,\n portId,\n cleanup: performCleanup,\n }, userPort)\n\n // EventPort exposes an explicit close hook — wire it so user.close() tears\n // down listeners locally and notifies the remote side. Real MessagePorts\n // have no equivalent; they rely on the FinalizationRegistry to notify.\n if (userPort instanceof EventPort) {\n userPort._onClose = () => {\n if (cleanedUp) return\n context.sendMessage({\n type: 'message-port-close',\n remoteUuid: context.remoteUuid,\n portId,\n })\n performCleanup()\n }\n }\n\n internalPort.addEventListener('message', internalPortListener as EventListener)\n internalPort.start()\n\n portHandlers.set(portId, handler)\n\n return userPort\n}\n\nconst typeCheck = () => {\n const port = {} as TypedMessagePort<{ foo: string }>\n const boxed = box(port, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: AnyPort<{ foo: string }> = revived\n // @ts-expect-error - wrong message type\n const wrongType: AnyPort<{ bar: number }> = revived\n // Promise-valued messages are fine now — EventChannel pass-by-reference\n // means we don't need StructurableTransferable here.\n box({} as TypedMessagePort<Promise<string>>, {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { UnderlyingType } from '.'\nimport type {\n BadFieldValue, BadFieldPath, BadFieldParent,\n ErrorMessage, BadValue, Path, ParentObject\n} from '../utils/capable-check'\n\nimport { BoxBase, serializeError } from './utils'\nimport {\n createRevivableChannel,\n revive as reviveMessagePort,\n BoxedMessagePort,\n AnyPort,\n} from './message-port'\n\nexport const type = 'promise' as const\n\nexport type Context =\n | { type: 'resolve', data: Capable }\n | { type: 'reject', error: string }\n\n// Error branches intersect with T so the user's own keys are present on the\n// target — otherwise TS's excess-property check flags the first user key\n// (e.g. `foo`) instead of reporting the failure against the whole argument.\ntype CapablePromise<T> = T extends Promise<infer U>\n ? U extends Capable\n ? T\n : T & {\n [ErrorMessage]: 'Value type must extend a Promise that resolves to a Capable'\n [BadValue]: BadFieldValue<U, Capable>\n [Path]: BadFieldPath<U, Capable>\n [ParentObject]: BadFieldParent<U, Capable>\n }\n : T & {\n [ErrorMessage]: 'Value type must extend a Promise that resolves to a Capable'\n [BadValue]: T\n [Path]: ''\n [ParentObject]: T\n }\n\ntype ExtractCapable<T> = T extends Promise<infer U>\n ? U extends Capable ? U : never\n : never\n\nconst isCapablePromise = <T, U extends Capable = ExtractCapable<T>>(value: T): value is T & Promise<U> =>\n value instanceof Promise\n\nexport type BoxedPromise<T extends Capable = Capable> =\n & BoxBaseType<typeof type>\n & { port: BoxedMessagePort<Context> }\n & { [UnderlyingType]: T }\n\n// Pins the revived port between executor return and result arrival. The\n// port↔listener cycle has no external anchor — the caller only holds the\n// returned Promise, which references its native resolvers, not the port.\n// Without this Set, GC under memory pressure can collect the cycle before\n// the result arrives and the Promise hangs forever. Mirrors the\n// inFlightReturnPorts pattern in function.ts.\nconst inFlightPromisePorts = new Set<AnyPort<Context>>()\n\nexport const isType = (value: unknown): value is Promise<any> =>\n value instanceof Promise\n\nexport const box = <T, T2 extends RevivableContext>(\n value: CapablePromise<T>,\n context: T2\n): BoxedPromise<ExtractCapable<T>> => {\n if (!isCapablePromise(value)) throw new TypeError('Expected Promise')\n const promise = value\n // Revivable-internal channel: localPort auto-boxes on send regardless of\n // transport (ProtocolPort over MessageChannel on clone, EventChannel +\n // portId on JSON). We just post the result and let it take care of boxing.\n const { localPort, boxedRemote } = createRevivableChannel<Context>(context)\n\n const sendResult = (result: Context) => {\n localPort.postMessage(result)\n localPort.close()\n }\n\n promise\n .then((data: ExtractCapable<T>) => sendResult({ type: 'resolve', data }))\n .catch((error: unknown) => sendResult({\n type: 'reject',\n error: serializeError(error),\n }))\n\n return { ...BoxBase, type, port: boxedRemote } as BoxedPromise<ExtractCapable<T>>\n}\n\nexport const revive = <T extends BoxedPromise, T2 extends RevivableContext>(\n value: T,\n context: T2\n) => {\n const port = reviveMessagePort(value.port, context)\n inFlightPromisePorts.add(port)\n return new Promise<T[UnderlyingType]>((resolve, reject) => {\n port.addEventListener('message', ({ data: result }) => {\n if (result.type === 'resolve') {\n resolve(result.data as T[UnderlyingType])\n } else {\n reject(result.error)\n }\n port.close()\n inFlightPromisePorts.delete(port)\n }, { once: true })\n port.start()\n })\n}\n\nconst typeCheck = () => {\n const boxed = box(Promise.resolve(1 as const), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Promise<1> = revived\n // @ts-expect-error\n const notExpected: Promise<string> = revived\n // @ts-expect-error\n box(1 as const, {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { UnderlyingType, RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { TypedMessagePort } from '../utils/typed-message-channel'\nimport type { AnyPort } from './message-port'\n\nimport { BoxBase, serializeError } from './utils'\nimport {\n createRevivableChannel,\n revive as reviveMessagePort,\n BoxedMessagePort,\n} from './message-port'\n\nexport const type = 'function' as const\n\ntype ResultMessage =\n | { __osra_ok__: true, value: Capable }\n | { __osra_err__: true, error: string }\n\ntype CallMessage = CallContext | { __osra_close__: true }\n\n// Per-call record so the FinalizationRegistry callback (and the synchronous\n// postMessage-failed path) can reject the right Promise and tear down the\n// matching return port. Each record is owned by a single in-flight call.\ntype CallRecord = {\n returnLocal: AnyPort<ResultMessage>\n reject: (error: unknown) => void\n}\n\n/**\n * FinalizationRegistry for automatically cleaning up function ports when the\n * revived function is garbage collected. Also rejects any in-flight calls that\n * were initiated through this function — without this, a caller that drops\n * `func` while awaiting its result would leak the return port and leave the\n * Promise hung forever.\n */\ntype FunctionCleanupInfo = {\n port: TypedMessagePort<CallMessage>\n inFlight: Set<CallRecord>\n}\n\nconst functionRegistry = new FinalizationRegistry<FunctionCleanupInfo>((info) => {\n try {\n info.port.postMessage({ __osra_close__: true })\n } catch { /* Port may already be closed */ }\n try {\n info.port.close()\n } catch { /* Port may already be closed */ }\n for (const { returnLocal, reject } of info.inFlight) {\n try { reject(new Error('osra function was garbage collected before result arrived')) } catch { /* listener gone */ }\n inFlightReturnPorts.delete(returnLocal)\n try { returnLocal.close() } catch { /* port may already be closed */ }\n }\n info.inFlight.clear()\n})\n\n// Pins caller-side return-value ports between send and result arriving. The\n// cycle (localPort↔listener↔remotePort) has no external anchor after the\n// Promise executor returns, so under memory pressure GC can collect it before\n// the result arrives — the Promise hangs forever. We remove the entries in\n// the once-listener and in every terminal-state cleanup path below.\nconst inFlightReturnPorts = new Set<AnyPort<any>>()\n\n/** Call-site payload (sent over the wire): the return port is pre-boxed by\n * createRevivableChannel; args are passed live and boxed by the channel. */\ntype SentCallContext = [BoxedMessagePort<ResultMessage>, Capable[]]\n\n/** Call-site payload as received by the callee, after box-side revival: the\n * return port is now a live AnyPort<ResultMessage> (ProtocolPort on clone,\n * EventPort on JSON); args are revived. */\nexport type CallContext = [AnyPort<ResultMessage>, Capable[]]\n\nexport type BoxedFunction<T extends (...args: any[]) => any = (...args: any[]) => any> =\n & BoxBaseType<typeof type>\n & { port: BoxedMessagePort<CallMessage> }\n & { [UnderlyingType]: (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>> }\n\ntype CapableFunction<T> = T extends (...args: infer P) => infer R\n ? P extends Capable[]\n ? R extends Capable ? T : never\n : never\n : never\n\nexport const isType = (value: unknown): value is (...args: any[]) => any =>\n typeof value === 'function'\n\nexport const box = <T extends (...args: any[]) => any, T2 extends RevivableContext>(\n value: T & CapableFunction<T>,\n context: T2\n): BoxedFunction<T> => {\n const { localPort, boxedRemote } = createRevivableChannel<CallMessage>(context)\n\n const cleanup = () => {\n localPort.close()\n }\n\n localPort.addEventListener('message', ({ data }) => {\n if (!Array.isArray(data)) {\n // __osra_close__ sentinel — only non-array message on this channel\n cleanup()\n return\n }\n const [returnPort, args] = data\n ;(async () => value(...(args as Parameters<T>)))()\n .then(\n (resolved) => {\n try {\n returnPort.postMessage({ __osra_ok__: true, value: resolved })\n } catch (postErr) {\n // Result wasn't clonable / boxable — surface as a remote error\n // instead of letting the caller hang waiting for a message that\n // can never be sent.\n try {\n returnPort.postMessage({\n __osra_err__: true,\n error: serializeError(postErr),\n })\n } catch { /* error itself failed to serialise; caller cleanup will reject */ }\n }\n },\n (error: unknown) => {\n try {\n returnPort.postMessage({\n __osra_err__: true,\n error: serializeError(error),\n })\n } catch { /* serialised error failed to post; caller cleanup will reject */ }\n },\n )\n .finally(() => {\n // Close after the message has flushed through the microtask queue so\n // the result actually dispatches before we tear the channel down.\n queueMicrotask(() => returnPort.close())\n })\n })\n localPort.start()\n\n return { ...BoxBase, type, port: boxedRemote } as BoxedFunction<T>\n}\n\nexport const revive = <T extends BoxedFunction, T2 extends RevivableContext>(\n value: T,\n context: T2\n): T[UnderlyingType] => {\n const port = reviveMessagePort(value.port, context)\n // Per-function bag of in-flight calls — captured by both the FinalizationRegistry\n // callback (rejects on func GC) and each call's once-listener (removes on settle).\n const inFlight = new Set<CallRecord>()\n\n const func = (...args: Capable[]) =>\n new Promise((resolve, reject) => {\n const { localPort: returnLocal, boxedRemote: returnBoxedRemote } =\n createRevivableChannel<ResultMessage>(context)\n // Pin ports to a module-level Set so GC can't collect the\n // port↔listener cycle while the call is in flight. Without this,\n // under memory pressure the listener (and thus `resolve`) can be\n // collected before the result arrives — the Promise hangs forever.\n inFlightReturnPorts.add(returnLocal)\n const record: CallRecord = { returnLocal, reject }\n inFlight.add(record)\n\n returnLocal.addEventListener('message', ({ data: result }) => {\n if ('__osra_ok__' in result) resolve(result.value)\n else reject(result.error)\n returnLocal.close()\n inFlightReturnPorts.delete(returnLocal)\n inFlight.delete(record)\n }, { once: true })\n returnLocal.start()\n\n // Boxing the args may throw synchronously (DataCloneError on a clone\n // transport, JSON cycle on a JSON transport). Without this catch, the\n // pin and the in-flight record would leak forever even though the\n // Promise itself rejects via the executor's implicit try/catch.\n try {\n port.postMessage([returnBoxedRemote, args] as SentCallContext as unknown as CallMessage)\n } catch (sendErr) {\n inFlightReturnPorts.delete(returnLocal)\n inFlight.delete(record)\n try { returnLocal.close() } catch { /* may already be closed */ }\n reject(sendErr)\n }\n })\n\n // Register the function for automatic cleanup when garbage collected. The\n // callback also rejects every in-flight call so abandoned awaits stop hanging.\n functionRegistry.register(func, { port, inFlight }, func)\n\n return func\n}\n\nconst typeCheck = () => {\n const boxed = box((a: number, b: string) => a + b.length, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: (a: number, b: string) => Promise<number> = revived\n // @ts-expect-error - wrong return type\n const wrongReturn: (a: number, b: string) => Promise<string> = revived\n // @ts-expect-error - wrong parameter types\n const wrongParams: (a: string, b: number) => Promise<number> = revived\n // @ts-expect-error - non-Capable parameter type (Set is not directly Capable as parameter)\n box((a: WeakMap<object, string>) => a, {} as RevivableContext)\n // @ts-expect-error - non-Capable return type\n box(() => new WeakMap(), {} as RevivableContext)\n}\n","import type { RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { UnderlyingType } from '.'\n\nimport { BoxBase } from './utils'\nimport {\n createRevivableChannel,\n revive as reviveMessagePort,\n BoxedMessagePort\n} from './message-port'\n\nexport const type = 'readableStream' as const\n\nexport type PullContext = {\n type: 'pull' | 'cancel'\n}\n\ntype ChunkMessage<T = unknown> = Promise<ReadableStreamReadResult<T>>\n\ntype Msg = PullContext | ChunkMessage\n\nexport type BoxedReadableStream<T extends ReadableStream = ReadableStream> =\n & BoxBaseType<typeof type>\n & { port: BoxedMessagePort<Msg> }\n & { [UnderlyingType]: T }\n\nexport const isType = (value: unknown): value is ReadableStream =>\n value instanceof ReadableStream\n\nexport const box = <T extends ReadableStream, T2 extends RevivableContext>(\n value: T,\n context: T2\n): BoxedReadableStream<T> => {\n const { localPort, boxedRemote } = createRevivableChannel<Msg>(context)\n const reader = value.getReader()\n\n localPort.addEventListener('message', ({ data }) => {\n if ('type' in data && data.type === 'pull') {\n // reader.read() is a Promise — posting it live works because localPort\n // (ProtocolPort or EventPort) boxes it internally for the transport.\n localPort.postMessage(reader.read())\n } else {\n reader.cancel()\n localPort.close()\n }\n })\n localPort.start()\n\n return { ...BoxBase, type, port: boxedRemote } as BoxedReadableStream<T>\n}\n\nexport const revive = <T extends BoxedReadableStream, T2 extends RevivableContext>(\n value: T,\n context: T2\n): T[UnderlyingType] => {\n const port = reviveMessagePort(value.port, context)\n port.start()\n\n return new ReadableStream({\n pull: (controller) => new Promise<void>((resolve, reject) => {\n port.addEventListener('message', ({ data }) => {\n if (!(data instanceof Promise)) return\n data\n .then(result => {\n if (result.done) controller.close()\n else controller.enqueue(result.value)\n resolve()\n })\n .catch(reject)\n }, { once: true })\n port.postMessage({ type: 'pull' })\n }),\n cancel: () => {\n port.postMessage({ type: 'cancel' })\n // Defer close so the cancel message dispatches before tear-down — same\n // pattern function.ts uses for return-port cleanup.\n queueMicrotask(() => port.close())\n },\n }) as T[UnderlyingType]\n}\n\nconst typeCheck = () => {\n const stream = new ReadableStream<number>()\n const boxed = box(stream, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: ReadableStream<number> = revived\n // @ts-expect-error - wrong stream type\n const wrongType: ReadableStream<string> = revived\n // @ts-expect-error - not a ReadableStream\n box('not a stream', {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { UnderlyingType } from '../utils/type'\nimport type { BoxedMessagePort } from './message-port'\n\nimport { BoxBase } from './utils'\nimport { recursiveBox, recursiveRevive } from '.'\nimport {\n createRevivableChannel,\n revive as reviveMessagePort\n} from './message-port'\n\nexport const type = 'abortSignal' as const\n\ntype AbortMessage = {\n type: 'abort'\n reason?: Capable\n}\n\nexport type BoxedAbortSignal<T extends AbortSignal = AbortSignal> =\n & BoxBaseType<typeof type>\n & {\n aborted: boolean\n reason?: Capable\n port: BoxedMessagePort<AbortMessage>\n }\n & { [UnderlyingType]: T }\n\nexport const isType = (value: unknown): value is AbortSignal =>\n value instanceof AbortSignal\n\nexport const box = <T extends AbortSignal, T2 extends RevivableContext>(\n value: T,\n context: T2\n): BoxedAbortSignal<T> => {\n const { localPort, boxedRemote } = createRevivableChannel<AbortMessage>(context)\n\n if (!value.aborted) {\n value.addEventListener('abort', () => {\n localPort.postMessage({ type: 'abort', reason: value.reason as Capable })\n localPort.close()\n }, { once: true })\n } else {\n localPort.close()\n }\n\n // Eagerly-aborted reason rides the wrapper instead of the channel, so it\n // has to go through recursiveBox here — the outer recursiveBox will see\n // OSRA_BOX on this object and short-circuit before descending into `reason`.\n // Without this, a reason carrying live values (Function/Promise/EventTarget/…)\n // throws DataCloneError on clone transports and silently loses fields on\n // JSON transports.\n return {\n ...BoxBase,\n type,\n aborted: value.aborted,\n reason: value.aborted ? recursiveBox(value.reason as Capable, context) as Capable : undefined,\n port: boxedRemote,\n } as BoxedAbortSignal<T>\n}\n\nexport const revive = <T extends BoxedAbortSignal, T2 extends RevivableContext>(\n value: T,\n context: T2\n): AbortSignal => {\n const controller = new AbortController()\n\n if (value.aborted) {\n controller.abort(recursiveRevive(value.reason as Capable, context))\n return controller.signal\n }\n\n const port = reviveMessagePort(value.port, context)\n port.start()\n\n port.addEventListener('message', ({ data: message }) => {\n if (message.type === 'abort') {\n controller.abort(recursiveRevive(message.reason as Capable, context))\n port.close()\n }\n })\n\n return controller.signal\n}\n\nconst typeCheck = () => {\n const boxed = box(new AbortController().signal, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: AbortSignal = revived\n // @ts-expect-error - not an AbortSignal\n const notAbortSignal: string = revived\n // @ts-expect-error - cannot box non-AbortSignal\n box('not an abort signal', {} as RevivableContext)\n}\n","import type { RevivableContext } from './utils'\n\nimport { BoxBase } from './utils'\nimport { box as boxHeaders, revive as reviveHeaders } from './headers'\nimport { box as boxReadableStream, revive as reviveReadableStream } from './readable-stream'\n\nexport const type = 'response' as const\n\nexport const isType = (value: unknown): value is Response =>\n value instanceof Response\n\nexport const box = <T extends Response, T2 extends RevivableContext>(\n value: T,\n context: T2\n) => ({\n ...BoxBase,\n type,\n status: value.status,\n statusText: value.statusText,\n headers: boxHeaders(value.headers, context),\n body: value.body ? boxReadableStream(value.body, context) : null,\n url: value.url,\n redirected: value.redirected\n})\n\nexport const revive = <T extends ReturnType<typeof box>, T2 extends RevivableContext>(\n value: T,\n context: T2\n): Response => {\n const headers = reviveHeaders(value.headers, context)\n const body = value.body ? reviveReadableStream(value.body, context) : null\n\n return new Response(body, {\n status: value.status,\n statusText: value.statusText,\n headers\n })\n}\n\nconst typeCheck = () => {\n const boxed = box(new Response('body', { status: 200 }), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Response = revived\n // @ts-expect-error - not a Response\n const notResponse: string = revived\n // @ts-expect-error - cannot box non-Response\n box('not a response', {} as RevivableContext)\n}\n","import type { RevivableContext } from './utils'\n\nimport { BoxBase } from './utils'\nimport { box as boxHeaders, revive as reviveHeaders } from './headers'\nimport { box as boxReadableStream, revive as reviveReadableStream } from './readable-stream'\n\nexport const type = 'request' as const\n\nexport const isType = (value: unknown): value is Request =>\n value instanceof Request\n\nexport const box = <T extends Request, T2 extends RevivableContext>(\n value: T,\n context: T2\n) => ({\n ...BoxBase,\n type,\n method: value.method,\n url: value.url,\n headers: boxHeaders(value.headers, context),\n body: value.body ? boxReadableStream(value.body, context) : null,\n credentials: value.credentials,\n cache: value.cache,\n redirect: value.redirect,\n referrer: value.referrer,\n referrerPolicy: value.referrerPolicy,\n integrity: value.integrity,\n keepalive: value.keepalive\n})\n\nexport const revive = <T extends ReturnType<typeof box>, T2 extends RevivableContext>(\n value: T,\n context: T2\n): Request => {\n const headers = reviveHeaders(value.headers, context)\n const body = value.body ? reviveReadableStream(value.body, context) : null\n\n return new Request(value.url, {\n method: value.method,\n headers,\n body,\n credentials: value.credentials,\n cache: value.cache,\n redirect: value.redirect,\n referrer: value.referrer,\n referrerPolicy: value.referrerPolicy,\n integrity: value.integrity,\n keepalive: value.keepalive,\n // @ts-expect-error - duplex is needed for streaming bodies\n duplex: 'half',\n })\n}\n\nconst typeCheck = () => {\n const boxed = box(new Request('https://example.com'), {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Request = revived\n // @ts-expect-error - not a Request\n const notRequest: string = revived\n // @ts-expect-error - cannot box non-Request\n box('not a request', {} as RevivableContext)\n}\n","import type { Capable, Message, Uuid } from '../types'\nimport type { RevivableContext, BoxBase as BoxBaseType } from './utils'\nimport type { UnderlyingType } from '../utils/type'\n\nimport { BoxBase } from './utils'\nimport { recursiveBox, recursiveRevive } from '.'\n\nexport const type = 'identity' as const\n\nexport type Messages = {\n type: 'identity-dispose'\n remoteUuid: Uuid\n /** id of the identity-wrapped value that was collected */\n id: string\n}\n\nexport declare const Messages: Messages\n\nconst IDENTITY_MARKER: unique symbol = Symbol.for('osra.identity')\n\ntype IdentityWrapper<T = unknown> = {\n readonly [IDENTITY_MARKER]: true\n readonly value: T\n}\n\nexport type BoxedIdentity<T extends Capable = Capable> = BoxBaseType<typeof type> & {\n id: string\n inner?: Capable\n [UnderlyingType]: T\n}\n\nconst isObjectOrFunction = (value: unknown): value is object =>\n value !== null && (typeof value === 'object' || typeof value === 'function')\n\nconst isIdentityWrapper = (value: unknown): value is IdentityWrapper =>\n isObjectOrFunction(value) && IDENTITY_MARKER in value && value[IDENTITY_MARKER] === true\n\nconst wrapperMemo = new WeakMap<object, IdentityWrapper>()\n\nconst wrap = (value: object): IdentityWrapper => {\n if (isIdentityWrapper(value)) return value\n const cached = wrapperMemo.get(value)\n if (cached) return cached\n const wrapper: IdentityWrapper = { [IDENTITY_MARKER]: true, value }\n wrapperMemo.set(value, wrapper)\n return wrapper\n}\n\n/**\n * Wrap a value so that osra preserves its reference identity across the\n * RPC boundary, per connection. Calling identity(X) twice on the same\n * value produces the same wrapper, and both wrapper sends resolve to the\n * same revived reference on the remote side.\n *\n * - Primitives pass through unchanged (there is no identity to preserve).\n * - Already-wrapped values pass through unchanged (idempotent).\n *\n * NOTE: This lies at the type level — the runtime value for object/function\n * inputs is an IdentityWrapper<T>, typed as T so the user's surrounding\n * code stays unchanged. The box-site unwraps it.\n */\nexport const identity = <T>(value: T): T =>\n (isObjectOrFunction(value) ? wrap(value) : value) as T\n\n/**\n * Per-connection state for the identity revivable. Stored in a module-level\n * WeakMap so the connection's RevivableContext acts as the key — when the\n * connection ends and the context is collected, the state goes with it.\n */\ntype IdentityState = {\n /** Send side: inner value → stable id for this connection. */\n readonly sendIds: WeakMap<object, string>\n /** Send side: id → weak ref to the value we originally sent. Lets a later\n * receive of our own id (round-trip: we sent, the peer sent it back)\n * resolve to the original reference instead of building a fresh proxy. */\n readonly idToSent: Map<string, WeakRef<object>>\n /** Send side: FinalizationRegistry firing when an inner value is GC'd. */\n readonly sendRegistry: FinalizationRegistry<string>\n /** Receive side: id → revived value (strong ref, explicit cleanup). */\n readonly receiveCache: Map<string, unknown>\n /** Receive side: revived value → id. Lets us detect when user code passes\n * a revived value back to its origin, so we can replay the original id\n * and the origin's revive can short-circuit to the real reference. */\n readonly revivedToId: WeakMap<object, string>\n /** True once the eventTarget listener has been installed. */\n listenerInstalled: boolean\n}\n\nconst connectionStates = new WeakMap<RevivableContext, IdentityState>()\n\nconst getOrCreateState = (context: RevivableContext): IdentityState => {\n const existing = connectionStates.get(context)\n if (existing) return existing\n // Construct the maps as locals first so the FinalizationRegistry callback\n // can close over them without a forward reference to `state` itself.\n const sendIds = new WeakMap<object, string>()\n const idToSent = new Map<string, WeakRef<object>>()\n const receiveCache = new Map<string, unknown>()\n const revivedToId = new WeakMap<object, string>()\n const sendRegistry = new FinalizationRegistry<string>((id) => {\n // Sender-side inner value was collected. Drop our send-side id record\n // (the WeakRef is already dead; keeping it would leak Map entries) and\n // tell the receiver to drop its cached revived value so both sides\n // converge. If the transport has already been torn down, swallow.\n idToSent.delete(id)\n try {\n context.sendMessage({\n type: 'identity-dispose',\n remoteUuid: context.remoteUuid,\n id,\n })\n } catch { /* connection already closed */ }\n })\n const state: IdentityState = {\n sendIds,\n idToSent,\n sendRegistry,\n receiveCache,\n revivedToId,\n listenerInstalled: false,\n }\n connectionStates.set(context, state)\n installReceiveListener(context, state)\n return state\n}\n\nconst installReceiveListener = (context: RevivableContext, state: IdentityState) => {\n if (state.listenerInstalled) return\n state.listenerInstalled = true\n context.eventTarget.addEventListener('message', ({ detail }) => {\n if (detail?.type === 'identity-dispose') {\n const revived = state.receiveCache.get(detail.id)\n state.receiveCache.delete(detail.id)\n if (revived !== undefined && isObjectOrFunction(revived)) {\n state.revivedToId.delete(revived)\n }\n }\n })\n}\n\nexport const isType = (value: unknown): value is IdentityWrapper =>\n isIdentityWrapper(value)\n\nexport const box = <T extends Capable, TContext extends RevivableContext>(\n wrapper: IdentityWrapper<T>,\n context: TContext,\n): BoxedIdentity<T> => {\n const state = getOrCreateState(context)\n const inner = wrapper.value\n const key = isObjectOrFunction(inner) ? inner : undefined\n if (key !== undefined) {\n const existingId = state.sendIds.get(key)\n if (existingId !== undefined) {\n // Subsequent send for this value on this connection: skip the inner\n // box entirely so the receiver resolves through its cache.\n return {\n ...BoxBase,\n type,\n id: existingId,\n } as BoxedIdentity<T>\n }\n const receivedId = state.revivedToId.get(key)\n if (receivedId !== undefined) {\n // Round-trip: user is handing us a value we originally revived from\n // the peer on this connection. Replay the peer's id so the peer's\n // revive resolves to its original reference (the one it first sent).\n return {\n ...BoxBase,\n type,\n id: receivedId,\n } as BoxedIdentity<T>\n }\n }\n const id = globalThis.crypto.randomUUID()\n const innerBox = recursiveBox(inner, context)\n if (key !== undefined) {\n state.sendIds.set(key, id)\n state.idToSent.set(id, new WeakRef(key))\n state.sendRegistry.register(key, id)\n }\n return {\n ...BoxBase,\n type,\n id,\n inner: innerBox,\n } as BoxedIdentity<T>\n}\n\nexport const revive = <T extends BoxedIdentity, TContext extends RevivableContext>(\n value: T,\n context: TContext,\n): T[UnderlyingType] => {\n const state = getOrCreateState(context)\n const cached = state.receiveCache.get(value.id)\n if (cached !== undefined) return cached as T[UnderlyingType]\n // The id may be one we originally sent — the peer is handing it back\n // (directly, or after arbitrary forwarding). Resolve to the original\n // reference instead of building a fresh proxy on top of one.\n const originated = state.idToSent.get(value.id)?.deref()\n if (originated !== undefined) return originated as T[UnderlyingType]\n if (!('inner' in value) || value.inner === undefined) {\n throw new Error(\n `osra identity: received id=${value.id} with no inner payload and no cached value`,\n )\n }\n const revived = recursiveRevive(value.inner, context)\n state.receiveCache.set(value.id, revived)\n if (isObjectOrFunction(revived)) {\n state.revivedToId.set(revived, value.id)\n }\n return revived as T[UnderlyingType]\n}\n\nconst typeCheck = () => {\n const fn = () => 42\n const wrapper = { [IDENTITY_MARKER]: true, value: fn } as IdentityWrapper<typeof fn>\n const boxed = box(wrapper, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n // Revive recovers the original function type via the UnderlyingType phantom.\n const expected: typeof fn = revived\n // @ts-expect-error - revived is the original function type, not string\n const notExpected: string = revived\n // @ts-expect-error - cannot box a non-Capable wrapper (Symbol not assignable)\n box({ [IDENTITY_MARKER]: true, value: Symbol() } as IdentityWrapper<symbol>, {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { BoxBase as BoxBaseType, RevivableContext, UnderlyingType } from './utils'\n\nimport { BoxBase } from './utils'\nimport { instanceOfAny, isJsonOnlyTransport } from '../utils'\nimport { recursiveBox, recursiveRevive } from '.'\n\nexport const type = 'transfer' as const\n\nconst TRANSFER_MARKER: unique symbol = Symbol.for('osra.transfer')\n\ntype TransferWrapper<T = unknown> = {\n readonly [TRANSFER_MARKER]: true\n readonly value: T\n}\n\nexport type BoxedTransfer<T extends Capable = Capable> = BoxBaseType<typeof type> & {\n inner: Capable\n degraded: boolean\n [UnderlyingType]: T\n}\n\nconst isObject = (value: unknown): value is object =>\n value !== null && typeof value === 'object'\n\nconst isTransferWrapper = (value: unknown): value is TransferWrapper =>\n isObject(value) && TRANSFER_MARKER in value && value[TRANSFER_MARKER] === true\n\n// The set of types `transfer()` accepts. Anything else — primitives, nullish,\n// plain objects, Dates, Errors, Promises, etc. — is returned unchanged so\n// normal payloads don't blow up if someone wraps the wrong thing.\nconst isWrappableTransferable = (value: unknown): boolean => {\n if (!isObject(value)) return false\n if (ArrayBuffer.isView(value)) return true\n return instanceOfAny(value, [\n globalThis.ArrayBuffer,\n globalThis.MessagePort,\n globalThis.ReadableStream,\n globalThis.WritableStream,\n globalThis.TransformStream,\n globalThis.ImageBitmap,\n globalThis.OffscreenCanvas,\n ])\n}\n\n/**\n * Opt into transfer semantics for a transferable value. Without this wrapper\n * osra sends transferables as structured clones (copies) — the sender-side\n * reference stays usable after the RPC. Wrapping hands the underlying storage\n * off to the receiver and neuters the sender-side reference, matching what\n * you'd get by listing it in the transfer list of `postMessage(msg, [buf])`.\n *\n * - Primitives, null, undefined, plain objects, Promises, Dates, etc. are\n * returned unchanged.\n * - Typed array views (`Uint8Array`, `DataView`, …) are accepted as a\n * convenience — their underlying `.buffer` is what actually gets moved.\n * - `transfer(transfer(x))` returns the same wrapper as `transfer(x)`.\n * - If the current platform cannot transfer the given type, the wrapper\n * silently degrades to a copy — nothing throws.\n *\n * NOTE: This lies at the type level — the runtime value for transferable\n * inputs is a TransferWrapper<T>, typed as T so the user's surrounding\n * code stays unchanged. The box-site unwraps it.\n */\nexport const transfer = <T>(value: T): T =>\n (isWrappableTransferable(value)\n ? { [TRANSFER_MARKER]: true, value }\n : value\n ) as T\n\n// -------------------------------------------------------------------------\n// Revivable module interface\n// -------------------------------------------------------------------------\n\nexport const isType = (value: unknown): value is TransferWrapper =>\n isTransferWrapper(value)\n\nexport const box = <T extends Capable, TContext extends RevivableContext>(\n wrapper: TransferWrapper<T>,\n context: TContext,\n): BoxedTransfer<T> => {\n const inner = wrapper.value\n const innerBoxed = recursiveBox(inner, context)\n // The `degraded` flag carries the transport mode to the send-time walker\n // in getTransferableObjects. When true, the walker treats this box as if\n // it weren't a transfer box at all — no mode flip, no transferables on\n // the transfer list — and the wrapper silently degrades to a copy. JSON\n // transports can't move ownership over the wire, so transfer semantics\n // don't apply and we degrade.\n return {\n ...BoxBase,\n type,\n inner: innerBoxed,\n degraded: isJsonOnlyTransport(context.transport),\n } as BoxedTransfer<T>\n}\n\nexport const revive = <T extends BoxedTransfer, TContext extends RevivableContext>(\n value: T,\n context: TContext,\n): T[UnderlyingType] =>\n recursiveRevive(value.inner, context) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const ab = new ArrayBuffer(10)\n const wrapper = { [TRANSFER_MARKER]: true, value: ab } as TransferWrapper<ArrayBuffer>\n const boxed = box(wrapper, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n // Revive recovers the original ArrayBuffer type via the UnderlyingType phantom.\n const expected: ArrayBuffer = revived\n // @ts-expect-error - revived is ArrayBuffer, not string\n const notExpected: string = revived\n // @ts-expect-error - cannot box a non-Capable wrapper (Symbol not assignable)\n box({ [TRANSFER_MARKER]: true, value: Symbol() } as TransferWrapper<symbol>, {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { RevivableContext, UnderlyingType, BoxBase as BoxBaseType } from './utils'\n\nimport { BoxBase } from './utils'\nimport { recursiveBox, recursiveRevive } from '.'\n\nexport const type = 'map' as const\n\nexport type BoxedMap<T extends Map<Capable, Capable> = Map<Capable, Capable>> =\n & BoxBaseType<typeof type>\n & { entries: Array<[Capable, Capable]> }\n & { [UnderlyingType]: T }\n\n// `Map<unknown, unknown>` rather than `Map<Capable, Capable>` here breaks\n// the Capable ↔ defaultRevivableModules ↔ this module type cycle.\n// box() narrows to Map<Capable, Capable> so misuse is still caught at the\n// box site.\nexport const isType = (value: unknown): value is Map<unknown, unknown> =>\n value instanceof Map\n\nexport const box = <T extends Map<Capable, Capable>, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): BoxedMap<T> => ({\n ...BoxBase,\n type,\n entries: Array.from(value, ([k, v]): [Capable, Capable] =>\n [recursiveBox(k, context) as Capable, recursiveBox(v, context) as Capable]),\n}) as BoxedMap<T>\n\nexport const revive = <T extends BoxedMap, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): T[UnderlyingType] =>\n new Map(value.entries.map(([k, v]) => [\n recursiveRevive(k, context),\n recursiveRevive(v, context),\n ])) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const m = new Map<string, number>([['a', 1]])\n const boxed = box(m, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Map<string, number> = revived\n // @ts-expect-error - wrong value type\n const wrongValue: Map<string, string> = revived\n // @ts-expect-error - cannot box non-Map\n box('not a map', {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { RevivableContext, UnderlyingType, BoxBase as BoxBaseType } from './utils'\n\nimport { BoxBase } from './utils'\nimport { recursiveBox, recursiveRevive } from '.'\n\nexport const type = 'set' as const\n\nexport type BoxedSet<T extends Set<Capable> = Set<Capable>> =\n & BoxBaseType<typeof type>\n & { values: Array<Capable> }\n & { [UnderlyingType]: T }\n\n// `Set<unknown>` rather than `Set<Capable>` here breaks the Capable ↔\n// defaultRevivableModules ↔ this module type cycle. box() narrows to\n// Set<Capable> so misuse is still caught at the box site.\nexport const isType = (value: unknown): value is Set<unknown> =>\n value instanceof Set\n\nexport const box = <T extends Set<Capable>, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): BoxedSet<T> => ({\n ...BoxBase,\n type,\n values: Array.from(value, v => recursiveBox(v, context) as Capable),\n}) as BoxedSet<T>\n\nexport const revive = <T extends BoxedSet, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): T[UnderlyingType] =>\n new Set(value.values.map(v => recursiveRevive(v, context))) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const s = new Set<number>([1, 2, 3])\n const boxed = box(s, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: Set<number> = revived\n // @ts-expect-error - wrong value type\n const wrongValue: Set<string> = revived\n // @ts-expect-error - cannot box non-Set\n box('not a set', {} as RevivableContext)\n}\n","import type { RevivableContext, UnderlyingType } from './utils'\n\nimport { BoxBase } from './utils'\n\nexport const type = 'bigint' as const\n\ntype BoxedBigInt<T extends bigint> =\n & typeof BoxBase\n & { type: typeof type }\n & { value: string }\n & { [UnderlyingType]: T }\n\nexport const isType = (value: unknown): value is bigint =>\n typeof value === 'bigint'\n\nexport const box = <T extends bigint, T2 extends RevivableContext>(\n value: T,\n _context: T2,\n): BoxedBigInt<T> =>\n ({ ...BoxBase, type, value: value.toString() }) as BoxedBigInt<T>\n\nexport const revive = <T extends BoxedBigInt<bigint>>(\n value: T,\n _context: RevivableContext,\n): T[UnderlyingType] =>\n BigInt(value.value) as T[UnderlyingType]\n\nconst typeCheck = () => {\n const boxed = box(123n, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: bigint = revived\n // @ts-expect-error - not a string\n const notString: string = revived\n // @ts-expect-error - cannot box non-bigint\n box('not a bigint', {} as RevivableContext)\n}\n","import type { Capable } from '../types'\nimport type { RevivableContext, BoxBase as BoxBaseType, UnderlyingType } from './utils'\nimport type { AnyPort, BoxedMessagePort } from './message-port'\n\nimport { BoxBase } from './utils'\nimport {\n createRevivableChannel,\n revive as reviveMessagePort,\n} from './message-port'\n\nexport const type = 'eventTarget' as const\n\n// Wire protocol — receiver tells source which event types to forward (so we\n// don't broadcast every dispatch); source pushes a serialised event when its\n// EventTarget fires a matching type. The `close` sentinel lets the revive\n// side notify the box side that the revived target is gone so it can tear\n// down its forwarder listeners.\ntype EventTargetMessage =\n | { kind: 'subscribe', eventType: string }\n | { kind: 'unsubscribe', eventType: string }\n | { kind: 'close' }\n | {\n kind: 'event'\n eventType: string\n bubbles: boolean\n cancelable: boolean\n composed: boolean\n // Present iff the source dispatched a CustomEvent — preserves `detail`\n // (boxed via the surrounding revivable graph so live values flow).\n detail?: Capable\n }\n\nexport type BoxedEventTarget<T extends EventTarget = EventTarget> =\n & BoxBaseType<typeof type>\n & { port: BoxedMessagePort<EventTargetMessage> }\n & { [UnderlyingType]: T }\n\n// FinalizationRegistry — when the revived EventTarget is collected the box\n// side needs to remove the forwarder listeners it installed on the user's\n// source EventTarget; otherwise long-lived sources (window, document, …)\n// retain the forwarder forever and keep posting into a dead channel on\n// every dispatch. We post a `close` sentinel through the revive-side port\n// but deliberately do NOT call .close() on the port here: on synthetic\n// EventPort channels (JSON transport) close() synchronously sends a\n// `message-port-close` to the box side via _onClose, which races ahead of\n// our queued sentinel and tears the box-side portHandlers entry down\n// before the sentinel arrives — so the sentinel gets dropped and tearDown\n// never runs. Leaving the port open lets messagePortRegistry clean it up\n// a GC cycle later, by which time the sentinel has already flushed.\ntype EventTargetCleanupInfo = {\n port: AnyPort<EventTargetMessage>\n}\n\nconst eventTargetRegistry = new FinalizationRegistry<EventTargetCleanupInfo>((info) => {\n try {\n info.port.postMessage({ kind: 'close' })\n } catch { /* Port may already be closed */ }\n})\n\nexport const isType = (value: unknown): value is EventTarget =>\n value instanceof EventTarget\n\nexport const box = <T extends EventTarget, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): BoxedEventTarget<T> => {\n const { localPort, boxedRemote } = createRevivableChannel<EventTargetMessage>(context)\n\n // One forwarder per event type, installed on demand and torn down when the\n // remote unsubscribes. Keyed by eventType so duplicate subscribes are no-ops.\n const sourceListeners = new Map<string, EventListener>()\n\n const tearDown = () => {\n for (const [eventType, listener] of sourceListeners) {\n value.removeEventListener(eventType, listener)\n }\n sourceListeners.clear()\n localPort.removeEventListener('message', messageListener as EventListener)\n localPort.close()\n }\n\n const messageListener = ({ data }: MessageEvent<EventTargetMessage>) => {\n if (data.kind === 'close') {\n tearDown()\n return\n }\n if (data.kind === 'subscribe') {\n if (sourceListeners.has(data.eventType)) return\n const listener: EventListener = (event) => {\n const message: EventTargetMessage = {\n kind: 'event',\n eventType: data.eventType,\n bubbles: event.bubbles,\n cancelable: event.cancelable,\n composed: event.composed,\n }\n if (event instanceof CustomEvent) {\n message.detail = event.detail as Capable\n }\n localPort.postMessage(message)\n }\n value.addEventListener(data.eventType, listener)\n sourceListeners.set(data.eventType, listener)\n return\n }\n if (data.kind === 'unsubscribe') {\n const existing = sourceListeners.get(data.eventType)\n if (!existing) return\n value.removeEventListener(data.eventType, existing)\n sourceListeners.delete(data.eventType)\n }\n }\n\n localPort.addEventListener('message', messageListener as EventListener)\n localPort.start()\n\n return { ...BoxBase, type, port: boxedRemote } as BoxedEventTarget<T>\n}\n\nconst extractCapture = (\n options?: boolean | EventListenerOptions | AddEventListenerOptions,\n): boolean => typeof options === 'boolean' ? options : !!options?.capture\n\nconst extractOnce = (options?: boolean | AddEventListenerOptions): boolean =>\n typeof options === 'object' && options !== null && !!options.once\n\ntype Subscriptions =\n Map<string, Map<EventListenerOrEventListenerObject, Map<boolean, EventListenerOrEventListenerObject>>>\n\n// Removes one (listener, capture) registration; returns true iff the\n// event type went from non-empty to empty so the caller can post unsubscribe.\nconst removeFromTracking = (\n subscriptions: Subscriptions,\n eventType: string,\n listener: EventListenerOrEventListenerObject,\n capture: boolean,\n): boolean => {\n const byListener = subscriptions.get(eventType)\n if (!byListener) return false\n const byCapture = byListener.get(listener)\n if (!byCapture) return false\n if (!byCapture.delete(capture)) return false\n if (byCapture.size === 0) byListener.delete(listener)\n if (byListener.size > 0) return false\n subscriptions.delete(eventType)\n return true\n}\n\n// Attaches the port-dispatch listener inside a helper so V8's closure scope\n// record for the listener contains only `targetRef` + `port` — not the outer\n// revive frame (which has a strong `target` binding that would pin the\n// revived EventTarget and defeat the FinalizationRegistry-based cleanup).\nconst wireMessageListener = (\n port: AnyPort<EventTargetMessage>,\n targetRef: WeakRef<EventTarget>,\n): void => {\n port.addEventListener('message', ({ data }: MessageEvent<EventTargetMessage>) => {\n if (data.kind !== 'event') return\n const t = targetRef.deref()\n if (!t) return\n const eventInit = {\n bubbles: data.bubbles,\n cancelable: data.cancelable,\n composed: data.composed,\n }\n const event = 'detail' in data\n ? new CustomEvent(data.eventType, { ...eventInit, detail: data.detail })\n : new Event(data.eventType, eventInit)\n t.dispatchEvent(event)\n })\n}\n\n// Builds the addEventListener/removeEventListener overrides inside a helper\n// so the closures they produce capture only the listed params — not `target`\n// from revive's scope (V8 retains whole context slots per closure, so leaving\n// `target` in the enclosing lexical scope would pin it alive indefinitely).\nconst installOverrides = (\n target: EventTarget,\n port: AnyPort<EventTargetMessage>,\n subscriptions: Subscriptions,\n): void => {\n const nativeAdd = EventTarget.prototype.addEventListener.bind(target)\n const nativeRemove = EventTarget.prototype.removeEventListener.bind(target)\n\n Object.defineProperty(target, 'addEventListener', {\n value: (\n eventType: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | AddEventListenerOptions,\n ) => {\n if (listener === null) return\n const capture = extractCapture(options)\n const once = extractOnce(options)\n\n let byListener = subscriptions.get(eventType)\n const isFirstForType = !byListener\n if (!byListener) {\n byListener = new Map()\n subscriptions.set(eventType, byListener)\n }\n let byCapture = byListener.get(listener)\n if (!byCapture) {\n byCapture = new Map()\n byListener.set(listener, byCapture)\n }\n if (byCapture.has(capture)) return\n\n // `{ once: true }` auto-removes the native registration after first\n // dispatch, but the DOM doesn't notify our override — so without a\n // wrapper, our tracking would diverge and we'd never send unsubscribe.\n const effective: EventListenerOrEventListenerObject = once\n ? (event: Event) => {\n const becameEmpty = removeFromTracking(subscriptions, eventType, listener, capture)\n if (becameEmpty) port.postMessage({ kind: 'unsubscribe', eventType })\n if (typeof listener === 'function') listener(event)\n else listener.handleEvent(event)\n }\n : listener\n\n byCapture.set(capture, effective)\n if (isFirstForType) port.postMessage({ kind: 'subscribe', eventType })\n nativeAdd(eventType, effective, options)\n },\n })\n\n Object.defineProperty(target, 'removeEventListener', {\n value: (\n eventType: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | EventListenerOptions,\n ) => {\n if (listener === null) return\n const capture = extractCapture(options)\n const effective = subscriptions.get(eventType)?.get(listener)?.get(capture)\n if (!effective) return\n nativeRemove(eventType, effective, options)\n const becameEmpty = removeFromTracking(subscriptions, eventType, listener, capture)\n if (becameEmpty) port.postMessage({ kind: 'unsubscribe', eventType })\n },\n })\n}\n\nexport const revive = <T extends BoxedEventTarget, T2 extends RevivableContext>(\n value: T,\n context: T2,\n): T[UnderlyingType] => {\n const port = reviveMessagePort(value.port, context)\n port.start()\n\n const target = new EventTarget()\n // Per-type registrations keyed by `(listener, capture)` because the DOM\n // uniques on that tuple: the same listener with capture=true and capture=false\n // are two distinct registrations and must be tracked independently. Tracking\n // on listener identity alone would silently drop one registration when the\n // other is removed, and miss `{ once: true }` self-removal.\n const subscriptions: Subscriptions = new Map()\n\n // WeakRef wrapping + helpers-with-tight-scope pattern: closures created\n // inside wireMessageListener / installOverrides only capture their params,\n // not `target` from this frame. That's what lets the FinalizationRegistry\n // fire when the user drops their revived-target reference.\n wireMessageListener(port, new WeakRef(target))\n installOverrides(target, port, subscriptions)\n\n eventTargetRegistry.register(target, { port }, target)\n\n return target as T[UnderlyingType]\n}\n\nconst typeCheck = () => {\n const et = new EventTarget()\n const boxed = box(et, {} as RevivableContext)\n const revived = revive(boxed, {} as RevivableContext)\n const expected: EventTarget = revived\n // @ts-expect-error - not a string\n const notString: string = revived\n // @ts-expect-error - cannot box non-EventTarget\n box('not an event target', {} as RevivableContext)\n}\n","import type { BoxBase, RevivableContext } from './utils'\nimport type { DeepReplaceWithBox, DeepReplaceWithRevive, ReplaceWithBox, ReplaceWithRevive } from '../utils/replace'\nimport type { MessageFields, Capable } from '../types'\n\nimport { isRevivableBox } from './utils'\nimport * as arrayBuffer from './array-buffer'\nimport * as date from './date'\nimport * as headers from './headers'\nimport * as error from './error'\nimport * as typedArray from './typed-array'\nimport * as promise from './promise'\nimport * as func from './function'\nimport * as messagePort from './message-port'\nimport * as readableStream from './readable-stream'\nimport * as abortSignal from './abort-signal'\nimport * as response from './response'\nimport * as request from './request'\nimport * as identity from './identity'\nimport * as transfer from './transfer'\nimport * as map from './map'\nimport * as set from './set'\nimport * as bigInt from './bigint'\nimport * as eventTarget from './event-target'\n\nexport { identity } from './identity'\nexport { transfer } from './transfer'\n\nexport * from './utils'\n\n// Module-level signatures intentionally widen to `any` on the box/revive/init\n// parameters: each module's concrete box takes a narrower input than the\n// shared interface can express, and TS treats `readonly`-property function\n// types contravariantly. The `any`s here are the bivariance escape hatch that\n// lets concrete modules be assigned to `RevivableModule[]` at all.\nexport type RevivableModule<\n T extends string = string,\n T2 = any,\n T3 extends BoxBase<T> = any,\n T4 extends MessageFields = MessageFields,\n> = {\n readonly type: T\n readonly isType: (value: unknown) => value is T2\n readonly box: ((value: T2, context: RevivableContext<any>) => T3) | ((...args: any[]) => any)\n readonly revive: (value: T3, context: RevivableContext<any>) => T2\n readonly init?: (context: RevivableContext<any>) => void\n readonly Messages?: T4\n}\n\nexport const defaultRevivableModules = [\n transfer,\n identity,\n arrayBuffer,\n date,\n headers,\n error,\n typedArray,\n promise,\n func,\n messagePort,\n readableStream,\n abortSignal,\n response,\n request,\n map,\n set,\n bigInt,\n // eventTarget MUST be last among instanceof-EventTarget revivables —\n // MessagePort, AbortSignal, EventPort, Window, Worker, etc. all extend\n // EventTarget; the more specific revivables (messagePort/abortSignal) need\n // first dibs via findBoxModule's iteration order.\n eventTarget,\n] as const\n\nexport type DefaultRevivableModules = typeof defaultRevivableModules\nexport type DefaultRevivableModule = DefaultRevivableModules[number]\n\nconst findBoxModule = (\n value: unknown,\n modules: readonly RevivableModule[]\n): RevivableModule | undefined =>\n modules.find(module => module.isType(value))\n\nconst findReviveModule = (\n value: BoxBase,\n modules: readonly RevivableModule[],\n): RevivableModule | undefined =>\n modules.find(module => module.type === value.type)\n\nconst isPlainObject = (value: unknown): value is Record<string, Capable> =>\n !!value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype\n\nconst descend = <TOut>(value: unknown, transform: (v: Capable) => unknown): TOut => {\n if (Array.isArray(value)) {\n return value.map(v => transform(v)) as TOut\n }\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries<Capable>(value).map(([k, v]) => [k, transform(v)]),\n ) as TOut\n }\n return value as TOut\n}\n\nexport const box = <\n T extends Capable,\n TModules extends readonly RevivableModule[]\n>(\n value: T,\n context: RevivableContext<TModules>\n): ReplaceWithBox<T, TModules[number]> => {\n const handledByModule = findBoxModule(value, context.revivableModules)\n if (handledByModule) {\n return handledByModule.box(value, context) as ReplaceWithBox<T, TModules[number]>\n }\n return value as ReplaceWithBox<T, TModules[number]>\n}\n\nexport const recursiveBox = <\n T extends Capable,\n TModules extends readonly RevivableModule[]\n>(\n value: T,\n context: RevivableContext<TModules>\n): DeepReplaceWithBox<T, TModules[number]> => {\n type ReturnCastType = DeepReplaceWithBox<T, TModules[number]>\n // Already-boxed values pass through — revivables (e.g. createRevivableChannel)\n // may embed a pre-built BoxedX in their outgoing payload; descending into it\n // would re-box raw ports nested inside.\n if (isRevivableBox(value)) return value as ReturnCastType\n const handledByModule = findBoxModule(value, context.revivableModules)\n if (handledByModule) {\n return handledByModule.box(value, context) as ReturnCastType\n }\n return descend<ReturnCastType>(value, v => recursiveBox(v, context))\n}\n\nexport const revive = <\n T extends ReturnType<typeof box>,\n TModules extends readonly RevivableModule[]\n>(\n value: T,\n context: RevivableContext<TModules>\n): ReplaceWithRevive<T, TModules[number]> => {\n if (!isRevivableBox(value)) return value as ReplaceWithRevive<T, TModules[number]>\n const handledByModule = findReviveModule(value, context.revivableModules)\n if (handledByModule) {\n return handledByModule.revive(value, context) as ReplaceWithRevive<T, TModules[number]>\n }\n return value as ReplaceWithRevive<T, TModules[number]>\n}\n\nexport const recursiveRevive = <\n T extends Capable,\n TModules extends readonly RevivableModule[]\n>(\n value: T,\n context: RevivableContext<TModules>\n): DeepReplaceWithRevive<T, TModules[number]> => {\n type ReturnCastType = DeepReplaceWithRevive<T, TModules[number]>\n if (isRevivableBox(value)) {\n const handledByModule = findReviveModule(value, context.revivableModules)\n if (handledByModule) {\n return handledByModule.revive(value, context) as ReturnCastType\n }\n }\n return descend<ReturnCastType>(value, v => recursiveRevive(v, context))\n}","import type { Transport } from '../utils/transport'\nimport type { DefaultRevivableModules, RevivableModule } from '../revivables'\nimport type { DeepReplaceWithBox } from '../utils/replace'\nimport type { ProtocolContext } from './utils'\nimport type {\n Capable, MessageEventTarget, MessageFields,\n MessageVariant, Uuid,\n} from '../types'\n\nimport { recursiveBox, recursiveRevive } from '../revivables'\nimport { isEmitTransport, isReceiveTransport } from '../utils/type-guards'\n\nexport const type = 'bidirectional' as const\n\nexport type InitMessage<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules,\n T extends Capable<TModules> = Capable<TModules>\n> = {\n type: 'init'\n remoteUuid: Uuid\n data: DeepReplaceWithBox<T, TModules[number]>\n}\n\nexport declare const Messages: <\n TModules extends readonly RevivableModule[] = DefaultRevivableModules,\n T extends Capable<TModules> = Capable<TModules>\n>(modules: TModules, value: T) =>\n | InitMessage<TModules, T>\n\nexport type Messages<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules,\n T extends Capable<TModules> = Capable<TModules>\n> = ReturnType<typeof Messages<TModules, T>>\n\nexport type ConnectionContext<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n type: 'bidirectional'\n eventTarget: MessageEventTarget<TModules>\n connection: BidirectionalConnection<TModules>\n}\n\nexport type ConnectionRevivableContext<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n transport: Transport\n remoteUuid: Uuid\n sendMessage: (message: MessageFields & Record<string, unknown>) => void\n revivableModules: TModules\n eventTarget: MessageEventTarget<TModules>\n}\n\nexport const startBidirectionalConnection = <\n TModules extends readonly RevivableModule[] = DefaultRevivableModules,\n>(\n { transport, value, remoteUuid, eventTarget, send, revivableModules }:\n {\n transport: Transport\n value: Capable<TModules>\n remoteUuid: Uuid\n eventTarget: MessageEventTarget<TModules>\n send: (message: MessageFields & Record<string, unknown>) => void\n revivableModules: TModules\n },\n) => {\n const revivableContext = {\n transport,\n remoteUuid,\n sendMessage: send,\n eventTarget,\n revivableModules\n } satisfies ConnectionRevivableContext<TModules>\n\n for (const module of revivableModules) {\n module.init?.(revivableContext)\n }\n\n const { promise, resolve } = Promise.withResolvers<InitMessage<TModules>['data']>()\n\n eventTarget.addEventListener('message', function listener ({ detail }) {\n if (detail.type === 'init') {\n resolve(detail.data)\n eventTarget.removeEventListener('message', listener)\n }\n })\n\n send({\n type: 'init',\n remoteUuid,\n data: recursiveBox(value, revivableContext)\n })\n\n return {\n revivableContext,\n remoteValue:\n promise\n .then(initData => recursiveRevive(initData, revivableContext) as Capable),\n }\n}\n\nexport type BidirectionalConnection<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n revivableContext: ConnectionRevivableContext<TModules>\n remoteValue: Promise<Capable>\n}\n\n/**\n * init() — mounts the bidirectional mode on the shared protocol context.\n * Only activates when the transport can both emit and receive. Owns the\n * announce / close handshake and routes per-connection messages (init /\n * message / message-port-close) to the right connection's eventTarget.\n */\nexport const init = <TModules extends readonly RevivableModule[]>(\n ctx: ProtocolContext<TModules>\n): void => {\n if (!(isEmitTransport(ctx.transport) && isReceiveTransport(ctx.transport))) return\n\n ctx.protocolEventTarget.addEventListener('message', ({ detail: message }) => {\n if (message.type === 'announce') {\n if (!message.remoteUuid) {\n ctx.sendMessage({ type: 'announce', remoteUuid: message.uuid })\n return\n }\n if (message.remoteUuid !== ctx.getUuid()) return\n // Already-tracked uuid is the normal handshake-echo case (the peer\n // re-announcing back at us after we replied to its initial announce),\n // not a uuid collision — silently drop it so we don't double-set up\n // the same connection.\n if (ctx.connectionContexts.has(message.uuid)) return\n // Send announce back so the other side can also create a connection\n // (in case they missed our initial announce due to timing)\n ctx.sendMessage({ type: 'announce', remoteUuid: message.uuid })\n const eventTarget = ctx.createConnectionEventTarget()\n const connectionContext = {\n type: 'bidirectional',\n eventTarget,\n connection:\n startBidirectionalConnection<TModules>({\n transport: ctx.transport,\n value: ctx.value,\n remoteUuid: message.uuid,\n eventTarget,\n send: (m) => ctx.sendMessage(m as MessageVariant),\n revivableModules: ctx.revivableModules\n })\n } satisfies ConnectionContext<TModules>\n ctx.connectionContexts.set(message.uuid, connectionContext)\n connectionContext.connection.remoteValue.then((remoteValue) =>\n ctx.resolveRemoteValue(remoteValue)\n )\n return\n }\n if (message.type === 'close') {\n if (message.remoteUuid !== ctx.getUuid()) return\n ctx.connectionContexts.delete(message.uuid)\n return\n }\n // \"init\" | \"message\" | \"message-port-close\"\n if (message.remoteUuid !== ctx.getUuid()) return\n const connection = ctx.connectionContexts.get(message.uuid)\n // drop messages that arrive before the remote has announced itself,\n // or after its connection has been torn down\n if (!connection) return\n connection.eventTarget.dispatchEvent(\n new CustomEvent('message', { detail: message })\n )\n })\n\n if (ctx.presetRemoteUuid !== undefined) {\n const eventTarget = ctx.createConnectionEventTarget()\n const connectionContext = {\n type: 'bidirectional',\n eventTarget,\n connection:\n startBidirectionalConnection<TModules>({\n transport: ctx.transport,\n value: ctx.value,\n remoteUuid: ctx.presetRemoteUuid,\n eventTarget,\n send: (m) => ctx.sendMessage(m as MessageVariant),\n revivableModules: ctx.revivableModules\n })\n } satisfies ConnectionContext<TModules>\n ctx.connectionContexts.set(ctx.presetRemoteUuid, connectionContext)\n connectionContext.connection.remoteValue.then((remoteValue) =>\n ctx.resolveRemoteValue(remoteValue)\n )\n return\n }\n\n ctx.sendMessage({ type: 'announce' })\n}\n","import type { UnderlyingType } from './type'\n\nexport type EventMap = Record<string, Event>\n\nexport interface TypedEventTarget<T extends EventMap> extends EventTarget {\n [UnderlyingType]?: T\n\n addEventListener<K extends keyof T & string>(\n type: K,\n listener: ((event: T[K]) => void) | null,\n options?: boolean | AddEventListenerOptions\n ): void\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | AddEventListenerOptions\n ): void\n\n removeEventListener<K extends keyof T & string>(\n type: K,\n listener: ((event: T[K]) => void) | null,\n options?: boolean | EventListenerOptions\n ): void\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject | null,\n options?: boolean | EventListenerOptions\n ): void\n}\n\n/**\n * Create a new `TypedEventTarget<T>` for a given event map. Centralises the\n * `EventTarget` → `TypedEventTarget<T>` cast so individual call sites don't\n * each need their own (`EventTarget` lacks the generic event map at the type\n * level, but the runtime behaviour is identical).\n */\nexport const createTypedEventTarget = <T extends EventMap>(): TypedEventTarget<T> =>\n new EventTarget() as TypedEventTarget<T>\n","import { transfer } from '../revivables/transfer'\nimport { isRevivableBox } from '../revivables/utils'\nimport { instanceOfAny, isClonable, isTransferable } from './type-guards'\n\nexport { transfer }\n\n// \"Must-transfer\" types: structured clone cannot copy these, so any occurrence\n// in the outgoing message has to go on the transfer list regardless of whether\n// the user opted in with `transfer()`. MessagePort is the canonical case —\n// cloning one would leave the remote side unable to respond.\nconst isMustTransfer = (value: unknown): value is Transferable =>\n instanceOfAny(value, [\n globalThis.MessagePort,\n globalThis.ReadableStream,\n globalThis.WritableStream,\n globalThis.TransformStream,\n globalThis.OffscreenCanvas,\n ])\n\n// Structural check for a transfer revivable box. Uses the 'transfer' string\n// literal rather than importing the module's exported `type` constant, so the\n// walker stays decoupled from the module's full graph.\n// The `degraded` flag is set by transfer.box() when the platform can't\n// actually transfer — a degraded box is a no-op for the walker.\nconst isTransferBox = (value: unknown): value is { inner: unknown, degraded: boolean } =>\n isRevivableBox(value) && value.type === 'transfer'\n\n/**\n * Walk a boxed message and collect the list of Transferable references that\n * should be moved (rather than cloned) when calling postMessage.\n *\n * The rules are:\n * 1. Must-transfer types (MessagePort, streams, OffscreenCanvas) are always\n * included — structured clone cannot represent them.\n * 2. Clonable types (SharedArrayBuffer) are skipped entirely.\n * 3. Other Transferable types (ArrayBuffer, ImageBitmap) are included only\n * when the walker is inside a non-degraded transfer box — i.e. when the\n * user explicitly opted into move semantics at the send site via\n * transfer() AND the platform supports transferring.\n *\n * The transfer intent is carried on the wire by the transfer revivable box;\n * recognising it structurally here (without importing the module) is all the\n * coupling this file needs.\n */\nexport const getTransferableObjects = (value: unknown): Transferable[] => {\n const transferables: Transferable[] = []\n const seen = new WeakSet<object>()\n\n const recurse = (value: unknown, inTransferBox: boolean): void => {\n if (!value || typeof value !== 'object') return\n if (seen.has(value)) return\n seen.add(value)\n\n if (isClonable(value)) return\n\n if (isTransferBox(value)) {\n // Non-degraded box: flip into transfer mode — every Transferable found\n // below this point on this branch of the walk gets added to the\n // transfer list. Degraded box (platform can't transfer): keep whatever\n // mode we were in, so the wrapper becomes a no-op and the inner gets\n // walked as a normal copy payload.\n recurse(value.inner, inTransferBox || !value.degraded)\n return\n }\n\n if (isMustTransfer(value)) {\n transferables.push(value)\n return\n }\n\n if (isTransferable(value)) {\n if (inTransferBox) {\n transferables.push(value)\n }\n return\n }\n\n // TypedArray / DataView expose every numeric index as an own key — iterating\n // `Object.keys` of a 100 KB buffer touches 100 K entries for no useful\n // result. The underlying buffer is the only thing we could transfer, and\n // that happens via the transfer box / typed-array revivable path anyway.\n if (ArrayBuffer.isView(value)) return\n\n if (Array.isArray(value)) {\n for (const item of value) recurse(item, inTransferBox)\n return\n }\n\n for (const item of Object.values(value)) recurse(item, inTransferBox)\n }\n\n recurse(value, false)\n return transferables\n}\n","import type {\n Message, MessageVariant, Uuid,\n Capable, MessageEventMap\n} from '../types'\nimport type { DefaultRevivableModules, RevivableModule } from '../revivables'\nimport type { Transport } from '../utils/transport'\nimport type { ConnectionContext } from '.'\nimport type { TypedEventTarget } from '../utils/typed-event-target'\n\nimport { defaultRevivableModules } from '../revivables'\nimport { isJsonOnlyTransport, isCustomTransport } from '../utils/type-guards'\n\nexport const normalizeTransport = (transport: Transport): Transport => {\n const isJson =\n 'isJson' in transport && transport.isJson !== undefined\n ? transport.isJson\n : isJsonOnlyTransport(transport)\n const ports =\n isCustomTransport(transport)\n ? transport\n : { emit: transport, receive: transport }\n return { isJson, ...ports } satisfies Transport\n}\n\nexport const mergeRevivableModules = <\n TUserModules extends readonly RevivableModule[]\n>(userModules: TUserModules | undefined) => [\n ...defaultRevivableModules.filter(\n d => !(userModules ?? []).some(u => u.type === d.type),\n ),\n ...(userModules ?? []),\n] as const\n\nexport type ProtocolEventMap<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n message: CustomEvent<Message<TModules>>\n}\n\nexport type ProtocolEventTarget<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = TypedEventTarget<ProtocolEventMap<TModules>>\n\nexport type ProtocolContext<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> = {\n transport: Transport\n value: Capable<TModules>\n revivableModules: TModules\n connectionContexts: Map<string, ConnectionContext<TModules>>\n getUuid: () => Uuid\n presetRemoteUuid?: Uuid\n sendMessage: (message: MessageVariant) => void\n protocolEventTarget: ProtocolEventTarget<TModules>\n resolveRemoteValue: (value: Capable<TModules>) => void\n createConnectionEventTarget: () => TypedEventTarget<MessageEventMap<TModules>>\n}\n\nexport type StartConnectionsOptions<\n TUserModules extends readonly RevivableModule[] = readonly []\n> = {\n transport: Transport\n name?: string\n remoteName?: string\n key?: string\n origin?: string\n unregisterSignal?: AbortSignal\n revivableModules?: TUserModules\n uuid?: Uuid\n remoteUuid?: Uuid\n}\n","import type { DefaultRevivableModules, RevivableModule } from '../revivables'\nimport type { ConnectionContext as BidirectionalConnectionContext } from './bidirectional'\nimport type {\n ProtocolContext,\n StartConnectionsOptions,\n} from '../utils'\nimport type {\n Message, MessageVariant, Uuid,\n Capable,\n} from '../types'\nimport type { MessageContext } from '../utils/transport'\n\nimport { OSRA_DEFAULT_KEY, OSRA_KEY } from '../types'\nimport * as bidirectional from './bidirectional'\nimport {\n isEmitTransport,\n isReceiveTransport,\n} from '../utils/type-guards'\nimport { createTypedEventTarget } from '../utils/typed-event-target'\nimport { getTransferableObjects } from '../utils/transferable'\nimport { registerOsraMessageListener, sendOsraMessage } from '../utils/transport'\nimport { mergeRevivableModules, normalizeTransport } from './utils'\n\nexport * from './bidirectional'\nexport * from './utils'\n\nexport type ConnectionModule<T> = {\n readonly type: string\n // ProtocolContext<any> rather than ProtocolContext<readonly RevivableModule[]>\n // for the same bivariance reason as RevivableModule.box — concrete modules\n // declare narrower context generics than the shared interface can express.\n readonly init: (ctx: ProtocolContext<any>) => void\n readonly Messages?: T\n}\n\nexport const connections = [\n bidirectional\n] as const\n\nexport type DefaultConnectionModules = typeof connections\nexport type DefaultConnectionModule = DefaultConnectionModules[number]\n\nexport type ConnectionMessage<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules,\n T extends Capable<TModules> = Capable<TModules>\n> =\n DefaultConnectionModule extends {\n Messages: (modules: TModules, value: T) => infer R\n }\n ? R\n : never\n\nexport type ConnectionContext<\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> =\n | BidirectionalConnectionContext<TModules>\n\nexport const startConnections = <\n T = unknown,\n const TUserModules extends readonly RevivableModule[] = readonly []\n>(\n value: Capable<[...DefaultRevivableModules, ...TUserModules]>,\n {\n transport: _transport,\n name,\n remoteName,\n key = OSRA_DEFAULT_KEY,\n origin = '*',\n unregisterSignal,\n revivableModules: _userRevivableModules,\n uuid: _uuid,\n remoteUuid: presetRemoteUuid,\n }: StartConnectionsOptions<TUserModules>\n): Promise<T> => {\n const transport = normalizeTransport(_transport)\n const mergedRevivableModules = mergeRevivableModules(_userRevivableModules)\n type MergedModules = typeof mergedRevivableModules\n const connectionContexts = new Map<string, ConnectionContext<MergedModules>>()\n\n const { promise: remoteValuePromise, resolve: resolveRemoteValue } =\n Promise.withResolvers<Capable<MergedModules>>()\n\n const uuid: Uuid = _uuid ?? globalThis.crypto.randomUUID()\n\n const sendMessage = (message: MessageVariant) => {\n if (unregisterSignal?.aborted) return\n if (!isEmitTransport(transport)) return\n const envelope = { [OSRA_KEY]: key, name, uuid, ...message }\n sendOsraMessage(transport, envelope, origin, getTransferableObjects(envelope))\n }\n\n const protocolEventTarget = createTypedEventTarget<{ message: CustomEvent<Message<MergedModules>> }>()\n\n const ctx: ProtocolContext<MergedModules> = {\n transport,\n value: value as Capable<MergedModules>,\n revivableModules: mergedRevivableModules,\n connectionContexts,\n getUuid: () => uuid,\n presetRemoteUuid,\n sendMessage,\n protocolEventTarget,\n resolveRemoteValue,\n createConnectionEventTarget: createTypedEventTarget,\n }\n\n const listener = (message: Message<MergedModules>, _: MessageContext) => {\n // own message looped back on the channel\n if (message.uuid === uuid) return\n protocolEventTarget.dispatchEvent(\n new CustomEvent('message', { detail: message }),\n )\n }\n\n if (isReceiveTransport(transport)) {\n registerOsraMessageListener({\n listener,\n transport,\n remoteName,\n key,\n unregisterSignal\n })\n }\n\n for (const connectionModule of connections) {\n connectionModule.init(ctx)\n }\n\n return remoteValuePromise as Promise<T>\n}\n","import type { Capable } from './types'\nimport type { DefaultRevivableModules } from './revivables'\nimport type { RevivableModule } from './revivables'\nimport type { StartConnectionsOptions } from './connections/utils'\nimport type {\n BadFieldValue, BadFieldPath, BadFieldParent,\n ErrorMessage, BadValue, Path, ParentObject\n} from './utils/capable-check'\n\nimport { startConnections } from './utils'\n\nexport * from './types'\nexport * from './revivables'\nexport * from './connections'\nexport * from './utils'\n\ntype CapableCheck<\n T,\n TModules extends readonly RevivableModule[] = DefaultRevivableModules\n> =\n T extends Capable<TModules>\n ? T\n : T & {\n [ErrorMessage]: 'Value type must resolve to a Capable'\n [BadValue]: BadFieldValue<T, Capable<TModules>>\n [Path]: BadFieldPath<T, Capable<TModules>>\n [ParentObject]: BadFieldParent<T, Capable<TModules>>\n }\n\nexport const expose = async <\n T = unknown,\n const TUserModules extends readonly RevivableModule[] = readonly [],\n const TValue = Capable<[...DefaultRevivableModules, ...TUserModules]>\n>(\n value: CapableCheck<TValue, [...DefaultRevivableModules, ...TUserModules]>,\n options: StartConnectionsOptions<TUserModules>\n): Promise<T> =>\n startConnections<T, TUserModules>(\n value as Capable<[...DefaultRevivableModules, ...TUserModules]>,\n options\n )\n"],"mappings":"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"}
|