// ../../node_modules/.pnpm/capnweb@0.1.0/node_modules/capnweb/dist/index.js if (!Symbol.dispose) { Symbol.dispose = Symbol.for("dispose"); } if (!Symbol.asyncDispose) { Symbol.asyncDispose = Symbol.for("asyncDispose"); } var workersModuleName = navigator.userAgent === "Cloudflare-Workers" ? "cloudflare:workers" : null; var workersModule; if (workersModuleName) { workersModule = await import( /* @vite-ignore */ workersModuleName ); } var RpcTarget = workersModule ? workersModule.RpcTarget : class { }; function typeForRpc(value) { switch (typeof value) { case "boolean": case "number": case "string": return "primitive"; case "undefined": return "undefined"; case "object": case "function": break; case "bigint": return "bigint"; default: return "unsupported"; } if (value === null) { return "primitive"; } let prototype = Object.getPrototypeOf(value); switch (prototype) { case Object.prototype: return "object"; case Function.prototype: return "function"; case Array.prototype: return "array"; case Date.prototype: return "date"; case Uint8Array.prototype: return "bytes"; // TODO: All other structured clone types. case RpcStub.prototype: return "stub"; case RpcPromise.prototype: return "rpc-promise"; // TODO: Promise or thenable default: if (workersModule) { if (prototype == workersModule.RpcStub.prototype || value instanceof workersModule.ServiceStub) { return "rpc-target"; } else if (prototype == workersModule.RpcPromise.prototype || prototype == workersModule.RpcProperty.prototype) { return "rpc-thenable"; } } if (value instanceof RpcTarget) { return "rpc-target"; } if (value instanceof Error) { return "error"; } return "unsupported"; } } function mapNotLoaded() { throw new Error("RPC map() implementation was not loaded."); } var mapImpl = { applyMap: mapNotLoaded, sendMap: mapNotLoaded }; var StubHook = class { }; var ErrorStubHook = class extends StubHook { constructor(error) { super(); this.error = error; } call(path, args) { return this; } map(path, captures, instructions) { return this; } get(path) { return this; } dup() { return this; } pull() { return Promise.reject(this.error); } ignoreUnhandledRejections() { } dispose() { } onBroken(callback) { try { callback(this.error); } catch (err) { Promise.resolve(err); } } }; var DISPOSED_HOOK = new ErrorStubHook( new Error("Attempted to use RPC stub after it has been disposed.") ); var doCall = (hook, path, params) => { return hook.call(path, params); }; function withCallInterceptor(interceptor, callback) { let oldValue = doCall; doCall = interceptor; try { return callback(); } finally { doCall = oldValue; } } var RAW_STUB = Symbol("realStub"); var PROXY_HANDLERS = { apply(target, thisArg, argumentsList) { let stub = target.raw; return new RpcPromise(doCall( stub.hook, stub.pathIfPromise || [], RpcPayload.fromAppParams(argumentsList) ), []); }, get(target, prop, receiver) { let stub = target.raw; if (prop === RAW_STUB) { return stub; } else if (prop in RpcPromise.prototype) { return stub[prop]; } else if (typeof prop === "string") { return new RpcPromise( stub.hook, stub.pathIfPromise ? [...stub.pathIfPromise, prop] : [prop] ); } else if (prop === Symbol.dispose && (!stub.pathIfPromise || stub.pathIfPromise.length == 0)) { return () => { stub.hook.dispose(); stub.hook = DISPOSED_HOOK; }; } else { return void 0; } }, has(target, prop) { let stub = target.raw; if (prop === RAW_STUB) { return true; } else if (prop in RpcPromise.prototype) { return prop in stub; } else if (typeof prop === "string") { return true; } else if (prop === Symbol.dispose && (!stub.pathIfPromise || stub.pathIfPromise.length == 0)) { return true; } else { return false; } }, construct(target, args) { throw new Error("An RPC stub cannot be used as a constructor."); }, defineProperty(target, property, attributes) { throw new Error("Can't define properties on RPC stubs."); }, deleteProperty(target, p) { throw new Error("Can't delete properties on RPC stubs."); }, getOwnPropertyDescriptor(target, p) { return void 0; }, getPrototypeOf(target) { return Object.getPrototypeOf(target.raw); }, isExtensible(target) { return false; }, ownKeys(target) { return []; }, preventExtensions(target) { return true; }, set(target, p, newValue, receiver) { throw new Error("Can't assign properties on RPC stubs."); }, setPrototypeOf(target, v) { throw new Error("Can't override prototype of RPC stubs."); } }; var RpcStub = class _RpcStub extends RpcTarget { // Although `hook` and `path` are declared `public` here, they are effectively hidden by the // proxy. constructor(hook, pathIfPromise) { super(); if (!(hook instanceof StubHook)) { let value = hook; if (value instanceof RpcTarget || value instanceof Function) { hook = TargetStubHook.create(value, void 0); } else { hook = new PayloadStubHook(RpcPayload.fromAppReturn(value)); } if (pathIfPromise) { throw new TypeError("RpcStub constructor expected one argument, received two."); } } this.hook = hook; this.pathIfPromise = pathIfPromise; let func = () => { }; func.raw = this; return new Proxy(func, PROXY_HANDLERS); } hook; pathIfPromise; dup() { let target = this[RAW_STUB]; if (target.pathIfPromise) { return new _RpcStub(target.hook.get(target.pathIfPromise)); } else { return new _RpcStub(target.hook.dup()); } } onRpcBroken(callback) { this[RAW_STUB].hook.onBroken(callback); } map(func) { let { hook, pathIfPromise } = this[RAW_STUB]; return mapImpl.sendMap(hook, pathIfPromise || [], func); } }; var RpcPromise = class extends RpcStub { // TODO: Support passing target value or promise to constructor. constructor(hook, pathIfPromise) { super(hook, pathIfPromise); } then(onfulfilled, onrejected) { return pullPromise(this).then(...arguments); } catch(onrejected) { return pullPromise(this).catch(...arguments); } finally(onfinally) { return pullPromise(this).finally(...arguments); } }; function unwrapStubTakingOwnership(stub) { let { hook, pathIfPromise } = stub[RAW_STUB]; if (pathIfPromise && pathIfPromise.length > 0) { return hook.get(pathIfPromise); } else { return hook; } } function unwrapStubAndDup(stub) { let { hook, pathIfPromise } = stub[RAW_STUB]; if (pathIfPromise) { return hook.get(pathIfPromise); } else { return hook.dup(); } } function unwrapStubNoProperties(stub) { let { hook, pathIfPromise } = stub[RAW_STUB]; if (pathIfPromise && pathIfPromise.length > 0) { return void 0; } return hook; } function unwrapStubOrParent(stub) { return stub[RAW_STUB].hook; } function unwrapStubAndPath(stub) { return stub[RAW_STUB]; } async function pullPromise(promise) { let { hook, pathIfPromise } = promise[RAW_STUB]; if (pathIfPromise.length > 0) { hook = hook.get(pathIfPromise); } let payload = await hook.pull(); return payload.deliverResolve(); } var RpcPayload = class _RpcPayload { // Private constructor; use factory functions above to construct. constructor(value, source, stubs, promises) { this.value = value; this.source = source; this.stubs = stubs; this.promises = promises; } // Create a payload from a value passed as params to an RPC from the app. // // The payload does NOT take ownership of any stubs in `value`, and but promises not to modify // `value`. If the payload is delivered locally, `value` will be deep-copied first, so as not // to have the sender and recipient end up sharing the same mutable object. `value` will not be // touched again after the call returns synchronously (returns a promise) -- by that point, // the value has either been copied or serialized to the wire. static fromAppParams(value) { return new _RpcPayload(value, "params"); } // Create a payload from a value return from an RPC implementation by the app. // // Unlike fromAppParams(), in this case the payload takes ownership of all stubs in `value`, and // may hold onto `value` for an arbitarily long time (e.g. to serve pipelined requests). It // will still avoid modifying `value` and will make a deep copy if it is delivered locally. static fromAppReturn(value) { return new _RpcPayload(value, "return"); } // Combine an array of payloads into a single payload whose value is an array. Ownership of all // stubs is transferred from the inputs to the outputs, hence if the output is disposed, the // inputs should not be. (In case of exception, nothing is disposed, though.) static fromArray(array) { let stubs = []; let promises = []; let resultArray = []; for (let payload of array) { payload.ensureDeepCopied(); for (let stub of payload.stubs) { stubs.push(stub); } for (let promise of payload.promises) { if (promise.parent === payload) { promise = { parent: resultArray, property: resultArray.length, promise: promise.promise }; } promises.push(promise); } resultArray.push(payload.value); } return new _RpcPayload(resultArray, "owned", stubs, promises); } // Create a payload from a value parsed off the wire using Evaluator.evaluate(). // // A payload is constructed with a null value and the given stubs and promises arrays. The value // is expected to be filled in by the evaluator, and the stubs and promises arrays are expected // to be extended with stubs found during parsing. (This weird usage model is necessary so that // if the root value turns out to be a promise, its `parent` in `promises` can be the payload // object itself.) // // When done, the payload takes ownership of the final value and all the stubs within. It may // modify the value in preparation for delivery, and may deliver the value directly to the app // without copying. static forEvaluate(stubs, promises) { return new _RpcPayload(null, "owned", stubs, promises); } // Deep-copy the given value, including dup()ing all stubs. // // If `value` is a function, it should be bound to `oldParent` as its `this`. // // If deep-copying from a branch of some other RpcPayload, it must be provided, to make sure // RpcTargets found within don't get duplicate stubs. static deepCopyFrom(value, oldParent, owner) { let result = new _RpcPayload(null, "owned", [], []); result.value = result.deepCopy( value, oldParent, "value", result, /*dupStubs=*/ true, owner ); return result; } // For `soruce === "return"` payloads only, this tracks any StubHooks created around RpcTargets // found in the payload at the time that it is serialized (or deep-copied) for return, so that we // can make sure they are not disposed before the pipeline ends. // // This is initialized on first use. rpcTargets; // Get the StubHook representing the given RpcTarget found inside this payload. getHookForRpcTarget(target, parent, dupStubs = true) { if (this.source === "params") { return TargetStubHook.create(target, parent); } else if (this.source === "return") { let hook = this.rpcTargets?.get(target); if (hook) { if (dupStubs) { return hook.dup(); } else { this.rpcTargets?.delete(target); return hook; } } else { hook = TargetStubHook.create(target, parent); if (dupStubs) { if (!this.rpcTargets) { this.rpcTargets = /* @__PURE__ */ new Map(); } this.rpcTargets.set(target, hook); return hook.dup(); } else { return hook; } } } else { throw new Error("owned payload shouldn't contain raw RpcTargets"); } } deepCopy(value, oldParent, property, parent, dupStubs, owner) { let kind = typeForRpc(value); switch (kind) { case "unsupported": return value; case "primitive": case "bigint": case "date": case "bytes": case "error": case "undefined": return value; case "array": { let array = value; let len = array.length; let result = new Array(len); for (let i = 0; i < len; i++) { result[i] = this.deepCopy(array[i], array, i, result, dupStubs, owner); } return result; } case "object": { let result = {}; let object = value; for (let i in object) { result[i] = this.deepCopy(object[i], object, i, result, dupStubs, owner); } return result; } case "stub": case "rpc-promise": { let stub = value; let hook; if (dupStubs) { hook = unwrapStubAndDup(stub); } else { hook = unwrapStubTakingOwnership(stub); } if (stub instanceof RpcPromise) { let promise = new RpcPromise(hook, []); this.promises.push({ parent, property, promise }); return promise; } else { let newStub = new RpcStub(hook); this.stubs.push(newStub); return newStub; } } case "function": case "rpc-target": { let target = value; let stub; if (owner) { stub = new RpcStub(owner.getHookForRpcTarget(target, oldParent, dupStubs)); } else { stub = new RpcStub(TargetStubHook.create(target, oldParent)); } this.stubs.push(stub); return stub; } case "rpc-thenable": { let target = value; let promise; if (owner) { promise = new RpcPromise(owner.getHookForRpcTarget(target, oldParent, dupStubs), []); } else { promise = new RpcPromise(TargetStubHook.create(target, oldParent), []); } this.promises.push({ parent, property, promise }); return promise; } default: throw new Error("unreachable"); } } // Ensures that if the value originally came from an unowned source, we have replaced it with a // deep copy. ensureDeepCopied() { if (this.source !== "owned") { let dupStubs = this.source === "params"; this.stubs = []; this.promises = []; try { this.value = this.deepCopy(this.value, void 0, "value", this, dupStubs, this); } catch (err) { this.stubs = void 0; this.promises = void 0; throw err; } this.source = "owned"; if (this.rpcTargets && this.rpcTargets.size > 0) { throw new Error("Not all rpcTargets were accounted for in deep-copy?"); } this.rpcTargets = void 0; } } // Resolve all promises in this payload and then assign the final value into `parent[property]`. deliverTo(parent, property, promises) { this.ensureDeepCopied(); if (this.value instanceof RpcPromise) { _RpcPayload.deliverRpcPromiseTo(this.value, parent, property, promises); } else { parent[property] = this.value; for (let record of this.promises) { _RpcPayload.deliverRpcPromiseTo(record.promise, record.parent, record.property, promises); } } } static deliverRpcPromiseTo(promise, parent, property, promises) { let hook = unwrapStubNoProperties(promise); if (!hook) { throw new Error("property promises should have been resolved earlier"); } let inner = hook.pull(); if (inner instanceof _RpcPayload) { inner.deliverTo(parent, property, promises); } else { promises.push(inner.then((payload) => { let subPromises = []; payload.deliverTo(parent, property, subPromises); if (subPromises.length > 0) { return Promise.all(subPromises); } })); } } // Call the given function with the payload as an argument. The call is made synchronously if // possible, in order to maintain e-order. However, if any RpcPromises exist in the payload, // they are awaited and substituted before calling the function. The result of the call is // wrapped into another payload. // // The payload is automatically disposed after the call completes. The caller should not call // dispose(). async deliverCall(func, thisArg) { try { let promises = []; this.deliverTo(this, "value", promises); if (promises.length > 0) { await Promise.all(promises); } let result = Function.prototype.apply.call(func, thisArg, this.value); if (result instanceof RpcPromise) { return _RpcPayload.fromAppReturn(result); } else { return _RpcPayload.fromAppReturn(await result); } } finally { this.dispose(); } } // Produce a promise for this payload for return to the application. Any RpcPromises in the // payload are awaited and substituted with their results first. // // The returned object will have a disposer which disposes the payload. The caller should not // separately dispose it. async deliverResolve() { try { let promises = []; this.deliverTo(this, "value", promises); if (promises.length > 0) { await Promise.all(promises); } let result = this.value; if (result instanceof Object) { if (!(Symbol.dispose in result)) { Object.defineProperty(result, Symbol.dispose, { // NOTE: Using `this.dispose.bind(this)` here causes Playwright's build of // Chromium 140.0.7339.16 to fail when the object is assigned to a `using` variable, // with the error: // TypeError: Symbol(Symbol.dispose) is not a function // I cannot reproduce this problem in Chrome 140.0.7339.127 nor in Node or workerd, // so maybe it was a short-lived V8 bug or something. To be safe, though, we use // `() => this.dispose()`, which seems to always work. value: () => this.dispose(), writable: true, enumerable: false, configurable: true }); } } return result; } catch (err) { this.dispose(); throw err; } } dispose() { if (this.source === "owned") { this.stubs.forEach((stub) => stub[Symbol.dispose]()); this.promises.forEach((promise) => promise.promise[Symbol.dispose]()); } else if (this.source === "return") { this.disposeImpl(this.value, void 0); if (this.rpcTargets && this.rpcTargets.size > 0) { throw new Error("Not all rpcTargets were accounted for in disposeImpl()?"); } } else ; this.source = "owned"; this.stubs = []; this.promises = []; } // Recursive dispose, called only when `source` is "return". disposeImpl(value, parent) { let kind = typeForRpc(value); switch (kind) { case "unsupported": case "primitive": case "bigint": case "bytes": case "date": case "error": case "undefined": return; case "array": { let array = value; let len = array.length; for (let i = 0; i < len; i++) { this.disposeImpl(array[i], array); } return; } case "object": { let object = value; for (let i in object) { this.disposeImpl(object[i], object); } return; } case "stub": case "rpc-promise": { let stub = value; let hook = unwrapStubNoProperties(stub); if (hook) { hook.dispose(); } return; } case "function": case "rpc-target": { let target = value; let hook = this.rpcTargets?.get(target); if (hook) { hook.dispose(); this.rpcTargets.delete(target); } else { disposeRpcTarget(target); } return; } case "rpc-thenable": return; default: return; } } // Ignore unhandled rejections in all promises in this payload -- that is, all promises that // *would* be awaited if this payload were to be delivered. See the similarly-named method of // StubHook for explanation. ignoreUnhandledRejections() { if (this.stubs) { this.stubs.forEach((stub) => { unwrapStubOrParent(stub).ignoreUnhandledRejections(); }); this.promises.forEach( (promise) => unwrapStubOrParent(promise.promise).ignoreUnhandledRejections() ); } else { this.ignoreUnhandledRejectionsImpl(this.value); } } ignoreUnhandledRejectionsImpl(value) { let kind = typeForRpc(value); switch (kind) { case "unsupported": case "primitive": case "bigint": case "bytes": case "date": case "error": case "undefined": case "function": case "rpc-target": return; case "array": { let array = value; let len = array.length; for (let i = 0; i < len; i++) { this.ignoreUnhandledRejectionsImpl(array[i]); } return; } case "object": { let object = value; for (let i in object) { this.ignoreUnhandledRejectionsImpl(object[i]); } return; } case "stub": case "rpc-promise": unwrapStubOrParent(value).ignoreUnhandledRejections(); return; case "rpc-thenable": value.then((_) => { }, (_) => { }); return; default: return; } } }; function followPath(value, parent, path, owner) { for (let i = 0; i < path.length; i++) { parent = value; let part = path[i]; if (part in Object.prototype) { value = void 0; continue; } let kind = typeForRpc(value); switch (kind) { case "object": case "function": if (Object.hasOwn(value, part)) { value = value[part]; } else { value = void 0; } break; case "array": if (Number.isInteger(part) && part >= 0) { value = value[part]; } else { value = void 0; } break; case "rpc-target": case "rpc-thenable": { if (Object.hasOwn(value, part)) { value = void 0; } else { value = value[part]; } owner = null; break; } case "stub": case "rpc-promise": { let { hook, pathIfPromise } = unwrapStubAndPath(value); return { hook, remainingPath: pathIfPromise ? pathIfPromise.concat(path.slice(i)) : path.slice(i) }; } case "primitive": case "bigint": case "bytes": case "date": case "error": value = void 0; break; case "undefined": value = value[part]; break; case "unsupported": { if (i === 0) { throw new TypeError(`RPC stub points at a non-serializable type.`); } else { let prefix = path.slice(0, i).join("."); let remainder = path.slice(0, i).join("."); throw new TypeError( `'${prefix}' is not a serializable type, so property ${remainder} cannot be accessed.` ); } } default: throw new TypeError("unreachable"); } } if (value instanceof RpcPromise) { let { hook, pathIfPromise } = unwrapStubAndPath(value); return { hook, remainingPath: pathIfPromise || [] }; } return { value, parent, owner }; } var ValueStubHook = class extends StubHook { call(path, args) { try { let { value, owner } = this.getValue(); let followResult = followPath(value, void 0, path, owner); if (followResult.hook) { return followResult.hook.call(followResult.remainingPath, args); } if (typeof followResult.value != "function") { throw new TypeError(`'${path.join(".")}' is not a function.`); } let promise = args.deliverCall(followResult.value, followResult.parent); return new PromiseStubHook(promise.then((payload) => { return new PayloadStubHook(payload); })); } catch (err) { return new ErrorStubHook(err); } } map(path, captures, instructions) { try { let followResult; try { let { value, owner } = this.getValue(); followResult = followPath(value, void 0, path, owner); ; } catch (err) { for (let cap of captures) { cap.dispose(); } throw err; } if (followResult.hook) { return followResult.hook.map(followResult.remainingPath, captures, instructions); } return mapImpl.applyMap( followResult.value, followResult.parent, followResult.owner, captures, instructions ); } catch (err) { return new ErrorStubHook(err); } } get(path) { try { let { value, owner } = this.getValue(); if (path.length === 0 && owner === null) { throw new Error("Can't dup an RpcTarget stub as a promise."); } let followResult = followPath(value, void 0, path, owner); if (followResult.hook) { return followResult.hook.get(followResult.remainingPath); } return new PayloadStubHook(RpcPayload.deepCopyFrom( followResult.value, followResult.parent, followResult.owner )); } catch (err) { return new ErrorStubHook(err); } } }; var PayloadStubHook = class _PayloadStubHook extends ValueStubHook { constructor(payload) { super(); this.payload = payload; } payload; // cleared when disposed getPayload() { if (this.payload) { return this.payload; } else { throw new Error("Attempted to use an RPC StubHook after it was disposed."); } } getValue() { let payload = this.getPayload(); return { value: payload.value, owner: payload }; } dup() { let thisPayload = this.getPayload(); return new _PayloadStubHook(RpcPayload.deepCopyFrom( thisPayload.value, void 0, thisPayload )); } pull() { return this.getPayload(); } ignoreUnhandledRejections() { if (this.payload) { this.payload.ignoreUnhandledRejections(); } } dispose() { if (this.payload) { this.payload.dispose(); this.payload = void 0; } } onBroken(callback) { if (this.payload) { if (this.payload.value instanceof RpcStub) { this.payload.value.onRpcBroken(callback); } } } }; function disposeRpcTarget(target) { if (Symbol.dispose in target) { try { target[Symbol.dispose](); } catch (err) { Promise.reject(err); } } } var TargetStubHook = class _TargetStubHook extends ValueStubHook { // Constructs a TargetStubHook that is not duplicated from an existing hook. // // If `value` is a function, `parent` is bound as its "this". static create(value, parent) { if (typeof value !== "function") { parent = void 0; } return new _TargetStubHook(value, parent); } constructor(target, parent, dupFrom) { super(); this.target = target; this.parent = parent; if (dupFrom) { if (dupFrom.refcount) { this.refcount = dupFrom.refcount; ++this.refcount.count; } } else if (Symbol.dispose in target) { this.refcount = { count: 1 }; } } target; // cleared when disposed parent; // `this` parameter when calling `target` refcount; // undefined if not needed (because target has no disposer) getTarget() { if (this.target) { return this.target; } else { throw new Error("Attempted to use an RPC StubHook after it was disposed."); } } getValue() { return { value: this.getTarget(), owner: null }; } dup() { return new _TargetStubHook(this.getTarget(), this.parent, this); } pull() { let target = this.getTarget(); if ("then" in target) { return Promise.resolve(target).then((resolution) => { return RpcPayload.fromAppReturn(resolution); }); } else { return Promise.reject(new Error("Tried to resolve a non-promise stub.")); } } ignoreUnhandledRejections() { } dispose() { if (this.target) { if (this.refcount) { if (--this.refcount.count == 0) { disposeRpcTarget(this.target); } } this.target = void 0; } } onBroken(callback) { } }; var PromiseStubHook = class _PromiseStubHook extends StubHook { promise; resolution; constructor(promise) { super(); this.promise = promise.then((res) => { this.resolution = res; return res; }); } call(path, args) { args.ensureDeepCopied(); return new _PromiseStubHook(this.promise.then((hook) => hook.call(path, args))); } map(path, captures, instructions) { return new _PromiseStubHook(this.promise.then( (hook) => hook.map(path, captures, instructions), (err) => { for (let cap of captures) { cap.dispose(); } throw err; } )); } get(path) { return new _PromiseStubHook(this.promise.then((hook) => hook.get(path))); } dup() { if (this.resolution) { return this.resolution.dup(); } else { return new _PromiseStubHook(this.promise.then((hook) => hook.dup())); } } pull() { if (this.resolution) { return this.resolution.pull(); } else { return this.promise.then((hook) => hook.pull()); } } ignoreUnhandledRejections() { if (this.resolution) { this.resolution.ignoreUnhandledRejections(); } else { this.promise.then((res) => { res.ignoreUnhandledRejections(); }, (err) => { }); } } dispose() { if (this.resolution) { this.resolution.dispose(); } else { this.promise.then((hook) => { hook.dispose(); }, (err) => { }); } } onBroken(callback) { if (this.resolution) { this.resolution.onBroken(callback); } else { this.promise.then((hook) => { hook.onBroken(callback); }, callback); } } }; var NullExporter = class { exportStub(stub) { throw new Error("Cannot serialize RPC stubs without an RPC session."); } exportPromise(stub) { throw new Error("Cannot serialize RPC stubs without an RPC session."); } getImport(hook) { return void 0; } unexport(ids) { } onSendError(error) { } }; var NULL_EXPORTER = new NullExporter(); var ERROR_TYPES = { Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, AggregateError // TODO: DOMError? Others? }; var Devaluator = class _Devaluator { constructor(exporter, source) { this.exporter = exporter; this.source = source; } // Devaluate the given value. // * value: The value to devaluate. // * parent: The value's parent object, which would be used as `this` if the value were called // as a function. // * exporter: Callbacks to the RPC session for exporting capabilities found in this message. // * source: The RpcPayload which contains the value, and therefore owns stubs within. // // Returns: The devaluated value, ready to be JSON-serialized. static devaluate(value, parent, exporter = NULL_EXPORTER, source) { let devaluator = new _Devaluator(exporter, source); try { return devaluator.devaluateImpl(value, parent, 0); } catch (err) { if (devaluator.exports) { try { exporter.unexport(devaluator.exports); } catch (err2) { } } throw err; } } exports; devaluateImpl(value, parent, depth) { if (depth >= 64) { throw new Error( "Serialization exceeded maximum allowed depth. (Does the message contain cycles?)" ); } let kind = typeForRpc(value); switch (kind) { case "unsupported": { let msg; try { msg = `Cannot serialize value: ${value}`; } catch (err) { msg = "Cannot serialize value: (couldn't stringify value)"; } throw new TypeError(msg); } case "primitive": return value; case "object": { let object = value; let result = {}; for (let key in object) { result[key] = this.devaluateImpl(object[key], object, depth + 1); } return result; } case "array": { let array = value; let len = array.length; let result = new Array(len); for (let i = 0; i < len; i++) { result[i] = this.devaluateImpl(array[i], array, depth + 1); } return [result]; } case "bigint": return ["bigint", value.toString()]; case "date": return ["date", value.getTime()]; case "bytes": { let bytes = value; if (bytes.toBase64) { return ["bytes", bytes.toBase64({ omitPadding: true })]; } else { return [ "bytes", btoa(String.fromCharCode.apply(null, bytes).replace(/=*$/, "")) ]; } } case "error": { let e = value; let rewritten = this.exporter.onSendError(e); if (rewritten) { e = rewritten; } let result = ["error", e.name, e.message]; if (rewritten && rewritten.stack) { result.push(rewritten.stack); } return result; } case "undefined": return ["undefined"]; case "stub": case "rpc-promise": { if (!this.source) { throw new Error("Can't serialize RPC stubs in this context."); } let { hook, pathIfPromise } = unwrapStubAndPath(value); let importId = this.exporter.getImport(hook); if (importId !== void 0) { if (pathIfPromise) { if (pathIfPromise.length > 0) { return ["pipeline", importId, pathIfPromise]; } else { return ["pipeline", importId]; } } else { return ["import", importId]; } } if (pathIfPromise) { hook = hook.get(pathIfPromise); } else { hook = hook.dup(); } return this.devaluateHook(pathIfPromise ? "promise" : "export", hook); } case "function": case "rpc-target": { if (!this.source) { throw new Error("Can't serialize RPC stubs in this context."); } let hook = this.source.getHookForRpcTarget(value, parent); return this.devaluateHook("export", hook); } case "rpc-thenable": { if (!this.source) { throw new Error("Can't serialize RPC stubs in this context."); } let hook = this.source.getHookForRpcTarget(value, parent); return this.devaluateHook("promise", hook); } default: throw new Error("unreachable"); } } devaluateHook(type, hook) { if (!this.exports) this.exports = []; let exportId = type === "promise" ? this.exporter.exportPromise(hook) : this.exporter.exportStub(hook); this.exports.push(exportId); return [type, exportId]; } }; var NullImporter = class { importStub(idx) { throw new Error("Cannot deserialize RPC stubs without an RPC session."); } importPromise(idx) { throw new Error("Cannot deserialize RPC stubs without an RPC session."); } getExport(idx) { return void 0; } }; var NULL_IMPORTER = new NullImporter(); var Evaluator = class _Evaluator { constructor(importer) { this.importer = importer; } stubs = []; promises = []; evaluate(value) { let payload = RpcPayload.forEvaluate(this.stubs, this.promises); try { payload.value = this.evaluateImpl(value, payload, "value"); return payload; } catch (err) { payload.dispose(); throw err; } } // Evaluate the value without destroying it. evaluateCopy(value) { return this.evaluate(structuredClone(value)); } evaluateImpl(value, parent, property) { if (value instanceof Array) { if (value.length == 1 && value[0] instanceof Array) { let result = value[0]; for (let i = 0; i < result.length; i++) { result[i] = this.evaluateImpl(result[i], result, i); } return result; } else switch (value[0]) { case "bigint": if (typeof value[1] == "string") { return BigInt(value[1]); } break; case "date": if (typeof value[1] == "number") { return new Date(value[1]); } break; case "bytes": { let b64 = Uint8Array; if (typeof value[1] == "string") { if (b64.fromBase64) { return b64.fromBase64(value[1]); } else { let bs = atob(value[1]); let len = bs.length; let bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = bs.charCodeAt(i); } return bytes; } } break; } case "error": if (value.length >= 3 && typeof value[1] === "string" && typeof value[2] === "string") { let cls = ERROR_TYPES[value[1]] || Error; let result = new cls(value[2]); if (typeof value[3] === "string") { result.stack = value[3]; } return result; } break; case "undefined": if (value.length === 1) { return void 0; } break; case "import": case "pipeline": { if (value.length < 2 || value.length > 4) { break; } if (typeof value[1] != "number") { break; } let hook = this.importer.getExport(value[1]); if (!hook) { throw new Error(`no such entry on exports table: ${value[1]}`); } let isPromise = value[0] == "pipeline"; let addStub = (hook2) => { if (isPromise) { let promise = new RpcPromise(hook2, []); this.promises.push({ promise, parent, property }); return promise; } else { let stub = new RpcPromise(hook2, []); this.stubs.push(stub); return stub; } }; if (value.length == 2) { if (isPromise) { return addStub(hook.get([])); } else { return addStub(hook.dup()); } } let path = value[2]; if (!(path instanceof Array)) { break; } if (!path.every( (part) => { return typeof part == "string" || typeof part == "number"; } )) { break; } if (value.length == 3) { return addStub(hook.get(path)); } let args = value[3]; if (!(args instanceof Array)) { break; } let subEval = new _Evaluator(this.importer); args = subEval.evaluate([args]); return addStub(hook.call(path, args)); } case "remap": { if (value.length !== 5 || typeof value[1] !== "number" || !(value[2] instanceof Array) || !(value[3] instanceof Array) || !(value[4] instanceof Array)) { break; } let hook = this.importer.getExport(value[1]); if (!hook) { throw new Error(`no such entry on exports table: ${value[1]}`); } let path = value[2]; if (!path.every( (part) => { return typeof part == "string" || typeof part == "number"; } )) { break; } let captures = value[3].map((cap) => { if (!(cap instanceof Array) || cap.length !== 2 || cap[0] !== "import" && cap[0] !== "export" || typeof cap[1] !== "number") { throw new TypeError(`unknown map capture: ${JSON.stringify(cap)}`); } if (cap[0] === "export") { return this.importer.importStub(cap[1]); } else { let exp = this.importer.getExport(cap[1]); if (!exp) { throw new Error(`no such entry on exports table: ${cap[1]}`); } return exp.dup(); } }); let instructions = value[4]; let resultHook = hook.map(path, captures, instructions); let promise = new RpcPromise(resultHook, []); this.promises.push({ promise, parent, property }); return promise; } case "export": case "promise": if (typeof value[1] == "number") { if (value[0] == "promise") { let hook = this.importer.importPromise(value[1]); let promise = new RpcPromise(hook, []); this.promises.push({ parent, property, promise }); return promise; } else { let hook = this.importer.importStub(value[1]); let stub = new RpcStub(hook); this.stubs.push(stub); return stub; } } break; } throw new TypeError(`unknown special value: ${JSON.stringify(value)}`); } else if (value instanceof Object) { let result = value; for (let key in result) { if (key in Object.prototype || key === "toJSON") { this.evaluateImpl(result[key], result, key); delete result[key]; } else { result[key] = this.evaluateImpl(result[key], result, key); } } return result; } else { return value; } } }; var ImportTableEntry = class { constructor(session, importId, pulling) { this.session = session; this.importId = importId; if (pulling) { this.activePull = Promise.withResolvers(); } } localRefcount = 0; remoteRefcount = 1; activePull; resolution; // List of integer indexes into session.onBrokenCallbacks which are callbacks registered on // this import. Initialized on first use (so `undefined` is the same as an empty list). onBrokenRegistrations; resolve(resolution) { if (this.localRefcount == 0) { resolution.dispose(); return; } this.resolution = resolution; this.sendRelease(); if (this.onBrokenRegistrations) { for (let i of this.onBrokenRegistrations) { let callback = this.session.onBrokenCallbacks[i]; let endIndex = this.session.onBrokenCallbacks.length; resolution.onBroken(callback); if (this.session.onBrokenCallbacks[endIndex] === callback) { delete this.session.onBrokenCallbacks[endIndex]; } else { delete this.session.onBrokenCallbacks[i]; } } this.onBrokenRegistrations = void 0; } if (this.activePull) { this.activePull.resolve(); this.activePull = void 0; } } async awaitResolution() { if (!this.activePull) { this.session.sendPull(this.importId); this.activePull = Promise.withResolvers(); } await this.activePull.promise; return this.resolution.pull(); } dispose() { if (this.resolution) { this.resolution.dispose(); } else { this.abort(new Error("RPC was canceled because the RpcPromise was disposed.")); this.sendRelease(); } } abort(error) { if (!this.resolution) { this.resolution = new ErrorStubHook(error); if (this.activePull) { this.activePull.reject(error); this.activePull = void 0; } this.onBrokenRegistrations = void 0; } } onBroken(callback) { if (this.resolution) { this.resolution.onBroken(callback); } else { let index = this.session.onBrokenCallbacks.length; this.session.onBrokenCallbacks.push(callback); if (!this.onBrokenRegistrations) this.onBrokenRegistrations = []; this.onBrokenRegistrations.push(index); } } sendRelease() { if (this.remoteRefcount > 0) { this.session.sendRelease(this.importId, this.remoteRefcount); this.remoteRefcount = 0; } } }; var RpcImportHook = class _RpcImportHook extends StubHook { // undefined when we're disposed // `pulling` is true if we already expect that this import is going to be resolved later, and // null if this import is not allowed to be pulled (i.e. it's a stub not a promise). constructor(isPromise, entry) { super(); this.isPromise = isPromise; ++entry.localRefcount; this.entry = entry; } entry; collectPath(path) { return this; } getEntry() { if (this.entry) { return this.entry; } else { throw new Error("This RpcImportHook was already disposed."); } } // ------------------------------------------------------------------------------------- // implements StubHook call(path, args) { let entry = this.getEntry(); if (entry.resolution) { return entry.resolution.call(path, args); } else { return entry.session.sendCall(entry.importId, path, args); } } map(path, captures, instructions) { let entry; try { entry = this.getEntry(); } catch (err) { for (let cap of captures) { cap.dispose(); } throw err; } if (entry.resolution) { return entry.resolution.map(path, captures, instructions); } else { return entry.session.sendMap(entry.importId, path, captures, instructions); } } get(path) { let entry = this.getEntry(); if (entry.resolution) { return entry.resolution.get(path); } else { return entry.session.sendCall(entry.importId, path); } } dup() { return new _RpcImportHook(false, this.getEntry()); } pull() { let entry = this.getEntry(); if (!this.isPromise) { throw new Error("Can't pull this hook because it's not a promise hook."); } if (entry.resolution) { return entry.resolution.pull(); } return entry.awaitResolution(); } ignoreUnhandledRejections() { } dispose() { let entry = this.entry; this.entry = void 0; if (entry) { if (--entry.localRefcount === 0) { entry.dispose(); } } } onBroken(callback) { if (this.entry) { this.entry.onBroken(callback); } } }; var RpcMainHook = class extends RpcImportHook { session; constructor(entry) { super(false, entry); this.session = entry.session; } dispose() { if (this.session) { let session = this.session; this.session = void 0; session.shutdown(); } } }; var RpcSessionImpl = class { constructor(transport, mainHook, options) { this.transport = transport; this.options = options; this.exports.push({ hook: mainHook, refcount: 1 }); this.imports.push(new ImportTableEntry(this, 0, false)); let rejectFunc; let abortPromise = new Promise((resolve, reject) => { rejectFunc = reject; }); this.cancelReadLoop = rejectFunc; this.readLoop(abortPromise).catch((err) => this.abort(err)); } exports = []; reverseExports = /* @__PURE__ */ new Map(); imports = []; abortReason; cancelReadLoop; // We assign positive numbers to imports we initiate, and negative numbers to exports we // initiate. So the next import ID is just `imports.length`, but the next export ID needs // to be tracked explicitly. nextExportId = -1; // If set, call this when all incoming calls are complete. onBatchDone; // How many promises is our peer expecting us to resolve? pullCount = 0; // Sparse array of onBrokenCallback registrations. Items are strictly appended to the end but // may be deleted from the middle (hence leaving the array sparse). onBrokenCallbacks = []; // Should only be called once immediately after construction. getMainImport() { return new RpcMainHook(this.imports[0]); } shutdown() { this.abort(new Error("RPC session was shut down by disposing the main stub"), false); } exportStub(hook) { if (this.abortReason) throw this.abortReason; let existingExportId = this.reverseExports.get(hook); if (existingExportId !== void 0) { ++this.exports[existingExportId].refcount; return existingExportId; } else { let exportId = this.nextExportId--; this.exports[exportId] = { hook, refcount: 1 }; this.reverseExports.set(hook, exportId); return exportId; } } exportPromise(hook) { if (this.abortReason) throw this.abortReason; let exportId = this.nextExportId--; this.exports[exportId] = { hook, refcount: 1 }; this.reverseExports.set(hook, exportId); this.ensureResolvingExport(exportId); return exportId; } unexport(ids) { for (let id of ids) { this.releaseExport(id, 1); } } releaseExport(exportId, refcount) { let entry = this.exports[exportId]; if (!entry) { throw new Error(`no such export ID: ${exportId}`); } if (entry.refcount < refcount) { throw new Error(`refcount would go negative: ${entry.refcount} < ${refcount}`); } entry.refcount -= refcount; if (entry.refcount === 0) { delete this.exports[exportId]; this.reverseExports.delete(entry.hook); entry.hook.dispose(); } } onSendError(error) { if (this.options.onSendError) { return this.options.onSendError(error); } } ensureResolvingExport(exportId) { let exp = this.exports[exportId]; if (!exp) { throw new Error(`no such export ID: ${exportId}`); } if (!exp.pull) { let resolve = async () => { let hook = exp.hook; for (; ; ) { let payload = await hook.pull(); if (payload.value instanceof RpcStub) { let { hook: inner, pathIfPromise } = unwrapStubAndPath(payload.value); if (pathIfPromise && pathIfPromise.length == 0) { if (this.getImport(hook) === void 0) { hook = inner; continue; } } } return payload; } }; ++this.pullCount; exp.pull = resolve().then( (payload) => { let value = Devaluator.devaluate(payload.value, void 0, this, payload); this.send(["resolve", exportId, value]); }, (error) => { this.send(["reject", exportId, Devaluator.devaluate(error, void 0, this)]); } ).catch( (error) => { try { this.send(["reject", exportId, Devaluator.devaluate(error, void 0, this)]); } catch (error2) { this.abort(error2); } } ).finally(() => { if (--this.pullCount === 0) { if (this.onBatchDone) { this.onBatchDone.resolve(); } } }); } } getImport(hook) { if (hook instanceof RpcImportHook && hook.entry && hook.entry.session === this) { return hook.entry.importId; } else { return void 0; } } importStub(idx) { if (this.abortReason) throw this.abortReason; let entry = this.imports[idx]; if (!entry) { entry = new ImportTableEntry(this, idx, false); this.imports[idx] = entry; } return new RpcImportHook( /*isPromise=*/ false, entry ); } importPromise(idx) { if (this.abortReason) throw this.abortReason; if (this.imports[idx]) { return new ErrorStubHook(new Error( "Bug in RPC system: The peer sent a promise reusing an existing export ID." )); } let entry = new ImportTableEntry(this, idx, true); this.imports[idx] = entry; return new RpcImportHook( /*isPromise=*/ true, entry ); } getExport(idx) { return this.exports[idx]?.hook; } send(msg) { if (this.abortReason !== void 0) { return; } let msgText; try { msgText = JSON.stringify(msg); } catch (err) { try { this.abort(err); } catch (err2) { } throw err; } this.transport.send(msgText).catch((err) => this.abort(err, false)); } sendCall(id, path, args) { if (this.abortReason) throw this.abortReason; let value = ["pipeline", id, path]; if (args) { let devalue = Devaluator.devaluate(args.value, void 0, this, args); value.push(devalue[0]); } this.send(["push", value]); let entry = new ImportTableEntry(this, this.imports.length, false); this.imports.push(entry); return new RpcImportHook( /*isPromise=*/ true, entry ); } sendMap(id, path, captures, instructions) { if (this.abortReason) { for (let cap of captures) { cap.dispose(); } throw this.abortReason; } let devaluedCaptures = captures.map((hook) => { let importId = this.getImport(hook); if (importId !== void 0) { return ["import", importId]; } else { return ["export", this.exportStub(hook)]; } }); let value = ["remap", id, path, devaluedCaptures, instructions]; this.send(["push", value]); let entry = new ImportTableEntry(this, this.imports.length, false); this.imports.push(entry); return new RpcImportHook( /*isPromise=*/ true, entry ); } sendPull(id) { if (this.abortReason) throw this.abortReason; this.send(["pull", id]); } sendRelease(id, remoteRefcount) { if (this.abortReason) return; this.send(["release", id, remoteRefcount]); delete this.imports[id]; } abort(error, trySendAbortMessage = true) { if (this.abortReason !== void 0) return; this.cancelReadLoop(error); if (trySendAbortMessage) { try { this.transport.send(JSON.stringify(["abort", Devaluator.devaluate(error, void 0, this)])).catch((err) => { }); } catch (err) { } } if (error === void 0) { error = "undefined"; } this.abortReason = error; if (this.onBatchDone) { this.onBatchDone.reject(error); } if (this.transport.abort) { try { this.transport.abort(error); } catch (err) { Promise.resolve(err); } } for (let i in this.onBrokenCallbacks) { try { this.onBrokenCallbacks[i](error); } catch (err) { Promise.resolve(err); } } for (let i in this.imports) { this.imports[i].abort(error); } for (let i in this.exports) { this.exports[i].hook.dispose(); } } async readLoop(abortPromise) { while (!this.abortReason) { let msg = JSON.parse(await Promise.race([this.transport.receive(), abortPromise])); if (this.abortReason) break; if (msg instanceof Array) { switch (msg[0]) { case "push": if (msg.length > 1) { let payload = new Evaluator(this).evaluate(msg[1]); let hook = new PayloadStubHook(payload); hook.ignoreUnhandledRejections(); this.exports.push({ hook, refcount: 1 }); continue; } break; case "pull": { let exportId = msg[1]; if (typeof exportId == "number") { this.ensureResolvingExport(exportId); continue; } break; } case "resolve": // ["resolve", ExportId, Expression] case "reject": { let importId = msg[1]; if (typeof importId == "number" && msg.length > 2) { let imp = this.imports[importId]; if (imp) { if (msg[0] == "resolve") { imp.resolve(new PayloadStubHook(new Evaluator(this).evaluate(msg[2]))); } else { let payload = new Evaluator(this).evaluate(msg[2]); payload.dispose(); imp.resolve(new ErrorStubHook(payload.value)); } } else { if (msg[0] == "resolve") { new Evaluator(this).evaluate(msg[2]).dispose(); } } continue; } break; } case "release": { let exportId = msg[1]; let refcount = msg[2]; if (typeof exportId == "number" && typeof refcount == "number") { this.releaseExport(exportId, refcount); continue; } break; } case "abort": { let payload = new Evaluator(this).evaluate(msg[1]); payload.dispose(); this.abort(payload, false); break; } } } throw new Error(`bad RPC message: ${JSON.stringify(msg)}`); } } async drain() { if (this.abortReason) { throw this.abortReason; } if (this.pullCount > 0) { let { promise, resolve, reject } = Promise.withResolvers(); this.onBatchDone = { resolve, reject }; await promise; } } getStats() { let result = { imports: 0, exports: 0 }; for (let i in this.imports) { ++result.imports; } for (let i in this.exports) { ++result.exports; } return result; } }; var RpcSession = class { #session; #mainStub; constructor(transport, localMain, options = {}) { let mainHook; if (localMain) { mainHook = new PayloadStubHook(RpcPayload.fromAppReturn(localMain)); } else { mainHook = new ErrorStubHook(new Error("This connection has no main object.")); } this.#session = new RpcSessionImpl(transport, mainHook, options); this.#mainStub = new RpcStub(this.#session.getMainImport()); } getRemoteMain() { return this.#mainStub; } getStats() { return this.#session.getStats(); } drain() { return this.#session.drain(); } }; function newWebSocketRpcSession(webSocket, localMain, options) { if (typeof webSocket === "string") { webSocket = new WebSocket(webSocket); } let transport = new WebSocketTransport(webSocket); let rpc = new RpcSession(transport, localMain, options); return rpc.getRemoteMain(); } function newWorkersWebSocketRpcResponse(request, localMain, options) { if (request.headers.get("Upgrade")?.toLowerCase() !== "websocket") { return new Response("This endpoint only accepts WebSocket requests.", { status: 400 }); } let pair = new WebSocketPair(); let server = pair[0]; server.accept(); newWebSocketRpcSession(server, localMain, options); return new Response(null, { status: 101, webSocket: pair[1] }); } var WebSocketTransport = class { constructor(webSocket) { this.#webSocket = webSocket; if (webSocket.readyState === WebSocket.CONNECTING) { this.#sendQueue = []; webSocket.addEventListener("open", (event) => { try { for (let message of this.#sendQueue) { webSocket.send(message); } } catch (err) { this.#receivedError(err); } this.#sendQueue = void 0; }); } webSocket.addEventListener("message", (event) => { if (this.#error) ; else if (typeof event.data === "string") { if (this.#receiveResolver) { this.#receiveResolver(event.data); this.#receiveResolver = void 0; this.#receiveRejecter = void 0; } else { this.#receiveQueue.push(event.data); } } else { this.#receivedError(new TypeError("Received non-string message from WebSocket.")); } }); webSocket.addEventListener("close", (event) => { this.#receivedError(new Error(`Peer closed WebSocket: ${event.code} ${event.reason}`)); }); webSocket.addEventListener("error", (event) => { this.#receivedError(new Error(`WebSocket connection failed.`)); }); } #webSocket; #sendQueue; // only if not opened yet #receiveResolver; #receiveRejecter; #receiveQueue = []; #error; async send(message) { if (this.#sendQueue === void 0) { this.#webSocket.send(message); } else { this.#sendQueue.push(message); } } async receive() { if (this.#receiveQueue.length > 0) { return this.#receiveQueue.shift(); } else if (this.#error) { throw this.#error; } else { return new Promise((resolve, reject) => { this.#receiveResolver = resolve; this.#receiveRejecter = reject; }); } } abort(reason) { let message; if (reason instanceof Error) { message = reason.message; } else { message = `${reason}`; } this.#webSocket.close(3e3, message); if (!this.#error) { this.#error = reason; } } #receivedError(reason) { if (!this.#error) { this.#error = reason; if (this.#receiveRejecter) { this.#receiveRejecter(reason); this.#receiveResolver = void 0; this.#receiveRejecter = void 0; } } } }; var BatchServerTransport = class { constructor(batch) { this.#batchToReceive = batch; } #batchToSend = []; #batchToReceive; #allReceived = Promise.withResolvers(); async send(message) { this.#batchToSend.push(message); } async receive() { let msg = this.#batchToReceive.shift(); if (msg !== void 0) { return msg; } else { this.#allReceived.resolve(); return new Promise((r) => { }); } } abort(reason) { this.#allReceived.reject(reason); } whenAllReceived() { return this.#allReceived.promise; } getResponseBody() { return this.#batchToSend.join("\n"); } }; async function newHttpBatchRpcResponse(request, localMain, options) { if (request.method !== "POST") { return new Response("This endpoint only accepts POST requests.", { status: 405 }); } let body = await request.text(); let batch = body === "" ? [] : body.split("\n"); let transport = new BatchServerTransport(batch); let rpc = new RpcSession(transport, localMain, options); await transport.whenAllReceived(); await rpc.drain(); return new Response(transport.getResponseBody()); } var currentMapBuilder; var MapBuilder = class { context; captureMap = /* @__PURE__ */ new Map(); instructions = []; constructor(subject, path) { if (currentMapBuilder) { this.context = { parent: currentMapBuilder, captures: [], subject: currentMapBuilder.capture(subject), path }; } else { this.context = { parent: void 0, captures: [], subject, path }; } currentMapBuilder = this; } unregister() { currentMapBuilder = this.context.parent; } makeInput() { return new MapVariableHook(this, 0); } makeOutput(result) { let devalued; try { devalued = Devaluator.devaluate(result.value, void 0, this, result); } finally { result.dispose(); } this.instructions.push(devalued); if (this.context.parent) { this.context.parent.instructions.push( [ "remap", this.context.subject, this.context.path, this.context.captures.map((cap) => ["import", cap]), this.instructions ] ); return new MapVariableHook(this.context.parent, this.context.parent.instructions.length); } else { return this.context.subject.map(this.context.path, this.context.captures, this.instructions); } } pushCall(hook, path, params) { let devalued = Devaluator.devaluate(params.value, void 0, this, params); devalued = devalued[0]; let subject = this.capture(hook.dup()); this.instructions.push(["pipeline", subject, path, devalued]); return new MapVariableHook(this, this.instructions.length); } pushGet(hook, path) { let subject = this.capture(hook.dup()); this.instructions.push(["pipeline", subject, path]); return new MapVariableHook(this, this.instructions.length); } capture(hook) { if (hook instanceof MapVariableHook && hook.mapper === this) { return hook.idx; } let result = this.captureMap.get(hook); if (result === void 0) { if (this.context.parent) { let parentIdx = this.context.parent.capture(hook); this.context.captures.push(parentIdx); } else { this.context.captures.push(hook); } result = -this.context.captures.length; this.captureMap.set(hook, result); } return result; } // --------------------------------------------------------------------------- // implements Exporter exportStub(hook) { throw new Error( "Can't construct an RpcTarget or RPC callback inside a mapper function. Try creating a new RpcStub outside the callback first, then using it inside the callback." ); } exportPromise(hook) { return this.exportStub(hook); } getImport(hook) { return this.capture(hook); } unexport(ids) { } onSendError(error) { } }; mapImpl.sendMap = (hook, path, func) => { let builder = new MapBuilder(hook, path); let result; try { result = RpcPayload.fromAppReturn(withCallInterceptor(builder.pushCall.bind(builder), () => { return func(new RpcPromise(builder.makeInput(), [])); })); } finally { builder.unregister(); } if (result instanceof Promise) { result.catch((err) => { }); throw new Error("RPC map() callbacks cannot be async."); } return new RpcPromise(builder.makeOutput(result), []); }; function throwMapperBuilderUseError() { throw new Error( "Attempted to use an abstract placeholder from a mapper function. Please make sure your map function has no side effects." ); } var MapVariableHook = class extends StubHook { constructor(mapper, idx) { super(); this.mapper = mapper; this.idx = idx; } // We don't have anything we actually need to dispose, so dup() can just return the same hook. dup() { return this; } dispose() { } get(path) { if (path.length == 0) { return this; } else if (currentMapBuilder) { return currentMapBuilder.pushGet(this, path); } else { throwMapperBuilderUseError(); } } // Other methods should never be called. call(path, args) { throwMapperBuilderUseError(); } map(path, captures, instructions) { throwMapperBuilderUseError(); } pull() { throwMapperBuilderUseError(); } ignoreUnhandledRejections() { } onBroken(callback) { throwMapperBuilderUseError(); } }; var MapApplicator = class { constructor(captures, input) { this.captures = captures; this.variables = [input]; } variables; dispose() { for (let variable of this.variables) { variable.dispose(); } } apply(instructions) { try { if (instructions.length < 1) { throw new Error("Invalid empty mapper function."); } for (let instruction of instructions.slice(0, -1)) { let payload = new Evaluator(this).evaluateCopy(instruction); if (payload.value instanceof RpcStub) { let hook = unwrapStubNoProperties(payload.value); if (hook) { this.variables.push(hook); continue; } } this.variables.push(new PayloadStubHook(payload)); } return new Evaluator(this).evaluateCopy(instructions[instructions.length - 1]); } finally { for (let variable of this.variables) { variable.dispose(); } } } importStub(idx) { throw new Error("A mapper function cannot refer to exports."); } importPromise(idx) { return this.importStub(idx); } getExport(idx) { if (idx < 0) { return this.captures[-idx - 1]; } else { return this.variables[idx]; } } }; function applyMapToElement(input, parent, owner, captures, instructions) { let inputHook = new PayloadStubHook(RpcPayload.deepCopyFrom(input, parent, owner)); let mapper = new MapApplicator(captures, inputHook); try { return mapper.apply(instructions); } finally { mapper.dispose(); } } mapImpl.applyMap = (input, parent, owner, captures, instructions) => { try { let result; if (input instanceof RpcPromise) { throw new Error("applyMap() can't be called on RpcPromise"); } else if (input instanceof Array) { let payloads = []; try { for (let elem of input) { payloads.push(applyMapToElement(elem, input, owner, captures, instructions)); } } catch (err) { for (let payload of payloads) { payload.dispose(); } throw err; } result = RpcPayload.fromArray(payloads); } else if (input === null || input === void 0) { result = RpcPayload.fromAppReturn(input); } else { result = applyMapToElement(input, parent, owner, captures, instructions); } return new PayloadStubHook(result); } finally { for (let cap of captures) { cap.dispose(); } } }; async function newWorkersRpcResponse(request, localMain) { if (request.method === "POST") { let response = await newHttpBatchRpcResponse(request, localMain); response.headers.set("Access-Control-Allow-Origin", "*"); return response; } else if (request.headers.get("Upgrade")?.toLowerCase() === "websocket") { return newWorkersWebSocketRpcResponse(request, localMain); } else { return new Response("This endpoint only accepts POST or WebSocket requests.", { status: 400 }); } } // templates/remoteBindings/ProxyServerWorker.ts import { EmailMessage } from "cloudflare:email"; var BindingNotFoundError = class extends Error { constructor(name) { super(`Binding ${name ? `"${name}"` : ""} not found`); } }; function getExposedJSRPCBinding(request, env) { const url = new URL(request.url); const bindingName = url.searchParams.get("MF-Binding"); if (!bindingName) { throw new BindingNotFoundError(); } const targetBinding = env[bindingName]; if (!targetBinding) { throw new BindingNotFoundError(bindingName); } if (targetBinding.constructor.name === "SendEmail") { return { async send(e) { const message = new EmailMessage(e.from, e.to, e["EmailMessage::raw"]); return targetBinding.send(message); } }; } if (url.searchParams.has("MF-Dispatch-Namespace-Options")) { const { name, args, options } = JSON.parse( url.searchParams.get("MF-Dispatch-Namespace-Options") ); return targetBinding.get(name, args, options); } return targetBinding; } function getExposedFetcher(request, env) { const bindingName = request.headers.get("MF-Binding"); if (!bindingName) { throw new BindingNotFoundError(); } const targetBinding = env[bindingName]; if (!targetBinding) { throw new BindingNotFoundError(bindingName); } const dispatchNamespaceOptions = request.headers.get( "MF-Dispatch-Namespace-Options" ); if (dispatchNamespaceOptions) { const { name, args, options } = JSON.parse(dispatchNamespaceOptions); return targetBinding.get(name, args, options); } return targetBinding; } function isJSRPCBinding(request) { const url = new URL(request.url); return request.headers.has("Upgrade") && url.searchParams.has("MF-Binding"); } var ProxyServerWorker_default = { async fetch(request, env) { try { if (isJSRPCBinding(request)) { return newWorkersRpcResponse( request, getExposedJSRPCBinding(request, env) ); } else { const fetcher = getExposedFetcher(request, env); const originalHeaders = new Headers(); for (const [name, value] of request.headers) { if (name.startsWith("mf-header-")) { originalHeaders.set(name.slice("mf-header-".length), value); } else if (name === "upgrade") { originalHeaders.set(name, value); } } return fetcher.fetch( request.headers.get("MF-URL") ?? "http://example.com", new Request(request, { redirect: "manual", headers: originalHeaders }) ); } } catch (e) { if (e instanceof BindingNotFoundError) { return new Response(e.message, { status: 400 }); } return new Response(e.message, { status: 500 }); } } }; export { ProxyServerWorker_default as default };