/// import { PostMessageChannel } from "./channel"; import { Name } from "./name"; import { Remotable } from "./remotable"; import { RPCSession } from "./session"; import { createServiceProxy } from "./service"; /** * Represents a constructor function for a Conduit-based WebWorker. */ type Constructor = { new(): T }; /** * Decorate a class as a Conduit-based Web Worker. * * This overload is compatible with Webpack and other bundlers which * use static code analysis to enable the worker to be placed in its own chunk. * * @unstable Caution: This API may change in minor or patch releases until it is marked as stable. * @environment Browser only * @param workerFactory A function which creates the Worker object. For instance, `() => new Worker(new URL('./my-worker', import.meta.url))`. */ export function WebWorker(workerFactory: () => Worker); /** * Decorate a class as a Conduit-based Web Worker. * * Caution: This overload is not compatible with Webpack and other bundlers which use static code analysis to * enable the worker to be placed in its own chunk. Instead, use the overload which accepts a `workerFactory` * * @unstable Caution: This API may change in minor or patch releases until it is marked as stable. * @environment Browser only * @param url The URL where this worker can be found when it is loaded from within the browser context. You may be * able to use `import.meta.url` for this depending on your build system. * @param options The options to use when constructing the `Worker` instance. */ export function WebWorker(url: string, options?: WorkerOptions); export function WebWorker(factoryOrUrl: string | (() => Worker), options?: WorkerOptions) { const factory = typeof factoryOrUrl === 'string' ? () => new Worker(factoryOrUrl, options) : factoryOrUrl; return (target: any) => { Reflect.defineMetadata('conduit:worker:factory', factory, target); Name('org.webrpc.worker')(target); Remotable()(target); if (isWorkerSide()) { new RPCSession(new PostMessageChannel(globalThis)) .registerService(target); } }; } /** * Create a new instance of the given Conduit-based WebWorker within the current browser environment. * * @unstable Caution: This API may change in minor or patch releases until it is marked as stable. * @environment Browser only * @param workerClass * @returns */ WebWorker.start = function startConduitWorker(workerClass: Constructor) { let $webWorker = factoryForConduitWorker(workerClass)(); let $session = new RPCSession(new PostMessageChannel($webWorker)); return createServiceProxy(Promise.resolve($session), workerClass, { /** * The Conduit RPCSession object associated with this web worker. */ $session, /** * The Web Platform `Worker` instance, which can be used for low level control of the web worker. */ $webWorker, /** * Aborts worker's associated global environment. * @returns */ $terminate: () => $webWorker.terminate() }); }; function factoryForConduitWorker(workerClass: Constructor) { return Reflect.getMetadata('conduit:worker:factory', workerClass) as () => Worker; }; function isWorkerSide() { return typeof globalThis['window'] === 'undefined' && typeof globalThis['WorkerGlobalScope'] !== 'undefined'; }