@irpclib/irpc 1.0.0-beta.20 → 1.0.0-beta.22

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/call.d.ts CHANGED
@@ -1,16 +1,18 @@
1
- import { IRPCPayload, IRPCStatus } from "./types.js";
1
+ import { IRPCTransport } from "./transport.js";
2
+ import { IRPCCallConfig, IRPCData, IRPCPacketStream, IRPCPayload, IRPCStatus } from "./types.js";
3
+ import { IRPCReader } from "./reader.js";
2
4
 
3
5
  //#region src/call.d.ts
4
-
6
+ declare const DEFAULT_RETRY_MODE = "exponential";
7
+ declare const DEFAULT_RETRY_DELAY = 1000;
5
8
  /**
6
9
  * Represents an RPC call with promise-like behavior for handling asynchronous operations.
7
10
  * Each call has a unique identifier and manages its own resolution state.
8
11
  */
9
12
  declare class IRPCCall {
13
+ transport: IRPCTransport;
10
14
  payload: IRPCPayload;
11
- private resolver;
12
- private rejector;
13
- timeout?: number | undefined;
15
+ options: IRPCCallConfig;
14
16
  /**
15
17
  * Unique identifier for this RPC call, generated using shortId().
16
18
  */
@@ -37,26 +39,31 @@ declare class IRPCCall {
37
39
  */
38
40
  value?: unknown;
39
41
  error?: Error;
42
+ private readonly timerId?;
43
+ private retries;
44
+ private retryReasons;
45
+ reader: IRPCReader<IRPCData>;
40
46
  /**
41
47
  * Creates a new IRPCCall instance.
48
+ * @param transport
42
49
  * @param payload - The RPC payload containing method and parameters
43
- * @param resolver - Function to resolve the associated promise with a value
44
- * @param rejector - Function to reject the associated promise with an error
45
- * @param timeout - Optional timeout value in milliseconds
50
+ * @param options - Options for the call, such as timeout, maxRetries, etc.
46
51
  */
47
- constructor(payload: IRPCPayload, resolver: (value: unknown) => void, rejector: (reason?: Error) => void, timeout?: number | undefined);
52
+ constructor(transport: IRPCTransport, payload: IRPCPayload, options: IRPCCallConfig);
53
+ enqueue(packet: IRPCPacketStream<IRPCData>): void;
48
54
  /**
49
55
  * Resolves the RPC call with the provided value.
50
56
  * If the call is already resolved, this method does nothing.
51
57
  * @param value - The value to resolve the promise with
52
58
  */
53
- resolve(value: unknown): void;
59
+ resolve(value: IRPCData): void;
54
60
  /**
55
61
  * Rejects the RPC call with the provided reason.
56
62
  * If the call is already resolved, this method does nothing.
57
63
  * @param reason - Optional error reason for rejecting the promise
64
+ * @param retriable - Flag indicating whether to retry the call
58
65
  */
59
- reject(reason?: Error): void;
66
+ reject(reason?: Error, retriable?: boolean): void;
60
67
  }
61
68
  //#endregion
62
- export { IRPCCall };
69
+ export { DEFAULT_RETRY_DELAY, DEFAULT_RETRY_MODE, IRPCCall };
package/dist/call.js CHANGED
@@ -1,7 +1,11 @@
1
- import { IRPC_STATUS } from "./enum.js";
1
+ import { IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
2
+ import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
3
+ import { IRPCReader } from "./reader.js";
2
4
  import { uuid } from "./uuid.js";
3
5
 
4
6
  //#region src/call.ts
7
+ const DEFAULT_RETRY_MODE = "exponential";
8
+ const DEFAULT_RETRY_DELAY = 1e3;
5
9
  /**
6
10
  * Represents an RPC call with promise-like behavior for handling asynchronous operations.
7
11
  * Each call has a unique identifier and manages its own resolution state.
@@ -33,18 +37,40 @@ var IRPCCall = class {
33
37
  */
34
38
  value;
35
39
  error;
40
+ timerId;
41
+ retries = 0;
42
+ retryReasons = /* @__PURE__ */ new Set();
43
+ reader;
36
44
  /**
37
45
  * Creates a new IRPCCall instance.
46
+ * @param transport
38
47
  * @param payload - The RPC payload containing method and parameters
39
- * @param resolver - Function to resolve the associated promise with a value
40
- * @param rejector - Function to reject the associated promise with an error
41
- * @param timeout - Optional timeout value in milliseconds
48
+ * @param options - Options for the call, such as timeout, maxRetries, etc.
42
49
  */
43
- constructor(payload, resolver, rejector, timeout) {
50
+ constructor(transport, payload, options) {
51
+ this.transport = transport;
44
52
  this.payload = payload;
45
- this.resolver = resolver;
46
- this.rejector = rejector;
47
- this.timeout = timeout;
53
+ this.options = options;
54
+ if (options.timeout) this.timerId = setTimeout(() => {
55
+ this.reader.push({
56
+ id: this.id,
57
+ name: this.payload.name,
58
+ type: IRPC_PACKET_TYPE.CLOSE,
59
+ status: IRPC_STATUS.ERROR,
60
+ error: {
61
+ code: ERROR_CODE.TIMEOUT,
62
+ message: ERROR_MESSAGE[ERROR_CODE.TIMEOUT]
63
+ },
64
+ createdAt: Date.now()
65
+ });
66
+ this.reject(new Error(ERROR_MESSAGE[ERROR_CODE.TIMEOUT]), false);
67
+ }, options.timeout);
68
+ this.reader = new IRPCReader(this.id);
69
+ }
70
+ enqueue(packet) {
71
+ this.reader.push(packet);
72
+ if (this.reader.status === IRPC_STATUS.SUCCESS) this.resolve(this.reader.data);
73
+ else if (this.reader.status === IRPC_STATUS.ERROR) this.reject(this.reader.error);
48
74
  }
49
75
  /**
50
76
  * Resolves the RPC call with the provided value.
@@ -57,22 +83,38 @@ var IRPCCall = class {
57
83
  this.status = IRPC_STATUS.SUCCESS;
58
84
  this.resolved = true;
59
85
  this.finishedAt = Date.now();
60
- this.resolver(value);
86
+ clearTimeout(this.timerId);
61
87
  }
62
88
  /**
63
89
  * Rejects the RPC call with the provided reason.
64
90
  * If the call is already resolved, this method does nothing.
65
91
  * @param reason - Optional error reason for rejecting the promise
92
+ * @param retriable - Flag indicating whether to retry the call
66
93
  */
67
- reject(reason) {
94
+ reject(reason, retriable = true) {
68
95
  if (this.resolved) return;
69
- this.error = reason;
70
- this.status = IRPC_STATUS.ERROR;
71
- this.resolved = true;
72
- this.finishedAt = Date.now();
73
- this.rejector(reason);
96
+ const { maxRetries, retryMode = DEFAULT_RETRY_MODE, retryDelay = DEFAULT_RETRY_DELAY } = this.options;
97
+ if (maxRetries && retriable) {
98
+ if (reason) this.retryReasons.add(reason);
99
+ if (this.retries >= maxRetries) {
100
+ console.error(ERROR_MESSAGE[ERROR_CODE.CALL_MAX_RETRIES_REACHED], this.retryReasons);
101
+ this.reject(reason, false);
102
+ return;
103
+ }
104
+ const delay = retryMode === "linear" ? retryDelay : retryDelay * 2 ** this.retries;
105
+ setTimeout(() => {
106
+ this.retries++;
107
+ this.transport.schedule(this);
108
+ }, delay);
109
+ } else {
110
+ this.error = reason;
111
+ this.status = IRPC_STATUS.ERROR;
112
+ this.resolved = true;
113
+ this.finishedAt = Date.now();
114
+ clearTimeout(this.timerId);
115
+ }
74
116
  }
75
117
  };
76
118
 
77
119
  //#endregion
78
- export { IRPCCall };
120
+ export { DEFAULT_RETRY_DELAY, DEFAULT_RETRY_MODE, IRPCCall };
package/dist/enum.d.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  declare const IRPC_PACKET_TYPE: {
3
3
  readonly CALL: "call";
4
4
  readonly EVENT: "event";
5
+ readonly CLOSE: "close";
5
6
  readonly ANSWER: "answer";
6
7
  readonly REQUEST: "request";
7
8
  readonly RESPONSE: "response";
package/dist/enum.js CHANGED
@@ -2,6 +2,7 @@
2
2
  const IRPC_PACKET_TYPE = {
3
3
  CALL: "call",
4
4
  EVENT: "event",
5
+ CLOSE: "close",
5
6
  ANSWER: "answer",
6
7
  REQUEST: "request",
7
8
  RESPONSE: "response"
package/dist/error.d.ts CHANGED
@@ -22,6 +22,8 @@ declare const ERROR_CODE: {
22
22
  RESOLVER_NOT_IMPLEMENTED: string;
23
23
  RESOLVER_NOT_FOUND: string;
24
24
  RESOLVER_NOT_SUPPORTED: string;
25
+ STREAM_ERROR: string;
26
+ CALL_MAX_RETRIES_REACHED: string;
25
27
  };
26
28
  type ErrorCode = (typeof ERROR_CODE)[keyof typeof ERROR_CODE];
27
29
  declare const ERROR_MESSAGE: {
@@ -41,10 +43,13 @@ declare const ERROR_MESSAGE: {
41
43
  [ERROR_CODE.TRANSPORT_INVALID]: string;
42
44
  [ERROR_CODE.TRANSPORT_NOT_IMPLEMENTED]: string;
43
45
  [ERROR_CODE.STUB_INVALID]: string;
46
+ [ERROR_CODE.STREAM_ERROR]: string;
44
47
  [ERROR_CODE.STUB_NOT_IMPLEMENTED]: string;
45
48
  [ERROR_CODE.RESOLVER_MISSING]: string;
46
49
  [ERROR_CODE.RESOLVER_NOT_IMPLEMENTED]: string;
47
50
  [ERROR_CODE.RESOLVER_NOT_FOUND]: string;
51
+ [ERROR_CODE.RESOLVER_NOT_SUPPORTED]: string;
52
+ [ERROR_CODE.CALL_MAX_RETRIES_REACHED]: string;
48
53
  };
49
54
  //#endregion
50
55
  export { ERROR_CODE, ERROR_MESSAGE, ErrorCode };
package/dist/error.js CHANGED
@@ -21,7 +21,9 @@ const ERROR_CODE = {
21
21
  RESOLVER_MISSING: "resolver_missing",
22
22
  RESOLVER_NOT_IMPLEMENTED: "resolver_not_implemented",
23
23
  RESOLVER_NOT_FOUND: "resolver_not_found",
24
- RESOLVER_NOT_SUPPORTED: "resolver_not_supported"
24
+ RESOLVER_NOT_SUPPORTED: "resolver_not_supported",
25
+ STREAM_ERROR: "stream_error",
26
+ CALL_MAX_RETRIES_REACHED: "call_max_retries_reached"
25
27
  };
26
28
  const ERROR_MESSAGE = {
27
29
  [ERROR_CODE.UNKNOWN]: "IRPC: Unknown error",
@@ -40,10 +42,13 @@ const ERROR_MESSAGE = {
40
42
  [ERROR_CODE.TRANSPORT_INVALID]: "IRPC: Transport invalid error",
41
43
  [ERROR_CODE.TRANSPORT_NOT_IMPLEMENTED]: "IRPC: Transport not implemented error",
42
44
  [ERROR_CODE.STUB_INVALID]: "IRPC: Stub invalid error",
45
+ [ERROR_CODE.STREAM_ERROR]: "IRPC: Stream error",
43
46
  [ERROR_CODE.STUB_NOT_IMPLEMENTED]: "IRPC: Stub not implemented error",
44
47
  [ERROR_CODE.RESOLVER_MISSING]: "IRPC: Resolver missing error",
45
48
  [ERROR_CODE.RESOLVER_NOT_IMPLEMENTED]: "IRPC: Resolver not implemented error",
46
- [ERROR_CODE.RESOLVER_NOT_FOUND]: "IRPC: Resolver not found error"
49
+ [ERROR_CODE.RESOLVER_NOT_FOUND]: "IRPC: Resolver not found error",
50
+ [ERROR_CODE.RESOLVER_NOT_SUPPORTED]: "IRPC: Resolver not supported error",
51
+ [ERROR_CODE.CALL_MAX_RETRIES_REACHED]: "IRPC: Call max retries reached error"
47
52
  };
48
53
 
49
54
  //#endregion
package/dist/index.d.ts CHANGED
@@ -2,9 +2,12 @@ import { IRPCCacheEntry, IRPCCacher } from "./cache.js";
2
2
  import { IRPC_DATA_TYPE, IRPC_EVENT_TYPE, IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
3
3
  import { ERROR_CODE, ERROR_MESSAGE, ErrorCode } from "./error.js";
4
4
  import { IRPCTransport } from "./transport.js";
5
- import { IRPCArraySchema, IRPCCache, IRPCContext, IRPCContextProvider, IRPCData, IRPCDataSchema, IRPCDataType, IRPCError, IRPCEventType, IRPCHandler, IRPCInit, IRPCInputs, IRPCObject, IRPCObjectSchema, IRPCOutput, IRPCPackageConfig, IRPCPackageInfo, IRPCPacket, IRPCPacketAnswer, IRPCPacketCall, IRPCPacketData, IRPCPacketEvent, IRPCPacketType, IRPCParseResult, IRPCPayload, IRPCPrimitive, IRPCPrimitiveSchema, IRPCReadable, IRPCRequest, IRPCResponse, IRPCSchema, IRPCSpec, IRPCSpecStore, IRPCStatus, IRPCStubStore, TransportConfig } from "./types.js";
6
- import { IRPCCall } from "./call.js";
5
+ import { IRPCArraySchema, IRPCCallConfig, IRPCContext, IRPCContextProvider, IRPCData, IRPCDataSchema, IRPCDataType, IRPCDeclareInit, IRPCError, IRPCEventType, IRPCHandler, IRPCInit, IRPCInputs, IRPCObject, IRPCObjectSchema, IRPCOutput, IRPCPackageConfig, IRPCPackageInfo, IRPCPacketAnswer, IRPCPacketBase, IRPCPacketCall, IRPCPacketClose, IRPCPacketData, IRPCPacketEvent, IRPCPacketStream, IRPCPacketType, IRPCParseResult, IRPCPayload, IRPCPrimitive, IRPCPrimitiveSchema, IRPCReadable, IRPCRequest, IRPCResponse, IRPCSchema, IRPCSpec, IRPCSpecStore, IRPCStatus, IRPCStubStore, TransportConfig } from "./types.js";
6
+ import { RemoteState, StreamConstructor, stream } from "./state.js";
7
+ import { IRPCReader } from "./reader.js";
8
+ import { DEFAULT_RETRY_DELAY, DEFAULT_RETRY_MODE, IRPCCall } from "./call.js";
7
9
  import { createContext, getContext, setContext, setContextProvider, withContext } from "./context.js";
8
10
  import { IRPCPackage, createPackage } from "./module.js";
9
11
  import { IRPCResolver } from "./resolver.js";
10
- export { ERROR_CODE, ERROR_MESSAGE, ErrorCode, IRPCArraySchema, IRPCCache, IRPCCacheEntry, IRPCCacher, IRPCCall, IRPCContext, IRPCContextProvider, IRPCData, IRPCDataSchema, IRPCDataType, IRPCError, IRPCEventType, IRPCHandler, IRPCInit, IRPCInputs, IRPCObject, IRPCObjectSchema, IRPCOutput, IRPCPackage, IRPCPackageConfig, IRPCPackageInfo, IRPCPacket, IRPCPacketAnswer, IRPCPacketCall, IRPCPacketData, IRPCPacketEvent, IRPCPacketType, IRPCParseResult, IRPCPayload, IRPCPrimitive, IRPCPrimitiveSchema, IRPCReadable, IRPCRequest, IRPCResolver, IRPCResponse, IRPCSchema, IRPCSpec, IRPCSpecStore, IRPCStatus, IRPCStubStore, IRPCTransport, IRPC_DATA_TYPE, IRPC_EVENT_TYPE, IRPC_PACKET_TYPE, IRPC_STATUS, TransportConfig, createContext, createPackage, getContext, setContext, setContextProvider, withContext };
12
+ import { IRPCStream } from "./stream.js";
13
+ export { DEFAULT_RETRY_DELAY, DEFAULT_RETRY_MODE, ERROR_CODE, ERROR_MESSAGE, ErrorCode, IRPCArraySchema, IRPCCacheEntry, IRPCCacher, IRPCCall, IRPCCallConfig, IRPCContext, IRPCContextProvider, IRPCData, IRPCDataSchema, IRPCDataType, IRPCDeclareInit, IRPCError, IRPCEventType, IRPCHandler, IRPCInit, IRPCInputs, IRPCObject, IRPCObjectSchema, IRPCOutput, IRPCPackage, IRPCPackageConfig, IRPCPackageInfo, IRPCPacketAnswer, IRPCPacketBase, IRPCPacketCall, IRPCPacketClose, IRPCPacketData, IRPCPacketEvent, IRPCPacketStream, IRPCPacketType, IRPCParseResult, IRPCPayload, IRPCPrimitive, IRPCPrimitiveSchema, IRPCReadable, IRPCReader, IRPCRequest, IRPCResolver, IRPCResponse, IRPCSchema, IRPCSpec, IRPCSpecStore, IRPCStatus, IRPCStream, IRPCStubStore, IRPCTransport, IRPC_DATA_TYPE, IRPC_EVENT_TYPE, IRPC_PACKET_TYPE, IRPC_STATUS, RemoteState, StreamConstructor, TransportConfig, createContext, createPackage, getContext, setContext, setContextProvider, stream, withContext };
package/dist/index.js CHANGED
@@ -1,10 +1,13 @@
1
1
  import { IRPCCacher } from "./cache.js";
2
2
  import { IRPC_DATA_TYPE, IRPC_EVENT_TYPE, IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
3
- import { IRPCCall } from "./call.js";
4
- import { createContext, getContext, setContext, setContextProvider, withContext } from "./context.js";
5
3
  import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
4
+ import { RemoteState, stream } from "./state.js";
5
+ import { IRPCReader } from "./reader.js";
6
+ import { DEFAULT_RETRY_DELAY, DEFAULT_RETRY_MODE, IRPCCall } from "./call.js";
7
+ import { createContext, getContext, setContext, setContextProvider, withContext } from "./context.js";
6
8
  import { IRPCTransport } from "./transport.js";
7
9
  import { IRPCPackage, createPackage } from "./module.js";
8
10
  import { IRPCResolver } from "./resolver.js";
11
+ import { IRPCStream } from "./stream.js";
9
12
 
10
- export { ERROR_CODE, ERROR_MESSAGE, IRPCCacher, IRPCCall, IRPCPackage, IRPCResolver, IRPCTransport, IRPC_DATA_TYPE, IRPC_EVENT_TYPE, IRPC_PACKET_TYPE, IRPC_STATUS, createContext, createPackage, getContext, setContext, setContextProvider, withContext };
13
+ export { DEFAULT_RETRY_DELAY, DEFAULT_RETRY_MODE, ERROR_CODE, ERROR_MESSAGE, IRPCCacher, IRPCCall, IRPCPackage, IRPCReader, IRPCResolver, IRPCStream, IRPCTransport, IRPC_DATA_TYPE, IRPC_EVENT_TYPE, IRPC_PACKET_TYPE, IRPC_STATUS, RemoteState, createContext, createPackage, getContext, setContext, setContextProvider, stream, withContext };
package/dist/module.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { IRPCCacher } from "./cache.js";
2
2
  import { IRPCTransport } from "./transport.js";
3
- import { IRPCData, IRPCHandler, IRPCInit, IRPCInputs, IRPCOutput, IRPCPackageConfig, IRPCPackageInfo, IRPCRequest, IRPCSpec, IRPCSpecStore, IRPCStubStore } from "./types.js";
3
+ import { IRPCData, IRPCDeclareInit, IRPCHandler, IRPCInputs, IRPCOutput, IRPCPackageConfig, IRPCPackageInfo, IRPCRequest, IRPCSpec, IRPCSpecStore, IRPCStubStore } from "./types.js";
4
+ import { RemoteState } from "./state.js";
4
5
 
5
6
  //#region src/module.d.ts
6
7
 
@@ -46,18 +47,18 @@ declare class IRPCPackage {
46
47
  constructor(config?: Partial<IRPCPackageConfig>);
47
48
  /**
48
49
  * Declares a new IRPC specification and creates a corresponding stub function
49
- * @param init - The initialization object containing the IRPC specification
50
+ * @param options - The initialization object containing the IRPC specification
50
51
  * @returns A stub function that can be used to call the IRPC
51
52
  * @throws Error if an IRPC with the same name already exists
52
53
  */
53
- declare<F, I extends IRPCInputs = IRPCInputs, O extends IRPCOutput = IRPCOutput>(init: IRPCInit<I, O>): F;
54
+ declare<F, I extends IRPCInputs = IRPCInputs, O extends IRPCOutput = IRPCOutput>(options: IRPCDeclareInit<F, I, O>): F;
54
55
  /**
55
56
  * Resolves and executes an IRPC call based on a request object
56
57
  * @param req - The request containing the IRPC name and arguments
57
58
  * @returns The result of the IRPC execution
58
59
  * @throws Error if the IRPC doesn't exist or doesn't have an implementation
59
60
  */
60
- resolve(req: IRPCRequest): Promise<IRPCData>;
61
+ resolve(req: IRPCRequest): IRPCData | Promise<IRPCData> | RemoteState<IRPCData>;
61
62
  /**
62
63
  * Associates a handler function with a stub function
63
64
  * @param stub - The stub function created by declare()
package/dist/module.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { IRPCCacher } from "./cache.js";
2
2
  import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
3
+ import { RemoteState } from "./state.js";
3
4
  import { IRPCTransport } from "./transport.js";
4
5
 
5
6
  //#region src/module.ts
@@ -65,33 +66,40 @@ var IRPCPackage = class {
65
66
  }
66
67
  /**
67
68
  * Declares a new IRPC specification and creates a corresponding stub function
68
- * @param init - The initialization object containing the IRPC specification
69
+ * @param options - The initialization object containing the IRPC specification
69
70
  * @returns A stub function that can be used to call the IRPC
70
71
  * @throws Error if an IRPC with the same name already exists
71
72
  */
72
- declare(init) {
73
- if (this.specs.has(init.name)) throw new Error(`IRPC ${init.name} already exists.`);
74
- const spec = { ...init };
73
+ declare(options) {
74
+ if (this.specs.has(options.name)) throw new Error(`IRPC ${options.name} already exists.`);
75
+ const spec = { ...options };
75
76
  const calls = /* @__PURE__ */ new Map();
76
77
  const caches = new IRPCCacher();
77
- const timeout = spec.timeout ?? this.config.timeout;
78
- const stub = (async (...args) => {
79
- if (!this.transport && typeof spec.handler !== "function") throw new Error(ERROR_MESSAGE[ERROR_CODE.TRANSPORT_MISSING]);
78
+ const stub = ((...args) => {
79
+ if (!this.transport && typeof spec.handler !== "function") return Promise.reject(new Error(ERROR_MESSAGE[ERROR_CODE.TRANSPORT_MISSING]));
80
80
  const callKey = JSON.stringify(args);
81
81
  const cached = caches.get(callKey);
82
82
  if (cached) return cached.value;
83
83
  if (spec.coalesce !== false && calls.has(callKey)) return calls.get(callKey);
84
- const call = typeof spec.handler === "function" ? spec.handler(...args) : this.transport.call(spec, args, timeout);
84
+ const { timeout, maxRetries, retryDelay, retryMode } = {
85
+ ...this.config,
86
+ ...spec
87
+ };
88
+ const config = {
89
+ timeout,
90
+ maxRetries,
91
+ retryDelay,
92
+ retryMode
93
+ };
94
+ const call = typeof spec.handler === "function" ? spec.handler(...args) : this.transport.call(spec, args, config);
85
95
  calls.set(callKey, call);
86
- try {
87
- const data = await call;
88
- if (spec.maxAge) caches.set(callKey, data, spec.maxAge);
89
- return data;
90
- } finally {
91
- calls.delete(callKey);
92
- }
96
+ if (spec.maxAge) caches.set(callKey, call, spec.maxAge);
97
+ if (typeof spec.init === "function" && call instanceof RemoteState && typeof call.data === "undefined") call.data = spec.init();
98
+ if (call instanceof Promise) call.finally(() => calls.delete(callKey)).catch(() => {});
99
+ else calls.delete(callKey);
100
+ return call;
93
101
  });
94
- this.specs.set(init.name, spec);
102
+ this.specs.set(options.name, spec);
95
103
  this.stubs.set(stub, spec);
96
104
  this.cache.set(stub, caches);
97
105
  return stub;
@@ -102,11 +110,11 @@ var IRPCPackage = class {
102
110
  * @returns The result of the IRPC execution
103
111
  * @throws Error if the IRPC doesn't exist or doesn't have an implementation
104
112
  */
105
- async resolve(req) {
113
+ resolve(req) {
106
114
  const spec = this.specs.get(req.name);
107
115
  if (!spec) return Promise.reject(/* @__PURE__ */ new Error(`IRPC ${req.name} does not exist.`));
108
116
  if (typeof spec.handler !== "function") return Promise.reject(/* @__PURE__ */ new Error(`IRPC ${req.name} does not have an implementation.`));
109
- return await spec.handler(...req.args);
117
+ return spec.handler(...req.args);
110
118
  }
111
119
  /**
112
120
  * Associates a handler function with a stub function
@@ -0,0 +1,24 @@
1
+ import { IRPCData, IRPCPacketStream } from "./types.js";
2
+ import { RemoteState } from "./state.js";
3
+
4
+ //#region src/reader.d.ts
5
+
6
+ /**
7
+ * A client-side consumer that hydrates `RemoteState` instances from network stream packets.
8
+ *
9
+ * @template T - The type of data yielded by the stream.
10
+ */
11
+ declare class IRPCReader<T extends IRPCData> extends RemoteState<T> {
12
+ id: string;
13
+ packets: Set<IRPCPacketStream<T>>;
14
+ constructor(id: string, init?: T);
15
+ /**
16
+ * Pushes incoming network packets into this reader, evaluating payload data
17
+ * and subsequently updating the core state values locally.
18
+ *
19
+ * @param packet - The incoming unified Stream Packet structure (`ANSWER`, `EVENT`, or `CLOSE`).
20
+ */
21
+ push(packet: IRPCPacketStream<T>): void;
22
+ }
23
+ //#endregion
24
+ export { IRPCReader };
package/dist/reader.js ADDED
@@ -0,0 +1,37 @@
1
+ import { IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
2
+ import { RemoteState } from "./state.js";
3
+ import { replay } from "@anchorlib/core";
4
+
5
+ //#region src/reader.ts
6
+ /**
7
+ * A client-side consumer that hydrates `RemoteState` instances from network stream packets.
8
+ *
9
+ * @template T - The type of data yielded by the stream.
10
+ */
11
+ var IRPCReader = class extends RemoteState {
12
+ packets = /* @__PURE__ */ new Set();
13
+ constructor(id, init) {
14
+ super(init);
15
+ this.id = id;
16
+ }
17
+ /**
18
+ * Pushes incoming network packets into this reader, evaluating payload data
19
+ * and subsequently updating the core state values locally.
20
+ *
21
+ * @param packet - The incoming unified Stream Packet structure (`ANSWER`, `EVENT`, or `CLOSE`).
22
+ */
23
+ push(packet) {
24
+ packet.arrivedAt = Date.now();
25
+ this.packets.add(packet);
26
+ if (packet.type === IRPC_PACKET_TYPE.ANSWER) if (packet.status === IRPC_STATUS.ERROR) this.error = new Error(packet.error.message);
27
+ else this.data = packet.data;
28
+ else if (packet.type === IRPC_PACKET_TYPE.EVENT) replay(this.state, packet.data);
29
+ else if (packet.type === IRPC_PACKET_TYPE.CLOSE) {
30
+ if (packet.error) this.error = new Error(packet.error.message);
31
+ }
32
+ this.status = packet.status;
33
+ }
34
+ };
35
+
36
+ //#endregion
37
+ export { IRPCReader };
@@ -1,4 +1,4 @@
1
- import { IRPCDataSchema, IRPCError, IRPCInputs, IRPCOutput, IRPCRequest, IRPCResponse, IRPCSpec } from "./types.js";
1
+ import { IRPCDataSchema, IRPCInputs, IRPCOutput, IRPCRequest, IRPCResponse, IRPCSpec } from "./types.js";
2
2
  import { IRPCPackage } from "./module.js";
3
3
 
4
4
  //#region src/resolver.d.ts
@@ -45,17 +45,7 @@ declare class IRPCResolver {
45
45
  id,
46
46
  name,
47
47
  args
48
- }: IRPCRequest, schema?: IRPCOutput): Promise<{
49
- id: string;
50
- name: string;
51
- result: string | number | boolean | IRPCDataSchema | Record<string, unknown> | (string | number | boolean | Record<string, unknown> | null | undefined)[] | null | undefined;
52
- error?: undefined;
53
- } | {
54
- id: string;
55
- name: string;
56
- error: IRPCError;
57
- result?: undefined;
58
- }>;
48
+ }: IRPCRequest, schema?: IRPCOutput): Promise<IRPCResponse>;
59
49
  }
60
50
  //#endregion
61
51
  export { IRPCResolver };
package/dist/resolver.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ERROR_CODE } from "./error.js";
2
+ import { RemoteState } from "./state.js";
2
3
 
3
4
  //#region src/resolver.ts
4
5
  /**
@@ -69,11 +70,28 @@ var IRPCResolver = class {
69
70
  */
70
71
  async forward({ id, name, args }, schema) {
71
72
  try {
72
- const output = parseOutput(await this.module.resolve({
73
+ const result = this.module.resolve({
73
74
  id,
74
75
  name,
75
76
  args
76
- }), schema);
77
+ });
78
+ if (result instanceof RemoteState) {
79
+ const output$1 = parseOutput(result.data, schema);
80
+ if (!output$1.success) return {
81
+ id,
82
+ name,
83
+ error: {
84
+ code: ERROR_CODE.INVALID_OUTPUT,
85
+ message: output$1.error?.message
86
+ }
87
+ };
88
+ return {
89
+ id,
90
+ name,
91
+ result
92
+ };
93
+ }
94
+ const output = parseOutput(await result, schema);
77
95
  if (output.success) return {
78
96
  id,
79
97
  name,
package/dist/state.d.ts CHANGED
@@ -3,17 +3,80 @@ import * as _anchorlib_core0 from "@anchorlib/core";
3
3
  import { StateSubscriber } from "@anchorlib/core";
4
4
 
5
5
  //#region src/state.d.ts
6
- declare class RemoteState<T> {
7
- #private;
6
+
7
+ /**
8
+ * A reactive state wrapper that implements the standard Promise interface.
9
+ *
10
+ * RemoteState acts as a dual-layer abstraction:
11
+ * 1. For asynchronous execution, it operates as a `Promise<T>` that resolves upon completion or rejects upon failure.
12
+ * 2. For reactive environments, it exposes an `.subscribe()` method to react to intermediate data mutations.
13
+ *
14
+ * @template T - The type of data held by the state.
15
+ */
16
+ declare class RemoteState<T> extends Promise<T> {
17
+ protected readonly state: IRPCReadable<T>;
18
+ protected readonly accept: (value: T) => void;
19
+ protected readonly reject: (error: Error) => void;
20
+ /**
21
+ * The current data payload of the state.
22
+ */
8
23
  get data(): T;
9
24
  set data(data: T);
25
+ /**
26
+ * The current error encountered by the state, if any.
27
+ */
10
28
  get error(): Error | undefined;
11
29
  set error(error: Error | undefined);
30
+ /**
31
+ * The execution status of the state (PENDING, SUCCESS, ERROR).
32
+ * Transitioning to a terminal status (SUCCESS or ERROR) will automatically resolve or reject the underlying Promise.
33
+ */
12
34
  get status(): IRPCStatus;
13
35
  set status(status: IRPCStatus);
14
- constructor(init: T);
36
+ /**
37
+ * Initializes a new RemoteState with an optional initial payload.
38
+ *
39
+ * @param init - An optional starting value for the data payload.
40
+ */
41
+ constructor(init?: T);
42
+ /**
43
+ * Subscribes to changes emitted by the internal state.
44
+ *
45
+ * @param handler - A callback function invoked whenever the state mutates.
46
+ * @returns An unsubscribe function to terminate the listener.
47
+ */
15
48
  subscribe(handler: StateSubscriber<IRPCReadable<T>>): _anchorlib_core0.StateUnsubscribe;
16
- destroy(): void;
49
+ /**
50
+ * Destroys the reactive state bindings.
51
+ */
52
+ protected destroy(): void;
53
+ /**
54
+ * Ensures that chained Promise operations return standard Promises
55
+ * rather than instantiating new RemoteState subclasses.
56
+ */
57
+ static get [Symbol.species](): PromiseConstructor;
17
58
  }
59
+ /**
60
+ * A callback function type used to natively construct and drive a reactive stream.
61
+ * It provides the initial reactive data reference and terminal resolution hooks
62
+ * without forcing strict async/await boundaries, securely yielding stream operations.
63
+ *
64
+ * @template T - The type of data yielded globally by the stream.
65
+ * @param data - The mutable data payload natively tracked by RemoteState.
66
+ * @param resolve - Callback to statically mark the stream as successfully completed, optionally with a resolved value.
67
+ * @param reject - Callback to forcefully throw a runtime error into the stream structure.
68
+ */
69
+ type StreamConstructor<T> = (data: T, resolve: (value?: T) => void, reject: (error: Error) => void) => void | Promise<void>;
70
+ /**
71
+ * A utility factory to structurally instantiate an active `RemoteState` pipeline natively
72
+ * decoupled from standard Promise chains. This elegantly captures constructor functions
73
+ * pushing events into the state before terminating mechanically via secure internal hooks.
74
+ *
75
+ * @template T - The type of the streamed payload data.
76
+ * @param construct - The isolated stream constructor callback that natively operates the pipeline.
77
+ * @param init - An optional initial value to prime the state payload inherently.
78
+ * @returns A fully active RemoteState inherently bound to the callbacks executing natively.
79
+ */
80
+ declare function stream<T>(construct: StreamConstructor<T>, init?: T): RemoteState<T>;
18
81
  //#endregion
19
- export { RemoteState };
82
+ export { RemoteState, StreamConstructor, stream };