@orpc/standard-server-peer 0.0.0 → 1.3.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/README.md CHANGED
@@ -49,6 +49,7 @@ You can find the full documentation [here](https://orpc.unnoq.com).
49
49
  - [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Build your API contract.
50
50
  - [@orpc/server](https://www.npmjs.com/package/@orpc/server): Build your API or implement API contract.
51
51
  - [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API on the client with type-safety.
52
+ - [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with NestJS.
52
53
  - [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions.
53
54
  - [@orpc/react-query](https://www.npmjs.com/package/@orpc/react-query): Integration with [React Query](https://tanstack.com/query/latest/docs/framework/react/overview).
54
55
  - [@orpc/vue-query](https://www.npmjs.com/package/@orpc/vue-query): Integration with [Vue Query](https://tanstack.com/query/latest/docs/framework/vue/overview).
package/dist/index.d.mts CHANGED
@@ -1,5 +1,32 @@
1
- import { EventMeta, StandardRequest, StandardResponse, StandardHeaders } from '@orpc/standard-server';
2
- import { CreateAsyncIteratorObjectOptions } from '@orpc/shared';
1
+ import { Promisable, AsyncIdQueueCloseOptions as AsyncIdQueueCloseOptions$1, CreateAsyncIteratorObjectCleanupFn } from '@orpc/shared';
2
+ import { StandardRequest, StandardResponse, EventMeta, StandardHeaders } from '@orpc/standard-server';
3
+
4
+ type EncodedMessage = string | ArrayBufferLike | Blob;
5
+ interface EncodedMessageSendFn {
6
+ (message: EncodedMessage): Promisable<void>;
7
+ }
8
+
9
+ interface ClientPeerCloseOptions extends AsyncIdQueueCloseOptions$1 {
10
+ /**
11
+ * Should abort or not?
12
+ *
13
+ * @default true
14
+ */
15
+ abort?: boolean;
16
+ }
17
+ declare class ClientPeer {
18
+ private readonly idGenerator;
19
+ private readonly responseQueue;
20
+ private readonly serverEventIteratorQueue;
21
+ private readonly serverControllers;
22
+ private readonly send;
23
+ constructor(send: EncodedMessageSendFn);
24
+ get length(): number;
25
+ open(id: number): AbortController;
26
+ request(request: StandardRequest): Promise<StandardResponse>;
27
+ message(raw: EncodedMessage): Promise<void>;
28
+ close(options?: AsyncIdQueueCloseOptions$1): void;
29
+ }
3
30
 
4
31
  declare enum MessageType {
5
32
  REQUEST = 1,
@@ -7,7 +34,6 @@ declare enum MessageType {
7
34
  EVENT_ITERATOR = 3,
8
35
  ABORT_SIGNAL = 4
9
36
  }
10
- type RawMessage = string | ArrayBufferLike | Blob;
11
37
  type EventIteratorEvent = 'message' | 'error' | 'done';
12
38
  interface EventIteratorPayload {
13
39
  event: EventIteratorEvent;
@@ -29,63 +55,51 @@ type DecodedMessageUnion<TMap extends RequestMessageMap | ResponseMessageMap> =
29
55
  }[keyof TMap];
30
56
  type DecodedRequestMessage = DecodedMessageUnion<RequestMessageMap>;
31
57
  type DecodedResponseMessage = DecodedMessageUnion<ResponseMessageMap>;
32
- declare function encodeRequestMessage<T extends keyof RequestMessageMap>(id: number, type: T, payload: RequestMessageMap[T]): Promise<RawMessage>;
33
- declare function decodeRequestMessage(raw: RawMessage): Promise<DecodedRequestMessage>;
34
- declare function encodeResponseMessage<T extends keyof ResponseMessageMap>(id: number, type: T, payload: ResponseMessageMap[T]): Promise<RawMessage>;
35
- declare function decodeResponseMessage(raw: RawMessage): Promise<DecodedResponseMessage>;
58
+ declare function encodeRequestMessage<T extends keyof RequestMessageMap>(id: number, type: T, payload: RequestMessageMap[T]): Promise<EncodedMessage>;
59
+ declare function decodeRequestMessage(raw: EncodedMessage): Promise<DecodedRequestMessage>;
60
+ declare function encodeResponseMessage<T extends keyof ResponseMessageMap>(id: number, type: T, payload: ResponseMessageMap[T]): Promise<EncodedMessage>;
61
+ declare function decodeResponseMessage(raw: EncodedMessage): Promise<DecodedResponseMessage>;
36
62
  declare function isEventIteratorHeaders(headers: StandardHeaders): boolean;
37
63
 
38
- declare class ClientPeer {
39
- private readonly idGenerator;
40
- private readonly clientRequestQueue;
41
- private readonly clientEventIteratorQueue;
42
- private readonly clientSignalQueue;
43
- private readonly serverResponseQueue;
44
- private readonly serverEventIterator;
45
- private readonly serverSignalQueue;
46
- constructor(send: (message: RawMessage) => void);
47
- request(request: StandardRequest): Promise<StandardResponse>;
48
- message(raw: RawMessage): Promise<void>;
49
- open(id: number): void;
50
- close(id?: number, reason?: any): void;
64
+ interface AsyncIdQueueCloseOptions {
65
+ id?: number;
66
+ reason?: Error;
51
67
  }
52
-
53
- declare abstract class AsyncIdQueue<T> {
68
+ declare class AsyncIdQueue<T> {
54
69
  private readonly openIds;
55
- abstract push(id: number, item: T): void;
56
- open(id: number): void;
57
- close(id: number): void;
58
- closeAll(): void;
59
- isOpen(id: number): boolean;
60
- assertOpen(id: number): void;
61
- }
62
- declare class PullableAsyncIdQueue<T> extends AsyncIdQueue<T> {
63
70
  private readonly items;
64
71
  private readonly pendingPulls;
72
+ get length(): number;
73
+ open(id: number): void;
74
+ isOpen(id: number): boolean;
65
75
  push(id: number, item: T): void;
66
76
  pull(id: number): Promise<T>;
67
- close(id: number, reason?: any): void;
77
+ close({ id, reason }?: AsyncIdQueueCloseOptions): void;
78
+ assertOpen(id: number): void;
68
79
  }
69
80
 
70
- declare function toEventIterator(queue: PullableAsyncIdQueue<EventIteratorPayload>, id: number, options?: CreateAsyncIteratorObjectOptions): AsyncGenerator;
71
- declare function sendEventIterator(queue: AsyncIdQueue<EventIteratorPayload>, id: number, iterator: AsyncIterator<any>, options?: {
72
- onComplete?: () => void;
73
- }): Promise<void>;
81
+ declare function toEventIterator(queue: AsyncIdQueue<EventIteratorPayload>, id: number, cleanup: CreateAsyncIteratorObjectCleanupFn): AsyncGenerator;
82
+ declare function resolveEventIterator(iterator: AsyncIterator<any>, callback: (payload: EventIteratorPayload) => Promise<'next' | 'abort'>): Promise<void>;
74
83
 
84
+ interface ServerPeerCloseOptions extends AsyncIdQueueCloseOptions$1 {
85
+ /**
86
+ * Should abort or not?
87
+ *
88
+ * @default true
89
+ */
90
+ abort?: boolean;
91
+ }
75
92
  declare class ServerPeer {
76
- private readonly serverResponseQueue;
77
- private readonly serverEventIteratorQueue;
78
- private readonly serverSignalQueue;
79
93
  private readonly clientEventIteratorQueue;
80
- private readonly clientSignalQueue;
81
- constructor(send: (message: RawMessage) => void);
82
- message(raw: RawMessage): Promise<[id: number, StandardRequest | undefined]>;
94
+ private readonly clientControllers;
95
+ private readonly send;
96
+ constructor(send: EncodedMessageSendFn);
97
+ get length(): number;
98
+ open(id: number): AbortController;
99
+ message(raw: EncodedMessage): Promise<[id: number, StandardRequest | undefined]>;
83
100
  response(id: number, response: StandardResponse): Promise<void>;
84
- open(id: number): void;
85
- close(id?: number, reason?: any): void;
101
+ close({ abort, ...options }?: ServerPeerCloseOptions): void;
86
102
  }
87
103
 
88
- declare function toAbortSignal(queue: PullableAsyncIdQueue<void>, id: number): AbortSignal;
89
-
90
- export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage, isEventIteratorHeaders, sendEventIterator, toAbortSignal, toEventIterator };
91
- export type { DecodedRequestMessage, DecodedResponseMessage, EventIteratorEvent, EventIteratorPayload, RawMessage, RequestMessageMap, ResponseMessageMap };
104
+ export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage, isEventIteratorHeaders, resolveEventIterator, toEventIterator };
105
+ export type { ClientPeerCloseOptions, DecodedRequestMessage, DecodedResponseMessage, EncodedMessage, EncodedMessageSendFn, EventIteratorEvent, EventIteratorPayload, RequestMessageMap, ResponseMessageMap, ServerPeerCloseOptions };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,32 @@
1
- import { EventMeta, StandardRequest, StandardResponse, StandardHeaders } from '@orpc/standard-server';
2
- import { CreateAsyncIteratorObjectOptions } from '@orpc/shared';
1
+ import { Promisable, AsyncIdQueueCloseOptions as AsyncIdQueueCloseOptions$1, CreateAsyncIteratorObjectCleanupFn } from '@orpc/shared';
2
+ import { StandardRequest, StandardResponse, EventMeta, StandardHeaders } from '@orpc/standard-server';
3
+
4
+ type EncodedMessage = string | ArrayBufferLike | Blob;
5
+ interface EncodedMessageSendFn {
6
+ (message: EncodedMessage): Promisable<void>;
7
+ }
8
+
9
+ interface ClientPeerCloseOptions extends AsyncIdQueueCloseOptions$1 {
10
+ /**
11
+ * Should abort or not?
12
+ *
13
+ * @default true
14
+ */
15
+ abort?: boolean;
16
+ }
17
+ declare class ClientPeer {
18
+ private readonly idGenerator;
19
+ private readonly responseQueue;
20
+ private readonly serverEventIteratorQueue;
21
+ private readonly serverControllers;
22
+ private readonly send;
23
+ constructor(send: EncodedMessageSendFn);
24
+ get length(): number;
25
+ open(id: number): AbortController;
26
+ request(request: StandardRequest): Promise<StandardResponse>;
27
+ message(raw: EncodedMessage): Promise<void>;
28
+ close(options?: AsyncIdQueueCloseOptions$1): void;
29
+ }
3
30
 
4
31
  declare enum MessageType {
5
32
  REQUEST = 1,
@@ -7,7 +34,6 @@ declare enum MessageType {
7
34
  EVENT_ITERATOR = 3,
8
35
  ABORT_SIGNAL = 4
9
36
  }
10
- type RawMessage = string | ArrayBufferLike | Blob;
11
37
  type EventIteratorEvent = 'message' | 'error' | 'done';
12
38
  interface EventIteratorPayload {
13
39
  event: EventIteratorEvent;
@@ -29,63 +55,51 @@ type DecodedMessageUnion<TMap extends RequestMessageMap | ResponseMessageMap> =
29
55
  }[keyof TMap];
30
56
  type DecodedRequestMessage = DecodedMessageUnion<RequestMessageMap>;
31
57
  type DecodedResponseMessage = DecodedMessageUnion<ResponseMessageMap>;
32
- declare function encodeRequestMessage<T extends keyof RequestMessageMap>(id: number, type: T, payload: RequestMessageMap[T]): Promise<RawMessage>;
33
- declare function decodeRequestMessage(raw: RawMessage): Promise<DecodedRequestMessage>;
34
- declare function encodeResponseMessage<T extends keyof ResponseMessageMap>(id: number, type: T, payload: ResponseMessageMap[T]): Promise<RawMessage>;
35
- declare function decodeResponseMessage(raw: RawMessage): Promise<DecodedResponseMessage>;
58
+ declare function encodeRequestMessage<T extends keyof RequestMessageMap>(id: number, type: T, payload: RequestMessageMap[T]): Promise<EncodedMessage>;
59
+ declare function decodeRequestMessage(raw: EncodedMessage): Promise<DecodedRequestMessage>;
60
+ declare function encodeResponseMessage<T extends keyof ResponseMessageMap>(id: number, type: T, payload: ResponseMessageMap[T]): Promise<EncodedMessage>;
61
+ declare function decodeResponseMessage(raw: EncodedMessage): Promise<DecodedResponseMessage>;
36
62
  declare function isEventIteratorHeaders(headers: StandardHeaders): boolean;
37
63
 
38
- declare class ClientPeer {
39
- private readonly idGenerator;
40
- private readonly clientRequestQueue;
41
- private readonly clientEventIteratorQueue;
42
- private readonly clientSignalQueue;
43
- private readonly serverResponseQueue;
44
- private readonly serverEventIterator;
45
- private readonly serverSignalQueue;
46
- constructor(send: (message: RawMessage) => void);
47
- request(request: StandardRequest): Promise<StandardResponse>;
48
- message(raw: RawMessage): Promise<void>;
49
- open(id: number): void;
50
- close(id?: number, reason?: any): void;
64
+ interface AsyncIdQueueCloseOptions {
65
+ id?: number;
66
+ reason?: Error;
51
67
  }
52
-
53
- declare abstract class AsyncIdQueue<T> {
68
+ declare class AsyncIdQueue<T> {
54
69
  private readonly openIds;
55
- abstract push(id: number, item: T): void;
56
- open(id: number): void;
57
- close(id: number): void;
58
- closeAll(): void;
59
- isOpen(id: number): boolean;
60
- assertOpen(id: number): void;
61
- }
62
- declare class PullableAsyncIdQueue<T> extends AsyncIdQueue<T> {
63
70
  private readonly items;
64
71
  private readonly pendingPulls;
72
+ get length(): number;
73
+ open(id: number): void;
74
+ isOpen(id: number): boolean;
65
75
  push(id: number, item: T): void;
66
76
  pull(id: number): Promise<T>;
67
- close(id: number, reason?: any): void;
77
+ close({ id, reason }?: AsyncIdQueueCloseOptions): void;
78
+ assertOpen(id: number): void;
68
79
  }
69
80
 
70
- declare function toEventIterator(queue: PullableAsyncIdQueue<EventIteratorPayload>, id: number, options?: CreateAsyncIteratorObjectOptions): AsyncGenerator;
71
- declare function sendEventIterator(queue: AsyncIdQueue<EventIteratorPayload>, id: number, iterator: AsyncIterator<any>, options?: {
72
- onComplete?: () => void;
73
- }): Promise<void>;
81
+ declare function toEventIterator(queue: AsyncIdQueue<EventIteratorPayload>, id: number, cleanup: CreateAsyncIteratorObjectCleanupFn): AsyncGenerator;
82
+ declare function resolveEventIterator(iterator: AsyncIterator<any>, callback: (payload: EventIteratorPayload) => Promise<'next' | 'abort'>): Promise<void>;
74
83
 
84
+ interface ServerPeerCloseOptions extends AsyncIdQueueCloseOptions$1 {
85
+ /**
86
+ * Should abort or not?
87
+ *
88
+ * @default true
89
+ */
90
+ abort?: boolean;
91
+ }
75
92
  declare class ServerPeer {
76
- private readonly serverResponseQueue;
77
- private readonly serverEventIteratorQueue;
78
- private readonly serverSignalQueue;
79
93
  private readonly clientEventIteratorQueue;
80
- private readonly clientSignalQueue;
81
- constructor(send: (message: RawMessage) => void);
82
- message(raw: RawMessage): Promise<[id: number, StandardRequest | undefined]>;
94
+ private readonly clientControllers;
95
+ private readonly send;
96
+ constructor(send: EncodedMessageSendFn);
97
+ get length(): number;
98
+ open(id: number): AbortController;
99
+ message(raw: EncodedMessage): Promise<[id: number, StandardRequest | undefined]>;
83
100
  response(id: number, response: StandardResponse): Promise<void>;
84
- open(id: number): void;
85
- close(id?: number, reason?: any): void;
101
+ close({ abort, ...options }?: ServerPeerCloseOptions): void;
86
102
  }
87
103
 
88
- declare function toAbortSignal(queue: PullableAsyncIdQueue<void>, id: number): AbortSignal;
89
-
90
- export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage, isEventIteratorHeaders, sendEventIterator, toAbortSignal, toEventIterator };
91
- export type { DecodedRequestMessage, DecodedResponseMessage, EventIteratorEvent, EventIteratorPayload, RawMessage, RequestMessageMap, ResponseMessageMap };
104
+ export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage, isEventIteratorHeaders, resolveEventIterator, toEventIterator };
105
+ export type { ClientPeerCloseOptions, DecodedRequestMessage, DecodedResponseMessage, EncodedMessage, EncodedMessageSendFn, EventIteratorEvent, EventIteratorPayload, RequestMessageMap, ResponseMessageMap, ServerPeerCloseOptions };
package/dist/index.mjs CHANGED
@@ -1,88 +1,5 @@
1
- import { toArray, stringifyJSON, isAsyncIteratorObject, createAsyncIteratorObject, isTypescriptObject, SequentialIdGenerator, PullableAsyncIdQueue as PullableAsyncIdQueue$1, ConsumableAsyncIdQueue as ConsumableAsyncIdQueue$1 } from '@orpc/shared';
2
- import { getFilenameFromContentDisposition, generateContentDisposition, withEventMeta, ErrorEvent, getEventMeta } from '@orpc/standard-server';
3
-
4
- class AsyncIdQueue {
5
- openIds = /* @__PURE__ */ new Set();
6
- open(id) {
7
- this.openIds.add(id);
8
- }
9
- close(id) {
10
- this.openIds.delete(id);
11
- }
12
- closeAll() {
13
- this.openIds.forEach((id) => this.close(id));
14
- }
15
- isOpen(id) {
16
- return this.openIds.has(id);
17
- }
18
- assertOpen(id) {
19
- if (!this.isOpen(id)) {
20
- throw new Error(`[AsyncIdQueue] Cannot access queue[${id}] because it is not open.`);
21
- }
22
- }
23
- }
24
- class PullableAsyncIdQueue extends AsyncIdQueue {
25
- items = /* @__PURE__ */ new Map();
26
- pendingPulls = /* @__PURE__ */ new Map();
27
- push(id, item) {
28
- this.assertOpen(id);
29
- const pending = this.pendingPulls.get(id);
30
- if (pending?.length) {
31
- pending.shift()[0](item);
32
- if (pending.length === 0) {
33
- this.pendingPulls.delete(id);
34
- }
35
- } else {
36
- const items = this.items.get(id);
37
- if (items) {
38
- items.push(item);
39
- } else {
40
- this.items.set(id, [item]);
41
- }
42
- }
43
- }
44
- async pull(id) {
45
- this.assertOpen(id);
46
- const items = this.items.get(id);
47
- if (items?.length) {
48
- const item = items.shift();
49
- if (items.length === 0) {
50
- this.items.delete(id);
51
- }
52
- return item;
53
- }
54
- return new Promise((resolve, reject) => {
55
- const waitingPulls = this.pendingPulls.get(id);
56
- const pending = [resolve, reject];
57
- if (waitingPulls) {
58
- waitingPulls.push(pending);
59
- } else {
60
- this.pendingPulls.set(id, [pending]);
61
- }
62
- });
63
- }
64
- close(id, reason) {
65
- const pendingPulls = this.pendingPulls.get(id);
66
- if (pendingPulls) {
67
- pendingPulls.forEach(([, reject]) => {
68
- reject(reason ?? new Error(`[PullableAsyncIdQueue] Queue[${id}] was closed while waiting for pulling.`));
69
- });
70
- this.pendingPulls.delete(id);
71
- }
72
- super.close(id);
73
- this.items.delete(id);
74
- }
75
- }
76
- class ConsumableAsyncIdQueue extends AsyncIdQueue {
77
- constructor(consume) {
78
- super();
79
- this.consume = consume;
80
- }
81
- push(id, item) {
82
- this.assertOpen(id);
83
- this.consume(id, item);
84
- }
85
- }
1
+ import { isAsyncIteratorObject, stringifyJSON, createAsyncIteratorObject, isTypescriptObject, SequentialIdGenerator, AsyncIdQueue } from '@orpc/shared';
2
+ import { flattenHeader, getFilenameFromContentDisposition, generateContentDisposition, withEventMeta, ErrorEvent, getEventMeta } from '@orpc/standard-server';
86
3
 
87
4
  var MessageType = /* @__PURE__ */ ((MessageType2) => {
88
5
  MessageType2[MessageType2["REQUEST"] = 1] = "REQUEST";
@@ -138,9 +55,9 @@ async function decodeRequestMessage(raw) {
138
55
  const payload = message.p;
139
56
  const headers = payload.h ?? {};
140
57
  let body = payload.b;
141
- const contentType = toArray(headers["content-type"])[0];
58
+ const contentType = flattenHeader(headers["content-type"]);
142
59
  if (blobData) {
143
- const contentDisposition = toArray(headers["content-disposition"])[0];
60
+ const contentDisposition = flattenHeader(headers["content-disposition"]);
144
61
  if (contentDisposition === void 0 && contentType?.startsWith("multipart/form-data")) {
145
62
  const tempRes = new Response(blobData, { headers: { "content-type": contentType } });
146
63
  body = await tempRes.formData();
@@ -199,9 +116,9 @@ async function decodeResponseMessage(raw) {
199
116
  const payload = message.p;
200
117
  const headers = payload.h ?? {};
201
118
  let body = payload.b;
202
- const contentType = toArray(headers["content-type"])[0];
119
+ const contentType = flattenHeader(headers["content-type"]);
203
120
  if (blobData) {
204
- const contentDisposition = toArray(headers["content-disposition"])[0];
121
+ const contentDisposition = flattenHeader(headers["content-disposition"]);
205
122
  if (contentDisposition === void 0 && contentType?.startsWith("multipart/form-data")) {
206
123
  const tempRes = new Response(blobData, { headers: { "content-type": contentType } });
207
124
  body = await tempRes.formData();
@@ -228,8 +145,8 @@ async function prepareBodyAndHeadersForSerialization(body, originalHeaders) {
228
145
  }
229
146
  if (body instanceof FormData) {
230
147
  const tempRes = new Response(body);
231
- const formDataBlob = await tempRes.blob();
232
148
  headers["content-type"] = tempRes.headers.get("content-type");
149
+ const formDataBlob = await tempRes.blob();
233
150
  return { body: formDataBlob, headers };
234
151
  }
235
152
  if (body instanceof URLSearchParams) {
@@ -243,7 +160,7 @@ async function prepareBodyAndHeadersForSerialization(body, originalHeaders) {
243
160
  return { body, headers };
244
161
  }
245
162
  function isEventIteratorHeaders(headers) {
246
- return Boolean(toArray(headers["content-type"])[0]?.startsWith("text/event-stream") && headers["content-disposition"] === void 0);
163
+ return Boolean(flattenHeader(headers["content-type"])?.startsWith("text/event-stream") && headers["content-disposition"] === void 0);
247
164
  }
248
165
  const JSON_AND_BINARY_DELIMITER = 255;
249
166
  async function encodeRawMessage(data, blobData) {
@@ -275,7 +192,7 @@ async function decodeRawMessage(raw) {
275
192
  };
276
193
  }
277
194
 
278
- function toEventIterator(queue, id, options = {}) {
195
+ function toEventIterator(queue, id, cleanup) {
279
196
  return createAsyncIteratorObject(async () => {
280
197
  const item = await queue.pull(id);
281
198
  switch (item.event) {
@@ -303,216 +220,174 @@ function toEventIterator(queue, id, options = {}) {
303
220
  return { value: data, done: true };
304
221
  }
305
222
  }
306
- }, options);
223
+ }, cleanup);
307
224
  }
308
- async function sendEventIterator(queue, id, iterator, options = {}) {
309
- let isInternal = false;
310
- try {
311
- while (true) {
312
- isInternal = false;
313
- const { value, done } = await iterator.next();
314
- isInternal = true;
315
- if (!queue.isOpen(id)) {
316
- if (!done) {
317
- isInternal = false;
318
- await iterator.return?.();
319
- isInternal = true;
225
+ async function resolveEventIterator(iterator, callback) {
226
+ while (true) {
227
+ const payload = await (async () => {
228
+ try {
229
+ const { value, done } = await iterator.next();
230
+ if (done) {
231
+ return { event: "done", data: value, meta: getEventMeta(value) };
320
232
  }
233
+ return { event: "message", data: value, meta: getEventMeta(value) };
234
+ } catch (err) {
235
+ return {
236
+ meta: getEventMeta(err),
237
+ event: "error",
238
+ data: err instanceof ErrorEvent ? err.data : void 0
239
+ };
240
+ }
241
+ })();
242
+ try {
243
+ const direction = await callback(payload);
244
+ if (payload.event === "done" || payload.event === "error") {
321
245
  return;
322
246
  }
323
- queue.push(id, {
324
- event: done ? "done" : "message",
325
- data: value,
326
- meta: getEventMeta(value)
327
- });
328
- if (done) {
247
+ if (direction === "abort") {
248
+ try {
249
+ await iterator.return?.();
250
+ } catch {
251
+ }
329
252
  return;
330
253
  }
331
- }
332
- } catch (err) {
333
- let currentError = err;
334
- if (isInternal) {
254
+ } catch (err) {
335
255
  try {
336
- await iterator.throw?.(currentError);
337
- } catch (err2) {
338
- currentError = err2;
256
+ await iterator.return?.();
257
+ } catch {
339
258
  }
259
+ throw err;
340
260
  }
341
- if (queue.isOpen(id)) {
342
- queue.push(id, {
343
- meta: getEventMeta(currentError),
344
- event: "error",
345
- data: currentError instanceof ErrorEvent ? currentError.data : void 0
346
- });
347
- }
348
- } finally {
349
- options.onComplete?.();
350
261
  }
351
262
  }
352
263
 
353
- function toAbortSignal(queue, id) {
354
- const controller = new AbortController();
355
- queue.pull(id).then(() => {
356
- controller.abort();
357
- }).catch(() => {
358
- });
359
- return controller.signal;
360
- }
361
-
362
264
  class ClientPeer {
363
265
  idGenerator = new SequentialIdGenerator();
364
- clientRequestQueue;
365
- clientEventIteratorQueue;
366
- clientSignalQueue;
367
- serverResponseQueue = new PullableAsyncIdQueue();
368
- serverEventIterator = new PullableAsyncIdQueue();
369
- serverSignalQueue = new PullableAsyncIdQueue();
266
+ responseQueue = new AsyncIdQueue();
267
+ serverEventIteratorQueue = new AsyncIdQueue();
268
+ serverControllers = /* @__PURE__ */ new Map();
269
+ send;
370
270
  constructor(send) {
371
- this.clientRequestQueue = new ConsumableAsyncIdQueue((id, { signal, ...request }) => {
372
- encodeRequestMessage(id, MessageType.REQUEST, request).then((raw) => {
373
- send(raw);
374
- if (signal) {
375
- if (signal.aborted) {
376
- this.clientSignalQueue.push(id);
377
- this.close(id, signal.reason);
378
- }
379
- signal.addEventListener("abort", () => {
380
- this.clientSignalQueue.push(id);
381
- this.close(id, signal.reason);
382
- }, { once: true });
383
- }
384
- if (isAsyncIteratorObject(request.body)) {
385
- sendEventIterator(this.clientEventIteratorQueue, id, request.body);
386
- const serverSignal = toAbortSignal(this.serverSignalQueue, id);
387
- serverSignal.addEventListener("abort", () => {
388
- this.clientEventIteratorQueue.close(id);
389
- }, { once: true });
390
- }
391
- }).catch((err) => {
392
- this.close(id, err);
393
- });
394
- });
395
- this.clientEventIteratorQueue = new ConsumableAsyncIdQueue((id, payload) => {
396
- encodeRequestMessage(id, MessageType.EVENT_ITERATOR, payload).then(send).catch((err) => {
397
- this.close(id, err);
398
- });
399
- });
400
- this.clientSignalQueue = new ConsumableAsyncIdQueue((id, payload) => {
401
- encodeRequestMessage(id, MessageType.ABORT_SIGNAL, payload).then(send).catch((err) => {
402
- this.close(id, err);
403
- });
271
+ this.send = async (id, ...rest) => encodeRequestMessage(id, ...rest).then(async (raw) => {
272
+ if (this.serverControllers.has(id)) {
273
+ await send(raw);
274
+ }
404
275
  });
405
276
  }
277
+ get length() {
278
+ return (+this.responseQueue.length + this.serverEventIteratorQueue.length + this.serverControllers.size) / 3;
279
+ }
280
+ open(id) {
281
+ this.serverEventIteratorQueue.open(id);
282
+ this.responseQueue.open(id);
283
+ const controller = new AbortController();
284
+ this.serverControllers.set(id, controller);
285
+ return controller;
286
+ }
406
287
  async request(request) {
407
288
  const signal = request.signal;
408
289
  if (signal?.aborted) {
409
290
  throw signal.reason;
410
291
  }
411
292
  const id = this.idGenerator.generate();
412
- this.open(id);
413
- this.clientRequestQueue.push(id, request);
293
+ const serverController = this.open(id);
414
294
  return new Promise((resolve, reject) => {
415
- this.serverResponseQueue.pull(id).then(resolve).catch(reject);
295
+ this.send(id, MessageType.REQUEST, request).then(async () => {
296
+ if (signal?.aborted) {
297
+ await this.send(id, MessageType.ABORT_SIGNAL, void 0);
298
+ this.close({ id, reason: signal.reason });
299
+ return;
300
+ }
301
+ signal?.addEventListener("abort", async () => {
302
+ await this.send(id, MessageType.ABORT_SIGNAL, void 0);
303
+ this.close({ id, reason: signal.reason });
304
+ }, { once: true });
305
+ if (isAsyncIteratorObject(request.body)) {
306
+ await resolveEventIterator(request.body, async (payload) => {
307
+ if (serverController.signal.aborted) {
308
+ return "abort";
309
+ }
310
+ await this.send(id, MessageType.EVENT_ITERATOR, payload);
311
+ return "next";
312
+ });
313
+ }
314
+ }).catch((err) => {
315
+ this.close({ id, reason: err });
316
+ reject(err);
317
+ });
318
+ this.responseQueue.pull(id).then(resolve).catch(reject);
416
319
  });
417
320
  }
418
321
  async message(raw) {
419
322
  const [id, type, payload] = await decodeResponseMessage(raw);
323
+ if (type === MessageType.ABORT_SIGNAL) {
324
+ this.serverControllers.get(id)?.abort();
325
+ return;
326
+ }
420
327
  if (type === MessageType.EVENT_ITERATOR) {
421
- if (this.serverEventIterator.isOpen(id)) {
422
- this.serverEventIterator.push(id, payload);
328
+ if (this.serverEventIteratorQueue.isOpen(id)) {
329
+ this.serverEventIteratorQueue.push(id, payload);
423
330
  }
424
331
  return;
425
332
  }
426
- if (type === MessageType.ABORT_SIGNAL) {
427
- if (this.serverSignalQueue.isOpen(id)) {
428
- this.serverSignalQueue.push(id, payload);
429
- }
333
+ if (!this.responseQueue.isOpen(id)) {
430
334
  return;
431
335
  }
432
336
  if (isEventIteratorHeaders(payload.headers)) {
433
- this.serverResponseQueue.push(id, {
337
+ this.responseQueue.push(id, {
434
338
  ...payload,
435
- body: toEventIterator(this.serverEventIterator, id, {
436
- onComplete: (reason) => {
339
+ body: toEventIterator(this.serverEventIteratorQueue, id, async (reason) => {
340
+ try {
437
341
  if (reason !== "next") {
438
- this.clientSignalQueue.push(id);
342
+ await this.send(id, MessageType.ABORT_SIGNAL, void 0);
439
343
  }
440
- this.close(id);
344
+ } finally {
345
+ this.close({ id });
441
346
  }
442
347
  })
443
348
  });
444
349
  } else {
445
- this.serverResponseQueue.push(id, payload);
446
- this.close(id);
350
+ this.responseQueue.push(id, payload);
351
+ this.close({ id });
447
352
  }
448
353
  }
449
- open(id) {
450
- this.clientSignalQueue.open(id);
451
- this.clientEventIteratorQueue.open(id);
452
- this.clientRequestQueue.open(id);
453
- this.serverSignalQueue.open(id);
454
- this.serverEventIterator.open(id);
455
- this.serverResponseQueue.open(id);
456
- }
457
- close(id, reason) {
458
- if (id !== void 0) {
459
- this.clientRequestQueue.close(id);
460
- this.clientEventIteratorQueue.close(id);
461
- this.clientSignalQueue.close(id);
462
- this.serverResponseQueue.close(id, reason);
463
- this.serverEventIterator.close(id, reason);
464
- this.serverResponseQueue.close(id, reason);
354
+ close(options = {}) {
355
+ if (options.id !== void 0) {
356
+ this.serverControllers.get(options.id)?.abort(options.reason);
357
+ this.serverControllers.delete(options.id);
465
358
  } else {
466
- this.clientRequestQueue.closeAll();
467
- this.clientEventIteratorQueue.closeAll();
468
- this.clientSignalQueue.closeAll();
469
- this.serverResponseQueue.closeAll();
470
- this.serverEventIterator.closeAll();
471
- this.serverResponseQueue.closeAll();
359
+ this.serverControllers.forEach((c) => c.abort(options.reason));
360
+ this.serverControllers.clear();
472
361
  }
362
+ this.responseQueue.close(options);
363
+ this.serverEventIteratorQueue.close(options);
473
364
  }
474
365
  }
475
366
 
476
367
  class ServerPeer {
477
- serverResponseQueue;
478
- serverEventIteratorQueue;
479
- serverSignalQueue;
480
- clientEventIteratorQueue = new PullableAsyncIdQueue$1();
481
- clientSignalQueue = new PullableAsyncIdQueue$1();
368
+ clientEventIteratorQueue = new AsyncIdQueue();
369
+ clientControllers = /* @__PURE__ */ new Map();
370
+ send;
482
371
  constructor(send) {
483
- this.serverResponseQueue = new ConsumableAsyncIdQueue$1((id, response) => {
484
- encodeResponseMessage(id, MessageType.RESPONSE, response).then(async (raw) => {
485
- send(raw);
486
- if (isAsyncIteratorObject(response.body)) {
487
- await sendEventIterator(this.serverEventIteratorQueue, id, response.body, {
488
- onComplete: () => {
489
- this.close(id);
490
- }
491
- });
492
- } else {
493
- this.close(id);
494
- }
495
- }).catch((err) => {
496
- this.close(id, err);
497
- });
498
- });
499
- this.serverEventIteratorQueue = new ConsumableAsyncIdQueue$1((id, payload) => {
500
- encodeResponseMessage(id, MessageType.EVENT_ITERATOR, payload).then(send).catch((err) => {
501
- this.close(id, err);
502
- });
503
- });
504
- this.serverSignalQueue = new ConsumableAsyncIdQueue$1((id, payload) => {
505
- encodeResponseMessage(id, MessageType.ABORT_SIGNAL, payload).then(send).catch((err) => {
506
- this.close(id, err);
507
- });
372
+ this.send = (id, ...rest) => encodeResponseMessage(id, ...rest).then(async (raw) => {
373
+ if (this.clientControllers.has(id)) {
374
+ await send(raw);
375
+ }
508
376
  });
509
377
  }
378
+ get length() {
379
+ return (this.clientEventIteratorQueue.length + this.clientControllers.size) / 2;
380
+ }
381
+ open(id) {
382
+ this.clientEventIteratorQueue.open(id);
383
+ const controller = new AbortController();
384
+ this.clientControllers.set(id, controller);
385
+ return controller;
386
+ }
510
387
  async message(raw) {
511
388
  const [id, type, payload] = await decodeRequestMessage(raw);
512
389
  if (type === MessageType.ABORT_SIGNAL) {
513
- if (this.clientSignalQueue.isOpen(id)) {
514
- this.clientSignalQueue.push(id, payload);
515
- }
390
+ this.close({ id });
516
391
  return [id, void 0];
517
392
  }
518
393
  if (type === MessageType.EVENT_ITERATOR) {
@@ -521,51 +396,53 @@ class ServerPeer {
521
396
  }
522
397
  return [id, void 0];
523
398
  }
524
- this.open(id);
525
- const clientSignal = toAbortSignal(this.clientSignalQueue, id);
526
- clientSignal.addEventListener("abort", () => {
527
- this.close(id, clientSignal.reason);
528
- }, { once: true });
399
+ const clientController = this.open(id);
529
400
  const request = {
530
401
  ...payload,
531
- signal: clientSignal,
532
- body: isEventIteratorHeaders(payload.headers) ? toEventIterator(this.clientEventIteratorQueue, id, {
533
- onComplete: (reason) => {
534
- if (reason !== "next") {
535
- this.serverSignalQueue.push(id);
536
- }
402
+ signal: clientController.signal,
403
+ body: isEventIteratorHeaders(payload.headers) ? toEventIterator(this.clientEventIteratorQueue, id, async (reason) => {
404
+ if (reason !== "next") {
405
+ await this.send(id, MessageType.ABORT_SIGNAL, void 0);
537
406
  }
538
407
  }) : payload.body
539
408
  };
540
409
  return [id, request];
541
410
  }
542
411
  async response(id, response) {
543
- if (this.serverResponseQueue.isOpen(id)) {
544
- this.serverResponseQueue.push(id, response);
412
+ const signal = this.clientControllers.get(id)?.signal;
413
+ if (!signal || signal.aborted) {
414
+ return;
545
415
  }
416
+ await this.send(id, MessageType.RESPONSE, response).then(async () => {
417
+ if (!signal.aborted && isAsyncIteratorObject(response.body)) {
418
+ await resolveEventIterator(response.body, async (payload) => {
419
+ if (signal.aborted) {
420
+ return "abort";
421
+ }
422
+ await this.send(id, MessageType.EVENT_ITERATOR, payload);
423
+ return "next";
424
+ });
425
+ }
426
+ this.close({ id, abort: false });
427
+ }).catch((reason) => {
428
+ this.close({ id, reason, abort: false });
429
+ throw reason;
430
+ });
546
431
  }
547
- open(id) {
548
- this.serverSignalQueue.open(id);
549
- this.serverEventIteratorQueue.open(id);
550
- this.serverResponseQueue.open(id);
551
- this.clientEventIteratorQueue.open(id);
552
- this.clientSignalQueue.open(id);
553
- }
554
- close(id, reason) {
555
- if (id !== void 0) {
556
- this.serverResponseQueue.close(id);
557
- this.serverEventIteratorQueue.close(id);
558
- this.serverResponseQueue.close(id);
559
- this.clientEventIteratorQueue.close(id, reason);
560
- this.clientSignalQueue.close(id, reason);
432
+ close({ abort = true, ...options } = {}) {
433
+ if (options.id === void 0) {
434
+ if (abort) {
435
+ this.clientControllers.forEach((c) => c.abort());
436
+ }
437
+ this.clientControllers.clear();
561
438
  } else {
562
- this.serverResponseQueue.closeAll();
563
- this.serverEventIteratorQueue.closeAll();
564
- this.serverResponseQueue.closeAll();
565
- this.clientEventIteratorQueue.closeAll();
566
- this.clientSignalQueue.closeAll();
439
+ if (abort) {
440
+ this.clientControllers.get(options.id)?.abort();
441
+ }
442
+ this.clientControllers.delete(options.id);
567
443
  }
444
+ this.clientEventIteratorQueue.close(options);
568
445
  }
569
446
  }
570
447
 
571
- export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage, isEventIteratorHeaders, sendEventIterator, toAbortSignal, toEventIterator };
448
+ export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage, isEventIteratorHeaders, resolveEventIterator, toEventIterator };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/standard-server-peer",
3
3
  "type": "module",
4
- "version": "0.0.0",
4
+ "version": "1.3.0",
5
5
  "license": "MIT",
6
6
  "homepage": "https://unnoq.com",
7
7
  "repository": {
@@ -23,8 +23,8 @@
23
23
  "dist"
24
24
  ],
25
25
  "dependencies": {
26
- "@orpc/shared": "1.1.1",
27
- "@orpc/standard-server": "1.1.1"
26
+ "@orpc/shared": "1.3.0",
27
+ "@orpc/standard-server": "1.3.0"
28
28
  },
29
29
  "scripts": {
30
30
  "build": "unbuild",