{"version":3,"file":"SyncChannel.mjs","names":[],"sources":["../src/sync/channel/connect.ts","../src/sync/channel/listen.ts"],"sourcesContent":["/**\n * SyncChannel connection APIs.\n * Provides functions for connecting, attaching, and checking sync channel status.\n *\n * @module\n */\n\nimport { Err, Ok, RESULT_VOID, type AsyncIOResult, type VoidIOResult } from 'happy-rusty';\nimport { Future } from 'tiny-future';\nimport { TIMEOUT_ERROR } from '../../shared/mod.ts';\nimport type { AttachSyncChannelOptions, ConnectSyncChannelOptions } from '../../shared/mod.ts';\nimport { SyncMessenger } from '../protocol.ts';\nimport { getSyncChannelState, setGlobalSyncOpTimeout, setMessenger, setSyncChannelState } from './state.ts';\n\n// #region Internal Variables\n\n/**\n * Default size of SharedArrayBuffer in bytes (1MB).\n */\nconst DEFAULT_BUFFER_LENGTH = 1024 * 1024;\n\n/**\n * Minimum required buffer size in bytes.\n * 16 bytes header + ~131 bytes for largest error response = 147 bytes.\n * Using 256 (power of 2) for better memory alignment.\n */\nconst MIN_BUFFER_LENGTH = 256;\n\n/**\n * Default timeout for sync operations in milliseconds.\n */\nconst DEFAULT_OP_TIMEOUT = 1000;\n\n/**\n * Default timeout for establishing the connection in milliseconds.\n * Covers worker startup, script load, and `SyncChannel.listen()` readiness.\n */\nconst DEFAULT_CONNECT_TIMEOUT = 10000;\n\n// #endregion\n\n/**\n * Connects to a worker and establishes a sync channel for synchronous file system operations.\n * Must be called before using any sync API functions.\n *\n * @param worker - The worker to communicate with. Can be a `Worker` instance, a `URL`, or a URL string.\n * @param options - Optional configuration options for the sync channel.\n * @returns A promise that resolves with an `AsyncIOResult` containing the `SharedArrayBuffer` when the worker is ready.\n *          The returned buffer can be shared with other contexts (e.g., iframes) via `postMessage`.\n * @since 1.1.0\n * @example\n * ```typescript\n * // Connect to worker and get SharedArrayBuffer\n * const result = await SyncChannel.connect(\n *     new URL('./worker.js', import.meta.url),\n *     { sharedBufferLength: 1024 * 1024, opTimeout: 5000, connectTimeout: 10000 }\n * );\n * result.inspect(sharedBuffer => {\n *     // Share with iframe\n *     iframe.contentWindow.postMessage({ sharedBuffer }, '*');\n * });\n * ```\n */\nexport async function connectSyncChannel(worker: Worker | URL | string, options?: ConnectSyncChannelOptions): AsyncIOResult<SharedArrayBuffer> {\n    const state = getSyncChannelState();\n    if (state === 'ready') {\n        return Err(new Error('Sync channel already connected'));\n    }\n    if (state === 'connecting') {\n        return Err(new Error('Sync channel is connecting'));\n    }\n\n    const {\n        sharedBufferLength = DEFAULT_BUFFER_LENGTH,\n        opTimeout = DEFAULT_OP_TIMEOUT,\n        connectTimeout = DEFAULT_CONNECT_TIMEOUT,\n    } = options ?? {};\n\n    // check parameters\n    if (!(worker instanceof Worker || worker instanceof URL || (typeof worker === 'string' && worker))) {\n        return Err(new TypeError('worker must be a Worker, URL, or non-empty string'));\n    }\n    if (!(sharedBufferLength >= MIN_BUFFER_LENGTH && sharedBufferLength % 4 === 0)) {\n        return Err(new TypeError('sharedBufferLength must be at least 256 and a multiple of 4'));\n    }\n    if (!(Number.isInteger(opTimeout) && opTimeout > 0)) {\n        return Err(new TypeError('opTimeout must be a positive integer'));\n    }\n    if (!(Number.isInteger(connectTimeout) && connectTimeout > 0)) {\n        return Err(new TypeError('connectTimeout must be a positive integer'));\n    }\n\n    // May throw if worker url is invalid\n    let workerAdapter: Worker;\n    try {\n        workerAdapter = worker instanceof Worker\n            ? worker\n            : new Worker(worker);\n    } catch (e) {\n        return Err(e as Error);\n    }\n\n    // Set state after all validations pass\n    setSyncChannelState('connecting');\n    setGlobalSyncOpTimeout(opTimeout);\n\n    const sab = new SharedArrayBuffer(sharedBufferLength);\n    const channel = new MessageChannel();\n    const future = new Future<SharedArrayBuffer>();\n\n    // Whether this function created the worker. Only owned workers may be\n    // terminated on failure; caller-supplied Workers are left intact.\n    const ownsWorker = !(worker instanceof Worker);\n\n    // Shared teardown: clear the timer and detach all event sources\n    // (error listener + port onmessage). Called exactly once — success and\n    // failure paths below are the only callers, and teardown detaches every\n    // other event source, so no second caller can reach teardown again.\n    const teardown = (): void => {\n        clearTimeout(timer);\n        workerAdapter.removeEventListener('error', onError);\n        channel.port1.onmessage = null;\n    };\n\n    // Failure path: close port, terminate owned worker, reset state so the\n    // caller may retry, and reject the future — connectSyncChannel returns\n    // Err instead of hanging forever when the worker never calls\n    // SyncChannel.listen().\n    const cleanup = (reason: unknown): void => {\n        teardown();\n        channel.port1.close();\n        if (ownsWorker) {\n            workerAdapter.terminate();\n        }\n        setSyncChannelState('idle');\n        future.reject(reason);\n    };\n\n    const onError = (e: ErrorEvent): void => {\n        cleanup(e.error ?? new Error(e.message || 'Worker failed to load'));\n    };\n\n    const timer = setTimeout(\n        () => cleanup(new DOMException('Sync channel connection timed out', TIMEOUT_ERROR)),\n        connectTimeout,\n    );\n\n    workerAdapter.addEventListener('error', onError);\n\n    // Use MessageChannel for the one-shot handshake only: worker sends a\n    // single null payload via port2 once it has called SyncChannel.listen()\n    // (see listen.ts). After that, all further communication goes through\n    // the SharedArrayBuffer-based SyncMessenger, not this port — so the\n    // onmessage handler fires exactly once and is detached by teardown().\n    // port1 stays in main thread, port2 is transferred to worker.\n    channel.port1.onmessage = (): void => {\n        teardown();\n        setMessenger(new SyncMessenger(sab));\n        future.resolve(sab);\n    };\n\n    workerAdapter.postMessage({ port: channel.port2, sab }, [channel.port2]);\n\n    try {\n        return Ok(await future.promise);\n    } catch (e) {\n        // future.reject path already cleaned up state/resources\n        return Err(e as Error);\n    }\n}\n\n/**\n * Checks if the sync channel is ready to use.\n *\n * @returns `true` if ready, `false` otherwise.\n * @since 1.11.0\n * @example\n * ```typescript\n * if (!SyncChannel.isReady()) {\n *     await SyncChannel.connect(new URL('./worker.js', import.meta.url));\n * }\n * ```\n */\nexport function isSyncChannelReady(): boolean {\n    return getSyncChannelState() === 'ready';\n}\n\n/**\n * Attaches to an existing `SharedArrayBuffer` for synchronous file system operations.\n * Used to share a sync channel connection with other contexts (e.g., iframes).\n *\n * After calling this function, sync APIs (e.g., `readFileSync`, `writeFileSync`)\n * can be used in the current context without calling `connect`.\n *\n * @param sharedBuffer - The `SharedArrayBuffer` received from another context.\n * @param options - Optional configuration options.\n * @returns A `VoidIOResult` indicating success or failure.\n * @since 1.8.5\n * @example\n * ```typescript\n * // In iframe: receive SharedArrayBuffer from main page\n * window.addEventListener('message', (event) => {\n *     if (event.data.sharedBuffer) {\n *         const result = SyncChannel.attach(event.data.sharedBuffer, { opTimeout: 5000 });\n *         if (result.isOk()) {\n *             // Now sync APIs can be used\n *             const fileResult = readTextFileSync('/data/file.txt');\n *         }\n *     }\n * });\n * ```\n */\nexport function attachSyncChannel(sharedBuffer: SharedArrayBuffer, options?: AttachSyncChannelOptions): VoidIOResult {\n    const state = getSyncChannelState();\n    if (state === 'connecting') {\n        return Err(new Error('Cannot attach: sync channel is connecting'));\n    }\n\n    if (!(sharedBuffer instanceof SharedArrayBuffer)) {\n        return Err(new TypeError('sharedBuffer must be a SharedArrayBuffer'));\n    }\n\n    const { opTimeout = DEFAULT_OP_TIMEOUT } = options ?? {};\n    if (!(Number.isInteger(opTimeout) && opTimeout > 0)) {\n        return Err(new TypeError('opTimeout must be a positive integer'));\n    }\n\n    setGlobalSyncOpTimeout(opTimeout);\n    setMessenger(new SyncMessenger(sharedBuffer));\n\n    return RESULT_VOID;\n}\n","import { Err, RESULT_VOID, type AsyncIOResult, type VoidIOResult } from 'happy-rusty';\nimport {\n    copy, createFile,\n    deleteTemp,\n    emptyDir, exists,\n    mkdir, mkTemp, move,\n    pruneTemp,\n    readBlobFile, readDir, readFile, remove,\n    stat,\n    truncate,\n    unzip,\n    writeFile,\n    zip,\n} from '../../async/mod.ts';\nimport { readBlobBytesSync } from '../../shared/internal/mod.ts';\nimport { isFileHandle, type DirEntry, type DirEntryLike, type FileSystemDirectoryHandleLike, type FileSystemFileHandleLike, type FileSystemHandleLike } from '../../shared/mod.ts';\nimport type { ErrorLike, FileMetadata } from '../defines.ts';\nimport { DATA_INDEX, decodePayload, encodePayload, MAIN_LOCK_INDEX, MAIN_UNLOCKED, SyncMessenger, WORKER_LOCK_INDEX, WORKER_UNLOCKED, WorkerOp } from '../protocol.ts';\n\n// #region Internal Variables\n\n/**\n * Worker thread locked value.\n * Default.\n */\nconst WORKER_LOCKED = MAIN_UNLOCKED;\n\n/**\n * Mapping of async operation enums to their corresponding OPFS functions.\n * Used by the worker loop to dispatch operations from the main thread.\n *\n * Key: `WorkerOp` value\n * Value: The async function to execute\n */\nconst opHandlers = {\n    [WorkerOp.createFile]: createFile,\n    [WorkerOp.mkdir]: mkdir,\n    [WorkerOp.move]: move,\n    [WorkerOp.readDir]: readDir,\n    [WorkerOp.readFile]: readFile,\n    [WorkerOp.remove]: remove,\n    [WorkerOp.stat]: stat,\n    [WorkerOp.truncate]: truncate,\n    [WorkerOp.writeFile]: writeFile,\n    [WorkerOp.copy]: copy,\n    [WorkerOp.emptyDir]: emptyDir,\n    [WorkerOp.exists]: exists,\n    [WorkerOp.deleteTemp]: deleteTemp,\n    [WorkerOp.mkTemp]: mkTemp,\n    [WorkerOp.pruneTemp]: pruneTemp,\n    [WorkerOp.readBlobFile]: readBlobFile,\n    [WorkerOp.unzip]: unzip,\n    [WorkerOp.zip]: zip,\n};\n\n/**\n * Cache the messenger instance.\n */\nlet messenger: SyncMessenger;\n\n/**\n * Flag to track if listenSyncChannel has been called.\n * Used to prevent multiple event listeners from being registered.\n */\nlet isListening = false;\n\n// #endregion\n\n/**\n * Starts listening for sync channel requests in a Web Worker.\n * Waits for a SharedArrayBuffer from the main thread and begins processing requests.\n *\n * @returns A `VoidIOResult` indicating success or failure.\n * @since 1.1.0\n * @example\n * ```typescript\n * // In worker.js\n * import { SyncChannel } from 'happy-opfs';\n * const result = SyncChannel.listen();\n * if (result.isErr()) {\n *     console.error('Failed to start listening:', result.unwrapErr());\n * }\n * ```\n */\nexport function listenSyncChannel(): VoidIOResult {\n    if (!isWorkerRuntime()) {\n        return Err(new Error('listenSyncChannel can only be called in Worker'));\n    }\n    if (isListening) {\n        return Err(new Error('Sync channel already listening'));\n    }\n\n    isListening = true;\n\n    const messageHandler = (event: MessageEvent<unknown>): void => {\n        const { data } = event;\n\n        // Ignore messages that are not SyncChannelInitMessage\n        if (!isSyncChannelInitMessage(data)) {\n            return;\n        }\n\n        // Remove listener after receiving valid init message\n        removeEventListener('message', messageHandler);\n\n        const { port, sab } = data;\n\n        messenger = new SyncMessenger(sab);\n\n        // Notify main thread that the worker is ready. This MessagePort is\n        // used for the one-shot handshake only — after this, requests and\n        // responses flow through the SharedArrayBuffer-based SyncMessenger.\n        // The main thread detaches port1.onmessage after receiving this signal.\n        port.postMessage(null);\n\n        // Start waiting for requests\n        runWorkerLoop();\n    };\n\n    addEventListener('message', messageHandler);\n\n    return RESULT_VOID;\n}\n\n// #region Internal Types\n\n/**\n * Message sent from main thread to worker to initialize sync channel.\n * Uses MessageChannel for isolated communication.\n */\ninterface SyncChannelInitMessage {\n    /**\n     * MessagePort for dedicated communication back to main thread.\n     */\n    port: MessagePort;\n    /**\n     * SharedArrayBuffer for cross-thread synchronous communication.\n     */\n    sab: SharedArrayBuffer;\n}\n\n// #endregion\n\n// #region Internal Functions\n\n/**\n * Checks whether the code is running in a Web Worker context.\n */\nfunction isWorkerRuntime(): boolean {\n    return typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;\n}\n\n/**\n * Type guard to check if a message is a SyncChannelInitMessage.\n * @param data - The message data to check.\n * @returns `true` if the message is a valid SyncChannelInitMessage.\n */\nfunction isSyncChannelInitMessage(data: unknown): data is SyncChannelInitMessage {\n    if (data == null || typeof data !== 'object') {\n        return false;\n    }\n\n    const message = data as SyncChannelInitMessage;\n    return message.port instanceof MessagePort && message.sab instanceof SharedArrayBuffer;\n}\n\n/**\n * Serializes a `FileSystemHandle` to a plain object for cross-thread communication.\n *\n * @param handle - `FileSystemHandle` object.\n * @returns Serializable version of FileSystemHandle that is FileSystemHandleLike.\n */\nasync function serializeFileSystemHandle(handle: FileSystemHandle): Promise<FileSystemHandleLike> {\n    const { name } = handle;\n\n    if (isFileHandle(handle)) {\n        const file = await handle.getFile();\n        const { size, lastModified, type } = file;\n\n        const fileHandle: FileSystemFileHandleLike = {\n            name,\n            kind: 'file',\n            type,\n            size,\n            lastModified,\n        };\n\n        return fileHandle;\n    }\n\n    const handleLike: FileSystemDirectoryHandleLike = {\n        name,\n        kind: 'directory',\n    };\n\n    return handleLike;\n}\n\n/**\n * Serializes an `Error` object to a plain object for cross-thread communication.\n *\n * @param error - The `Error` object to serialize, or `null`.\n * @returns A serializable `ErrorLike` object, or `null` if input is `null`.\n */\nfunction serializeError(error: Error | null): ErrorLike | null {\n    return error ? {\n        name: error.name,\n        message: error.message,\n    } : error;\n}\n\n/**\n * Handles incoming requests from main thread and sends responses.\n * This function runs in the worker thread and processes one request.\n *\n * @param messenger - The `SyncMessenger` instance for communication.\n * @param transfer - Async function that processes request data and returns response data.\n */\nasync function respondToMainFromWorker(messenger: SyncMessenger, transfer: (data: Uint8Array<SharedArrayBuffer>) => Promise<Uint8Array<ArrayBuffer>>): Promise<void> {\n    const { i32a, maxDataLength } = messenger;\n\n    // Busy-wait until main thread signals a request is ready\n    // Using busy-wait instead of Atomics.wait() because Atomics.notify() may not work reliably cross-thread\n    while (true) {\n        if (Atomics.load(i32a, WORKER_LOCK_INDEX) === WORKER_UNLOCKED) {\n            break;\n        }\n    }\n\n    // payload and length\n    const requestLength = i32a[DATA_INDEX];\n    const data = messenger.getPayload(requestLength);\n\n    // call async I/O operation\n    let response = await transfer(data);\n\n    // check whether response is too large\n    if (response.byteLength > maxDataLength) {\n        const message = `Response is too large: ${ response.byteLength } > ${ maxDataLength }. Consider increasing the size of SharedArrayBuffer`;\n\n        // Error response is guaranteed to fit since bufferLength >= 256 bytes\n        // and error response is ~147 bytes (16 header + 131 payload)\n        response = encodePayload([{\n            name: 'RangeError',\n            message,\n        }]);\n    }\n\n    // write response data\n    i32a[DATA_INDEX] = response.byteLength;\n    messenger.setPayload(response);\n\n    // lock worker thread\n    Atomics.store(i32a, WORKER_LOCK_INDEX, WORKER_LOCKED);\n\n    // wakeup main thread\n    Atomics.store(i32a, MAIN_LOCK_INDEX, MAIN_UNLOCKED);\n}\n\n/**\n * Deserializes request arguments based on operation type.\n * Binary data is received as the last element from the binary protocol.\n *\n * @param op - The operation type.\n * @param args - The arguments to deserialize.\n */\nfunction deserializeArgs(op: WorkerOp, args: unknown[]): void {\n    switch (op) {\n        case WorkerOp.writeFile: {\n            // Request format: [filePath, options?, Uint8Array]\n            // Expected args: [filePath, Uint8Array, options?]\n            // Move Uint8Array from last position to second position\n            const data = args.pop();\n            const options = args[1];\n            args[1] = data;\n            args[2] = options;\n            break;\n        }\n        case WorkerOp.readFile: {\n            // Always use bytes encoding (default) - adapter handles encoding conversion\n            // This avoids double encoding/decoding for utf8 (string -> bytes -> string)\n            args.length = 1;\n            break;\n        }\n        case WorkerOp.pruneTemp: {\n            // Date was serialized as ISO string, reconstruct Date object\n            args[0] = new Date(args[0] as Date);\n            break;\n        }\n        // Other operations need no deserialization\n    }\n}\n\n/**\n * Serializes a readDir result (async iterator) to an array of DirEntryLike.\n * Uses parallel processing for better performance since getFile() involves disk I/O.\n *\n * @param iterator - The async iterator from readDir.\n * @returns Promise resolving to array of serializable directory entries.\n */\nasync function serializeReadDirResult(iterator: AsyncIterableIterator<DirEntry>): Promise<DirEntryLike[]> {\n    // Collect and serialize handles in parallel - getFile() involves disk I/O\n    const tasks: Promise<DirEntryLike>[] = [];\n\n    for await (const { path, handle } of iterator) {\n        tasks.push((async () => ({\n            path,\n            handle: await serializeFileSystemHandle(handle),\n        }))());\n    }\n\n    return Promise.all(tasks);\n}\n\n/**\n * Serializes readBlobFile result to [metadata, Uint8Array] for binary protocol.\n *\n * @param file - The File object from readBlobFile.\n * @returns Array of [metadata, bytes] to be spread into response.\n */\nfunction serializeReadBlobFileResult(file: File): [FileMetadata, Uint8Array<ArrayBuffer>] {\n    const metadata: FileMetadata = {\n        name: file.name,\n        type: file.type,\n        lastModified: file.lastModified,\n    };\n    return [metadata, readBlobBytesSync(file)];\n}\n\n/**\n * Processes a single request from the main thread.\n *\n * @param data - The encoded request data.\n * @returns The encoded response data.\n */\nasync function processRequest(data: Uint8Array<SharedArrayBuffer>): Promise<Uint8Array<ArrayBuffer>> {\n    try {\n        // Decode the request: [operation, ...arguments]\n        const [op, ...args] = decodePayload<[WorkerOp, ...Parameters<typeof opHandlers[WorkerOp]>]>(data);\n\n        deserializeArgs(op, args);\n\n        const handle = opHandlers[op] as (...args: unknown[]) => AsyncIOResult<unknown>;\n        const res = await handle(...args);\n\n        if (res.isErr()) {\n            // Operation failed - encode error only: [serializedError]\n            return encodePayload([serializeError(res.unwrapErr())]);\n        }\n\n        const result = res.unwrap();\n        // Build response array: [null (no error), ...serialized result]\n        const response: [null, ...unknown[]] = [null];\n\n        // Serialize result based on operation type\n        switch (op) {\n            case WorkerOp.stat: {\n                response.push(await serializeFileSystemHandle(result as FileSystemHandle));\n                break;\n            }\n            case WorkerOp.readDir: {\n                response.push(await serializeReadDirResult(result as AsyncIterableIterator<DirEntry>));\n                break;\n            }\n            case WorkerOp.readBlobFile: {\n                response.push(...serializeReadBlobFileResult(result as File));\n                break;\n            }\n            default: {\n                // Result is void, boolean, string, or Uint8Array\n                response.push(result);\n            }\n        }\n\n        return encodePayload(response);\n    } catch (e) {\n        return encodePayload([serializeError(e as Error)]);\n    }\n}\n\n/**\n * Main loop that continuously processes requests from the main thread.\n * Runs indefinitely until the worker is terminated.\n */\nasync function runWorkerLoop(): Promise<void> {\n    // No try-catch needed:\n    // - processRequest catches all exceptions and returns encoded error response\n    // - respondToMainFromWorker never throws (error response always fits in buffer >= 256 bytes)\n    while (true) {\n        await respondToMainFromWorker(messenger, processRequest);\n    }\n}\n\n// #endregion\n"],"mappings":"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"}