+183
-187
@@ -1,3 +0,4 @@ | ||
| type ArgumentsType<T> = T extends (...args: infer A) => any ? A : never; | ||
| type ReturnType<T> = T extends (...args: any) => infer R ? R : never; | ||
| //#region src/index.d.ts | ||
| type ArgumentsType<T> = T extends ((...args: infer A) => any) ? A : never; | ||
| type ReturnType<T> = T extends ((...args: any) => infer R) ? R : never; | ||
| type PromisifyFn<T> = ReturnType<T> extends Promise<any> ? T : (...args: ArgumentsType<T>) => Promise<Awaited<ReturnType<T>>>; | ||
@@ -7,202 +8,198 @@ type Thenable<T> = T | PromiseLike<T>; | ||
| interface ChannelOptions { | ||
| /** | ||
| * Function to post raw message | ||
| */ | ||
| post: (data: any, ...extras: any[]) => any | Promise<any>; | ||
| /** | ||
| * Listener to receive raw message | ||
| */ | ||
| on: (fn: (data: any, ...extras: any[]) => void) => any | Promise<any>; | ||
| /** | ||
| * Clear the listener when `$close` is called | ||
| */ | ||
| off?: (fn: (data: any, ...extras: any[]) => void) => any | Promise<any>; | ||
| /** | ||
| * Custom function to serialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| serialize?: (data: any) => any; | ||
| /** | ||
| * Custom function to deserialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| deserialize?: (data: any) => any; | ||
| /** | ||
| * Call the methods with the RPC context or the original functions object | ||
| */ | ||
| bind?: 'rpc' | 'functions'; | ||
| /** | ||
| * Custom meta data to attached to the RPC instance's `$meta` property | ||
| */ | ||
| meta?: any; | ||
| /** | ||
| * Function to post raw message | ||
| */ | ||
| post: (data: any, ...extras: any[]) => any | Promise<any>; | ||
| /** | ||
| * Listener to receive raw message | ||
| */ | ||
| on: (fn: (data: any, ...extras: any[]) => void) => any | Promise<any>; | ||
| /** | ||
| * Clear the listener when `$close` is called | ||
| */ | ||
| off?: (fn: (data: any, ...extras: any[]) => void) => any | Promise<any>; | ||
| /** | ||
| * Custom function to serialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| serialize?: (data: any) => any; | ||
| /** | ||
| * Custom function to deserialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| deserialize?: (data: any) => any; | ||
| /** | ||
| * Call the methods with the RPC context or the original functions object | ||
| */ | ||
| bind?: 'rpc' | 'functions'; | ||
| /** | ||
| * Custom meta data to attached to the RPC instance's `$meta` property | ||
| */ | ||
| meta?: any; | ||
| } | ||
| interface EventOptions<RemoteFunctions, LocalFunctions extends object = Record<string, never>> { | ||
| /** | ||
| * Names of remote functions that do not need response. | ||
| */ | ||
| eventNames?: (keyof RemoteFunctions)[]; | ||
| /** | ||
| * Maximum timeout for waiting for response, in milliseconds. | ||
| * | ||
| * @default 60_000 | ||
| */ | ||
| timeout?: number; | ||
| /** | ||
| * Custom resolver to resolve function to be called | ||
| * | ||
| * For advanced use cases only | ||
| */ | ||
| resolver?: BirpcResolver<BirpcReturn<RemoteFunctions, LocalFunctions>>; | ||
| /** | ||
| * Hook triggered before an event is sent to the remote | ||
| * | ||
| * @param req - Request parameters | ||
| * @param next - Function to continue the request | ||
| * @param resolve - Function to resolve the response directly | ||
| */ | ||
| onRequest?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, req: Request, next: (req?: Request) => Promise<any>, resolve: (res: any) => void) => void | Promise<void>; | ||
| /** | ||
| * Custom error handler | ||
| * | ||
| * @deprecated use `onFunctionError` and `onGeneralError` instead | ||
| */ | ||
| onError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for errors occurred in local functions being called | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onFunctionError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for errors occurred during serialization or messsaging | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onGeneralError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName?: string, args?: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for timeouts | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onTimeoutError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Names of remote functions that do not need response. | ||
| */ | ||
| eventNames?: (keyof RemoteFunctions)[]; | ||
| /** | ||
| * Maximum timeout for waiting for response, in milliseconds. | ||
| * | ||
| * @default 60_000 | ||
| */ | ||
| timeout?: number; | ||
| /** | ||
| * Custom resolver to resolve function to be called | ||
| * | ||
| * For advanced use cases only | ||
| */ | ||
| resolver?: BirpcResolver<BirpcReturn<RemoteFunctions, LocalFunctions>>; | ||
| /** | ||
| * Hook triggered before an event is sent to the remote | ||
| * | ||
| * @param req - Request parameters | ||
| * @param next - Function to continue the request | ||
| * @param resolve - Function to resolve the response directly | ||
| */ | ||
| onRequest?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, req: Request, next: (req?: Request) => Promise<any>, resolve: (res: any) => void) => void | Promise<void>; | ||
| /** | ||
| * Custom error handler | ||
| * | ||
| * @deprecated use `onFunctionError` and `onGeneralError` instead | ||
| */ | ||
| onError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for errors occurred in local functions being called | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onFunctionError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for errors occurred during serialization or messsaging | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onGeneralError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName?: string, args?: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for timeouts | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onTimeoutError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, functionName: string, args: any[]) => boolean | void; | ||
| } | ||
| type BirpcOptions<RemoteFunctions, LocalFunctions extends object = Record<string, never>> = EventOptions<RemoteFunctions, LocalFunctions> & ChannelOptions; | ||
| type BirpcFn<T> = PromisifyFn<T> & { | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| asEvent: (...args: ArgumentsType<T>) => Promise<void>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| asEvent: (...args: ArgumentsType<T>) => Promise<void>; | ||
| }; | ||
| interface BirpcGroupFn<T> { | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| */ | ||
| (...args: ArgumentsType<T>): Promise<Awaited<ReturnType<T>>[]>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| asEvent: (...args: ArgumentsType<T>) => Promise<void>; | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| */ | ||
| (...args: ArgumentsType<T>): Promise<Awaited<ReturnType<T>>[]>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| asEvent: (...args: ArgumentsType<T>) => Promise<void>; | ||
| } | ||
| interface BirpcReturnBuiltin<RemoteFunctions, LocalFunctions = Record<string, never>> { | ||
| /** | ||
| * Raw functions object | ||
| */ | ||
| $functions: LocalFunctions; | ||
| /** | ||
| * Whether the RPC is closed | ||
| */ | ||
| readonly $closed: boolean; | ||
| /** | ||
| * Custom meta data attached to the RPC instance | ||
| */ | ||
| readonly $meta: any; | ||
| /** | ||
| * Close the RPC connection | ||
| */ | ||
| $close: (error?: Error) => void; | ||
| /** | ||
| * Reject pending calls | ||
| */ | ||
| $rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[]; | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| * An alternative to directly calling the function | ||
| */ | ||
| $call: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]>>>; | ||
| /** | ||
| * Same as `$call`, but returns `undefined` if the function is not defined on the remote side. | ||
| */ | ||
| $callOptional: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]> | undefined>>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| $callEvent: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<void>; | ||
| /** | ||
| * Call the remote function with the raw options. | ||
| */ | ||
| $callRaw: (options: { | ||
| method: string; | ||
| args: unknown[]; | ||
| event?: boolean; | ||
| optional?: boolean; | ||
| }) => Promise<Awaited<ReturnType<any>>[]>; | ||
| /** | ||
| * Raw functions object | ||
| */ | ||
| $functions: LocalFunctions; | ||
| /** | ||
| * Whether the RPC is closed | ||
| */ | ||
| readonly $closed: boolean; | ||
| /** | ||
| * Custom meta data attached to the RPC instance | ||
| */ | ||
| readonly $meta: any; | ||
| /** | ||
| * Close the RPC connection | ||
| */ | ||
| $close: (error?: Error) => void; | ||
| /** | ||
| * Reject pending calls | ||
| */ | ||
| $rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[]; | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| * An alternative to directly calling the function | ||
| */ | ||
| $call: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]>>>; | ||
| /** | ||
| * Same as `$call`, but returns `undefined` if the function is not defined on the remote side. | ||
| */ | ||
| $callOptional: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]> | undefined>>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| $callEvent: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<void>; | ||
| /** | ||
| * Call the remote function with the raw options. | ||
| */ | ||
| $callRaw: (options: { | ||
| method: string; | ||
| args: unknown[]; | ||
| event?: boolean; | ||
| optional?: boolean; | ||
| }) => Promise<Awaited<ReturnType<any>>[]>; | ||
| } | ||
| type BirpcReturn<RemoteFunctions, LocalFunctions = Record<string, never>> = { | ||
| [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]>; | ||
| } & BirpcReturnBuiltin<RemoteFunctions, LocalFunctions>; | ||
| type BirpcReturn<RemoteFunctions, LocalFunctions = Record<string, never>> = { [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]> } & BirpcReturnBuiltin<RemoteFunctions, LocalFunctions>; | ||
| type PendingCallHandler = (options: Pick<PromiseEntry, 'method' | 'reject'>) => void | Promise<void>; | ||
| interface BirpcGroupReturnBuiltin<RemoteFunctions> { | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| * An alternative to directly calling the function | ||
| */ | ||
| $call: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]>>>; | ||
| /** | ||
| * Same as `$call`, but returns `undefined` if the function is not defined on the remote side. | ||
| */ | ||
| $callOptional: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]> | undefined>>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| $callEvent: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<void>; | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| * An alternative to directly calling the function | ||
| */ | ||
| $call: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]>>>; | ||
| /** | ||
| * Same as `$call`, but returns `undefined` if the function is not defined on the remote side. | ||
| */ | ||
| $callOptional: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]> | undefined>>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| $callEvent: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<void>; | ||
| } | ||
| type BirpcGroupReturn<RemoteFunctions> = { | ||
| [K in keyof RemoteFunctions]: BirpcGroupFn<RemoteFunctions[K]>; | ||
| } & BirpcGroupReturnBuiltin<RemoteFunctions>; | ||
| type BirpcGroupReturn<RemoteFunctions> = { [K in keyof RemoteFunctions]: BirpcGroupFn<RemoteFunctions[K]> } & BirpcGroupReturnBuiltin<RemoteFunctions>; | ||
| interface BirpcGroup<RemoteFunctions, LocalFunctions = Record<string, never>> { | ||
| readonly clients: BirpcReturn<RemoteFunctions, LocalFunctions>[]; | ||
| readonly functions: LocalFunctions; | ||
| readonly broadcast: BirpcGroupReturn<RemoteFunctions>; | ||
| updateChannels: (fn?: ((channels: ChannelOptions[]) => void)) => BirpcReturn<RemoteFunctions, LocalFunctions>[]; | ||
| readonly clients: BirpcReturn<RemoteFunctions, LocalFunctions>[]; | ||
| readonly functions: LocalFunctions; | ||
| readonly broadcast: BirpcGroupReturn<RemoteFunctions>; | ||
| updateChannels: (fn?: ((channels: ChannelOptions[]) => void)) => BirpcReturn<RemoteFunctions, LocalFunctions>[]; | ||
| } | ||
| interface PromiseEntry { | ||
| resolve: (arg: any) => void; | ||
| reject: (error: any) => void; | ||
| method: string; | ||
| timeoutId?: ReturnType<typeof setTimeout>; | ||
| resolve: (arg: any) => void; | ||
| reject: (error: any) => void; | ||
| method: string; | ||
| timeoutId?: ReturnType<typeof setTimeout>; | ||
| } | ||
| declare const TYPE_REQUEST: "q"; | ||
| interface Request { | ||
| /** | ||
| * Type | ||
| */ | ||
| t: typeof TYPE_REQUEST; | ||
| /** | ||
| * ID | ||
| */ | ||
| i?: string; | ||
| /** | ||
| * Method | ||
| */ | ||
| m: string; | ||
| /** | ||
| * Arguments | ||
| */ | ||
| a: any[]; | ||
| /** | ||
| * Optional | ||
| */ | ||
| o?: boolean; | ||
| /** | ||
| * Type | ||
| */ | ||
| t: typeof TYPE_REQUEST; | ||
| /** | ||
| * ID | ||
| */ | ||
| i?: string; | ||
| /** | ||
| * Method | ||
| */ | ||
| m: string; | ||
| /** | ||
| * Arguments | ||
| */ | ||
| a: any[]; | ||
| /** | ||
| * Optional | ||
| */ | ||
| o?: boolean; | ||
| } | ||
@@ -212,6 +209,5 @@ declare const DEFAULT_TIMEOUT = 60000; | ||
| declare function createBirpc<RemoteFunctions = Record<string, never>, LocalFunctions extends object = Record<string, never>>($functions: LocalFunctions, options: BirpcOptions<RemoteFunctions, LocalFunctions>): BirpcReturn<RemoteFunctions, LocalFunctions>; | ||
| declare function cachedMap<T, R>(items: T[], fn: ((i: T) => R)): R[]; | ||
| declare function cachedMap<T, R$1>(items: T[], fn: ((i: T) => R$1)): R$1[]; | ||
| declare function createBirpcGroup<RemoteFunctions = Record<string, never>, LocalFunctions extends object = Record<string, never>>(functions: LocalFunctions, channels: ChannelOptions[] | (() => ChannelOptions[]), options?: EventOptions<RemoteFunctions, LocalFunctions>): BirpcGroup<RemoteFunctions, LocalFunctions>; | ||
| export { DEFAULT_TIMEOUT, cachedMap, createBirpc, createBirpcGroup }; | ||
| export type { ArgumentsType, BirpcFn, BirpcGroup, BirpcGroupFn, BirpcGroupReturn, BirpcGroupReturnBuiltin, BirpcOptions, BirpcResolver, BirpcReturn, BirpcReturnBuiltin, ChannelOptions, EventOptions, PromisifyFn, ReturnType, Thenable }; | ||
| //#endregion | ||
| export { ArgumentsType, BirpcFn, BirpcGroup, BirpcGroupFn, BirpcGroupReturn, BirpcGroupReturnBuiltin, BirpcOptions, BirpcResolver, BirpcReturn, BirpcReturnBuiltin, ChannelOptions, DEFAULT_TIMEOUT, EventOptions, PromisifyFn, ReturnType, Thenable, cachedMap, createBirpc, createBirpcGroup }; |
+253
-270
@@ -0,1 +1,2 @@ | ||
| //#region src/index.ts | ||
| const TYPE_REQUEST = "q"; | ||
@@ -5,3 +6,3 @@ const TYPE_RESPONSE = "s"; | ||
| function defaultSerialize(i) { | ||
| return i; | ||
| return i; | ||
| } | ||
@@ -12,282 +13,264 @@ const defaultDeserialize = defaultSerialize; | ||
| function createBirpc($functions, options) { | ||
| const { | ||
| post, | ||
| on, | ||
| off = () => { | ||
| }, | ||
| eventNames = [], | ||
| serialize = defaultSerialize, | ||
| deserialize = defaultDeserialize, | ||
| resolver, | ||
| bind = "rpc", | ||
| timeout = DEFAULT_TIMEOUT | ||
| } = options; | ||
| let $closed = false; | ||
| const _rpcPromiseMap = /* @__PURE__ */ new Map(); | ||
| let _promiseInit; | ||
| let rpc; | ||
| async function _call(method, args, event, optional) { | ||
| if ($closed) | ||
| throw new Error(`[birpc] rpc is closed, cannot call "${method}"`); | ||
| const req = { m: method, a: args, t: TYPE_REQUEST }; | ||
| if (optional) | ||
| req.o = true; | ||
| const send = async (_req) => post(serialize(_req)); | ||
| if (event) { | ||
| await send(req); | ||
| return; | ||
| } | ||
| if (_promiseInit) { | ||
| try { | ||
| await _promiseInit; | ||
| } finally { | ||
| _promiseInit = void 0; | ||
| } | ||
| } | ||
| let { promise, resolve, reject } = createPromiseWithResolvers(); | ||
| const id = nanoid(); | ||
| req.i = id; | ||
| let timeoutId; | ||
| async function handler(newReq = req) { | ||
| if (timeout >= 0) { | ||
| timeoutId = setTimeout(() => { | ||
| try { | ||
| const handleResult = options.onTimeoutError?.call(rpc, method, args); | ||
| if (handleResult !== true) | ||
| throw new Error(`[birpc] timeout on calling "${method}"`); | ||
| } catch (e) { | ||
| reject(e); | ||
| } | ||
| _rpcPromiseMap.delete(id); | ||
| }, timeout); | ||
| if (typeof timeoutId === "object") | ||
| timeoutId = timeoutId.unref?.(); | ||
| } | ||
| _rpcPromiseMap.set(id, { resolve, reject, timeoutId, method }); | ||
| await send(newReq); | ||
| return promise; | ||
| } | ||
| try { | ||
| if (options.onRequest) | ||
| await options.onRequest.call(rpc, req, handler, resolve); | ||
| else | ||
| await handler(); | ||
| } catch (e) { | ||
| if (options.onGeneralError?.call(rpc, e) !== true) | ||
| throw e; | ||
| return; | ||
| } finally { | ||
| clearTimeout(timeoutId); | ||
| _rpcPromiseMap.delete(id); | ||
| } | ||
| return promise; | ||
| } | ||
| const $call = (method, ...args) => _call(method, args, false); | ||
| const $callOptional = (method, ...args) => _call(method, args, false, true); | ||
| const $callEvent = (method, ...args) => _call(method, args, true); | ||
| const $callRaw = (options2) => _call(options2.method, options2.args, options2.event, options2.optional); | ||
| const builtinMethods = { | ||
| $call, | ||
| $callOptional, | ||
| $callEvent, | ||
| $callRaw, | ||
| $rejectPendingCalls, | ||
| get $closed() { | ||
| return $closed; | ||
| }, | ||
| get $meta() { | ||
| return options.meta; | ||
| }, | ||
| $close, | ||
| $functions | ||
| }; | ||
| rpc = new Proxy({}, { | ||
| get(_, method) { | ||
| if (Object.prototype.hasOwnProperty.call(builtinMethods, method)) | ||
| return builtinMethods[method]; | ||
| if (method === "then" && !eventNames.includes("then") && !("then" in $functions)) | ||
| return void 0; | ||
| const sendEvent = (...args) => _call(method, args, true); | ||
| if (eventNames.includes(method)) { | ||
| sendEvent.asEvent = sendEvent; | ||
| return sendEvent; | ||
| } | ||
| const sendCall = (...args) => _call(method, args, false); | ||
| sendCall.asEvent = sendEvent; | ||
| return sendCall; | ||
| } | ||
| }); | ||
| function $close(customError) { | ||
| $closed = true; | ||
| _rpcPromiseMap.forEach(({ reject, method }) => { | ||
| const error = new Error(`[birpc] rpc is closed, cannot call "${method}"`); | ||
| if (customError) { | ||
| customError.cause ??= error; | ||
| return reject(customError); | ||
| } | ||
| reject(error); | ||
| }); | ||
| _rpcPromiseMap.clear(); | ||
| off(onMessage); | ||
| } | ||
| function $rejectPendingCalls(handler) { | ||
| const entries = Array.from(_rpcPromiseMap.values()); | ||
| const handlerResults = entries.map(({ method, reject }) => { | ||
| if (!handler) { | ||
| return reject(new Error(`[birpc]: rejected pending call "${method}".`)); | ||
| } | ||
| return handler({ method, reject }); | ||
| }); | ||
| _rpcPromiseMap.clear(); | ||
| return handlerResults; | ||
| } | ||
| async function onMessage(data, ...extra) { | ||
| let msg; | ||
| try { | ||
| msg = deserialize(data); | ||
| } catch (e) { | ||
| if (options.onGeneralError?.call(rpc, e) !== true) | ||
| throw e; | ||
| return; | ||
| } | ||
| if (msg.t === TYPE_REQUEST) { | ||
| const { m: method, a: args, o: optional } = msg; | ||
| let result, error; | ||
| let fn = await (resolver ? resolver.call(rpc, method, $functions[method]) : $functions[method]); | ||
| if (optional) | ||
| fn ||= () => void 0; | ||
| if (!fn) { | ||
| error = new Error(`[birpc] function "${method}" not found`); | ||
| } else { | ||
| try { | ||
| result = await fn.apply(bind === "rpc" ? rpc : $functions, args); | ||
| } catch (e) { | ||
| error = e; | ||
| } | ||
| } | ||
| if (msg.i) { | ||
| if (error && options.onError) | ||
| options.onError.call(rpc, error, method, args); | ||
| if (error && options.onFunctionError) { | ||
| if (options.onFunctionError.call(rpc, error, method, args) === true) | ||
| return; | ||
| } | ||
| if (!error) { | ||
| try { | ||
| await post(serialize({ t: TYPE_RESPONSE, i: msg.i, r: result }), ...extra); | ||
| return; | ||
| } catch (e) { | ||
| error = e; | ||
| if (options.onGeneralError?.call(rpc, e, method, args) !== true) | ||
| throw e; | ||
| } | ||
| } | ||
| try { | ||
| await post(serialize({ t: TYPE_RESPONSE, i: msg.i, e: error }), ...extra); | ||
| } catch (e) { | ||
| if (options.onGeneralError?.call(rpc, e, method, args) !== true) | ||
| throw e; | ||
| } | ||
| } | ||
| } else { | ||
| const { i: ack, r: result, e: error } = msg; | ||
| const promise = _rpcPromiseMap.get(ack); | ||
| if (promise) { | ||
| clearTimeout(promise.timeoutId); | ||
| if (error) | ||
| promise.reject(error); | ||
| else | ||
| promise.resolve(result); | ||
| } | ||
| _rpcPromiseMap.delete(ack); | ||
| } | ||
| } | ||
| _promiseInit = on(onMessage); | ||
| return rpc; | ||
| const { post, on, off = () => {}, eventNames = [], serialize = defaultSerialize, deserialize = defaultDeserialize, resolver, bind = "rpc", timeout = DEFAULT_TIMEOUT } = options; | ||
| let $closed = false; | ||
| const _rpcPromiseMap = /* @__PURE__ */ new Map(); | ||
| let _promiseInit; | ||
| let rpc; | ||
| async function _call(method, args, event, optional) { | ||
| if ($closed) throw new Error(`[birpc] rpc is closed, cannot call "${method}"`); | ||
| const req = { | ||
| m: method, | ||
| a: args, | ||
| t: TYPE_REQUEST | ||
| }; | ||
| if (optional) req.o = true; | ||
| const send = async (_req) => post(serialize(_req)); | ||
| if (event) { | ||
| await send(req); | ||
| return; | ||
| } | ||
| if (_promiseInit) try { | ||
| await _promiseInit; | ||
| } finally { | ||
| _promiseInit = void 0; | ||
| } | ||
| let { promise, resolve, reject } = createPromiseWithResolvers(); | ||
| const id = nanoid(); | ||
| req.i = id; | ||
| let timeoutId; | ||
| async function handler(newReq = req) { | ||
| if (timeout >= 0) { | ||
| timeoutId = setTimeout(() => { | ||
| try { | ||
| if (options.onTimeoutError?.call(rpc, method, args) !== true) throw new Error(`[birpc] timeout on calling "${method}"`); | ||
| } catch (e) { | ||
| reject(e); | ||
| } | ||
| _rpcPromiseMap.delete(id); | ||
| }, timeout); | ||
| if (typeof timeoutId === "object") timeoutId = timeoutId.unref?.(); | ||
| } | ||
| _rpcPromiseMap.set(id, { | ||
| resolve, | ||
| reject, | ||
| timeoutId, | ||
| method | ||
| }); | ||
| await send(newReq); | ||
| return promise; | ||
| } | ||
| try { | ||
| if (options.onRequest) await options.onRequest.call(rpc, req, handler, resolve); | ||
| else await handler(); | ||
| } catch (e) { | ||
| if (options.onGeneralError?.call(rpc, e) !== true) throw e; | ||
| return; | ||
| } finally { | ||
| clearTimeout(timeoutId); | ||
| _rpcPromiseMap.delete(id); | ||
| } | ||
| return promise; | ||
| } | ||
| const $call = (method, ...args) => _call(method, args, false); | ||
| const $callOptional = (method, ...args) => _call(method, args, false, true); | ||
| const $callEvent = (method, ...args) => _call(method, args, true); | ||
| const $callRaw = (options$1) => _call(options$1.method, options$1.args, options$1.event, options$1.optional); | ||
| const builtinMethods = { | ||
| $call, | ||
| $callOptional, | ||
| $callEvent, | ||
| $callRaw, | ||
| $rejectPendingCalls, | ||
| get $closed() { | ||
| return $closed; | ||
| }, | ||
| get $meta() { | ||
| return options.meta; | ||
| }, | ||
| $close, | ||
| $functions | ||
| }; | ||
| rpc = new Proxy({}, { get(_, method) { | ||
| if (Object.prototype.hasOwnProperty.call(builtinMethods, method)) return builtinMethods[method]; | ||
| if (method === "then" && !eventNames.includes("then") && !("then" in $functions)) return void 0; | ||
| const sendEvent = (...args) => _call(method, args, true); | ||
| if (eventNames.includes(method)) { | ||
| sendEvent.asEvent = sendEvent; | ||
| return sendEvent; | ||
| } | ||
| const sendCall = (...args) => _call(method, args, false); | ||
| sendCall.asEvent = sendEvent; | ||
| return sendCall; | ||
| } }); | ||
| function $close(customError) { | ||
| $closed = true; | ||
| _rpcPromiseMap.forEach(({ reject, method }) => { | ||
| const error = /* @__PURE__ */ new Error(`[birpc] rpc is closed, cannot call "${method}"`); | ||
| if (customError) { | ||
| customError.cause ??= error; | ||
| return reject(customError); | ||
| } | ||
| reject(error); | ||
| }); | ||
| _rpcPromiseMap.clear(); | ||
| off(onMessage); | ||
| } | ||
| function $rejectPendingCalls(handler) { | ||
| const handlerResults = Array.from(_rpcPromiseMap.values()).map(({ method, reject }) => { | ||
| if (!handler) return reject(/* @__PURE__ */ new Error(`[birpc]: rejected pending call "${method}".`)); | ||
| return handler({ | ||
| method, | ||
| reject | ||
| }); | ||
| }); | ||
| _rpcPromiseMap.clear(); | ||
| return handlerResults; | ||
| } | ||
| async function onMessage(data, ...extra) { | ||
| let msg; | ||
| try { | ||
| msg = deserialize(data); | ||
| } catch (e) { | ||
| if (options.onGeneralError?.call(rpc, e) !== true) throw e; | ||
| return; | ||
| } | ||
| if (msg.t === TYPE_REQUEST) { | ||
| const { m: method, a: args, o: optional } = msg; | ||
| let result, error; | ||
| let fn = await (resolver ? resolver.call(rpc, method, $functions[method]) : $functions[method]); | ||
| if (optional) fn ||= () => void 0; | ||
| if (!fn) error = /* @__PURE__ */ new Error(`[birpc] function "${method}" not found`); | ||
| else try { | ||
| result = await fn.apply(bind === "rpc" ? rpc : $functions, args); | ||
| } catch (e) { | ||
| error = e; | ||
| } | ||
| if (msg.i) { | ||
| if (error && options.onError) options.onError.call(rpc, error, method, args); | ||
| if (error && options.onFunctionError) { | ||
| if (options.onFunctionError.call(rpc, error, method, args) === true) return; | ||
| } | ||
| if (!error) try { | ||
| await post(serialize({ | ||
| t: TYPE_RESPONSE, | ||
| i: msg.i, | ||
| r: result | ||
| }), ...extra); | ||
| return; | ||
| } catch (e) { | ||
| error = e; | ||
| if (options.onGeneralError?.call(rpc, e, method, args) !== true) throw e; | ||
| } | ||
| try { | ||
| await post(serialize({ | ||
| t: TYPE_RESPONSE, | ||
| i: msg.i, | ||
| e: error | ||
| }), ...extra); | ||
| } catch (e) { | ||
| if (options.onGeneralError?.call(rpc, e, method, args) !== true) throw e; | ||
| } | ||
| } | ||
| } else { | ||
| const { i: ack, r: result, e: error } = msg; | ||
| const promise = _rpcPromiseMap.get(ack); | ||
| if (promise) { | ||
| clearTimeout(promise.timeoutId); | ||
| if (error) promise.reject(error); | ||
| else promise.resolve(result); | ||
| } | ||
| _rpcPromiseMap.delete(ack); | ||
| } | ||
| } | ||
| _promiseInit = on(onMessage); | ||
| return rpc; | ||
| } | ||
| const cacheMap = /* @__PURE__ */ new WeakMap(); | ||
| function cachedMap(items, fn) { | ||
| return items.map((i) => { | ||
| let r = cacheMap.get(i); | ||
| if (!r) { | ||
| r = fn(i); | ||
| cacheMap.set(i, r); | ||
| } | ||
| return r; | ||
| }); | ||
| return items.map((i) => { | ||
| let r = cacheMap.get(i); | ||
| if (!r) { | ||
| r = fn(i); | ||
| cacheMap.set(i, r); | ||
| } | ||
| return r; | ||
| }); | ||
| } | ||
| function createBirpcGroup(functions, channels, options = {}) { | ||
| const getChannels = () => typeof channels === "function" ? channels() : channels; | ||
| const getClients = (channels2 = getChannels()) => cachedMap(channels2, (s) => createBirpc(functions, { ...options, ...s })); | ||
| function _boardcast(method, args, event, optional) { | ||
| const clients = getClients(); | ||
| return Promise.all(clients.map((c) => c.$callRaw({ method, args, event, optional }))); | ||
| } | ||
| function $call(method, ...args) { | ||
| return _boardcast(method, args, false); | ||
| } | ||
| function $callOptional(method, ...args) { | ||
| return _boardcast(method, args, false, true); | ||
| } | ||
| function $callEvent(method, ...args) { | ||
| return _boardcast(method, args, true); | ||
| } | ||
| const broadcastBuiltin = { | ||
| $call, | ||
| $callOptional, | ||
| $callEvent | ||
| }; | ||
| const broadcastProxy = new Proxy({}, { | ||
| get(_, method) { | ||
| if (Object.prototype.hasOwnProperty.call(broadcastBuiltin, method)) | ||
| return broadcastBuiltin[method]; | ||
| const client = getClients(); | ||
| const callbacks = client.map((c) => c[method]); | ||
| const sendCall = (...args) => { | ||
| return Promise.all(callbacks.map((i) => i(...args))); | ||
| }; | ||
| sendCall.asEvent = async (...args) => { | ||
| await Promise.all(callbacks.map((i) => i.asEvent(...args))); | ||
| }; | ||
| return sendCall; | ||
| } | ||
| }); | ||
| function updateChannels(fn) { | ||
| const channels2 = getChannels(); | ||
| fn?.(channels2); | ||
| return getClients(channels2); | ||
| } | ||
| getClients(); | ||
| return { | ||
| get clients() { | ||
| return getClients(); | ||
| }, | ||
| functions, | ||
| updateChannels, | ||
| broadcast: broadcastProxy, | ||
| /** | ||
| * @deprecated use `broadcast` | ||
| */ | ||
| // @ts-expect-error deprecated | ||
| boardcast: broadcastProxy | ||
| }; | ||
| const getChannels = () => typeof channels === "function" ? channels() : channels; | ||
| const getClients = (channels$1 = getChannels()) => cachedMap(channels$1, (s) => createBirpc(functions, { | ||
| ...options, | ||
| ...s | ||
| })); | ||
| function _boardcast(method, args, event, optional) { | ||
| const clients = getClients(); | ||
| return Promise.all(clients.map((c) => c.$callRaw({ | ||
| method, | ||
| args, | ||
| event, | ||
| optional | ||
| }))); | ||
| } | ||
| function $call(method, ...args) { | ||
| return _boardcast(method, args, false); | ||
| } | ||
| function $callOptional(method, ...args) { | ||
| return _boardcast(method, args, false, true); | ||
| } | ||
| function $callEvent(method, ...args) { | ||
| return _boardcast(method, args, true); | ||
| } | ||
| const broadcastBuiltin = { | ||
| $call, | ||
| $callOptional, | ||
| $callEvent | ||
| }; | ||
| const broadcastProxy = new Proxy({}, { get(_, method) { | ||
| if (Object.prototype.hasOwnProperty.call(broadcastBuiltin, method)) return broadcastBuiltin[method]; | ||
| const callbacks = getClients().map((c) => c[method]); | ||
| const sendCall = (...args) => { | ||
| return Promise.all(callbacks.map((i) => i(...args))); | ||
| }; | ||
| sendCall.asEvent = async (...args) => { | ||
| await Promise.all(callbacks.map((i) => i.asEvent(...args))); | ||
| }; | ||
| return sendCall; | ||
| } }); | ||
| function updateChannels(fn) { | ||
| const channels$1 = getChannels(); | ||
| fn?.(channels$1); | ||
| return getClients(channels$1); | ||
| } | ||
| getClients(); | ||
| return { | ||
| get clients() { | ||
| return getClients(); | ||
| }, | ||
| functions, | ||
| updateChannels, | ||
| broadcast: broadcastProxy, | ||
| boardcast: broadcastProxy | ||
| }; | ||
| } | ||
| function createPromiseWithResolvers() { | ||
| let resolve; | ||
| let reject; | ||
| const promise = new Promise((res, rej) => { | ||
| resolve = res; | ||
| reject = rej; | ||
| }); | ||
| return { promise, resolve, reject }; | ||
| let resolve; | ||
| let reject; | ||
| return { | ||
| promise: new Promise((res, rej) => { | ||
| resolve = res; | ||
| reject = rej; | ||
| }), | ||
| resolve, | ||
| reject | ||
| }; | ||
| } | ||
| const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"; | ||
| function nanoid(size = 21) { | ||
| let id = ""; | ||
| let i = size; | ||
| while (i--) | ||
| id += urlAlphabet[random() * 64 | 0]; | ||
| return id; | ||
| let id = ""; | ||
| let i = size; | ||
| while (i--) id += urlAlphabet[random() * 64 | 0]; | ||
| return id; | ||
| } | ||
| export { DEFAULT_TIMEOUT, cachedMap, createBirpc, createBirpcGroup }; | ||
| //#endregion | ||
| export { DEFAULT_TIMEOUT, cachedMap, createBirpc, createBirpcGroup }; |
+9
-12
| { | ||
| "name": "birpc", | ||
| "type": "module", | ||
| "version": "2.9.0", | ||
| "version": "3.0.0", | ||
| "description": "Message based Two-way remote procedure call", | ||
@@ -23,11 +23,8 @@ "author": "Anthony Fu <anthonyfu117@hotmail.com>", | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "import": "./dist/index.mjs", | ||
| "require": "./dist/index.cjs" | ||
| } | ||
| ".": "./dist/index.mjs", | ||
| "./package.json": "./package.json" | ||
| }, | ||
| "main": "./dist/index.cjs", | ||
| "main": "./dist/index.mjs", | ||
| "module": "./dist/index.mjs", | ||
| "types": "./dist/index.d.ts", | ||
| "types": "./dist/index.d.mts", | ||
| "files": [ | ||
@@ -40,8 +37,8 @@ "dist" | ||
| "@types/node": "^24.10.1", | ||
| "@vitest/coverage-v8": "3.0.9", | ||
| "@vitest/coverage-v8": "^4.0.15", | ||
| "bumpp": "^10.3.2", | ||
| "eslint": "^9.39.1", | ||
| "tsdown": "0.17.0-beta.5", | ||
| "tsx": "^4.21.0", | ||
| "typescript": "^5.9.3", | ||
| "unbuild": "^3.6.1", | ||
| "vite": "^7.2.6", | ||
@@ -51,4 +48,4 @@ "vitest": "^4.0.15" | ||
| "scripts": { | ||
| "build": "unbuild", | ||
| "dev": "unbuild --stub", | ||
| "build": "tsdown", | ||
| "watch": "tsdown --watch", | ||
| "lint": "eslint .", | ||
@@ -55,0 +52,0 @@ "release": "bumpp", |
-296
| 'use strict'; | ||
| const TYPE_REQUEST = "q"; | ||
| const TYPE_RESPONSE = "s"; | ||
| const DEFAULT_TIMEOUT = 6e4; | ||
| function defaultSerialize(i) { | ||
| return i; | ||
| } | ||
| const defaultDeserialize = defaultSerialize; | ||
| const { clearTimeout, setTimeout } = globalThis; | ||
| const random = Math.random.bind(Math); | ||
| function createBirpc($functions, options) { | ||
| const { | ||
| post, | ||
| on, | ||
| off = () => { | ||
| }, | ||
| eventNames = [], | ||
| serialize = defaultSerialize, | ||
| deserialize = defaultDeserialize, | ||
| resolver, | ||
| bind = "rpc", | ||
| timeout = DEFAULT_TIMEOUT | ||
| } = options; | ||
| let $closed = false; | ||
| const _rpcPromiseMap = /* @__PURE__ */ new Map(); | ||
| let _promiseInit; | ||
| let rpc; | ||
| async function _call(method, args, event, optional) { | ||
| if ($closed) | ||
| throw new Error(`[birpc] rpc is closed, cannot call "${method}"`); | ||
| const req = { m: method, a: args, t: TYPE_REQUEST }; | ||
| if (optional) | ||
| req.o = true; | ||
| const send = async (_req) => post(serialize(_req)); | ||
| if (event) { | ||
| await send(req); | ||
| return; | ||
| } | ||
| if (_promiseInit) { | ||
| try { | ||
| await _promiseInit; | ||
| } finally { | ||
| _promiseInit = void 0; | ||
| } | ||
| } | ||
| let { promise, resolve, reject } = createPromiseWithResolvers(); | ||
| const id = nanoid(); | ||
| req.i = id; | ||
| let timeoutId; | ||
| async function handler(newReq = req) { | ||
| if (timeout >= 0) { | ||
| timeoutId = setTimeout(() => { | ||
| try { | ||
| const handleResult = options.onTimeoutError?.call(rpc, method, args); | ||
| if (handleResult !== true) | ||
| throw new Error(`[birpc] timeout on calling "${method}"`); | ||
| } catch (e) { | ||
| reject(e); | ||
| } | ||
| _rpcPromiseMap.delete(id); | ||
| }, timeout); | ||
| if (typeof timeoutId === "object") | ||
| timeoutId = timeoutId.unref?.(); | ||
| } | ||
| _rpcPromiseMap.set(id, { resolve, reject, timeoutId, method }); | ||
| await send(newReq); | ||
| return promise; | ||
| } | ||
| try { | ||
| if (options.onRequest) | ||
| await options.onRequest.call(rpc, req, handler, resolve); | ||
| else | ||
| await handler(); | ||
| } catch (e) { | ||
| if (options.onGeneralError?.call(rpc, e) !== true) | ||
| throw e; | ||
| return; | ||
| } finally { | ||
| clearTimeout(timeoutId); | ||
| _rpcPromiseMap.delete(id); | ||
| } | ||
| return promise; | ||
| } | ||
| const $call = (method, ...args) => _call(method, args, false); | ||
| const $callOptional = (method, ...args) => _call(method, args, false, true); | ||
| const $callEvent = (method, ...args) => _call(method, args, true); | ||
| const $callRaw = (options2) => _call(options2.method, options2.args, options2.event, options2.optional); | ||
| const builtinMethods = { | ||
| $call, | ||
| $callOptional, | ||
| $callEvent, | ||
| $callRaw, | ||
| $rejectPendingCalls, | ||
| get $closed() { | ||
| return $closed; | ||
| }, | ||
| get $meta() { | ||
| return options.meta; | ||
| }, | ||
| $close, | ||
| $functions | ||
| }; | ||
| rpc = new Proxy({}, { | ||
| get(_, method) { | ||
| if (Object.prototype.hasOwnProperty.call(builtinMethods, method)) | ||
| return builtinMethods[method]; | ||
| if (method === "then" && !eventNames.includes("then") && !("then" in $functions)) | ||
| return void 0; | ||
| const sendEvent = (...args) => _call(method, args, true); | ||
| if (eventNames.includes(method)) { | ||
| sendEvent.asEvent = sendEvent; | ||
| return sendEvent; | ||
| } | ||
| const sendCall = (...args) => _call(method, args, false); | ||
| sendCall.asEvent = sendEvent; | ||
| return sendCall; | ||
| } | ||
| }); | ||
| function $close(customError) { | ||
| $closed = true; | ||
| _rpcPromiseMap.forEach(({ reject, method }) => { | ||
| const error = new Error(`[birpc] rpc is closed, cannot call "${method}"`); | ||
| if (customError) { | ||
| customError.cause ??= error; | ||
| return reject(customError); | ||
| } | ||
| reject(error); | ||
| }); | ||
| _rpcPromiseMap.clear(); | ||
| off(onMessage); | ||
| } | ||
| function $rejectPendingCalls(handler) { | ||
| const entries = Array.from(_rpcPromiseMap.values()); | ||
| const handlerResults = entries.map(({ method, reject }) => { | ||
| if (!handler) { | ||
| return reject(new Error(`[birpc]: rejected pending call "${method}".`)); | ||
| } | ||
| return handler({ method, reject }); | ||
| }); | ||
| _rpcPromiseMap.clear(); | ||
| return handlerResults; | ||
| } | ||
| async function onMessage(data, ...extra) { | ||
| let msg; | ||
| try { | ||
| msg = deserialize(data); | ||
| } catch (e) { | ||
| if (options.onGeneralError?.call(rpc, e) !== true) | ||
| throw e; | ||
| return; | ||
| } | ||
| if (msg.t === TYPE_REQUEST) { | ||
| const { m: method, a: args, o: optional } = msg; | ||
| let result, error; | ||
| let fn = await (resolver ? resolver.call(rpc, method, $functions[method]) : $functions[method]); | ||
| if (optional) | ||
| fn ||= () => void 0; | ||
| if (!fn) { | ||
| error = new Error(`[birpc] function "${method}" not found`); | ||
| } else { | ||
| try { | ||
| result = await fn.apply(bind === "rpc" ? rpc : $functions, args); | ||
| } catch (e) { | ||
| error = e; | ||
| } | ||
| } | ||
| if (msg.i) { | ||
| if (error && options.onError) | ||
| options.onError.call(rpc, error, method, args); | ||
| if (error && options.onFunctionError) { | ||
| if (options.onFunctionError.call(rpc, error, method, args) === true) | ||
| return; | ||
| } | ||
| if (!error) { | ||
| try { | ||
| await post(serialize({ t: TYPE_RESPONSE, i: msg.i, r: result }), ...extra); | ||
| return; | ||
| } catch (e) { | ||
| error = e; | ||
| if (options.onGeneralError?.call(rpc, e, method, args) !== true) | ||
| throw e; | ||
| } | ||
| } | ||
| try { | ||
| await post(serialize({ t: TYPE_RESPONSE, i: msg.i, e: error }), ...extra); | ||
| } catch (e) { | ||
| if (options.onGeneralError?.call(rpc, e, method, args) !== true) | ||
| throw e; | ||
| } | ||
| } | ||
| } else { | ||
| const { i: ack, r: result, e: error } = msg; | ||
| const promise = _rpcPromiseMap.get(ack); | ||
| if (promise) { | ||
| clearTimeout(promise.timeoutId); | ||
| if (error) | ||
| promise.reject(error); | ||
| else | ||
| promise.resolve(result); | ||
| } | ||
| _rpcPromiseMap.delete(ack); | ||
| } | ||
| } | ||
| _promiseInit = on(onMessage); | ||
| return rpc; | ||
| } | ||
| const cacheMap = /* @__PURE__ */ new WeakMap(); | ||
| function cachedMap(items, fn) { | ||
| return items.map((i) => { | ||
| let r = cacheMap.get(i); | ||
| if (!r) { | ||
| r = fn(i); | ||
| cacheMap.set(i, r); | ||
| } | ||
| return r; | ||
| }); | ||
| } | ||
| function createBirpcGroup(functions, channels, options = {}) { | ||
| const getChannels = () => typeof channels === "function" ? channels() : channels; | ||
| const getClients = (channels2 = getChannels()) => cachedMap(channels2, (s) => createBirpc(functions, { ...options, ...s })); | ||
| function _boardcast(method, args, event, optional) { | ||
| const clients = getClients(); | ||
| return Promise.all(clients.map((c) => c.$callRaw({ method, args, event, optional }))); | ||
| } | ||
| function $call(method, ...args) { | ||
| return _boardcast(method, args, false); | ||
| } | ||
| function $callOptional(method, ...args) { | ||
| return _boardcast(method, args, false, true); | ||
| } | ||
| function $callEvent(method, ...args) { | ||
| return _boardcast(method, args, true); | ||
| } | ||
| const broadcastBuiltin = { | ||
| $call, | ||
| $callOptional, | ||
| $callEvent | ||
| }; | ||
| const broadcastProxy = new Proxy({}, { | ||
| get(_, method) { | ||
| if (Object.prototype.hasOwnProperty.call(broadcastBuiltin, method)) | ||
| return broadcastBuiltin[method]; | ||
| const client = getClients(); | ||
| const callbacks = client.map((c) => c[method]); | ||
| const sendCall = (...args) => { | ||
| return Promise.all(callbacks.map((i) => i(...args))); | ||
| }; | ||
| sendCall.asEvent = async (...args) => { | ||
| await Promise.all(callbacks.map((i) => i.asEvent(...args))); | ||
| }; | ||
| return sendCall; | ||
| } | ||
| }); | ||
| function updateChannels(fn) { | ||
| const channels2 = getChannels(); | ||
| fn?.(channels2); | ||
| return getClients(channels2); | ||
| } | ||
| getClients(); | ||
| return { | ||
| get clients() { | ||
| return getClients(); | ||
| }, | ||
| functions, | ||
| updateChannels, | ||
| broadcast: broadcastProxy, | ||
| /** | ||
| * @deprecated use `broadcast` | ||
| */ | ||
| // @ts-expect-error deprecated | ||
| boardcast: broadcastProxy | ||
| }; | ||
| } | ||
| function createPromiseWithResolvers() { | ||
| let resolve; | ||
| let reject; | ||
| const promise = new Promise((res, rej) => { | ||
| resolve = res; | ||
| reject = rej; | ||
| }); | ||
| return { promise, resolve, reject }; | ||
| } | ||
| const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"; | ||
| function nanoid(size = 21) { | ||
| let id = ""; | ||
| let i = size; | ||
| while (i--) | ||
| id += urlAlphabet[random() * 64 | 0]; | ||
| return id; | ||
| } | ||
| exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT; | ||
| exports.cachedMap = cachedMap; | ||
| exports.createBirpc = createBirpc; | ||
| exports.createBirpcGroup = createBirpcGroup; |
-215
| type ArgumentsType<T> = T extends (...args: infer A) => any ? A : never; | ||
| type ReturnType<T> = T extends (...args: any) => infer R ? R : never; | ||
| type PromisifyFn<T> = ReturnType<T> extends Promise<any> ? T : (...args: ArgumentsType<T>) => Promise<Awaited<ReturnType<T>>>; | ||
| type Thenable<T> = T | PromiseLike<T>; | ||
| type BirpcResolver<This> = (this: This, name: string, resolved: (...args: unknown[]) => unknown) => Thenable<((...args: any[]) => any) | undefined>; | ||
| interface ChannelOptions { | ||
| /** | ||
| * Function to post raw message | ||
| */ | ||
| post: (data: any, ...extras: any[]) => any | Promise<any>; | ||
| /** | ||
| * Listener to receive raw message | ||
| */ | ||
| on: (fn: (data: any, ...extras: any[]) => void) => any | Promise<any>; | ||
| /** | ||
| * Clear the listener when `$close` is called | ||
| */ | ||
| off?: (fn: (data: any, ...extras: any[]) => void) => any | Promise<any>; | ||
| /** | ||
| * Custom function to serialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| serialize?: (data: any) => any; | ||
| /** | ||
| * Custom function to deserialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| deserialize?: (data: any) => any; | ||
| /** | ||
| * Call the methods with the RPC context or the original functions object | ||
| */ | ||
| bind?: 'rpc' | 'functions'; | ||
| /** | ||
| * Custom meta data to attached to the RPC instance's `$meta` property | ||
| */ | ||
| meta?: any; | ||
| } | ||
| interface EventOptions<RemoteFunctions, LocalFunctions extends object = Record<string, never>> { | ||
| /** | ||
| * Names of remote functions that do not need response. | ||
| */ | ||
| eventNames?: (keyof RemoteFunctions)[]; | ||
| /** | ||
| * Maximum timeout for waiting for response, in milliseconds. | ||
| * | ||
| * @default 60_000 | ||
| */ | ||
| timeout?: number; | ||
| /** | ||
| * Custom resolver to resolve function to be called | ||
| * | ||
| * For advanced use cases only | ||
| */ | ||
| resolver?: BirpcResolver<BirpcReturn<RemoteFunctions, LocalFunctions>>; | ||
| /** | ||
| * Hook triggered before an event is sent to the remote | ||
| * | ||
| * @param req - Request parameters | ||
| * @param next - Function to continue the request | ||
| * @param resolve - Function to resolve the response directly | ||
| */ | ||
| onRequest?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, req: Request, next: (req?: Request) => Promise<any>, resolve: (res: any) => void) => void | Promise<void>; | ||
| /** | ||
| * Custom error handler | ||
| * | ||
| * @deprecated use `onFunctionError` and `onGeneralError` instead | ||
| */ | ||
| onError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for errors occurred in local functions being called | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onFunctionError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for errors occurred during serialization or messsaging | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onGeneralError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName?: string, args?: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for timeouts | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onTimeoutError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, functionName: string, args: any[]) => boolean | void; | ||
| } | ||
| type BirpcOptions<RemoteFunctions, LocalFunctions extends object = Record<string, never>> = EventOptions<RemoteFunctions, LocalFunctions> & ChannelOptions; | ||
| type BirpcFn<T> = PromisifyFn<T> & { | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| asEvent: (...args: ArgumentsType<T>) => Promise<void>; | ||
| }; | ||
| interface BirpcGroupFn<T> { | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| */ | ||
| (...args: ArgumentsType<T>): Promise<Awaited<ReturnType<T>>[]>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| asEvent: (...args: ArgumentsType<T>) => Promise<void>; | ||
| } | ||
| interface BirpcReturnBuiltin<RemoteFunctions, LocalFunctions = Record<string, never>> { | ||
| /** | ||
| * Raw functions object | ||
| */ | ||
| $functions: LocalFunctions; | ||
| /** | ||
| * Whether the RPC is closed | ||
| */ | ||
| readonly $closed: boolean; | ||
| /** | ||
| * Custom meta data attached to the RPC instance | ||
| */ | ||
| readonly $meta: any; | ||
| /** | ||
| * Close the RPC connection | ||
| */ | ||
| $close: (error?: Error) => void; | ||
| /** | ||
| * Reject pending calls | ||
| */ | ||
| $rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[]; | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| * An alternative to directly calling the function | ||
| */ | ||
| $call: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]>>>; | ||
| /** | ||
| * Same as `$call`, but returns `undefined` if the function is not defined on the remote side. | ||
| */ | ||
| $callOptional: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]> | undefined>>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| $callEvent: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<void>; | ||
| /** | ||
| * Call the remote function with the raw options. | ||
| */ | ||
| $callRaw: (options: { | ||
| method: string; | ||
| args: unknown[]; | ||
| event?: boolean; | ||
| optional?: boolean; | ||
| }) => Promise<Awaited<ReturnType<any>>[]>; | ||
| } | ||
| type BirpcReturn<RemoteFunctions, LocalFunctions = Record<string, never>> = { | ||
| [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]>; | ||
| } & BirpcReturnBuiltin<RemoteFunctions, LocalFunctions>; | ||
| type PendingCallHandler = (options: Pick<PromiseEntry, 'method' | 'reject'>) => void | Promise<void>; | ||
| interface BirpcGroupReturnBuiltin<RemoteFunctions> { | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| * An alternative to directly calling the function | ||
| */ | ||
| $call: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]>>>; | ||
| /** | ||
| * Same as `$call`, but returns `undefined` if the function is not defined on the remote side. | ||
| */ | ||
| $callOptional: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]> | undefined>>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| $callEvent: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<void>; | ||
| } | ||
| type BirpcGroupReturn<RemoteFunctions> = { | ||
| [K in keyof RemoteFunctions]: BirpcGroupFn<RemoteFunctions[K]>; | ||
| } & BirpcGroupReturnBuiltin<RemoteFunctions>; | ||
| interface BirpcGroup<RemoteFunctions, LocalFunctions = Record<string, never>> { | ||
| readonly clients: BirpcReturn<RemoteFunctions, LocalFunctions>[]; | ||
| readonly functions: LocalFunctions; | ||
| readonly broadcast: BirpcGroupReturn<RemoteFunctions>; | ||
| updateChannels: (fn?: ((channels: ChannelOptions[]) => void)) => BirpcReturn<RemoteFunctions, LocalFunctions>[]; | ||
| } | ||
| interface PromiseEntry { | ||
| resolve: (arg: any) => void; | ||
| reject: (error: any) => void; | ||
| method: string; | ||
| timeoutId?: ReturnType<typeof setTimeout>; | ||
| } | ||
| declare const TYPE_REQUEST: "q"; | ||
| interface Request { | ||
| /** | ||
| * Type | ||
| */ | ||
| t: typeof TYPE_REQUEST; | ||
| /** | ||
| * ID | ||
| */ | ||
| i?: string; | ||
| /** | ||
| * Method | ||
| */ | ||
| m: string; | ||
| /** | ||
| * Arguments | ||
| */ | ||
| a: any[]; | ||
| /** | ||
| * Optional | ||
| */ | ||
| o?: boolean; | ||
| } | ||
| declare const DEFAULT_TIMEOUT = 60000; | ||
| declare const setTimeout: typeof globalThis.setTimeout; | ||
| declare function createBirpc<RemoteFunctions = Record<string, never>, LocalFunctions extends object = Record<string, never>>($functions: LocalFunctions, options: BirpcOptions<RemoteFunctions, LocalFunctions>): BirpcReturn<RemoteFunctions, LocalFunctions>; | ||
| declare function cachedMap<T, R>(items: T[], fn: ((i: T) => R)): R[]; | ||
| declare function createBirpcGroup<RemoteFunctions = Record<string, never>, LocalFunctions extends object = Record<string, never>>(functions: LocalFunctions, channels: ChannelOptions[] | (() => ChannelOptions[]), options?: EventOptions<RemoteFunctions, LocalFunctions>): BirpcGroup<RemoteFunctions, LocalFunctions>; | ||
| export { DEFAULT_TIMEOUT, cachedMap, createBirpc, createBirpcGroup }; | ||
| export type { ArgumentsType, BirpcFn, BirpcGroup, BirpcGroupFn, BirpcGroupReturn, BirpcGroupReturnBuiltin, BirpcOptions, BirpcResolver, BirpcReturn, BirpcReturnBuiltin, ChannelOptions, EventOptions, PromisifyFn, ReturnType, Thenable }; |
-215
| type ArgumentsType<T> = T extends (...args: infer A) => any ? A : never; | ||
| type ReturnType<T> = T extends (...args: any) => infer R ? R : never; | ||
| type PromisifyFn<T> = ReturnType<T> extends Promise<any> ? T : (...args: ArgumentsType<T>) => Promise<Awaited<ReturnType<T>>>; | ||
| type Thenable<T> = T | PromiseLike<T>; | ||
| type BirpcResolver<This> = (this: This, name: string, resolved: (...args: unknown[]) => unknown) => Thenable<((...args: any[]) => any) | undefined>; | ||
| interface ChannelOptions { | ||
| /** | ||
| * Function to post raw message | ||
| */ | ||
| post: (data: any, ...extras: any[]) => any | Promise<any>; | ||
| /** | ||
| * Listener to receive raw message | ||
| */ | ||
| on: (fn: (data: any, ...extras: any[]) => void) => any | Promise<any>; | ||
| /** | ||
| * Clear the listener when `$close` is called | ||
| */ | ||
| off?: (fn: (data: any, ...extras: any[]) => void) => any | Promise<any>; | ||
| /** | ||
| * Custom function to serialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| serialize?: (data: any) => any; | ||
| /** | ||
| * Custom function to deserialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| deserialize?: (data: any) => any; | ||
| /** | ||
| * Call the methods with the RPC context or the original functions object | ||
| */ | ||
| bind?: 'rpc' | 'functions'; | ||
| /** | ||
| * Custom meta data to attached to the RPC instance's `$meta` property | ||
| */ | ||
| meta?: any; | ||
| } | ||
| interface EventOptions<RemoteFunctions, LocalFunctions extends object = Record<string, never>> { | ||
| /** | ||
| * Names of remote functions that do not need response. | ||
| */ | ||
| eventNames?: (keyof RemoteFunctions)[]; | ||
| /** | ||
| * Maximum timeout for waiting for response, in milliseconds. | ||
| * | ||
| * @default 60_000 | ||
| */ | ||
| timeout?: number; | ||
| /** | ||
| * Custom resolver to resolve function to be called | ||
| * | ||
| * For advanced use cases only | ||
| */ | ||
| resolver?: BirpcResolver<BirpcReturn<RemoteFunctions, LocalFunctions>>; | ||
| /** | ||
| * Hook triggered before an event is sent to the remote | ||
| * | ||
| * @param req - Request parameters | ||
| * @param next - Function to continue the request | ||
| * @param resolve - Function to resolve the response directly | ||
| */ | ||
| onRequest?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, req: Request, next: (req?: Request) => Promise<any>, resolve: (res: any) => void) => void | Promise<void>; | ||
| /** | ||
| * Custom error handler | ||
| * | ||
| * @deprecated use `onFunctionError` and `onGeneralError` instead | ||
| */ | ||
| onError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for errors occurred in local functions being called | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onFunctionError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for errors occurred during serialization or messsaging | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onGeneralError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, error: Error, functionName?: string, args?: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for timeouts | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onTimeoutError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions>, functionName: string, args: any[]) => boolean | void; | ||
| } | ||
| type BirpcOptions<RemoteFunctions, LocalFunctions extends object = Record<string, never>> = EventOptions<RemoteFunctions, LocalFunctions> & ChannelOptions; | ||
| type BirpcFn<T> = PromisifyFn<T> & { | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| asEvent: (...args: ArgumentsType<T>) => Promise<void>; | ||
| }; | ||
| interface BirpcGroupFn<T> { | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| */ | ||
| (...args: ArgumentsType<T>): Promise<Awaited<ReturnType<T>>[]>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| asEvent: (...args: ArgumentsType<T>) => Promise<void>; | ||
| } | ||
| interface BirpcReturnBuiltin<RemoteFunctions, LocalFunctions = Record<string, never>> { | ||
| /** | ||
| * Raw functions object | ||
| */ | ||
| $functions: LocalFunctions; | ||
| /** | ||
| * Whether the RPC is closed | ||
| */ | ||
| readonly $closed: boolean; | ||
| /** | ||
| * Custom meta data attached to the RPC instance | ||
| */ | ||
| readonly $meta: any; | ||
| /** | ||
| * Close the RPC connection | ||
| */ | ||
| $close: (error?: Error) => void; | ||
| /** | ||
| * Reject pending calls | ||
| */ | ||
| $rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[]; | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| * An alternative to directly calling the function | ||
| */ | ||
| $call: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]>>>; | ||
| /** | ||
| * Same as `$call`, but returns `undefined` if the function is not defined on the remote side. | ||
| */ | ||
| $callOptional: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]> | undefined>>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| $callEvent: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<void>; | ||
| /** | ||
| * Call the remote function with the raw options. | ||
| */ | ||
| $callRaw: (options: { | ||
| method: string; | ||
| args: unknown[]; | ||
| event?: boolean; | ||
| optional?: boolean; | ||
| }) => Promise<Awaited<ReturnType<any>>[]>; | ||
| } | ||
| type BirpcReturn<RemoteFunctions, LocalFunctions = Record<string, never>> = { | ||
| [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]>; | ||
| } & BirpcReturnBuiltin<RemoteFunctions, LocalFunctions>; | ||
| type PendingCallHandler = (options: Pick<PromiseEntry, 'method' | 'reject'>) => void | Promise<void>; | ||
| interface BirpcGroupReturnBuiltin<RemoteFunctions> { | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| * An alternative to directly calling the function | ||
| */ | ||
| $call: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]>>>; | ||
| /** | ||
| * Same as `$call`, but returns `undefined` if the function is not defined on the remote side. | ||
| */ | ||
| $callOptional: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<Awaited<ReturnType<RemoteFunctions[K]> | undefined>>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| $callEvent: <K extends keyof RemoteFunctions>(method: K, ...args: ArgumentsType<RemoteFunctions[K]>) => Promise<void>; | ||
| } | ||
| type BirpcGroupReturn<RemoteFunctions> = { | ||
| [K in keyof RemoteFunctions]: BirpcGroupFn<RemoteFunctions[K]>; | ||
| } & BirpcGroupReturnBuiltin<RemoteFunctions>; | ||
| interface BirpcGroup<RemoteFunctions, LocalFunctions = Record<string, never>> { | ||
| readonly clients: BirpcReturn<RemoteFunctions, LocalFunctions>[]; | ||
| readonly functions: LocalFunctions; | ||
| readonly broadcast: BirpcGroupReturn<RemoteFunctions>; | ||
| updateChannels: (fn?: ((channels: ChannelOptions[]) => void)) => BirpcReturn<RemoteFunctions, LocalFunctions>[]; | ||
| } | ||
| interface PromiseEntry { | ||
| resolve: (arg: any) => void; | ||
| reject: (error: any) => void; | ||
| method: string; | ||
| timeoutId?: ReturnType<typeof setTimeout>; | ||
| } | ||
| declare const TYPE_REQUEST: "q"; | ||
| interface Request { | ||
| /** | ||
| * Type | ||
| */ | ||
| t: typeof TYPE_REQUEST; | ||
| /** | ||
| * ID | ||
| */ | ||
| i?: string; | ||
| /** | ||
| * Method | ||
| */ | ||
| m: string; | ||
| /** | ||
| * Arguments | ||
| */ | ||
| a: any[]; | ||
| /** | ||
| * Optional | ||
| */ | ||
| o?: boolean; | ||
| } | ||
| declare const DEFAULT_TIMEOUT = 60000; | ||
| declare const setTimeout: typeof globalThis.setTimeout; | ||
| declare function createBirpc<RemoteFunctions = Record<string, never>, LocalFunctions extends object = Record<string, never>>($functions: LocalFunctions, options: BirpcOptions<RemoteFunctions, LocalFunctions>): BirpcReturn<RemoteFunctions, LocalFunctions>; | ||
| declare function cachedMap<T, R>(items: T[], fn: ((i: T) => R)): R[]; | ||
| declare function createBirpcGroup<RemoteFunctions = Record<string, never>, LocalFunctions extends object = Record<string, never>>(functions: LocalFunctions, channels: ChannelOptions[] | (() => ChannelOptions[]), options?: EventOptions<RemoteFunctions, LocalFunctions>): BirpcGroup<RemoteFunctions, LocalFunctions>; | ||
| export { DEFAULT_TIMEOUT, cachedMap, createBirpc, createBirpcGroup }; | ||
| export type { ArgumentsType, BirpcFn, BirpcGroup, BirpcGroupFn, BirpcGroupReturn, BirpcGroupReturnBuiltin, BirpcOptions, BirpcResolver, BirpcReturn, BirpcReturnBuiltin, ChannelOptions, EventOptions, PromisifyFn, ReturnType, Thenable }; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
22243
-55.2%5
-37.5%272
-65.96%1
Infinity%