import type { HttpHandler } from "@statewalker/webrun-http-streams"; import { type PortWebSocketClass, type WebSocketClassOptions, type WebSocketConnection } from "../ws/client.js"; import { KEEPALIVE_MESSAGE, WAKE_MESSAGE } from "./protocol.js"; export interface SwHttpAdapterOptions { /** The first path segment under the scope that this page's handlers serve. */ key: string; scope?: string; serviceWorkerUrl?: string; /** * Upper bound, in ms, for `start()`'s wait for the worker to activate, take * control of the page and answer the handshake. `start()` rejects with a * `ServiceWorkerControlError` past it instead of waiting forever. * Default `DEFAULT_SERVICE_WORKER_TIMEOUT` (30 s). */ timeout?: number; /** * If the page is still uncontrolled once the worker is active — after a * hard reload, say — and the worker does not take it over when asked, * reload the page once instead of rejecting. Default `false`. */ reloadIfUncontrolled?: boolean; /** * Per-stream inactivity timeout of the links, in ms (webrun-rpc's): a * request or response body with no chunk for that long fails. Unset — the * default — means none: a slow reader is throttled, never failed. */ streamTimeout?: number; /** The handler slot of this page's own handlers. Default: one per adapter. */ id?: string; /** What a `route` function in the ServiceWorker sees of this page's handlers. */ meta?: unknown; /** Options of the `WebSocket` class (`adapter.WebSocket`). */ webSocket?: WebSocketClassOptions; /** @deprecated Version 1 only; ignored. */ bindPort?: (port: MessagePort) => void | Promise; } export interface SwHttpRegistration { baseUrl: string; prefix: string; remove(): Promise; } export interface AttachWorkerOptions { /** The key the worker serves. Default: the adapter's. */ key?: string; /** The handler slot. Attaching an id the key has already replaces it. Default: a fresh one. */ id?: string; /** What a `route` function sees of this handler. */ meta?: unknown; } /** A Dedicated Worker attached as a handler. */ export interface WorkerLink { readonly key: string; readonly id: string; /** Token of this attachment; `drain` and `detach` name it. */ readonly owner: string; /** * Hand-over: the worker gets no new requests (they wait for the next owner * of the slot), and those in flight may finish for up to `ms`. Then the * link is closed. */ drain(options?: { ms?: number; }): Promise; /** Removes the link now. Requests in flight fail. */ detach(): Promise; } /** * The page side of the same-origin ServiceWorker: registers the worker, and * attaches handler links to it. * * - `register(prefix, handler)` serves a handler in this page, under * `//...`. * - `attachWorker(worker)` links a Dedicated Worker that runs * `serveHttpInWorker(handler)`: the ServiceWorker then talks to the worker * directly, and this page carries nothing. * - `connectWebSocket(url, protocols)` and `WebSocket` open sockets to * handlers, through the ServiceWorker or straight to a handler of this page. * * Links are attached again whenever the ServiceWorker asks (after a restart), * and requests in flight on a handler that dies fail at once. */ export declare class SwHttpAdapter { readonly options: SwHttpAdapterOptions; private readonly _handlers; private readonly _endpoint; private readonly _ownerLock; private readonly _id; private readonly _owner; private readonly _workers; private _releaseOwner?; private _serviceWorkerUrl?; private _serviceWorker?; private _registration?; private _registrationPromise?; private _cleanup; private _attaching?; private _routerLock?; private _WebSocket?; constructor(options: SwHttpAdapterOptions); get key(): string; get scope(): string; /** * The scope as a url on the worker's origin. Resolved against the worker's * own url when one is given, not against this module's: a bundle that is * not an ES module (an IIFE, Theia's frontend) has no `import.meta.url`, and * `new URL(scope, undefined)` threw `Invalid URL` there. Only without a * worker url does the module's location decide (its default `sw-worker.js` * sits next to it). */ get rootUrl(): URL; get serviceWorkerUrl(): string; /** * Registers the worker and waits until it is activated and controls this * page, then attaches this page's handler link. The page must be controlled, * because only a controlled page's `fetch()` reaches the worker. When the * page loaded uncontrolled (a hard reload does that), the worker is asked to * claim it. Rejects with a `ServiceWorkerControlError` when that fails or * `timeout` passes (`reason` says which step); a later `start()` tries * again. */ start(): Promise; /** Detaches every link, and unregisters the worker. */ stop(): Promise; /** * Registers an HTTP handler on a prefix. Returns the resulting base URL and a * disposer. */ register(prefix: string, handler: HttpHandler): Promise; /** * Links a Dedicated Worker that runs `serveHttpInWorker(handler)` as a * handler of `key`. The ServiceWorker sends it requests directly, without * this page relaying anything, so a busy or throttled page does not slow * them down. */ attachWorker(worker: Worker, options?: AttachWorkerOptions): Promise; /** * Opens the transport of a socket to the handler `url` routes to: a handler * of this page directly, any other through the ServiceWorker. Resolves once * the handler accepted. An arrow function, so it can be handed around: * `createWebSocketClass(adapter.connectWebSocket)`. */ connectWebSocket: (url: string | URL, protocols?: string[]) => Promise; /** * A WHATWG `WebSocket` class whose sockets reach this adapter's handlers: * `new adapter.WebSocket(`${baseUrl}chat`, ["v1"])`. The global * `WebSocket` is left alone. */ get WebSocket(): PortWebSocketClass; /** * Attaches again every link not made for the router holding * `currentRouterLock` (every link, without it). The ServiceWorker asks for * this after a restart; a page may call it too. */ relink(currentRouterLock?: string): Promise; /** @internal Posts a plain message to the ServiceWorker, which starts it if stopped. */ _poke(type: typeof WAKE_MESSAGE | typeof KEEPALIVE_MESSAGE): void; /** @internal */ _worker(): ServiceWorker; /** @internal */ _forget(link: WorkerLinkImpl): void; /** @internal How long a call to the ServiceWorker may take. */ _callTimeout(): number; private _attachPage; private _findHandler; private _handleHttpRequest; } declare class WorkerLinkImpl implements WorkerLink { private readonly _adapter; private readonly _control; readonly key: string; readonly id: string; readonly owner: string; routerLock?: string; private readonly _meta; private readonly _ownerLock?; private _attaching?; private _detached; constructor(_adapter: SwHttpAdapter, _control: MessagePort, init: { key: string; id: string; owner: string; meta?: unknown; ownerLock?: string; }); /** * Forgets this link without telling the ServiceWorker: another attachment * took its slot, and the ServiceWorker retires it by itself. */ retire(): void; /** Makes fresh channels and attaches them; the worker gets its ends. */ attach(): Promise; drain({ ms }?: { ms?: number; }): Promise; detach(): Promise; private _unlink; } export {}; //# sourceMappingURL=sw-http-adapter.d.ts.map