@xentobias/worker-rpc 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/error.d.ts +11 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/types.d.ts +16 -2
- package/package.json +1 -1
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SerializedError } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Serialize an Error into a wire-format object.
|
|
4
|
+
* Captures message, name, stack, custom own enumerable properties, and cause chain.
|
|
5
|
+
*/
|
|
6
|
+
export declare function serializeError(err: Error): SerializedError;
|
|
7
|
+
/**
|
|
8
|
+
* Deserialize a wire-format error back into an Error instance.
|
|
9
|
+
* Restores message, name, stack, custom properties, and cause chain.
|
|
10
|
+
*/
|
|
11
|
+
export declare function deserializeError(data: SerializedError): Error;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Endpoint, type EndpointOptions } from "./endpoint";
|
|
2
2
|
import { type MessageTarget, type RemoteObject } from "./types";
|
|
3
3
|
export * from "./types";
|
|
4
|
+
export * from "./error";
|
|
4
5
|
export * from "./endpoint";
|
|
5
6
|
export * from "./proxy";
|
|
6
7
|
export * from "./broadcast";
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var V;((K)=>{K[K.Call=0]="Call";K[K.Result=1]="Result";K[K.Error=2]="Error";K[K.Callback=3]="Callback";K[K.CallbackRelease=4]="CallbackRelease";K[K.EndpointRelease=5]="EndpointRelease"})(V||={});var f=30000;class S{static generateRandomId(){return Math.random().toString(36).slice(2,8)}static extractEndpointId(q){return q.split(":")[1]??""}target;options;exposedApi=null;exposeOptions={};id;callCounter=0;callbackCounter=0;pendingCalls=new Map;callbacks=new Map;remoteCallbacks=new Map;boundMessageHandler;released=!1;constructor(q,z={}){this.target=q,this.id=z.id??S.generateRandomId(),this.options={id:this.id,timeout:z.timeout??f,onError:z.onError??console.error,debug:z.debug??!1,onRelease:z.onRelease??(()=>{})},this.boundMessageHandler=this.handleMessage.bind(this),this.attachListener()}generateCallId(){return`c:${this.id}:${++this.callCounter}`}generateCallbackId(){return`cb:${this.id}:${++this.callbackCounter}`}attachListener(){if(this.target.addEventListener)this.target.addEventListener("message",this.boundMessageHandler);else if(this.target.onmessage!==void 0)this.target.onmessage=this.boundMessageHandler}detachListener(){if(this.target.removeEventListener)this.target.removeEventListener("message",this.boundMessageHandler);else if(this.target.onmessage!==void 0)this.target.onmessage=null}debug(...q){if(this.options.debug)console.log("[worker-rpc]",...q)}expose(q,z={}){this.exposedApi=q,this.exposeOptions={maxDepth:z.maxDepth??10}}handleMessage(q){let z=q.data;if(typeof z!=="object"||z===null||!("t"in z))return;switch(this.debug("received",V[z.t],z),z.t){case 0:this.handleCall(z);break;case 1:this.handleResult(z);break;case 2:this.handleError(z);break;case 3:this.handleCallback(z);break;case 4:this.handleCallbackRelease(z);break;case 5:this.handleEndpointRelease();break}}async handleCall(q){let{id:z,p:G,a:Q,c:Z}=q;try{let{method:$,thisArg:K}=this.resolveMethod(G);if(typeof $!=="function")throw Error(`Method not found: ${G.join(".")}`);let J=Q.map((Y,L)=>{let N=Z?.[L];if(N)return this.createRemoteCallback(N);return Y}),U=await $.apply(K,J),{rawValue:W,callbackMap:H}=this.processResult(U);this.send({t:1,id:z,v:W,...Object.keys(H).length>0&&{cm:H}})}catch($){let K=$ instanceof Error?$:Error(String($));this.send({t:2,id:z,e:K.message,n:K.name,s:K.stack})}}resolveMethod(q){if(!this.exposedApi)throw Error("No API exposed");let z=this.exposedApi,G=null;for(let Q=0;Q<q.length;Q++){let Z=q[Q];if(z===null||z===void 0)throw Error(`Cannot access property '${Z}' of ${z}`);if(Z===void 0)throw Error(`Invalid path at index ${Q}`);if(G=z,z=z[Z],Q>=(this.exposeOptions.maxDepth??10))throw Error("Maximum nesting depth exceeded")}return{target:this.exposedApi,method:z,thisArg:G}}handleResult(q){let z=this.pendingCalls.get(q.id);if(!z){this.debug("Received result for unknown call:",q.id);return}if(this.pendingCalls.delete(q.id),z.timer)clearTimeout(z.timer);if(q.cm&&Object.keys(q.cm).length>0)z.resolve(this.reconstructResult(q.v,q.cm));else z.resolve(q.v)}handleError(q){let z=this.pendingCalls.get(q.id);if(!z){this.debug("Received error for unknown call:",q.id);return}if(this.pendingCalls.delete(q.id),z.timer)clearTimeout(z.timer);let G=Error(q.e);if(q.n)G.name=q.n;if(q.s)G.stack=q.s;z.reject(G)}async handleCallback(q){let{id:z,c:G,a:Q,cb:Z}=q,$=this.callbacks.get(G);if(!$){this.send({t:2,id:z,e:`Callback not found: ${G}`});return}try{let K=Q.map((H,Y)=>{let L=Z?.[Y];if(L)return this.createRemoteCallback(L);return H}),J=await $.fn(...K);if($.remaining>0){if($.remaining--,$.remaining===0)this.callbacks.delete(G)}let{rawValue:U,callbackMap:W}=this.processResult(J);this.send({t:1,id:z,v:U,...Object.keys(W).length>0&&{cm:W}})}catch(K){let J=K instanceof Error?K:Error(String(K));this.send({t:2,id:z,e:J.message,n:J.name,s:J.stack})}}handleCallbackRelease(q){for(let z of q.c)this.callbacks.delete(z)}handleEndpointRelease(){this.debug("Remote endpoint released"),this.options.onRelease(),this.release({silent:!0})}registerCallback(q,z=-1){let G=this.generateCallbackId();return this.callbacks.set(G,{fn:q,remaining:z}),G}createRemoteCallback(q){let z=this.remoteCallbacks.get(q);if(z)return z;return z=async(...G)=>{return this.invokeCallback(q,G)},this.remoteCallbacks.set(q,z),z}async invokeCallback(q,z){let G=this.generateCallId(),Q=[],Z={},$=[];for(let K=0;K<z.length;K++){let J=z[K];if(X(J))Z[K]=this.registerCallback(J),Q.push(null);else if(j(J))$.push(J),Q.push(J);else Q.push(J)}return new Promise((K,J)=>{let U=setTimeout(()=>{this.pendingCalls.delete(G),J(Error(`Callback invocation timed out: ${q}`))},this.options.timeout);this.pendingCalls.set(G,{resolve:K,reject:J,timer:U});let W={t:3,id:G,c:q,a:Q,...Object.keys(Z).length>0&&{cb:Z}};this.send(W,$)})}processArgs(q){let z=[],G={},Q=[];for(let Z=0;Z<q.length;Z++){let $=q[Z];if(X($))G[Z]=this.registerCallback($),z.push(null);else if(j($))Q.push($),z.push($);else z.push($)}return{rawArgs:z,callbackMap:G,transferables:Q}}processResult(q){if(X(q))return{rawValue:null,callbackMap:{"":this.registerCallback(q)}};if(q!==null&&typeof q==="object"&&!Array.isArray(q)&&!j(q)&&!(q instanceof ArrayBuffer)){let z={},G={};for(let Q in q){let Z=q[Q];if(X(Z))z[Q]=this.registerCallback(Z);else G[Q]=Z}if(Object.keys(z).length>0)return{rawValue:G,callbackMap:z}}return{rawValue:q,callbackMap:{}}}reconstructResult(q,z){if(""in z)return this.createRemoteCallback(z[""]);let G=q&&typeof q==="object"?{...q}:{};for(let Q in z){let Z=z[Q];if(Z)G[Q]=this.createRemoteCallback(Z)}return G}buildCallMessage(q,z,G,Q){return{t:0,id:q,p:z,a:G,...Object.keys(Q).length>0&&{c:Q}}}call(q,z){if(this.released)return Promise.reject(Error("Endpoint has been released"));let{rawArgs:G,callbackMap:Q,transferables:Z}=this.processArgs(z),$=this.generateCallId(),K=this.buildCallMessage($,q,G,Q);return new Promise((J,U)=>{let W=setTimeout(()=>{this.pendingCalls.delete($),U(Error(`Call timed out: ${q.join(".")}`))},this.options.timeout);this.pendingCalls.set($,{resolve:J,reject:U,timer:W}),this.send(K,Z)})}send(q,z=[]){this.debug("sending",V[q.t],q),this.target.postMessage(q,z)}getPendingCallCount(){return this.pendingCalls.size}hasPendingCalls(){return this.pendingCalls.size>0}async shutdown(q={}){let{timeout:z=f}=q;if(this.released)return{success:!0,timeout:!1};if(!this.hasPendingCalls())return this.release(),{success:!0,timeout:!1};return new Promise((G)=>{let Q=!1,Z=(K)=>{if(Q)return;if(Q=!0,clearTimeout($),!this.released)this.release();G(K)},$=setTimeout(()=>{Z({success:!1,timeout:!0})},z);for(let[,K]of this.pendingCalls){let{resolve:J,reject:U}=K;K.resolve=(W)=>{if(J(W),!this.hasPendingCalls())Z({success:!0,timeout:!1})},K.reject=(W)=>{if(U(W),!this.hasPendingCalls())Z({success:!0,timeout:!1})}}})}release(q={}){if(this.released)return;this.released=!0;for(let[,G]of this.pendingCalls){if(G.timer)clearTimeout(G.timer);G.reject(Error("Endpoint released"))}this.pendingCalls.clear();let{silent:z=!1}=q;if(!z){if(this.remoteCallbacks.size>0){let G=[...this.remoteCallbacks.keys()];this.send({t:4,id:this.generateCallId(),c:G})}this.send({t:5,id:this.generateCallId()})}this.remoteCallbacks.clear(),this.callbacks.clear(),this.detachListener()}getTarget(){return this.target}}function X(q){return typeof q==="function"}function j(q){return typeof MessagePort<"u"&&q instanceof MessagePort}function D(q,z){return new S(q,z)}var F=Symbol("rpc:path"),B=Symbol("rpc:proxy-endpoint"),_=Symbol.for("rpc:remote-proxy"),C=Symbol.for("rpc:endpoint"),R=Symbol.for("rpc:release"),w={get(q,z){if(z===_)return!0;if(z===C)return q[B];if(z===R)return()=>{q[B].release()};if(z==="then"){if(q[F].length===0)return;let G=q[B],Q=q[F],Z=G.call(Q,[]);return Z.then.bind(Z)}if(z==="toJSON")return;if(z===Symbol.toStringTag||z===Symbol.iterator||z===Symbol.asyncIterator||z==="constructor"||z==="prototype")return;if(typeof z==="string"){let G=q[B],Z=[...q[F],z];return O(G,Z)}},apply(q,z,G){let Q=q[B],Z=q[F];return Q.call(Z,G)},set(){throw Error("Cannot set properties on a remote proxy")},deleteProperty(){throw Error("Cannot delete properties on a remote proxy")},getPrototypeOf(){return Function.prototype},has(q,z){return z===_||z===C||z===R}};function O(q,z){let G=function(){};return G[B]=q,G[F]=z,new Proxy(G,w)}function x(q){return O(q,[])}function A(q){if(q===null||q===void 0)return!1;try{return q[_]===!0}catch{return!1}}function T(q){if(A(q))return q[C]}function v(q){if(A(q))q[R]()}class P extends S{pendingBroadcastCalls=new Map;get broadcastTarget(){return this.target}call(q,z){if(this.released)return Promise.reject(Error("Endpoint has been released"));let{rawArgs:G,callbackMap:Q,transferables:Z}=this.processArgs(z),$=this.generateCallId(),K=this.buildCallMessage($,q,G,Q);return this.sendBroadcast($,K,Z,q)}sendBroadcast(q,z,G,Q){return this.debug("sending broadcast",V[z.t],z),new Promise((Z,$)=>{let K={resolve:Z,reject:$,timer:setTimeout(()=>this.handleTimeout(q,Q),this.options.timeout),expectedCount:1/0,results:[],errors:[]};this.pendingBroadcastCalls.set(q,K),Promise.resolve(this.broadcastTarget.postMessage(z,G)).then((J)=>this.handleSubscriberCount(q,J))})}handleTimeout(q,z){let G=this.pendingBroadcastCalls.get(q);if(!G)return;this.pendingBroadcastCalls.delete(q);let Q=G.results.length+G.errors.length,Z=G.expectedCount===1/0?0:G.expectedCount-Q;if(Z>0){let $=Error(`Broadcast timed out: ${z.join(".")}`);$.name="TimeoutError";for(let K=0;K<Z;K++)G.errors.push($)}if(this.debug(`Broadcast timed out with ${G.results.length} results, ${G.errors.length} errors (${Z} timed out)`),G.results.length>0||G.errors.length>0)G.resolve({results:G.results,errors:G.errors});else G.reject(Error(`Broadcast timed out: ${z.join(".")}`))}handleSubscriberCount(q,z){let G=this.pendingBroadcastCalls.get(q);if(!G)return;if(z===0){this.completeBroadcast(q,G);return}G.expectedCount=z,this.checkCompletion(q,G)}checkCompletion(q,z){if(z.results.length+z.errors.length>=z.expectedCount)this.completeBroadcast(q,z)}completeBroadcast(q,z){this.pendingBroadcastCalls.delete(q),clearTimeout(z.timer),z.resolve({results:z.results,errors:z.errors})}handleResult(q){let z=this.pendingBroadcastCalls.get(q.id);if(!z){super.handleResult(q);return}if(q.cm&&Object.keys(q.cm).length>0)z.results.push(this.reconstructResult(q.v,q.cm));else z.results.push(q.v);this.debug(`Broadcast received ${z.results.length}/${z.expectedCount} responses`),this.checkCompletion(q.id,z)}handleError(q){let z=this.pendingBroadcastCalls.get(q.id);if(!z){super.handleError(q);return}let G=Error(q.e);if(q.n)G.name=q.n;if(q.s)G.stack=q.s;z.errors.push(G),this.debug(`Broadcast received error (${z.results.length} results, ${z.errors.length} errors / ${z.expectedCount} expected)`),this.checkCompletion(q.id,z)}getPendingCallCount(){return super.getPendingCallCount()+this.pendingBroadcastCalls.size}hasPendingCalls(){return super.hasPendingCalls()||this.pendingBroadcastCalls.size>0}release(q={}){for(let[,z]of this.pendingBroadcastCalls)clearTimeout(z.timer),z.reject(Error("Endpoint released"));this.pendingBroadcastCalls.clear(),super.release(q)}}function y(q,z){return new P(q,z)}function l(q,z){let Q=D(globalThis,z);return Q.expose(q),Q}function o(q,z){let G=D(q,z);return x(G)}export{x as wrap,o as remote,v as releaseProxy,A as isProxy,j as isMessagePort,X as isFunction,T as getEndpoint,l as expose,D as createEndpoint,y as createBroadcastEndpoint,_ as REMOTE_PROXY,R as RELEASE,B as PROXY_ENDPOINT,F as PATH,V as MessageType,S as Endpoint,C as ENDPOINT,P as BroadcastEndpoint};
|
|
2
|
+
var B;((K)=>{K[K.Call=0]="Call";K[K.Result=1]="Result";K[K.Error=2]="Error";K[K.Callback=3]="Callback";K[K.CallbackRelease=4]="CallbackRelease";K[K.EndpointRelease=5]="EndpointRelease"})(B||={});var h=new Set(["message","name","stack","cause"]);function Y(q){let G={e:q.message,n:q.name,s:q.stack},Q={};for(let Z of Object.keys(q))if(!h.has(Z))Q[Z]=q[Z];if(Object.keys(Q).length>0)G.d=Q;if(q.cause instanceof Error)G.c=Y(q.cause);else if(q.cause!==void 0)G.c={e:String(q.cause),d:{cause:q.cause}};return G}function H(q){let G=q.c?{cause:H(q.c)}:void 0,Q=Error(q.e,G);if(q.n)Q.name=q.n;if(q.s)Q.stack=q.s;if(q.d)Object.assign(Q,q.d);return Q}var O=30000;class L{static generateRandomId(){return Math.random().toString(36).slice(2,8)}static extractEndpointId(q){return q.split(":")[1]??""}target;options;exposedApi=null;exposeOptions={};id;callCounter=0;callbackCounter=0;pendingCalls=new Map;callbacks=new Map;remoteCallbacks=new Map;boundMessageHandler;released=!1;constructor(q,G={}){this.target=q,this.id=G.id??L.generateRandomId(),this.options={id:this.id,timeout:G.timeout??O,onError:G.onError??console.error,debug:G.debug??!1,onRelease:G.onRelease??(()=>{})},this.boundMessageHandler=this.handleMessage.bind(this),this.attachListener()}generateCallId(){return`c:${this.id}:${++this.callCounter}`}generateCallbackId(){return`cb:${this.id}:${++this.callbackCounter}`}attachListener(){if(this.target.addEventListener)this.target.addEventListener("message",this.boundMessageHandler);else if(this.target.onmessage!==void 0)this.target.onmessage=this.boundMessageHandler}detachListener(){if(this.target.removeEventListener)this.target.removeEventListener("message",this.boundMessageHandler);else if(this.target.onmessage!==void 0)this.target.onmessage=null}debug(...q){if(this.options.debug)console.log("[worker-rpc]",...q)}expose(q,G={}){this.exposedApi=q,this.exposeOptions={maxDepth:G.maxDepth??10}}handleMessage(q){let G=q.data;if(typeof G!=="object"||G===null||!("t"in G))return;switch(this.debug("received",B[G.t],G),G.t){case 0:this.handleCall(G);break;case 1:this.handleResult(G);break;case 2:this.handleError(G);break;case 3:this.handleCallback(G);break;case 4:this.handleCallbackRelease(G);break;case 5:this.handleEndpointRelease();break}}async handleCall(q){let{id:G,p:Q,a:Z,c:$}=q;try{let{method:J,thisArg:K}=this.resolveMethod(Q);if(typeof J!=="function")throw Error(`Method not found: ${Q.join(".")}`);let W=Z.map((C,X)=>{let x=$?.[X];if(x)return this.createRemoteCallback(x);return C}),V=await J.apply(K,W),{rawValue:U,callbackMap:S}=this.processResult(V);this.send({t:1,id:G,v:U,...Object.keys(S).length>0&&{cm:S}})}catch(J){let K=J instanceof Error?J:Error(String(J));this.send({t:2,id:G,...Y(K)})}}resolveMethod(q){if(!this.exposedApi)throw Error("No API exposed");let G=this.exposedApi,Q=null;for(let Z=0;Z<q.length;Z++){let $=q[Z];if(G===null||G===void 0)throw Error(`Cannot access property '${$}' of ${G}`);if($===void 0)throw Error(`Invalid path at index ${Z}`);if(Q=G,G=G[$],Z>=(this.exposeOptions.maxDepth??10))throw Error("Maximum nesting depth exceeded")}return{target:this.exposedApi,method:G,thisArg:Q}}handleResult(q){let G=this.pendingCalls.get(q.id);if(!G){this.debug("Received result for unknown call:",q.id);return}if(this.pendingCalls.delete(q.id),G.timer)clearTimeout(G.timer);if(q.cm&&Object.keys(q.cm).length>0)G.resolve(this.reconstructResult(q.v,q.cm));else G.resolve(q.v)}handleError(q){let G=this.pendingCalls.get(q.id);if(!G){this.debug("Received error for unknown call:",q.id);return}if(this.pendingCalls.delete(q.id),G.timer)clearTimeout(G.timer);G.reject(H(q))}async handleCallback(q){let{id:G,c:Q,a:Z,cb:$}=q,J=this.callbacks.get(Q);if(!J){this.send({t:2,id:G,e:`Callback not found: ${Q}`});return}try{let K=Z.map((S,C)=>{let X=$?.[C];if(X)return this.createRemoteCallback(X);return S}),W=await J.fn(...K);if(J.remaining>0){if(J.remaining--,J.remaining===0)this.callbacks.delete(Q)}let{rawValue:V,callbackMap:U}=this.processResult(W);this.send({t:1,id:G,v:V,...Object.keys(U).length>0&&{cm:U}})}catch(K){let W=K instanceof Error?K:Error(String(K));this.send({t:2,id:G,...Y(W)})}}handleCallbackRelease(q){for(let G of q.c)this.callbacks.delete(G)}handleEndpointRelease(){this.debug("Remote endpoint released"),this.options.onRelease(),this.release({silent:!0})}registerCallback(q,G=-1){let Q=this.generateCallbackId();return this.callbacks.set(Q,{fn:q,remaining:G}),Q}createRemoteCallback(q){let G=this.remoteCallbacks.get(q);if(G)return G;return G=async(...Q)=>{return this.invokeCallback(q,Q)},this.remoteCallbacks.set(q,G),G}async invokeCallback(q,G){let Q=this.generateCallId(),Z=[],$={},J=[];for(let K=0;K<G.length;K++){let W=G[K];if(j(W))$[K]=this.registerCallback(W),Z.push(null);else if(D(W))J.push(W),Z.push(W);else Z.push(W)}return new Promise((K,W)=>{let V=setTimeout(()=>{this.pendingCalls.delete(Q),W(Error(`Callback invocation timed out: ${q}`))},this.options.timeout);this.pendingCalls.set(Q,{resolve:K,reject:W,timer:V});let U={t:3,id:Q,c:q,a:Z,...Object.keys($).length>0&&{cb:$}};this.send(U,J)})}processArgs(q){let G=[],Q={},Z=[];for(let $=0;$<q.length;$++){let J=q[$];if(j(J))Q[$]=this.registerCallback(J),G.push(null);else if(D(J))Z.push(J),G.push(J);else G.push(J)}return{rawArgs:G,callbackMap:Q,transferables:Z}}processResult(q){if(j(q))return{rawValue:null,callbackMap:{"":this.registerCallback(q)}};if(q!==null&&typeof q==="object"&&!Array.isArray(q)&&!D(q)&&!(q instanceof ArrayBuffer)){let G={},Q={};for(let Z in q){let $=q[Z];if(j($))G[Z]=this.registerCallback($);else Q[Z]=$}if(Object.keys(G).length>0)return{rawValue:Q,callbackMap:G}}return{rawValue:q,callbackMap:{}}}reconstructResult(q,G){if(""in G)return this.createRemoteCallback(G[""]);let Q=q&&typeof q==="object"?{...q}:{};for(let Z in G){let $=G[Z];if($)Q[Z]=this.createRemoteCallback($)}return Q}buildCallMessage(q,G,Q,Z){return{t:0,id:q,p:G,a:Q,...Object.keys(Z).length>0&&{c:Z}}}call(q,G){if(this.released)return Promise.reject(Error("Endpoint has been released"));let{rawArgs:Q,callbackMap:Z,transferables:$}=this.processArgs(G),J=this.generateCallId(),K=this.buildCallMessage(J,q,Q,Z);return new Promise((W,V)=>{let U=setTimeout(()=>{this.pendingCalls.delete(J),V(Error(`Call timed out: ${q.join(".")}`))},this.options.timeout);this.pendingCalls.set(J,{resolve:W,reject:V,timer:U}),this.send(K,$)})}send(q,G=[]){this.debug("sending",B[q.t],q),this.target.postMessage(q,G)}getPendingCallCount(){return this.pendingCalls.size}hasPendingCalls(){return this.pendingCalls.size>0}async shutdown(q={}){let{timeout:G=O}=q;if(this.released)return{success:!0,timeout:!1};if(!this.hasPendingCalls())return this.release(),{success:!0,timeout:!1};return new Promise((Q)=>{let Z=!1,$=(K)=>{if(Z)return;if(Z=!0,clearTimeout(J),!this.released)this.release();Q(K)},J=setTimeout(()=>{$({success:!1,timeout:!0})},G);for(let[,K]of this.pendingCalls){let{resolve:W,reject:V}=K;K.resolve=(U)=>{if(W(U),!this.hasPendingCalls())$({success:!0,timeout:!1})},K.reject=(U)=>{if(V(U),!this.hasPendingCalls())$({success:!0,timeout:!1})}}})}release(q={}){if(this.released)return;this.released=!0;for(let[,Q]of this.pendingCalls){if(Q.timer)clearTimeout(Q.timer);Q.reject(Error("Endpoint released"))}this.pendingCalls.clear();let{silent:G=!1}=q;if(!G){if(this.remoteCallbacks.size>0){let Q=[...this.remoteCallbacks.keys()];this.send({t:4,id:this.generateCallId(),c:Q})}this.send({t:5,id:this.generateCallId()})}this.remoteCallbacks.clear(),this.callbacks.clear(),this.detachListener()}getTarget(){return this.target}}function j(q){return typeof q==="function"}function D(q){return typeof MessagePort<"u"&&q instanceof MessagePort}function _(q,G){return new L(q,G)}var z=Symbol("rpc:path"),F=Symbol("rpc:proxy-endpoint"),N=Symbol.for("rpc:remote-proxy"),R=Symbol.for("rpc:endpoint"),f=Symbol.for("rpc:release"),E={get(q,G){if(G===N)return!0;if(G===R)return q[F];if(G===f)return()=>{q[F].release()};if(G==="then"){if(q[z].length===0)return;let Q=q[F],Z=q[z],$=Q.call(Z,[]);return $.then.bind($)}if(G==="toJSON")return;if(G===Symbol.toStringTag||G===Symbol.iterator||G===Symbol.asyncIterator||G==="constructor"||G==="prototype")return;if(typeof G==="string"){let Q=q[F],$=[...q[z],G];return A(Q,$)}},apply(q,G,Q){let Z=q[F],$=q[z];return Z.call($,Q)},set(){throw Error("Cannot set properties on a remote proxy")},deleteProperty(){throw Error("Cannot delete properties on a remote proxy")},getPrototypeOf(){return Function.prototype},has(q,G){return G===N||G===R||G===f}};function A(q,G){let Q=function(){};return Q[F]=q,Q[z]=G,new Proxy(Q,E)}function P(q){return A(q,[])}function w(q){if(q===null||q===void 0)return!1;try{return q[N]===!0}catch{return!1}}function y(q){if(w(q))return q[R]}function u(q){if(w(q))q[f]()}class I extends L{pendingBroadcastCalls=new Map;get broadcastTarget(){return this.target}call(q,G){if(this.released)return Promise.reject(Error("Endpoint has been released"));let{rawArgs:Q,callbackMap:Z,transferables:$}=this.processArgs(G),J=this.generateCallId(),K=this.buildCallMessage(J,q,Q,Z);return this.sendBroadcast(J,K,$,q)}sendBroadcast(q,G,Q,Z){return this.debug("sending broadcast",B[G.t],G),new Promise(($,J)=>{let K={resolve:$,reject:J,timer:setTimeout(()=>this.handleTimeout(q,Z),this.options.timeout),expectedCount:1/0,results:[],errors:[]};this.pendingBroadcastCalls.set(q,K),Promise.resolve(this.broadcastTarget.postMessage(G,Q)).then((W)=>this.handleSubscriberCount(q,W))})}handleTimeout(q,G){let Q=this.pendingBroadcastCalls.get(q);if(!Q)return;this.pendingBroadcastCalls.delete(q);let Z=Q.results.length+Q.errors.length,$=Q.expectedCount===1/0?0:Q.expectedCount-Z;if($>0){let J=Error(`Broadcast timed out: ${G.join(".")}`);J.name="TimeoutError";for(let K=0;K<$;K++)Q.errors.push(J)}if(this.debug(`Broadcast timed out with ${Q.results.length} results, ${Q.errors.length} errors (${$} timed out)`),Q.results.length>0||Q.errors.length>0)Q.resolve({results:Q.results,errors:Q.errors});else Q.reject(Error(`Broadcast timed out: ${G.join(".")}`))}handleSubscriberCount(q,G){let Q=this.pendingBroadcastCalls.get(q);if(!Q)return;if(G===0){this.completeBroadcast(q,Q);return}Q.expectedCount=G,this.checkCompletion(q,Q)}checkCompletion(q,G){if(G.results.length+G.errors.length>=G.expectedCount)this.completeBroadcast(q,G)}completeBroadcast(q,G){this.pendingBroadcastCalls.delete(q),clearTimeout(G.timer),G.resolve({results:G.results,errors:G.errors})}handleResult(q){let G=this.pendingBroadcastCalls.get(q.id);if(!G){super.handleResult(q);return}if(q.cm&&Object.keys(q.cm).length>0)G.results.push(this.reconstructResult(q.v,q.cm));else G.results.push(q.v);this.debug(`Broadcast received ${G.results.length}/${G.expectedCount} responses`),this.checkCompletion(q.id,G)}handleError(q){let G=this.pendingBroadcastCalls.get(q.id);if(!G){super.handleError(q);return}G.errors.push(H(q)),this.debug(`Broadcast received error (${G.results.length} results, ${G.errors.length} errors / ${G.expectedCount} expected)`),this.checkCompletion(q.id,G)}getPendingCallCount(){return super.getPendingCallCount()+this.pendingBroadcastCalls.size}hasPendingCalls(){return super.hasPendingCalls()||this.pendingBroadcastCalls.size>0}release(q={}){for(let[,G]of this.pendingBroadcastCalls)clearTimeout(G.timer),G.reject(Error("Endpoint released"));this.pendingBroadcastCalls.clear(),super.release(q)}}function o(q,G){return new I(q,G)}function n(q,G){let Z=_(globalThis,G);return Z.expose(q),Z}function s(q,G){let Q=_(q,G);return P(Q)}export{P as wrap,Y as serializeError,s as remote,u as releaseProxy,w as isProxy,D as isMessagePort,j as isFunction,y as getEndpoint,n as expose,H as deserializeError,_ as createEndpoint,o as createBroadcastEndpoint,N as REMOTE_PROXY,f as RELEASE,F as PROXY_ENDPOINT,z as PATH,B as MessageType,L as Endpoint,R as ENDPOINT,I as BroadcastEndpoint};
|
package/dist/types.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ export interface ResultMessage extends BaseMessage {
|
|
|
41
41
|
/** Callback map: property key -> callbackId (empty string key "" for single function return) */
|
|
42
42
|
cm?: Record<string, CallbackId>;
|
|
43
43
|
}
|
|
44
|
+
/** Serialized error data (used for error cause chains) */
|
|
45
|
+
export type SerializedError = Omit<ErrorMessage, 't' | 'id'>;
|
|
44
46
|
/** Error response */
|
|
45
47
|
export interface ErrorMessage extends BaseMessage {
|
|
46
48
|
t: MessageType.Error;
|
|
@@ -50,6 +52,10 @@ export interface ErrorMessage extends BaseMessage {
|
|
|
50
52
|
n?: string;
|
|
51
53
|
/** Error stack trace */
|
|
52
54
|
s?: string;
|
|
55
|
+
/** Custom error properties (own enumerable properties beyond message/name/stack) */
|
|
56
|
+
d?: Record<string, unknown>;
|
|
57
|
+
/** Serialized error cause (recursive chain) */
|
|
58
|
+
c?: SerializedError;
|
|
53
59
|
}
|
|
54
60
|
/** Callback invocation request */
|
|
55
61
|
export interface CallbackMessage extends BaseMessage {
|
|
@@ -75,14 +81,22 @@ export interface EndpointReleaseMessage extends BaseMessage {
|
|
|
75
81
|
export type RpcMessage = CallMessage | ResultMessage | ErrorMessage | CallbackMessage | CallbackReleaseMessage | EndpointReleaseMessage;
|
|
76
82
|
/** Unwrap a Promise type */
|
|
77
83
|
export type Unpromise<T> = T extends Promise<infer U> ? U : T;
|
|
84
|
+
/**
|
|
85
|
+
* Transform first-level functions in a return value to async versions.
|
|
86
|
+
* This matches the runtime behavior where only first-level object properties
|
|
87
|
+
* are scanned for functions (for performance reasons).
|
|
88
|
+
*/
|
|
89
|
+
export type RemoteReturnValue<T> = T extends (...args: infer A) => infer R ? (...args: A) => Promise<Unpromise<R>> : T extends object ? {
|
|
90
|
+
[K in keyof T]: T[K] extends (...args: infer A) => infer R ? (...args: A) => Promise<Unpromise<R>> : T[K];
|
|
91
|
+
} : T;
|
|
78
92
|
/** Helper to convert a single property to its remote version */
|
|
79
|
-
export type RemoteProperty<T> = T extends (...args: infer A) => infer R ? (...args: A) => Promise<Unpromise<R
|
|
93
|
+
export type RemoteProperty<T> = T extends (...args: infer A) => infer R ? (...args: A) => Promise<RemoteReturnValue<Unpromise<R>>> : T extends object ? RemoteObject<T> : T;
|
|
80
94
|
/** Convert an object type to its remote callable version */
|
|
81
95
|
export type RemoteObject<T> = {
|
|
82
96
|
[K in keyof T]: RemoteProperty<T[K]>;
|
|
83
97
|
};
|
|
84
98
|
/** Helper to convert a single property to its broadcast remote version */
|
|
85
|
-
export type RemoteBroadcastProperty<T> = T extends (...args: infer A) => infer R ? (...args: A) => Promise<BroadcastResult<Unpromise<R
|
|
99
|
+
export type RemoteBroadcastProperty<T> = T extends (...args: infer A) => infer R ? (...args: A) => Promise<BroadcastResult<RemoteReturnValue<Unpromise<R>>>> : T extends object ? RemoteBroadcastObject<T> : T;
|
|
86
100
|
/** Convert an object type to its broadcast remote version (all methods return arrays) */
|
|
87
101
|
export type RemoteBroadcastObject<T> = {
|
|
88
102
|
[K in keyof T]: RemoteBroadcastProperty<T[K]>;
|