@standardserver/peer 0.0.7 → 0.0.8

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/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { StandardRequest, StandardResponse } from '@standardserver/core';
2
- import { AsyncIdQueueCloseOptions, AsyncCleanupFn, AsyncIteratorClass } from '@standardserver/shared';
1
+ import { StandardRequest, StandardResponse, StandardLazyResponse, StandardLazyRequest } from '@standardserver/core';
3
2
  import { EventStreamMessage } from '@standardserver/core/event-stream';
3
+ import { Queue, AsyncCleanupFn, AsyncIteratorClass } from '@standardserver/shared';
4
4
 
5
5
  /**
6
6
  * Base interface for all peer messages.
@@ -68,17 +68,17 @@ interface PeerResponseMessage extends PeerMessage {
68
68
  * - **Client → Server**: Cancel an in-flight request or stop consuming a stream.
69
69
  * - **Server → Client**: Signal an error or premature termination.
70
70
  */
71
- interface PeerAbortMessage extends PeerMessage {
71
+ interface PeerCancelMessage extends PeerMessage {
72
72
  /**
73
73
  * The kind of the message.
74
74
  */
75
- kind: 'abort';
75
+ kind: 'cancel';
76
76
  /**
77
77
  * This message does not have a JSON payload.
78
78
  */
79
79
  json?: undefined;
80
80
  /**
81
- * Abort messages carry no binary payload.
81
+ * Cancel messages carry no binary payload.
82
82
  */
83
83
  binary?: undefined;
84
84
  }
@@ -164,29 +164,20 @@ interface PeerStreamCancelMessage extends PeerMessage {
164
164
  */
165
165
  binary?: undefined;
166
166
  }
167
+ /**
168
+ * Union of all messages a client peer may send to a server peer.
169
+ */
170
+ type ClientPeerSendMessage = PeerRequestMessage | PeerCancelMessage | PeerEventStreamMessage | PeerOctetStreamMessage;
171
+ /**
172
+ * Union of all messages a server peer may send to a client peer.
173
+ */
174
+ type ServerPeerSendMessage = PeerResponseMessage | PeerCancelMessage | PeerOctetStreamMessage | PeerEventStreamMessage | PeerStreamCancelMessage;
167
175
 
168
- interface ClientPeerCloseOptions extends AsyncIdQueueCloseOptions {
169
- }
170
176
  declare class ClientPeer {
171
177
  private readonly send;
172
178
  private readonly idGenerator;
173
- /**
174
- * Messages waiting to be processed
175
- */
176
- private readonly responseMessageQueue;
177
- private readonly eventStreamMessageQueue;
178
- private readonly octetStreamMessageQueue;
179
- /**
180
- * Transmitters for event streams and octet streams
181
- * Should be cancelled when needed
182
- */
183
- private readonly requestEventStreamTransmitters;
184
- private readonly requestOctetStreamTransmitters;
185
- /**
186
- * Cleanup functions invoked when the request/response is completed
187
- */
188
- private readonly cleanupFns;
189
- constructor(send: (message: PeerAbortMessage | PeerRequestMessage | PeerEventStreamMessage | PeerOctetStreamMessage) => Promise<void>);
179
+ private readonly requests;
180
+ constructor(send: (message: ClientPeerSendMessage) => Promise<void>);
190
181
  /**
191
182
  * Use to measure resources usage
192
183
  */
@@ -194,12 +185,14 @@ declare class ClientPeer {
194
185
  /**
195
186
  * Send a request to the server peer
196
187
  */
197
- request(request: StandardRequest): Promise<StandardResponse>;
188
+ request(request: StandardRequest): Promise<StandardLazyResponse>;
198
189
  /**
199
190
  * Handle a message from server
200
191
  */
201
- message(message: PeerResponseMessage | PeerAbortMessage | PeerEventStreamMessage | PeerOctetStreamMessage | PeerStreamCancelMessage): Promise<void>;
202
- close(options?: AsyncIdQueueCloseOptions): Promise<void>;
192
+ message(message: ServerPeerSendMessage): Promise<void>;
193
+ close(reason?: unknown): Promise<void>;
194
+ private closeById;
195
+ private abortById;
203
196
  }
204
197
 
205
198
  interface EncodePeerMessageOptions {
@@ -261,7 +254,7 @@ declare function decodePeerMessage(encoded: string | Uint8Array<ArrayBuffer>, op
261
254
  * Creates an AsyncIterator from a queue of peer event-stream messages.
262
255
  * The iterator yields normal events, throws error events, and completes on done.
263
256
  */
264
- declare function toEventIterator(pull: () => Promise<PeerEventStreamMessage>, cleanup: AsyncCleanupFn): AsyncIteratorClass<unknown>;
257
+ declare function toEventIterator(queue: Queue<PeerEventStreamMessage>, cleanup: AsyncCleanupFn): AsyncIteratorClass<unknown>;
265
258
  /**
266
259
  * Transmits events to a peer event-stream.
267
260
  */
@@ -287,22 +280,10 @@ declare class HibernationEventIterator<T, TReturn = unknown, TNext = unknown> ex
287
280
  constructor(hibernationCallback: HibernationEventIteratorCallback);
288
281
  }
289
282
 
290
- interface ServerPeerCloseOptions extends AsyncIdQueueCloseOptions {
291
- }
292
283
  declare class ServerPeer {
293
284
  private readonly send;
294
- /**
295
- * Messages waiting to be processed
296
- */
297
- private readonly eventStreamMessageQueue;
298
- private readonly octetStreamMessageQueue;
299
- private readonly eventStreamTransmitters;
300
- private readonly octetStreamTransmitters;
301
- /**
302
- * Map of abort controllers for each request
303
- */
304
- private readonly controller;
305
- constructor(send: (message: PeerResponseMessage | PeerAbortMessage | PeerOctetStreamMessage | PeerEventStreamMessage | PeerStreamCancelMessage) => Promise<void>);
285
+ private readonly requests;
286
+ constructor(send: (message: ServerPeerSendMessage) => Promise<void>);
306
287
  /**
307
288
  * Use for measure resources usage
308
289
  */
@@ -310,9 +291,20 @@ declare class ServerPeer {
310
291
  /**
311
292
  * Handle a message from client
312
293
  */
313
- message(message: PeerRequestMessage | PeerEventStreamMessage | PeerOctetStreamMessage | PeerAbortMessage, handleRequest: (request: StandardRequest) => Promise<StandardResponse>): Promise<void>;
314
- close(options?: ServerPeerCloseOptions): Promise<void>;
294
+ message(message: ClientPeerSendMessage, handleRequest: (request: StandardLazyRequest) => Promise<StandardResponse>): Promise<void>;
295
+ close(reason?: unknown): Promise<void>;
296
+ private closeById;
315
297
  }
316
298
 
317
- export { ClientPeer, EventStreamTransmitter, HibernationEventIterator, ServerPeer, decodePeerMessage, encodePeerMessage, toEventIterator };
318
- export type { ClientPeerCloseOptions, DecodePeerMessageOptions, DecodePeerMessageResult, EncodePeerMessageOptions, HibernationEventIteratorCallback, PeerAbortMessage, PeerEventStreamMessage, PeerMessage, PeerOctetStreamMessage, PeerRequestMessage, PeerResponseMessage, PeerStreamCancelMessage, ServerPeerCloseOptions };
299
+ declare function isPeerMessage(maybe: unknown): maybe is PeerMessage;
300
+ declare function isPeerRequestMessage(maybe: PeerMessage): maybe is PeerRequestMessage;
301
+ declare function isPeerResponseMessage(maybe: PeerMessage): maybe is PeerResponseMessage;
302
+ declare function isPeerCancelMessage(maybe: PeerMessage): maybe is PeerCancelMessage;
303
+ declare function isPeerEventStreamMessage(maybe: PeerMessage): maybe is PeerEventStreamMessage;
304
+ declare function isPeerOctetStreamMessage(maybe: PeerMessage): maybe is PeerOctetStreamMessage;
305
+ declare function isPeerStreamCancelMessage(maybe: PeerMessage): maybe is PeerStreamCancelMessage;
306
+ declare function isClientPeerSendMessage(maybe: PeerMessage): maybe is ClientPeerSendMessage;
307
+ declare function isServerPeerSendMessage(maybe: PeerMessage): maybe is ServerPeerSendMessage;
308
+
309
+ export { ClientPeer, EventStreamTransmitter, HibernationEventIterator, ServerPeer, decodePeerMessage, encodePeerMessage, isClientPeerSendMessage, isPeerCancelMessage, isPeerEventStreamMessage, isPeerMessage, isPeerOctetStreamMessage, isPeerRequestMessage, isPeerResponseMessage, isPeerStreamCancelMessage, isServerPeerSendMessage, toEventIterator };
310
+ export type { ClientPeerSendMessage, DecodePeerMessageOptions, DecodePeerMessageResult, EncodePeerMessageOptions, HibernationEventIteratorCallback, PeerCancelMessage, PeerEventStreamMessage, PeerMessage, PeerOctetStreamMessage, PeerRequestMessage, PeerResponseMessage, PeerStreamCancelMessage, ServerPeerSendMessage };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { StandardRequest, StandardResponse } from '@standardserver/core';
2
- import { AsyncIdQueueCloseOptions, AsyncCleanupFn, AsyncIteratorClass } from '@standardserver/shared';
1
+ import { StandardRequest, StandardResponse, StandardLazyResponse, StandardLazyRequest } from '@standardserver/core';
3
2
  import { EventStreamMessage } from '@standardserver/core/event-stream';
3
+ import { Queue, AsyncCleanupFn, AsyncIteratorClass } from '@standardserver/shared';
4
4
 
5
5
  /**
6
6
  * Base interface for all peer messages.
@@ -68,17 +68,17 @@ interface PeerResponseMessage extends PeerMessage {
68
68
  * - **Client → Server**: Cancel an in-flight request or stop consuming a stream.
69
69
  * - **Server → Client**: Signal an error or premature termination.
70
70
  */
71
- interface PeerAbortMessage extends PeerMessage {
71
+ interface PeerCancelMessage extends PeerMessage {
72
72
  /**
73
73
  * The kind of the message.
74
74
  */
75
- kind: 'abort';
75
+ kind: 'cancel';
76
76
  /**
77
77
  * This message does not have a JSON payload.
78
78
  */
79
79
  json?: undefined;
80
80
  /**
81
- * Abort messages carry no binary payload.
81
+ * Cancel messages carry no binary payload.
82
82
  */
83
83
  binary?: undefined;
84
84
  }
@@ -164,29 +164,20 @@ interface PeerStreamCancelMessage extends PeerMessage {
164
164
  */
165
165
  binary?: undefined;
166
166
  }
167
+ /**
168
+ * Union of all messages a client peer may send to a server peer.
169
+ */
170
+ type ClientPeerSendMessage = PeerRequestMessage | PeerCancelMessage | PeerEventStreamMessage | PeerOctetStreamMessage;
171
+ /**
172
+ * Union of all messages a server peer may send to a client peer.
173
+ */
174
+ type ServerPeerSendMessage = PeerResponseMessage | PeerCancelMessage | PeerOctetStreamMessage | PeerEventStreamMessage | PeerStreamCancelMessage;
167
175
 
168
- interface ClientPeerCloseOptions extends AsyncIdQueueCloseOptions {
169
- }
170
176
  declare class ClientPeer {
171
177
  private readonly send;
172
178
  private readonly idGenerator;
173
- /**
174
- * Messages waiting to be processed
175
- */
176
- private readonly responseMessageQueue;
177
- private readonly eventStreamMessageQueue;
178
- private readonly octetStreamMessageQueue;
179
- /**
180
- * Transmitters for event streams and octet streams
181
- * Should be cancelled when needed
182
- */
183
- private readonly requestEventStreamTransmitters;
184
- private readonly requestOctetStreamTransmitters;
185
- /**
186
- * Cleanup functions invoked when the request/response is completed
187
- */
188
- private readonly cleanupFns;
189
- constructor(send: (message: PeerAbortMessage | PeerRequestMessage | PeerEventStreamMessage | PeerOctetStreamMessage) => Promise<void>);
179
+ private readonly requests;
180
+ constructor(send: (message: ClientPeerSendMessage) => Promise<void>);
190
181
  /**
191
182
  * Use to measure resources usage
192
183
  */
@@ -194,12 +185,14 @@ declare class ClientPeer {
194
185
  /**
195
186
  * Send a request to the server peer
196
187
  */
197
- request(request: StandardRequest): Promise<StandardResponse>;
188
+ request(request: StandardRequest): Promise<StandardLazyResponse>;
198
189
  /**
199
190
  * Handle a message from server
200
191
  */
201
- message(message: PeerResponseMessage | PeerAbortMessage | PeerEventStreamMessage | PeerOctetStreamMessage | PeerStreamCancelMessage): Promise<void>;
202
- close(options?: AsyncIdQueueCloseOptions): Promise<void>;
192
+ message(message: ServerPeerSendMessage): Promise<void>;
193
+ close(reason?: unknown): Promise<void>;
194
+ private closeById;
195
+ private abortById;
203
196
  }
204
197
 
205
198
  interface EncodePeerMessageOptions {
@@ -261,7 +254,7 @@ declare function decodePeerMessage(encoded: string | Uint8Array<ArrayBuffer>, op
261
254
  * Creates an AsyncIterator from a queue of peer event-stream messages.
262
255
  * The iterator yields normal events, throws error events, and completes on done.
263
256
  */
264
- declare function toEventIterator(pull: () => Promise<PeerEventStreamMessage>, cleanup: AsyncCleanupFn): AsyncIteratorClass<unknown>;
257
+ declare function toEventIterator(queue: Queue<PeerEventStreamMessage>, cleanup: AsyncCleanupFn): AsyncIteratorClass<unknown>;
265
258
  /**
266
259
  * Transmits events to a peer event-stream.
267
260
  */
@@ -287,22 +280,10 @@ declare class HibernationEventIterator<T, TReturn = unknown, TNext = unknown> ex
287
280
  constructor(hibernationCallback: HibernationEventIteratorCallback);
288
281
  }
289
282
 
290
- interface ServerPeerCloseOptions extends AsyncIdQueueCloseOptions {
291
- }
292
283
  declare class ServerPeer {
293
284
  private readonly send;
294
- /**
295
- * Messages waiting to be processed
296
- */
297
- private readonly eventStreamMessageQueue;
298
- private readonly octetStreamMessageQueue;
299
- private readonly eventStreamTransmitters;
300
- private readonly octetStreamTransmitters;
301
- /**
302
- * Map of abort controllers for each request
303
- */
304
- private readonly controller;
305
- constructor(send: (message: PeerResponseMessage | PeerAbortMessage | PeerOctetStreamMessage | PeerEventStreamMessage | PeerStreamCancelMessage) => Promise<void>);
285
+ private readonly requests;
286
+ constructor(send: (message: ServerPeerSendMessage) => Promise<void>);
306
287
  /**
307
288
  * Use for measure resources usage
308
289
  */
@@ -310,9 +291,20 @@ declare class ServerPeer {
310
291
  /**
311
292
  * Handle a message from client
312
293
  */
313
- message(message: PeerRequestMessage | PeerEventStreamMessage | PeerOctetStreamMessage | PeerAbortMessage, handleRequest: (request: StandardRequest) => Promise<StandardResponse>): Promise<void>;
314
- close(options?: ServerPeerCloseOptions): Promise<void>;
294
+ message(message: ClientPeerSendMessage, handleRequest: (request: StandardLazyRequest) => Promise<StandardResponse>): Promise<void>;
295
+ close(reason?: unknown): Promise<void>;
296
+ private closeById;
315
297
  }
316
298
 
317
- export { ClientPeer, EventStreamTransmitter, HibernationEventIterator, ServerPeer, decodePeerMessage, encodePeerMessage, toEventIterator };
318
- export type { ClientPeerCloseOptions, DecodePeerMessageOptions, DecodePeerMessageResult, EncodePeerMessageOptions, HibernationEventIteratorCallback, PeerAbortMessage, PeerEventStreamMessage, PeerMessage, PeerOctetStreamMessage, PeerRequestMessage, PeerResponseMessage, PeerStreamCancelMessage, ServerPeerCloseOptions };
299
+ declare function isPeerMessage(maybe: unknown): maybe is PeerMessage;
300
+ declare function isPeerRequestMessage(maybe: PeerMessage): maybe is PeerRequestMessage;
301
+ declare function isPeerResponseMessage(maybe: PeerMessage): maybe is PeerResponseMessage;
302
+ declare function isPeerCancelMessage(maybe: PeerMessage): maybe is PeerCancelMessage;
303
+ declare function isPeerEventStreamMessage(maybe: PeerMessage): maybe is PeerEventStreamMessage;
304
+ declare function isPeerOctetStreamMessage(maybe: PeerMessage): maybe is PeerOctetStreamMessage;
305
+ declare function isPeerStreamCancelMessage(maybe: PeerMessage): maybe is PeerStreamCancelMessage;
306
+ declare function isClientPeerSendMessage(maybe: PeerMessage): maybe is ClientPeerSendMessage;
307
+ declare function isServerPeerSendMessage(maybe: PeerMessage): maybe is ServerPeerSendMessage;
308
+
309
+ export { ClientPeer, EventStreamTransmitter, HibernationEventIterator, ServerPeer, decodePeerMessage, encodePeerMessage, isClientPeerSendMessage, isPeerCancelMessage, isPeerEventStreamMessage, isPeerMessage, isPeerOctetStreamMessage, isPeerRequestMessage, isPeerResponseMessage, isPeerStreamCancelMessage, isServerPeerSendMessage, toEventIterator };
310
+ export type { ClientPeerSendMessage, DecodePeerMessageOptions, DecodePeerMessageResult, EncodePeerMessageOptions, HibernationEventIteratorCallback, PeerCancelMessage, PeerEventStreamMessage, PeerMessage, PeerOctetStreamMessage, PeerRequestMessage, PeerResponseMessage, PeerStreamCancelMessage, ServerPeerSendMessage };
package/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
- import { AsyncIteratorClass, isTypescriptObject, isAsyncIteratorObject, SequentialIdGenerator, AsyncIdQueue, AbortError, stringifyJSON } from '@standardserver/shared';
2
- import { generateContentDisposition, flattenStandardHeader, getFilenameFromContentDisposition } from '@standardserver/core';
1
+ import { AsyncIteratorClass, isTypescriptObject, isAsyncIteratorObject, Queue, SequentialIdGenerator, omit, emitUnhandledRejection, AbortError, stringifyJSON } from '@standardserver/shared';
2
+ import { generateContentDisposition, flattenStandardHeader, getFilenameFromContentDisposition, isStandardRequest, isStandardResponse } from '@standardserver/core';
3
3
  import { withEventIteratorEventMeta, EventIteratorErrorEvent, unwrapEventIteratorEvent } from '@standardserver/core/event-stream';
4
4
 
5
- function toEventIterator(pull, cleanup) {
5
+ function toEventIterator(queue, cleanup) {
6
6
  return new AsyncIteratorClass(async () => {
7
7
  while (true) {
8
- const { json } = await pull();
8
+ const { json } = await queue.pull();
9
9
  switch (json.event) {
10
10
  case "message": {
11
11
  let data = json.data;
@@ -46,61 +46,69 @@ class EventStreamTransmitter {
46
46
  }
47
47
  async transmit() {
48
48
  while (true) {
49
- let json;
50
49
  try {
51
50
  const item = await this.iterator.next();
52
51
  if (this.isCompleted) {
53
52
  return;
54
53
  }
54
+ const [data, meta] = unwrapEventIteratorEvent(item.value);
55
+ try {
56
+ await this.send({
57
+ kind: "event-stream",
58
+ id: this.messageId,
59
+ json: { ...meta, event: item.done ? "close" : "message", data }
60
+ });
61
+ } catch (error) {
62
+ if (!item.done) {
63
+ await this.cancel();
64
+ }
65
+ throw error;
66
+ }
55
67
  if (item.done) {
56
68
  this.isCompleted = true;
69
+ return;
57
70
  }
58
- const [data, meta] = unwrapEventIteratorEvent(item.value);
59
- json = { ...meta, event: item.done ? "close" : "message", data };
60
- } catch (err) {
61
- if (err instanceof EventIteratorErrorEvent) {
62
- if (this.isCompleted) {
63
- return;
64
- }
71
+ } catch (error) {
72
+ if (this.isCompleted) {
73
+ throw error;
74
+ }
75
+ if (error instanceof EventIteratorErrorEvent) {
76
+ const [resolvedError, meta] = unwrapEventIteratorEvent(error);
77
+ await this.send({
78
+ kind: "event-stream",
79
+ id: this.messageId,
80
+ json: { ...meta, event: "error", data: resolvedError.data }
81
+ });
65
82
  this.isCompleted = true;
66
- const [resolvedError, meta] = unwrapEventIteratorEvent(err);
67
- json = { ...meta, event: "error", data: resolvedError.data };
83
+ return;
68
84
  } else {
69
85
  this.isCompleted = true;
70
- throw err;
86
+ throw error;
71
87
  }
72
88
  }
73
- await this.send({
74
- json,
75
- kind: "event-stream",
76
- id: this.messageId
77
- });
78
- if (this.isCompleted) {
79
- return;
80
- }
81
89
  }
82
90
  }
83
91
  }
84
92
 
85
- function toOctetStream(pull, cleanup) {
93
+ function toOctetStream(queue, cleanup) {
86
94
  return new ReadableStream({
87
95
  async pull(controller) {
88
96
  try {
89
- const { json, binary } = await pull();
97
+ const { json, binary } = await queue.pull();
90
98
  if (binary) {
91
99
  controller.enqueue(binary instanceof Uint8Array ? binary : new Uint8Array(await binary.arrayBuffer()));
92
100
  }
93
101
  if (json.close) {
94
- await cleanup(true);
102
+ await cleanup({ isCancelled: false });
95
103
  controller.close();
96
104
  }
97
- } catch (err) {
98
- await cleanup(true);
99
- controller.error(err);
105
+ } catch (error) {
106
+ await cleanup({ isCancelled: false, error });
107
+ controller.error(error);
100
108
  }
101
109
  },
102
110
  async cancel() {
103
- await cleanup(false);
111
+ await cleanup({ isCancelled: true });
104
112
  }
105
113
  });
106
114
  }
@@ -120,8 +128,11 @@ class OctetStreamTransmitter {
120
128
  }
121
129
  async transmit() {
122
130
  while (true) {
123
- const { done, value } = await this.reader.read();
124
- if (!this.isCompleted) {
131
+ try {
132
+ const { done, value } = await this.reader.read();
133
+ if (this.isCompleted) {
134
+ return;
135
+ }
125
136
  try {
126
137
  await this.send({
127
138
  json: { close: done },
@@ -130,56 +141,71 @@ class OctetStreamTransmitter {
130
141
  id: this.messageId
131
142
  });
132
143
  } catch (err) {
133
- await this.cancel();
144
+ if (!done) {
145
+ await this.cancel();
146
+ }
134
147
  throw err;
135
148
  }
136
- }
137
- if (done) {
149
+ if (done) {
150
+ this.isCompleted = true;
151
+ return;
152
+ }
153
+ } catch (error) {
138
154
  this.isCompleted = true;
139
- break;
155
+ throw error;
140
156
  }
141
157
  }
142
158
  }
143
159
  }
144
160
 
145
- async function toStandardBody(message, eventStreamMessageQueue, octetStreamMessageQueue, cleanup) {
161
+ function toStandardBody(message, cleanup) {
146
162
  const bodyHint = flattenStandardHeader(message.json.headers["standard-server"]);
147
163
  if (bodyHint === "event-stream") {
148
- return toEventIterator(
149
- () => eventStreamMessageQueue.pull(message.id),
150
- cleanup
151
- );
164
+ const eventStreamMessageQueue = new Queue();
165
+ return {
166
+ resolveBody: async () => toEventIterator(eventStreamMessageQueue, cleanup),
167
+ eventStreamMessageQueue
168
+ };
152
169
  }
153
170
  if (bodyHint === "octet-stream") {
154
- return toOctetStream(
155
- () => octetStreamMessageQueue.pull(message.id),
156
- cleanup
157
- );
171
+ const octetStreamMessageQueue = new Queue();
172
+ return {
173
+ resolveBody: async () => toOctetStream(octetStreamMessageQueue, cleanup),
174
+ octetStreamMessageQueue
175
+ };
158
176
  }
159
- try {
160
- if (bodyHint === "file") {
161
- const contentDisposition = flattenStandardHeader(message.json.headers["content-disposition"]);
162
- const filename = contentDisposition !== void 0 ? getFilenameFromContentDisposition(contentDisposition) : "undefined";
163
- return new File(message.binary ? [message.binary] : [], filename ?? "blob", {
164
- type: flattenStandardHeader(message.json.headers["content-type"]) ?? "application/octet-stream"
165
- });
166
- }
167
- if (bodyHint === "form-data") {
168
- const res = new Response(message.binary, {
169
- headers: {
170
- "content-type": flattenStandardHeader(message.json.headers["content-type"]) ?? "multipart/form-data"
171
- }
172
- });
173
- const fromData = await res.formData();
174
- return fromData;
175
- }
176
- if (bodyHint === "url-search-params" && typeof message.json.body === "string") {
177
- return new URLSearchParams(message.json.body);
177
+ const resolveBody = async () => {
178
+ let errorRef;
179
+ try {
180
+ if (bodyHint === "file") {
181
+ const contentDisposition = flattenStandardHeader(message.json.headers["content-disposition"]);
182
+ const filename = contentDisposition !== void 0 ? getFilenameFromContentDisposition(contentDisposition) : void 0;
183
+ const body = new File(message.binary ? [message.binary] : [], filename ?? "blob", {
184
+ type: flattenStandardHeader(message.json.headers["content-type"]) ?? "application/octet-stream"
185
+ });
186
+ return body;
187
+ }
188
+ if (bodyHint === "form-data") {
189
+ const res = new Response(message.binary, {
190
+ headers: {
191
+ "content-type": flattenStandardHeader(message.json.headers["content-type"]) ?? "multipart/form-data"
192
+ }
193
+ });
194
+ const body = await res.formData();
195
+ return body;
196
+ }
197
+ if (bodyHint === "url-search-params" && typeof message.json.body === "string") {
198
+ return new URLSearchParams(message.json.body);
199
+ }
200
+ return message.json.body;
201
+ } catch (error) {
202
+ errorRef = { value: error };
203
+ throw error;
204
+ } finally {
205
+ await cleanup(errorRef ? { isCancelled: false, error: errorRef.value } : { isCancelled: false });
178
206
  }
179
- return message.json.body;
180
- } finally {
181
- await cleanup(true);
182
- }
207
+ };
208
+ return { resolveBody };
183
209
  }
184
210
  async function encodeAtomicStandardBody(body, headers) {
185
211
  headers = { ...headers };
@@ -218,27 +244,12 @@ class ClientPeer {
218
244
  this.send = send;
219
245
  }
220
246
  idGenerator = new SequentialIdGenerator();
221
- /**
222
- * Messages waiting to be processed
223
- */
224
- responseMessageQueue = new AsyncIdQueue();
225
- eventStreamMessageQueue = new AsyncIdQueue();
226
- octetStreamMessageQueue = new AsyncIdQueue();
227
- /**
228
- * Transmitters for event streams and octet streams
229
- * Should be cancelled when needed
230
- */
231
- requestEventStreamTransmitters = /* @__PURE__ */ new Map();
232
- requestOctetStreamTransmitters = /* @__PURE__ */ new Map();
233
- /**
234
- * Cleanup functions invoked when the request/response is completed
235
- */
236
- cleanupFns = /* @__PURE__ */ new Map();
247
+ requests = /* @__PURE__ */ new Map();
237
248
  /**
238
249
  * Use to measure resources usage
239
250
  */
240
251
  get size() {
241
- return this.responseMessageQueue.length + this.eventStreamMessageQueue.length + this.octetStreamMessageQueue.length + this.requestEventStreamTransmitters.size + this.requestOctetStreamTransmitters.size + this.cleanupFns.size;
252
+ return this.requests.size;
242
253
  }
243
254
  /**
244
255
  * Send a request to the server peer
@@ -247,162 +258,228 @@ class ClientPeer {
247
258
  const signal = request.signal;
248
259
  signal?.throwIfAborted();
249
260
  const id = this.idGenerator.generate();
250
- this.eventStreamMessageQueue.open(id);
251
- this.octetStreamMessageQueue.open(id);
252
- this.responseMessageQueue.open(id);
261
+ const state = {};
262
+ this.requests.set(id, state);
253
263
  let abortListener;
254
- signal?.addEventListener("abort", abortListener = async () => {
255
- await Promise.all([
256
- /**
257
- * Let server know request was aborted
258
- *
259
- * We don't need to check if is there any abort message already sent
260
- * since this listener is removed when the request is closed.
261
- */
262
- this.send({ id, kind: "abort" }),
263
- this.close({ id, reason: signal.reason })
264
- ]);
264
+ signal?.addEventListener("abort", abortListener = () => this.abortById(id, signal.reason));
265
+ state.cleanupFns ??= [];
266
+ state.cleanupFns.push(() => {
267
+ signal?.removeEventListener("abort", abortListener);
265
268
  });
266
- const cleanupFns = [
267
- /**
268
- * Make sure to remove the abort listener when the request/response is closed.
269
- * Since a signal can be reused for multiple requests, if each request
270
- * adds listeners without removing them, it can lead to excessive memory usage
271
- * until the signal is garbage collected.
272
- */
273
- () => {
274
- signal?.removeEventListener("abort", abortListener);
275
- }
276
- ];
277
- this.cleanupFns.set(id, cleanupFns);
278
269
  try {
279
270
  const [jsonBody, headers, binary] = await encodeAtomicStandardBody(request.body, request.headers);
280
271
  signal?.throwIfAborted();
281
- const requestMessage = {
272
+ await this.send({
282
273
  id,
283
274
  kind: "request",
284
275
  json: {
285
- ...request,
276
+ ...omit(request, ["signal"]),
286
277
  headers,
287
- body: jsonBody,
288
- ...{ signal: void 0 }
289
- // remove signal from request
278
+ body: jsonBody
290
279
  },
291
280
  binary
292
- };
293
- await this.send(requestMessage);
281
+ });
294
282
  signal?.throwIfAborted();
295
283
  if (isAsyncIteratorObject(request.body)) {
296
284
  const transmitter = new EventStreamTransmitter(request.body, id, this.send);
297
- this.requestEventStreamTransmitters.set(id, transmitter);
298
- void transmitter.transmit().catch(async (reason) => {
299
- await Promise.all([
300
- /**
301
- * We don't need to send abort message if transmitter was cancelled
302
- * or request was aborted
303
- */
304
- this.requestEventStreamTransmitters.has(id) ? this.send({ id, kind: "abort" }) : void 0,
305
- this.close({ id, reason })
306
- ]);
285
+ state.eventStreamTransmitter = transmitter;
286
+ void transmitter.transmit().catch(async (error) => {
287
+ if (state.eventStreamTransmitter) {
288
+ await this.abortById(id, error);
289
+ } else {
290
+ emitUnhandledRejection(error);
291
+ }
307
292
  });
308
293
  } else if (request.body instanceof ReadableStream) {
309
294
  const transmitter = new OctetStreamTransmitter(request.body, id, this.send);
310
- this.requestOctetStreamTransmitters.set(id, transmitter);
311
- void transmitter.transmit().catch(async (reason) => {
312
- await Promise.all([
313
- /**
314
- * We don't need to send abort message if transmitter was cancelled
315
- * or request was aborted
316
- */
317
- this.requestOctetStreamTransmitters.has(id) ? this.send({ id, kind: "abort" }) : void 0,
318
- this.close({ id, reason })
319
- ]);
295
+ state.octetStreamTransmitter = transmitter;
296
+ void transmitter.transmit().catch(async (error) => {
297
+ if (state.octetStreamTransmitter) {
298
+ await this.abortById(id, error);
299
+ } else {
300
+ emitUnhandledRejection(error);
301
+ }
302
+ /* v8 ignore stop -- @preserve */
320
303
  });
321
304
  }
322
- const peerResponseMessage = await this.responseMessageQueue.pull(id);
323
- return {
324
- ...peerResponseMessage.json,
325
- body: await toStandardBody(
326
- peerResponseMessage,
327
- this.eventStreamMessageQueue,
328
- this.octetStreamMessageQueue,
329
- async (isCompleted) => {
330
- await Promise.all([
331
- /**
332
- * We don't need to send abort message if completed
333
- * or request was aborted
334
- */
335
- !isCompleted && (this.eventStreamMessageQueue.isOpen(id) || this.octetStreamMessageQueue.isOpen(id)) ? this.send({ id, kind: "abort" }) : void 0,
336
- this.close({ id })
337
- ]);
338
- }
339
- )
340
- };
341
305
  } catch (reason) {
342
- await this.close({ id, reason });
306
+ await this.closeById(id, reason);
343
307
  throw reason;
344
308
  }
309
+ return new Promise((resolve, reject) => {
310
+ state.resolve = resolve;
311
+ state.reject = reject;
312
+ });
345
313
  }
346
314
  /**
347
315
  * Handle a message from server
348
316
  */
349
317
  async message(message) {
318
+ const id = message.id;
319
+ const state = this.requests.get(id);
320
+ if (!state) {
321
+ return;
322
+ }
350
323
  if (message.kind === "stream/cancel") {
351
324
  const promise = Promise.all([
352
- this.requestEventStreamTransmitters.get(message.id)?.cancel(),
353
- this.requestOctetStreamTransmitters.get(message.id)?.cancel()
325
+ state.eventStreamTransmitter?.cancel(),
326
+ state.octetStreamTransmitter?.cancel()
354
327
  ]);
355
- this.requestEventStreamTransmitters.delete(message.id);
356
- this.requestOctetStreamTransmitters.delete(message.id);
328
+ state.eventStreamTransmitter = void 0;
329
+ state.octetStreamTransmitter = void 0;
357
330
  await promise;
358
331
  return;
359
332
  }
360
- if (message.kind === "abort") {
361
- await this.close({ id: message.id, reason: new AbortError("Server peer aborted the request") });
333
+ if (message.kind === "cancel") {
334
+ await this.closeById(id, new AbortError("Server canceled the request"));
362
335
  return;
363
336
  }
364
337
  if (message.kind === "event-stream") {
365
- if (this.eventStreamMessageQueue.isOpen(message.id)) {
366
- this.eventStreamMessageQueue.push(message.id, message);
367
- }
338
+ state.eventStreamMessageQueue?.push(message);
368
339
  return;
369
340
  }
370
341
  if (message.kind === "octet-stream") {
371
- if (this.octetStreamMessageQueue.isOpen(message.id)) {
372
- this.octetStreamMessageQueue.push(message.id, message);
373
- }
342
+ state.octetStreamMessageQueue?.push(message);
374
343
  return;
375
344
  }
376
- if (this.responseMessageQueue.isOpen(message.id)) {
377
- this.responseMessageQueue.push(message.id, message);
345
+ if (!state.resolve) {
346
+ return;
347
+ }
348
+ const resolve = state.resolve;
349
+ state.resolve = void 0;
350
+ try {
351
+ const decoded = toStandardBody(message, async ({ isCancelled, error }) => {
352
+ if (isCancelled) {
353
+ await this.abortById(id, error);
354
+ } else if (state.eventStreamMessageQueue || state.octetStreamMessageQueue) {
355
+ await this.closeById(id, error);
356
+ }
357
+ });
358
+ state.eventStreamMessageQueue = decoded.eventStreamMessageQueue;
359
+ state.octetStreamMessageQueue = decoded.octetStreamMessageQueue;
360
+ resolve({ ...message.json, resolveBody: decoded.resolveBody });
361
+ if (!state.eventStreamMessageQueue && !state.octetStreamMessageQueue) {
362
+ await this.closeById(id);
363
+ }
364
+ } catch (reason) {
365
+ await this.closeById(id, reason);
378
366
  }
379
367
  }
380
- async close(options = {}) {
381
- const promises = [];
382
- this.responseMessageQueue.close(options);
383
- this.eventStreamMessageQueue.close(options);
384
- this.octetStreamMessageQueue.close(options);
385
- if (options.id !== void 0) {
386
- promises.push(
387
- this.requestEventStreamTransmitters.get(options.id)?.cancel(),
388
- this.requestOctetStreamTransmitters.get(options.id)?.cancel()
389
- );
390
- this.requestEventStreamTransmitters.delete(options.id);
391
- this.requestOctetStreamTransmitters.delete(options.id);
392
- this.cleanupFns.get(options.id)?.forEach((fn) => fn());
393
- this.cleanupFns.delete(options.id);
394
- } else {
395
- this.requestEventStreamTransmitters.forEach((t) => promises.push(t.cancel()));
396
- this.requestOctetStreamTransmitters.forEach((t) => promises.push(t.cancel()));
397
- this.requestEventStreamTransmitters.clear();
398
- this.requestOctetStreamTransmitters.clear();
399
- this.cleanupFns.forEach((fns) => fns.forEach((fn) => fn()));
400
- this.cleanupFns.clear();
368
+ async close(reason) {
369
+ reason ??= new AbortError("Peer was closed");
370
+ await Promise.all(
371
+ Array.from(this.requests.keys()).map((id) => this.closeById(id, reason))
372
+ );
373
+ }
374
+ async closeById(id, reason) {
375
+ const state = this.requests.get(id);
376
+ if (!state) {
377
+ return;
378
+ }
379
+ this.requests.delete(id);
380
+ reason ??= new AbortError("Request was closed");
381
+ state.reject?.(reason);
382
+ state.resolve = void 0;
383
+ state.reject = void 0;
384
+ state.eventStreamMessageQueue?.close(reason);
385
+ state.octetStreamMessageQueue?.close(reason);
386
+ state.eventStreamMessageQueue = void 0;
387
+ state.octetStreamMessageQueue = void 0;
388
+ const promises = [
389
+ state.eventStreamTransmitter?.cancel(),
390
+ state.octetStreamTransmitter?.cancel()
391
+ ];
392
+ state.eventStreamTransmitter = void 0;
393
+ state.octetStreamTransmitter = void 0;
394
+ state.cleanupFns?.forEach((fn) => fn());
395
+ state.cleanupFns = void 0;
396
+ await Promise.all(promises);
397
+ }
398
+ async abortById(id, reason) {
399
+ const state = this.requests.get(id);
400
+ if (!state) {
401
+ return;
401
402
  }
403
+ this.requests.delete(id);
404
+ reason ??= new AbortError("Request was aborted");
405
+ state.reject?.(reason);
406
+ state.resolve = void 0;
407
+ state.reject = void 0;
408
+ state.eventStreamMessageQueue?.abort(reason);
409
+ state.octetStreamMessageQueue?.abort(reason);
410
+ state.eventStreamMessageQueue = void 0;
411
+ state.octetStreamMessageQueue = void 0;
412
+ const promises = [
413
+ this.send({ id, kind: "cancel" }),
414
+ state.eventStreamTransmitter?.cancel(),
415
+ state.octetStreamTransmitter?.cancel()
416
+ ];
417
+ state.eventStreamTransmitter = void 0;
418
+ state.octetStreamTransmitter = void 0;
419
+ state.cleanupFns?.forEach((fn) => fn());
420
+ state.cleanupFns = void 0;
402
421
  await Promise.all(promises);
403
422
  }
404
423
  }
405
424
 
425
+ function isPeerMessage(maybe) {
426
+ if (!isTypescriptObject(maybe)) {
427
+ return false;
428
+ }
429
+ if (typeof maybe.id !== "string") {
430
+ return false;
431
+ }
432
+ if (typeof maybe.kind !== "string") {
433
+ return false;
434
+ }
435
+ if (maybe.binary !== void 0 && !(maybe.binary instanceof Uint8Array) && !(maybe.binary instanceof Blob)) {
436
+ return false;
437
+ }
438
+ return true;
439
+ }
440
+ function isPeerRequestMessage(maybe) {
441
+ return maybe.kind === "request" && isStandardRequest(maybe.json);
442
+ }
443
+ function isPeerResponseMessage(maybe) {
444
+ return maybe.kind === "response" && isStandardResponse(maybe.json);
445
+ }
446
+ function isPeerCancelMessage(maybe) {
447
+ return maybe.kind === "cancel" && maybe.json === void 0 && maybe.binary === void 0;
448
+ }
449
+ function isPeerEventStreamMessage(maybe) {
450
+ if (maybe.kind !== "event-stream" || maybe.binary !== void 0) {
451
+ return false;
452
+ }
453
+ if (!isTypescriptObject(maybe.json)) {
454
+ return false;
455
+ }
456
+ if (maybe.json.id !== void 0 && typeof maybe.json.id !== "string") {
457
+ return false;
458
+ }
459
+ if (maybe.json.event !== void 0 && typeof maybe.json.event !== "string") {
460
+ return false;
461
+ }
462
+ if (maybe.json.retry !== void 0 && !Number.isFinite(maybe.json.retry)) {
463
+ return false;
464
+ }
465
+ if (maybe.json.comments !== void 0 && !(Array.isArray(maybe.json.comments) && maybe.json.comments.every((v) => typeof v === "string"))) {
466
+ return false;
467
+ }
468
+ return true;
469
+ }
470
+ function isPeerOctetStreamMessage(maybe) {
471
+ return maybe.kind === "octet-stream" && isTypescriptObject(maybe.json) && typeof maybe.json.close === "boolean";
472
+ }
473
+ function isPeerStreamCancelMessage(maybe) {
474
+ return maybe.kind === "stream/cancel" && maybe.json === void 0 && maybe.binary === void 0;
475
+ }
476
+ function isClientPeerSendMessage(maybe) {
477
+ return isPeerRequestMessage(maybe) || isPeerCancelMessage(maybe) || isPeerEventStreamMessage(maybe) || isPeerOctetStreamMessage(maybe);
478
+ }
479
+ function isServerPeerSendMessage(maybe) {
480
+ return isPeerResponseMessage(maybe) || isPeerCancelMessage(maybe) || isPeerEventStreamMessage(maybe) || isPeerOctetStreamMessage(maybe) || isPeerStreamCancelMessage(maybe);
481
+ }
482
+
406
483
  const JSON_BINARY_DELIMITER = 255;
407
484
  const textEncoder = new TextEncoder();
408
485
  const textDecoder = new TextDecoder();
@@ -424,37 +501,48 @@ async function encodePeerMessage(message, options = {}) {
424
501
  return output;
425
502
  }
426
503
  function decodePeerMessage(encoded, options = {}) {
427
- if (typeof encoded === "string") {
428
- if (options.prefix) {
429
- if (!encoded.startsWith(options.prefix)) {
504
+ try {
505
+ if (typeof encoded === "string") {
506
+ if (options.prefix) {
507
+ if (!encoded.startsWith(options.prefix)) {
508
+ return { matched: false };
509
+ }
510
+ encoded = encoded.slice(options.prefix.length);
511
+ }
512
+ const message2 = JSON.parse(encoded);
513
+ if (!isPeerMessage(message2)) {
430
514
  return { matched: false };
431
515
  }
432
- encoded = encoded.slice(options.prefix.length);
516
+ return { matched: true, message: message2 };
433
517
  }
434
- return { matched: true, message: JSON.parse(encoded) };
435
- }
436
- if (options.prefix) {
437
- const prefixBytes = textEncoder.encode(options.prefix);
438
- for (let i = 0; i < prefixBytes.length; i++) {
439
- if (encoded[i] !== prefixBytes[i]) {
518
+ if (options.prefix) {
519
+ const prefixBytes = textEncoder.encode(options.prefix);
520
+ for (let i = 0; i < prefixBytes.length; i++) {
521
+ if (encoded[i] !== prefixBytes[i]) {
522
+ return { matched: false };
523
+ }
524
+ }
525
+ encoded = encoded.subarray(prefixBytes.length);
526
+ }
527
+ const separatorIndex = encoded.indexOf(JSON_BINARY_DELIMITER);
528
+ if (separatorIndex === -1) {
529
+ const message2 = JSON.parse(textDecoder.decode(encoded));
530
+ if (!isPeerMessage(message2)) {
440
531
  return { matched: false };
441
532
  }
533
+ return { matched: true, message: message2 };
442
534
  }
443
- encoded = encoded.subarray(prefixBytes.length);
444
- }
445
- const separatorIndex = encoded.indexOf(JSON_BINARY_DELIMITER);
446
- if (separatorIndex === -1) {
447
- return { matched: true, message: JSON.parse(textDecoder.decode(encoded)) };
448
- }
449
- const jsonBytes = encoded.subarray(0, separatorIndex);
450
- const binaryBytes = encoded.subarray(separatorIndex + 1);
451
- return {
452
- matched: true,
453
- message: {
454
- ...JSON.parse(textDecoder.decode(jsonBytes)),
455
- binary: binaryBytes
535
+ const jsonBytes = encoded.subarray(0, separatorIndex);
536
+ const binaryBytes = encoded.subarray(separatorIndex + 1);
537
+ const message = JSON.parse(textDecoder.decode(jsonBytes));
538
+ if (!isPeerMessage(message)) {
539
+ return { matched: false };
456
540
  }
457
- };
541
+ message.binary = binaryBytes;
542
+ return { matched: true, message };
543
+ } catch {
544
+ return { matched: false };
545
+ }
458
546
  }
459
547
 
460
548
  class HibernationEventIterator extends AsyncIteratorClass {
@@ -466,8 +554,8 @@ class HibernationEventIterator extends AsyncIteratorClass {
466
554
  constructor(hibernationCallback) {
467
555
  super(async () => {
468
556
  throw new Error("Cannot use hibernating iterator directly");
469
- }, async (isCompleted) => {
470
- if (!isCompleted) {
557
+ }, async ({ isCancelled }) => {
558
+ if (isCancelled) {
471
559
  throw new Error("Cannot use hibernating iterator directly");
472
560
  }
473
561
  });
@@ -479,66 +567,48 @@ class ServerPeer {
479
567
  constructor(send) {
480
568
  this.send = send;
481
569
  }
482
- /**
483
- * Messages waiting to be processed
484
- */
485
- eventStreamMessageQueue = new AsyncIdQueue();
486
- octetStreamMessageQueue = new AsyncIdQueue();
487
- eventStreamTransmitters = /* @__PURE__ */ new Map();
488
- octetStreamTransmitters = /* @__PURE__ */ new Map();
489
- /**
490
- * Map of abort controllers for each request
491
- */
492
- controller = /* @__PURE__ */ new Map();
570
+ requests = /* @__PURE__ */ new Map();
493
571
  /**
494
572
  * Use for measure resources usage
495
573
  */
496
574
  get size() {
497
- return this.eventStreamMessageQueue.length + this.octetStreamMessageQueue.length + this.controller.size + this.eventStreamTransmitters.size + this.octetStreamTransmitters.size;
575
+ return this.requests.size;
498
576
  }
499
577
  /**
500
578
  * Handle a message from client
501
579
  */
502
580
  async message(message, handleRequest) {
503
- if (message.kind === "abort") {
504
- await this.close({ id: message.id, reason: new AbortError("Client peer aborted the request") });
581
+ const id = message.id;
582
+ if (message.kind === "cancel") {
583
+ await this.closeById(id, new AbortError("Client aborted the request"));
505
584
  return;
506
585
  }
507
586
  if (message.kind === "event-stream") {
508
- if (this.eventStreamMessageQueue.isOpen(message.id)) {
509
- this.eventStreamMessageQueue.push(message.id, message);
510
- }
587
+ this.requests.get(id)?.eventStreamMessageQueue?.push(message);
511
588
  return;
512
589
  }
513
590
  if (message.kind === "octet-stream") {
514
- if (this.octetStreamMessageQueue.isOpen(message.id)) {
515
- this.octetStreamMessageQueue.push(message.id, message);
516
- }
591
+ this.requests.get(id)?.octetStreamMessageQueue?.push(message);
592
+ return;
593
+ }
594
+ if (this.requests.has(id)) {
517
595
  return;
518
596
  }
519
- this.eventStreamMessageQueue.open(message.id);
520
- this.octetStreamMessageQueue.open(message.id);
521
597
  const controller = new AbortController();
522
- this.controller.set(message.id, controller);
598
+ const state = { controller };
599
+ this.requests.set(id, state);
523
600
  const signal = controller.signal;
524
601
  try {
525
- const request = {
526
- ...message.json,
527
- signal,
528
- body: await toStandardBody(
529
- message,
530
- this.eventStreamMessageQueue,
531
- this.octetStreamMessageQueue,
532
- async (isCompleted) => {
533
- this.eventStreamMessageQueue.close({ id: message.id });
534
- this.octetStreamMessageQueue.close({ id: message.id });
535
- if (!isCompleted && this.controller.has(message.id)) {
536
- await this.send({ id: message.id, kind: "stream/cancel" });
537
- }
538
- }
539
- )
540
- };
541
- const response = await handleRequest(request);
602
+ const decoded = toStandardBody(message, async ({ isCancelled }) => {
603
+ if (isCancelled && (state.eventStreamMessageQueue || state.octetStreamMessageQueue)) {
604
+ state.eventStreamMessageQueue = void 0;
605
+ state.octetStreamMessageQueue = void 0;
606
+ await this.send({ id, kind: "stream/cancel" });
607
+ }
608
+ });
609
+ state.eventStreamMessageQueue = decoded.eventStreamMessageQueue;
610
+ state.octetStreamMessageQueue = decoded.octetStreamMessageQueue;
611
+ const response = await handleRequest({ ...message.json, signal, resolveBody: decoded.resolveBody });
542
612
  if (signal.aborted) {
543
613
  return;
544
614
  }
@@ -549,13 +619,7 @@ class ServerPeer {
549
619
  const responseMessage = {
550
620
  id: message.id,
551
621
  kind: "response",
552
- json: {
553
- ...response,
554
- headers,
555
- body: jsonBody,
556
- ...{ signal: void 0 }
557
- // remove signal from request
558
- },
622
+ json: { ...response, headers, body: jsonBody },
559
623
  binary
560
624
  };
561
625
  await this.send(responseMessage);
@@ -567,50 +631,54 @@ class ServerPeer {
567
631
  response.body.hibernationCallback?.(message.id);
568
632
  } else {
569
633
  const transmitter = new EventStreamTransmitter(response.body, message.id, this.send);
570
- this.eventStreamTransmitters.set(message.id, transmitter);
634
+ state.eventStreamTransmitter = transmitter;
571
635
  await transmitter.transmit();
572
636
  }
573
637
  } else if (response.body instanceof ReadableStream) {
574
638
  const transmitter = new OctetStreamTransmitter(response.body, message.id, this.send);
575
- this.octetStreamTransmitters.set(message.id, transmitter);
639
+ state.octetStreamTransmitter = transmitter;
576
640
  await transmitter.transmit();
577
641
  }
578
- this.controller.delete(message.id);
579
- await this.close({ id: message.id });
642
+ state.controller = void 0;
643
+ await this.closeById(id);
580
644
  } catch (reason) {
581
645
  await Promise.all([
582
646
  /**
583
- * Do not need to send abort message if request was closed or aborted
647
+ * Do not need to send cancel message if request was closed or aborted
584
648
  */
585
- this.controller.has(message.id) ? this.send({ id: message.id, kind: "abort" }) : void 0,
586
- this.close({ id: message.id, reason })
649
+ this.requests.has(message.id) ? this.send({ id: message.id, kind: "cancel" }) : void 0,
650
+ this.closeById(id, reason)
587
651
  ]);
588
652
  throw reason;
589
653
  }
590
654
  }
591
- async close(options = {}) {
592
- const promises = [];
593
- this.eventStreamMessageQueue.close(options);
594
- this.octetStreamMessageQueue.close(options);
595
- if (options.id === void 0) {
596
- this.eventStreamTransmitters.forEach((t) => promises.push(t.cancel()));
597
- this.octetStreamTransmitters.forEach((t) => promises.push(t.cancel()));
598
- this.eventStreamTransmitters.clear();
599
- this.octetStreamTransmitters.clear();
600
- this.controller.forEach((c) => c.abort(options.reason));
601
- this.controller.clear();
602
- } else {
603
- promises.push(
604
- this.eventStreamTransmitters.get(options.id)?.cancel(),
605
- this.octetStreamTransmitters.get(options.id)?.cancel()
606
- );
607
- this.eventStreamTransmitters.delete(options.id);
608
- this.octetStreamTransmitters.delete(options.id);
609
- this.controller.get(options.id)?.abort(options.reason);
610
- this.controller.delete(options.id);
655
+ async close(reason) {
656
+ reason ??= new AbortError("Peer was closed");
657
+ await Promise.all(
658
+ Array.from(this.requests.keys()).map((id) => this.closeById(id, reason))
659
+ );
660
+ }
661
+ async closeById(id, reason) {
662
+ const state = this.requests.get(id);
663
+ if (!state) {
664
+ return;
611
665
  }
666
+ this.requests.delete(id);
667
+ reason ??= new AbortError("Request was closed");
668
+ state.controller?.abort(reason);
669
+ state.controller = void 0;
670
+ state.eventStreamMessageQueue?.close(reason);
671
+ state.octetStreamMessageQueue?.close(reason);
672
+ state.eventStreamMessageQueue = void 0;
673
+ state.octetStreamMessageQueue = void 0;
674
+ const promises = [
675
+ state.eventStreamTransmitter?.cancel(),
676
+ state.octetStreamTransmitter?.cancel()
677
+ ];
678
+ state.eventStreamTransmitter = void 0;
679
+ state.octetStreamTransmitter = void 0;
612
680
  await Promise.all(promises);
613
681
  }
614
682
  }
615
683
 
616
- export { ClientPeer, EventStreamTransmitter, HibernationEventIterator, ServerPeer, decodePeerMessage, encodePeerMessage, toEventIterator };
684
+ export { ClientPeer, EventStreamTransmitter, HibernationEventIterator, ServerPeer, decodePeerMessage, encodePeerMessage, isClientPeerSendMessage, isPeerCancelMessage, isPeerEventStreamMessage, isPeerMessage, isPeerOctetStreamMessage, isPeerRequestMessage, isPeerResponseMessage, isPeerStreamCancelMessage, isServerPeerSendMessage, toEventIterator };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@standardserver/peer",
3
3
  "type": "module",
4
- "version": "0.0.7",
4
+ "version": "0.0.8",
5
5
  "license": "MIT",
6
6
  "homepage": "https://standardserver.dev",
7
7
  "repository": {
@@ -20,8 +20,8 @@
20
20
  "dist"
21
21
  ],
22
22
  "dependencies": {
23
- "@standardserver/core": "0.0.7",
24
- "@standardserver/shared": "0.0.7"
23
+ "@standardserver/core": "0.0.8",
24
+ "@standardserver/shared": "0.0.8"
25
25
  },
26
26
  "scripts": {
27
27
  "build": "unbuild",