@irpclib/irpc 1.0.0-beta.24 → 1.0.0

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/module.js CHANGED
@@ -1,6 +1,6 @@
1
+ import { HandlerError, ResolveError, StubError, TransportError } from "./error.js";
1
2
  import { IRPCCacher } from "./cache.js";
2
3
  import { IRPC_STATUS } from "./enum.js";
3
- import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
4
4
  import { getAbortSignal } from "./context.js";
5
5
  import { RemoteState } from "./state.js";
6
6
  import { IRPCReader } from "./reader.js";
@@ -37,6 +37,7 @@ var IRPCPackage = class {
37
37
  config = {
38
38
  name: "global",
39
39
  version: "1.0.0",
40
+ key: "id",
40
41
  timeout: DEFAULT_TIMEOUT
41
42
  };
42
43
  /**
@@ -71,23 +72,29 @@ var IRPCPackage = class {
71
72
  this.configure(config ?? {});
72
73
  IRPC_STORE.register(this);
73
74
  }
74
- /**
75
- * Declares a new IRPC specification and creates a corresponding stub function
76
- * @param options - The initialization object containing the IRPC specification
77
- * @returns A stub function that can be used to call the IRPC
78
- * @throws Error if an IRPC with the same name already exists
79
- */
80
- declare(options) {
75
+ declare(nameOrOptions, seedOrConfig, config) {
76
+ let options;
77
+ if (typeof nameOrOptions === "string") if (typeof seedOrConfig === "function") options = {
78
+ name: nameOrOptions,
79
+ seed: seedOrConfig,
80
+ ...config
81
+ };
82
+ else options = {
83
+ name: nameOrOptions,
84
+ ...seedOrConfig
85
+ };
86
+ else options = nameOrOptions;
81
87
  const $options = options;
82
- if (this.specs.has($options.name)) throw new Error(`IRPC ${$options.name} already exists.`);
88
+ if (this.specs.has($options.name)) throw StubError.duplicate($options.name);
89
+ if ($options.init && !$options.seed) $options.seed = $options.init;
83
90
  const spec = {
84
- init: () => void 0,
91
+ seed: () => void 0,
85
92
  ...$options
86
93
  };
87
94
  const calls = /* @__PURE__ */ new Map();
88
95
  const caches = new IRPCCacher();
89
96
  const stub = ((...args) => {
90
- return execute(args, new IRPCReader(uuid(), spec.init()));
97
+ return execute(args, new IRPCReader(uuid(), spec.seed()));
91
98
  });
92
99
  /** Browser only stub for single immediate execution **/
93
100
  stub.once = (...args) => {
@@ -100,7 +107,7 @@ var IRPCPackage = class {
100
107
  return prepare(typeof getArgs === "function" ? getArgs : () => getArgs, true, debounce);
101
108
  };
102
109
  stub.later = (debounce) => {
103
- const reader = new IRPCReader(uuid(), spec.init(), IRPC_STATUS.IDLE, true);
110
+ const reader = new IRPCReader(uuid(), spec.seed(), IRPC_STATUS.IDLE, true);
104
111
  if (debounce) {
105
112
  const [schedule, cancel] = microtask(debounce);
106
113
  reader.dispatch = (...args) => schedule(() => {
@@ -125,7 +132,7 @@ var IRPCPackage = class {
125
132
  * @returns {IRPCReader<IRPCData>} - The reader for the call.
126
133
  */
127
134
  function prepare(getArgs, deferred, debounce = 0) {
128
- const reader = new IRPCReader(uuid(), spec.init(), deferred ? IRPC_STATUS.IDLE : IRPC_STATUS.PENDING);
135
+ const reader = new IRPCReader(uuid(), spec.seed(), deferred ? IRPC_STATUS.IDLE : IRPC_STATUS.PENDING);
129
136
  if (isBrowser()) {
130
137
  const observer = createObserver(() => {
131
138
  observer.reset();
@@ -149,29 +156,28 @@ var IRPCPackage = class {
149
156
  return reader;
150
157
  }
151
158
  const execute = (args, reader) => {
152
- if (!this.transport && typeof spec.handler !== "function") return Promise.reject(new Error(ERROR_MESSAGE[ERROR_CODE.TRANSPORT_MISSING]));
159
+ if (!this.transport && typeof spec.handler !== "function") return Promise.reject(TransportError.missing());
153
160
  reader.status = IRPC_STATUS.PENDING;
154
161
  const callKey = JSON.stringify(args);
155
162
  const cached = caches.get(callKey);
156
163
  if (cached) return cached.value;
157
164
  if (spec.coalesce !== false && calls.has(callKey)) return calls.get(callKey);
158
- const { timeout, maxRetries, retryDelay, retryMode, init } = {
165
+ const { timeout, maxRetries, retryDelay, retryMode } = {
159
166
  ...this.config,
160
167
  ...spec
161
168
  };
162
- const config = {
169
+ const config$1 = {
163
170
  timeout,
164
171
  maxRetries,
165
172
  retryDelay,
166
- retryMode,
167
- init
173
+ retryMode
168
174
  };
169
175
  const hooks = this.hooks.get(spec);
170
176
  if (hooks) hooks.forEach((hook) => hook({
171
177
  name: spec.name,
172
178
  args
173
179
  }));
174
- const call = typeof spec.handler === "function" ? intercept(spec, args, reader) : this.transport.call(spec, args, config, reader);
180
+ const call = typeof spec.handler === "function" ? intercept(spec, args, reader) : this.transport.call(spec, args, config$1, reader);
175
181
  calls.set(callKey, call);
176
182
  if (spec.maxAge) caches.set(callKey, call, spec.maxAge);
177
183
  onCleanup(() => call.close());
@@ -185,6 +191,50 @@ var IRPCPackage = class {
185
191
  return stub;
186
192
  }
187
193
  /**
194
+ * Declares CRUD stubs (get, create, update, delete) for an entity
195
+ * @param name - The entity name used as prefix for stub names
196
+ * @param seed - Factory function returning a default entity instance
197
+ * @param options - Optional configuration for caching, schemas, and call behavior
198
+ * @returns An object containing the four CRUD stub functions
199
+ */
200
+ crud(name, seed, options) {
201
+ const { description, schema, maxAge, coalesce,...callConfig } = options ?? {};
202
+ const desc = (method) => typeof description === "string" ? description : description?.[method];
203
+ const init = (method) => ({
204
+ ...callConfig,
205
+ name: `${name}.${method}`,
206
+ seed,
207
+ description: desc(method),
208
+ schema: schema?.[method],
209
+ ...method === "get" ? { maxAge } : {},
210
+ coalesce
211
+ });
212
+ return {
213
+ get: this.declare(init("get")),
214
+ create: this.declare(init("create")),
215
+ update: this.declare(init("update")),
216
+ delete: this.declare(init("delete"))
217
+ };
218
+ }
219
+ /**
220
+ * Removes CRUD methods from a stubs object and unregisters their specs
221
+ * @param stubs - The CRUD stubs object to modify
222
+ * @param keys - The method names to remove
223
+ * @returns The stubs object without the excluded methods
224
+ */
225
+ exclude(stubs, keys) {
226
+ for (const key of keys) {
227
+ const stub = stubs[key];
228
+ if (stub) {
229
+ const spec = this.stubs.get(stub);
230
+ if (spec) this.specs.delete(spec.name);
231
+ this.stubs.delete(stub);
232
+ }
233
+ delete stubs[key];
234
+ }
235
+ return stubs;
236
+ }
237
+ /**
188
238
  * Resolves and executes an IRPC call based on a request object
189
239
  * @param req - The request containing the IRPC name and arguments
190
240
  * @returns The result of the IRPC execution
@@ -192,8 +242,8 @@ var IRPCPackage = class {
192
242
  */
193
243
  resolve(req) {
194
244
  const spec = this.specs.get(req.name);
195
- if (!spec) return Promise.reject(/* @__PURE__ */ new Error(`IRPC ${req.name} does not exist.`));
196
- if (typeof spec.handler !== "function") return Promise.reject(/* @__PURE__ */ new Error(`IRPC ${req.name} does not have an implementation.`));
245
+ if (!spec) return Promise.reject(ResolveError.notFound(req.name));
246
+ if (typeof spec.handler !== "function") return Promise.reject(HandlerError.missing(req.name));
197
247
  return spec.handler(...req.args);
198
248
  }
199
249
  /**
@@ -204,28 +254,28 @@ var IRPCPackage = class {
204
254
  * @throws Error if the stub or handler is invalid, or if no IRPC exists for the stub
205
255
  */
206
256
  construct(stub, handler) {
207
- if (typeof stub !== "function") throw new Error(ERROR_MESSAGE[ERROR_CODE.STUB_INVALID]);
208
- if (typeof handler !== "function") throw new Error(ERROR_MESSAGE[ERROR_CODE.INVALID_HANDLER]);
257
+ if (typeof stub !== "function") throw StubError.invalid();
258
+ if (typeof handler !== "function") throw HandlerError.invalid();
209
259
  const spec = this.stubs.get(stub);
210
- if (!spec?.name) throw new Error(ERROR_MESSAGE[ERROR_CODE.NOT_FOUND]);
260
+ if (!spec?.name) throw StubError.notFound();
211
261
  spec.handler = handler;
212
262
  return this;
213
263
  }
214
- /**
215
- * Registers a hook function for a specific stub function
216
- * @param stub - The stub function created by declare()
217
- * @param handler - The hook function to register
218
- * @returns This IRPCPackage instance for chaining
219
- * @throws Error if the stub is invalid or if no IRPC exists for the stub
220
- */
221
- hook(stub, handler) {
222
- if (!this.stubs.has(stub)) {
223
- const error = new Error(ERROR_MESSAGE[ERROR_CODE.NOT_FOUND]);
224
- IRPC_STORE.error(error);
264
+ hook(stubOrGroup, handler) {
265
+ if (typeof stubOrGroup === "function") {
266
+ if (!this.stubs.has(stubOrGroup)) {
267
+ const error = StubError.notFound();
268
+ IRPC_STORE.error(error);
269
+ return this;
270
+ }
271
+ const spec = this.stubs.get(stubOrGroup);
272
+ this.hooks.get(spec).add(handler);
225
273
  return this;
226
274
  }
227
- const spec = this.stubs.get(stub);
228
- this.hooks.get(spec).add(handler);
275
+ for (const stub of Object.values(stubOrGroup)) if (typeof stub === "function" && this.stubs.has(stub)) {
276
+ const spec = this.stubs.get(stub);
277
+ this.hooks.get(spec).add(handler);
278
+ }
229
279
  return this;
230
280
  }
231
281
  /**
@@ -236,7 +286,7 @@ var IRPCPackage = class {
236
286
  */
237
287
  async resolveHooks(req) {
238
288
  const spec = this.specs.get(req.name);
239
- if (!spec || !this.hooks.has(spec)) throw new Error(ERROR_MESSAGE[ERROR_CODE.NOT_FOUND]);
289
+ if (!spec || !this.hooks.has(spec)) throw StubError.notFound();
240
290
  const hooks = this.hooks.get(spec);
241
291
  for (const hook of hooks) await hook(req);
242
292
  }
@@ -247,7 +297,7 @@ var IRPCPackage = class {
247
297
  * @throws Error if the transport is not a valid Transport instance
248
298
  */
249
299
  use(transport) {
250
- if (!(transport instanceof IRPCTransport)) throw new Error(ERROR_MESSAGE[ERROR_CODE.TRANSPORT_INVALID]);
300
+ if (!(transport instanceof IRPCTransport)) throw TransportError.invalid();
251
301
  if (this.transport) this.transport.modules.delete(this);
252
302
  transport.modules.add(this);
253
303
  this.config.transport = transport;
@@ -269,8 +319,8 @@ var IRPCPackage = class {
269
319
  * @throws Error if the provided name or version is invalid
270
320
  */
271
321
  configure(config) {
272
- if (config.name && !NAME_CONSTRAINT.test(config.name)) throw new Error(`Invalid IRPC name: ${config.name}`);
273
- if (config.version && !VERSION_CONSTRAINT.test(config.version)) throw new Error(`Invalid IRPC version: ${config.version}`);
322
+ if (config.name && !NAME_CONSTRAINT.test(config.name)) throw StubError.invalidName(config.name);
323
+ if (config.version && !VERSION_CONSTRAINT.test(config.version)) throw StubError.invalidVersion(config.version);
274
324
  Object.assign(this.config, config);
275
325
  return this;
276
326
  }
package/dist/reader.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { IRPCError } from "./error.js";
1
2
  import { IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
2
3
  import { RemoteState } from "./state.js";
3
4
  import { replay } from "@anchorlib/core";
@@ -30,11 +31,11 @@ var IRPCReader = class extends RemoteState {
30
31
  */
31
32
  push(packet) {
32
33
  packet.arrivedAt = Date.now();
33
- if (packet.type === IRPC_PACKET_TYPE.ANSWER) if (packet.status === IRPC_STATUS.ERROR) this.error = new Error(packet.error.message);
34
+ if (packet.type === IRPC_PACKET_TYPE.ANSWER) if (packet.status === IRPC_STATUS.ERROR) this.error = IRPCError.from(packet.error);
34
35
  else this.data = packet.data;
35
36
  else if (packet.type === IRPC_PACKET_TYPE.EVENT) replay(this.state, packet.data);
36
37
  else if (packet.type === IRPC_PACKET_TYPE.CLOSE) {
37
- if (packet.error) this.error = new Error(packet.error.message);
38
+ if (packet.error) this.error = IRPCError.from(packet.error);
38
39
  }
39
40
  this.status = packet.status;
40
41
  }
@@ -1,5 +1,5 @@
1
- import { IRPCPackage } from "./module.js";
2
1
  import { IRPCDataSchema, IRPCInputs, IRPCOutput, IRPCRequest, IRPCResponse, IRPCSpec } from "./types.js";
2
+ import { IRPCPackage } from "./module.js";
3
3
 
4
4
  //#region src/resolver.d.ts
5
5
 
package/dist/resolver.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ERROR_CODE } from "./error.js";
1
+ import { HandlerError, ResolveError } from "./error.js";
2
2
  import { RemoteState } from "./state.js";
3
3
 
4
4
  //#region src/resolver.ts
@@ -40,20 +40,14 @@ var IRPCResolver = class {
40
40
  if (!this.spec) return {
41
41
  id,
42
42
  name,
43
- error: {
44
- code: ERROR_CODE.NOT_FOUND,
45
- message: `IRPC "${name}" does not exist.`
46
- }
43
+ error: ResolveError.notFound(name).json()
47
44
  };
48
45
  const { schema } = this.spec;
49
46
  const inputs = parseInput(args, schema?.input);
50
47
  if (!inputs.success) return {
51
48
  id,
52
49
  name,
53
- error: {
54
- code: ERROR_CODE.INVALID_INPUT,
55
- message: inputs.error
56
- }
50
+ error: ResolveError.invalidInput(inputs.error).json()
57
51
  };
58
52
  return this.forward({
59
53
  id,
@@ -85,10 +79,7 @@ var IRPCResolver = class {
85
79
  if (!output$1.success) return {
86
80
  id,
87
81
  name,
88
- error: {
89
- code: ERROR_CODE.INVALID_OUTPUT,
90
- message: output$1.error?.message
91
- }
82
+ error: ResolveError.invalidOutput(output$1.error).json()
92
83
  };
93
84
  return {
94
85
  id,
@@ -103,10 +94,7 @@ var IRPCResolver = class {
103
94
  if (!output$1.success) return {
104
95
  id,
105
96
  name,
106
- error: {
107
- code: ERROR_CODE.INVALID_OUTPUT,
108
- message: output$1.error?.message
109
- }
97
+ error: ResolveError.invalidOutput(output$1.error).json()
110
98
  };
111
99
  return {
112
100
  id,
@@ -123,19 +111,13 @@ var IRPCResolver = class {
123
111
  else return {
124
112
  id,
125
113
  name,
126
- error: {
127
- code: ERROR_CODE.INVALID_OUTPUT,
128
- message: output.error?.message
129
- }
114
+ error: ResolveError.invalidOutput(output.error).json()
130
115
  };
131
116
  } catch (error) {
132
117
  return {
133
118
  id,
134
119
  name,
135
- error: {
136
- code: ERROR_CODE.HANDLER_ERROR,
137
- message: error.message
138
- }
120
+ error: HandlerError.failed(error).json()
139
121
  };
140
122
  }
141
123
  }
package/dist/router.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { IRPCPackage } from "./module.js";
2
1
  import { IRPCTransport } from "./transport.js";
3
- import { IRPCRequest } from "./types.js";
2
+ import { IRPCPacketError, IRPCRequest } from "./types.js";
3
+ import { IRPCPackage } from "./module.js";
4
4
 
5
5
  //#region src/router.d.ts
6
6
  type IRPCHook = () => void | Promise<void>;
@@ -42,10 +42,7 @@ declare class IRPCRouter {
42
42
  name: string;
43
43
  type: "close";
44
44
  status: "error";
45
- error: {
46
- code: string;
47
- message: string;
48
- };
45
+ error: IRPCPacketError;
49
46
  createdAt: number;
50
47
  } | undefined>;
51
48
  }
package/dist/router.js CHANGED
@@ -1,5 +1,5 @@
1
+ import { HookError } from "./error.js";
1
2
  import { IRPC_BASE_CONTEXT, IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
2
- import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
3
3
  import { createContextStore, withContext } from "./context.js";
4
4
  import { IRPC_STORE } from "./store.js";
5
5
 
@@ -24,7 +24,7 @@ var IRPCRouter = class {
24
24
  */
25
25
  use(hook) {
26
26
  if (typeof hook !== "function") {
27
- const error = new Error(ERROR_MESSAGE[ERROR_CODE.INVALID_HOOK]);
27
+ const error = HookError.invalid();
28
28
  IRPC_STORE.error(error);
29
29
  return this;
30
30
  }
@@ -67,10 +67,7 @@ var IRPCRouter = class {
67
67
  name: req.name,
68
68
  type: IRPC_PACKET_TYPE.CLOSE,
69
69
  status: IRPC_STATUS.ERROR,
70
- error: {
71
- code: ERROR_CODE.UNKNOWN,
72
- message: ERROR_MESSAGE[ERROR_CODE.UNKNOWN]
73
- },
70
+ error: HookError.failed(error).json(),
74
71
  createdAt: Date.now()
75
72
  };
76
73
  }
package/dist/state.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { IRPCReadable, IRPCStatus, StreamConstructor } from "./types.js";
2
- import * as _anchorlib_core0 from "@anchorlib/core";
3
- import { StateSubscriber } from "@anchorlib/core";
2
+ import { StateSubscriber, StateUnsubscribe } from "@anchorlib/core";
4
3
 
5
4
  //#region src/state.d.ts
6
5
 
@@ -41,8 +40,21 @@ declare class RemoteState<T> extends Promise<T> {
41
40
  * @param resumable - Whether the state should be resumable after being closed.
42
41
  */
43
42
  constructor(init?: T, status?: IRPCStatus, resumable?: boolean | undefined);
43
+ /**
44
+ * Transitions the state to SUCCESS and resolves the underlying Promise.
45
+ *
46
+ * @param value - Optional final value to resolve with.
47
+ */
44
48
  accept(value?: T): void;
49
+ /**
50
+ * Transitions the state to ERROR and rejects the underlying Promise.
51
+ *
52
+ * @param error - Optional error to reject with.
53
+ */
45
54
  reject(error?: Error): void;
55
+ /**
56
+ * Aborts the current execution, transitioning the status to ABORTED.
57
+ */
46
58
  abort(): void;
47
59
  /**
48
60
  * Subscribes to changes emitted by the internal state.
@@ -50,14 +62,34 @@ declare class RemoteState<T> extends Promise<T> {
50
62
  * @param handler - A callback function invoked whenever the state mutates.
51
63
  * @returns An unsubscribe function to terminate the listener.
52
64
  */
53
- subscribe(handler: StateSubscriber<IRPCReadable<T>>): _anchorlib_core0.StateUnsubscribe;
65
+ subscribe(handler: StateSubscriber<IRPCReadable<T>>): StateUnsubscribe;
54
66
  /**
55
67
  * Closes the reactive state and terminates the underlying Promise.
56
68
  */
57
69
  close(): void;
70
+ /**
71
+ * Resumes a closed state if it was marked as resumable.
72
+ */
58
73
  protected resume(): void;
74
+ /**
75
+ * Temporarily disables the `.then()` method to prevent automatic Promise chaining.
76
+ *
77
+ * @returns The current instance for chaining.
78
+ */
59
79
  pipe(): this;
80
+ /**
81
+ * Restores the `.then()` method if it was previously locked via `.pipe()`.
82
+ *
83
+ * @returns The current instance for chaining.
84
+ */
60
85
  unpipe(): this;
86
+ /**
87
+ * Pipes all state mutations from this instance to a target RemoteState.
88
+ *
89
+ * @param target - The destination RemoteState to receive the updates.
90
+ * @returns The current instance for chaining.
91
+ */
92
+ pipeTo(target: RemoteState<T>): this;
61
93
  /**
62
94
  * Destroys the reactive state bindings.
63
95
  */
@@ -75,9 +107,9 @@ declare class RemoteState<T> extends Promise<T> {
75
107
  *
76
108
  * @template T - The type of the streamed payload data.
77
109
  * @param construct - The isolated stream constructor callback that natively operates the pipeline.
78
- * @param init - An optional initial value to prime the state payload inherently.
110
+ * @param seed - An optional initial value to prime the state payload inherently.
79
111
  * @returns A fully active RemoteState inherently bound to the callbacks executing natively.
80
112
  */
81
- declare function stream<T>(construct: StreamConstructor<T>, init?: T): RemoteState<T>;
113
+ declare function stream<T>(construct: StreamConstructor<T>, seed?: T): RemoteState<T>;
82
114
  //#endregion
83
115
  export { RemoteState, stream };
package/dist/state.js CHANGED
@@ -1,7 +1,7 @@
1
+ import { IRPCError, IRPC_ERROR_TYPE } from "./error.js";
1
2
  import { IRPC_STATUS } from "./enum.js";
2
- import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
3
3
  import { getAbortSignal } from "./context.js";
4
- import { $do, anchor, mutable, onCleanup, subscribe } from "@anchorlib/core";
4
+ import { $do, anchor, mutable, onCleanup, replay, subscribe } from "@anchorlib/core";
5
5
 
6
6
  //#region src/state.ts
7
7
  /**
@@ -17,6 +17,7 @@ var RemoteState = class extends Promise {
17
17
  #state;
18
18
  #accept;
19
19
  #reject;
20
+ #pipes = /* @__PURE__ */ new Set();
20
21
  #closed = false;
21
22
  #locked;
22
23
  get state() {
@@ -97,10 +98,13 @@ var RemoteState = class extends Promise {
97
98
  if (args.length) this.#state.error = args[0];
98
99
  this.#closed = true;
99
100
  this.#state.status = IRPC_STATUS.ERROR;
100
- this.#reject(this.error ?? new Error(ERROR_MESSAGE[ERROR_CODE.UNKNOWN]));
101
+ this.#reject(this.error ?? new IRPCError(IRPC_ERROR_TYPE.CALL, "unknown", "Unknown error."));
101
102
  this.destroy();
102
103
  });
103
104
  }
105
+ /**
106
+ * Aborts the current execution, transitioning the status to ABORTED.
107
+ */
104
108
  abort() {
105
109
  $do(() => {
106
110
  this.#closed = true;
@@ -116,7 +120,9 @@ var RemoteState = class extends Promise {
116
120
  * @returns An unsubscribe function to terminate the listener.
117
121
  */
118
122
  subscribe(handler) {
119
- return subscribe(this.state, handler);
123
+ const unsubscribe = subscribe(this.state, handler);
124
+ this.#pipes.add(unsubscribe);
125
+ return unsubscribe;
120
126
  }
121
127
  /**
122
128
  * Closes the reactive state and terminates the underlying Promise.
@@ -127,14 +133,27 @@ var RemoteState = class extends Promise {
127
133
  this.#accept(this.data);
128
134
  this.destroy();
129
135
  }
136
+ /**
137
+ * Resumes a closed state if it was marked as resumable.
138
+ */
130
139
  resume() {
131
140
  this.#closed = false;
132
141
  }
142
+ /**
143
+ * Temporarily disables the `.then()` method to prevent automatic Promise chaining.
144
+ *
145
+ * @returns The current instance for chaining.
146
+ */
133
147
  pipe() {
134
148
  this.#locked = this.then;
135
149
  this.then = void 0;
136
150
  return this;
137
151
  }
152
+ /**
153
+ * Restores the `.then()` method if it was previously locked via `.pipe()`.
154
+ *
155
+ * @returns The current instance for chaining.
156
+ */
138
157
  unpipe() {
139
158
  if (!this.#locked) return this;
140
159
  this.then = this.#locked;
@@ -142,10 +161,28 @@ var RemoteState = class extends Promise {
142
161
  return this;
143
162
  }
144
163
  /**
164
+ * Pipes all state mutations from this instance to a target RemoteState.
165
+ *
166
+ * @param target - The destination RemoteState to receive the updates.
167
+ * @returns The current instance for chaining.
168
+ */
169
+ pipeTo(target) {
170
+ this.subscribe((_, event) => {
171
+ if (event.type === "init") {
172
+ anchor.assign(target.state, this.state);
173
+ return;
174
+ }
175
+ replay(target.state, event);
176
+ });
177
+ return this;
178
+ }
179
+ /**
145
180
  * Destroys the reactive state bindings.
146
181
  */
147
182
  destroy() {
148
183
  if (this.resumable) return;
184
+ for (const unsubscribe of this.#pipes) unsubscribe();
185
+ this.#pipes.clear();
149
186
  anchor.destroy(this.state);
150
187
  }
151
188
  /**
@@ -163,11 +200,11 @@ var RemoteState = class extends Promise {
163
200
  *
164
201
  * @template T - The type of the streamed payload data.
165
202
  * @param construct - The isolated stream constructor callback that natively operates the pipeline.
166
- * @param init - An optional initial value to prime the state payload inherently.
203
+ * @param seed - An optional initial value to prime the state payload inherently.
167
204
  * @returns A fully active RemoteState inherently bound to the callbacks executing natively.
168
205
  */
169
- function stream(construct, init) {
170
- const state = new RemoteState(init);
206
+ function stream(construct, seed) {
207
+ const state = new RemoteState(seed);
171
208
  const abortSignal = getAbortSignal();
172
209
  const accept = ((...values) => {
173
210
  if (values.length > 0) state.data = values[0];
package/dist/store.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { IRPC_STORE_EVENT } from "./enum.js";
2
- import { IRPCPackage } from "./module.js";
3
2
  import { IRPCData } from "./types.js";
3
+ import { IRPCPackage } from "./module.js";
4
4
  import { IRPCRouter } from "./router.js";
5
5
  import { IRPCStream } from "./stream.js";
6
6
 
@@ -27,7 +27,7 @@ declare class IRPCStore {
27
27
  #private;
28
28
  calls: Set<IRPCStream<IRPCData>>;
29
29
  routers: Set<IRPCRouter>;
30
- packages: Set<IRPCPackage>;
30
+ packages: Set<IRPCPackage<"id">>;
31
31
  callCount: number;
32
32
  errorCount: number;
33
33
  register(pkg: IRPCPackage): void;
package/dist/stream.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { IRPCData, IRPCDataSchema, IRPCError, IRPCInputs, IRPCPacketStream, IRPCResponse, IRPCSpec, IRPCStatus } from "./types.js";
1
+ import { IRPCData, IRPCDataSchema, IRPCInputs, IRPCPacketError, IRPCPacketStream, IRPCResponse, IRPCSpec, IRPCStatus } from "./types.js";
2
2
  import { IRPCRouter } from "./router.js";
3
3
 
4
4
  //#region src/stream.d.ts
@@ -21,7 +21,7 @@ declare class IRPCStream<T extends IRPCData> {
21
21
  private closeHandlers;
22
22
  private errorHandlers;
23
23
  value?: T;
24
- error?: IRPCError;
24
+ error?: IRPCPacketError;
25
25
  status: IRPCStatus;
26
26
  closed: boolean;
27
27
  createdAt: number;
@@ -55,7 +55,7 @@ declare class IRPCStream<T extends IRPCData> {
55
55
  *
56
56
  * @param handler - A callback function to receive stream errors.
57
57
  */
58
- catch(handler: (error: IRPCError) => void): void;
58
+ catch(handler: (error: IRPCPacketError) => void): void;
59
59
  /**
60
60
  * Binds a handler triggered upon terminal completion of the stream process (success or error).
61
61
  *
package/dist/stream.js CHANGED
@@ -1,5 +1,5 @@
1
+ import { CallError, HandlerError, ResolveError } from "./error.js";
1
2
  import { IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
2
- import { ERROR_CODE } from "./error.js";
3
3
  import { getAbortController, getAbortSignal } from "./context.js";
4
4
  import { RemoteState } from "./state.js";
5
5
  import { IRPC_STORE } from "./store.js";
@@ -68,10 +68,7 @@ var IRPCStream = class {
68
68
  this.value = result.data;
69
69
  if (result.status === IRPC_STATUS.SUCCESS || result.status === IRPC_STATUS.ERROR) {
70
70
  if (result.status === IRPC_STATUS.ERROR) {
71
- this.error = {
72
- code: ERROR_CODE.HANDLER_ERROR,
73
- message: result.error.message
74
- };
71
+ this.error = HandlerError.failed(result.error).json();
75
72
  this.status = IRPC_STATUS.ERROR;
76
73
  } else this.status = IRPC_STATUS.SUCCESS;
77
74
  const packet = {
@@ -119,10 +116,7 @@ var IRPCStream = class {
119
116
  if (state.status !== IRPC_STATUS.SUCCESS && state.status !== IRPC_STATUS.ERROR) return;
120
117
  this.status = state.status;
121
118
  if (state.status === IRPC_STATUS.ERROR) {
122
- this.error = {
123
- code: ERROR_CODE.STREAM_ERROR,
124
- message: state.error.message
125
- };
119
+ this.error = CallError.streamError(state.error).json();
126
120
  this.errorHandlers.forEach((handler) => handler(this.error));
127
121
  }
128
122
  this.pipeHandlers.forEach((handler) => {
@@ -169,10 +163,7 @@ var IRPCStream = class {
169
163
  id: this.id,
170
164
  name: this.name
171
165
  }]);
172
- this.error = {
173
- code: ERROR_CODE.RESOLVE_ERROR,
174
- message: error.message
175
- };
166
+ this.error = ResolveError.failed(error).json();
176
167
  this.status = IRPC_STATUS.ERROR;
177
168
  this.pipeHandlers.forEach((handler) => {
178
169
  handler({