@standardserver/peer 0.0.1 → 0.0.3

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
@@ -202,22 +202,60 @@ declare class ClientPeer {
202
202
  close(options?: AsyncIdQueueCloseOptions): Promise<void>;
203
203
  }
204
204
 
205
+ interface EncodePeerMessageOptions {
206
+ /**
207
+ * Optional string prepended to the encoded message.
208
+ * Used to distinguish messages when multiple protocols share the same peer.
209
+ */
210
+ prefix?: string;
211
+ }
212
+ /**
213
+ * Encodes a {@link PeerMessage} into a wire-safe representation.
214
+ *
215
+ * Encoding rules:
216
+ * - If no binary payload is present, the message is encoded as a JSON string.
217
+ * - If binary data exists, the output layout is:
218
+ *
219
+ * [ UTF-8 (prefix + JSON) | delimiter byte | raw binary bytes ]
220
+ *
221
+ * The optional prefix is prepended to the JSON portion before encoding.
222
+ */
223
+ declare function encodePeerMessage(message: PeerMessage, options?: EncodePeerMessageOptions): Promise<string | Uint8Array<ArrayBuffer>>;
224
+ interface DecodePeerMessageOptions {
225
+ /**
226
+ * Optional prefix expected at the start of the encoded message.
227
+ * If present and the message does not start with this prefix,
228
+ * the decoder returns `matched: false`.
229
+ */
230
+ prefix?: string;
231
+ }
205
232
  /**
206
- * Encodes a PeerMessage into a wire-safe representation.
233
+ * Result of a decode attempt.
207
234
  *
208
- * - If no binary data is present, the message is encoded as a JSON string.
209
- * - If binary data exists, the output is:
210
- * [ UTF-8 JSON bytes | separator byte | raw binary bytes ]
235
+ * - `matched: false` indicates the input does not belong to this decoder
236
+ * (typically due to a prefix mismatch).
237
+ * - `matched: true` indicates successful decoding of a {@link PeerMessage}.
211
238
  */
212
- declare function encodePeerMessage(message: PeerMessage): Promise<string | Uint8Array<ArrayBuffer>>;
239
+ type DecodePeerMessageResult = {
240
+ matched: false;
241
+ message?: undefined;
242
+ } | {
243
+ matched: true;
244
+ message: PeerMessage;
245
+ };
213
246
  /**
214
- * Decodes a wire-encoded PeerMessage.
247
+ * Decodes a wire-encoded {@link PeerMessage}.
248
+ *
249
+ * Decoding rules:
250
+ * - String input is treated as a JSON-only message.
251
+ * - Binary input may contain:
252
+ * - JSON only, or
253
+ * - JSON followed by binary data separated by the delimiter byte.
215
254
  *
216
- * - String input is treated as pure JSON.
217
- * - Binary input may contain only JSON bytes, or JSON followed by binary data
218
- * separated by the separator byte.
255
+ * If a prefix is provided, it must be present at the start of the payload
256
+ * or the decode attempt will return `matched: false`.
219
257
  */
220
- declare function decodePeerMessage(data: string | Uint8Array<ArrayBuffer>): PeerMessage;
258
+ declare function decodePeerMessage(encoded: string | Uint8Array<ArrayBuffer>, options?: DecodePeerMessageOptions): DecodePeerMessageResult;
221
259
 
222
260
  /**
223
261
  * Creates an AsyncIterator from a queue of peer event-stream messages.
@@ -277,4 +315,4 @@ declare class ServerPeer {
277
315
  }
278
316
 
279
317
  export { ClientPeer, EventStreamTransmitter, HibernationEventIterator, ServerPeer, decodePeerMessage, encodePeerMessage, toEventIterator };
280
- export type { ClientPeerCloseOptions, HibernationEventIteratorCallback, PeerAbortMessage, PeerEventStreamMessage, PeerMessage, PeerOctetStreamMessage, PeerRequestMessage, PeerResponseMessage, PeerStreamCancelMessage, ServerPeerCloseOptions };
318
+ export type { ClientPeerCloseOptions, DecodePeerMessageOptions, DecodePeerMessageResult, EncodePeerMessageOptions, HibernationEventIteratorCallback, PeerAbortMessage, PeerEventStreamMessage, PeerMessage, PeerOctetStreamMessage, PeerRequestMessage, PeerResponseMessage, PeerStreamCancelMessage, ServerPeerCloseOptions };
package/dist/index.d.ts CHANGED
@@ -202,22 +202,60 @@ declare class ClientPeer {
202
202
  close(options?: AsyncIdQueueCloseOptions): Promise<void>;
203
203
  }
204
204
 
205
+ interface EncodePeerMessageOptions {
206
+ /**
207
+ * Optional string prepended to the encoded message.
208
+ * Used to distinguish messages when multiple protocols share the same peer.
209
+ */
210
+ prefix?: string;
211
+ }
212
+ /**
213
+ * Encodes a {@link PeerMessage} into a wire-safe representation.
214
+ *
215
+ * Encoding rules:
216
+ * - If no binary payload is present, the message is encoded as a JSON string.
217
+ * - If binary data exists, the output layout is:
218
+ *
219
+ * [ UTF-8 (prefix + JSON) | delimiter byte | raw binary bytes ]
220
+ *
221
+ * The optional prefix is prepended to the JSON portion before encoding.
222
+ */
223
+ declare function encodePeerMessage(message: PeerMessage, options?: EncodePeerMessageOptions): Promise<string | Uint8Array<ArrayBuffer>>;
224
+ interface DecodePeerMessageOptions {
225
+ /**
226
+ * Optional prefix expected at the start of the encoded message.
227
+ * If present and the message does not start with this prefix,
228
+ * the decoder returns `matched: false`.
229
+ */
230
+ prefix?: string;
231
+ }
205
232
  /**
206
- * Encodes a PeerMessage into a wire-safe representation.
233
+ * Result of a decode attempt.
207
234
  *
208
- * - If no binary data is present, the message is encoded as a JSON string.
209
- * - If binary data exists, the output is:
210
- * [ UTF-8 JSON bytes | separator byte | raw binary bytes ]
235
+ * - `matched: false` indicates the input does not belong to this decoder
236
+ * (typically due to a prefix mismatch).
237
+ * - `matched: true` indicates successful decoding of a {@link PeerMessage}.
211
238
  */
212
- declare function encodePeerMessage(message: PeerMessage): Promise<string | Uint8Array<ArrayBuffer>>;
239
+ type DecodePeerMessageResult = {
240
+ matched: false;
241
+ message?: undefined;
242
+ } | {
243
+ matched: true;
244
+ message: PeerMessage;
245
+ };
213
246
  /**
214
- * Decodes a wire-encoded PeerMessage.
247
+ * Decodes a wire-encoded {@link PeerMessage}.
248
+ *
249
+ * Decoding rules:
250
+ * - String input is treated as a JSON-only message.
251
+ * - Binary input may contain:
252
+ * - JSON only, or
253
+ * - JSON followed by binary data separated by the delimiter byte.
215
254
  *
216
- * - String input is treated as pure JSON.
217
- * - Binary input may contain only JSON bytes, or JSON followed by binary data
218
- * separated by the separator byte.
255
+ * If a prefix is provided, it must be present at the start of the payload
256
+ * or the decode attempt will return `matched: false`.
219
257
  */
220
- declare function decodePeerMessage(data: string | Uint8Array<ArrayBuffer>): PeerMessage;
258
+ declare function decodePeerMessage(encoded: string | Uint8Array<ArrayBuffer>, options?: DecodePeerMessageOptions): DecodePeerMessageResult;
221
259
 
222
260
  /**
223
261
  * Creates an AsyncIterator from a queue of peer event-stream messages.
@@ -277,4 +315,4 @@ declare class ServerPeer {
277
315
  }
278
316
 
279
317
  export { ClientPeer, EventStreamTransmitter, HibernationEventIterator, ServerPeer, decodePeerMessage, encodePeerMessage, toEventIterator };
280
- export type { ClientPeerCloseOptions, HibernationEventIteratorCallback, PeerAbortMessage, PeerEventStreamMessage, PeerMessage, PeerOctetStreamMessage, PeerRequestMessage, PeerResponseMessage, PeerStreamCancelMessage, ServerPeerCloseOptions };
318
+ export type { ClientPeerCloseOptions, DecodePeerMessageOptions, DecodePeerMessageResult, EncodePeerMessageOptions, HibernationEventIteratorCallback, PeerAbortMessage, PeerEventStreamMessage, PeerMessage, PeerOctetStreamMessage, PeerRequestMessage, PeerResponseMessage, PeerStreamCancelMessage, ServerPeerCloseOptions };
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AsyncIteratorClass, isTypescriptObject, isAsyncIteratorObject, SequentialIdGenerator, AsyncIdQueue, AbortError, stringifyJSON } from '@standardserver/shared';
2
2
  import { generateContentDisposition, flattenStandardHeader, getFilenameFromContentDisposition } from '@standardserver/core';
3
- import { withEventIteratorEventMeta, EventIteratorErrorEvent, resolveEventIteratorEvent } from '@standardserver/core/event-stream';
3
+ import { withEventIteratorEventMeta, EventIteratorErrorEvent, unwrapEventIteratorEvent } from '@standardserver/core/event-stream';
4
4
 
5
5
  function toEventIterator(pull, cleanup) {
6
6
  return new AsyncIteratorClass(async () => {
@@ -55,7 +55,7 @@ class EventStreamTransmitter {
55
55
  if (item.done) {
56
56
  this.isCompleted = true;
57
57
  }
58
- const [data, meta] = resolveEventIteratorEvent(item.value);
58
+ const [data, meta] = unwrapEventIteratorEvent(item.value);
59
59
  json = { ...meta, event: item.done ? "close" : "message", data };
60
60
  } catch (err) {
61
61
  if (err instanceof EventIteratorErrorEvent) {
@@ -63,7 +63,7 @@ class EventStreamTransmitter {
63
63
  return;
64
64
  }
65
65
  this.isCompleted = true;
66
- const [resolvedError, meta] = resolveEventIteratorEvent(err);
66
+ const [resolvedError, meta] = unwrapEventIteratorEvent(err);
67
67
  json = { ...meta, event: "error", data: resolvedError.data };
68
68
  } else {
69
69
  this.isCompleted = true;
@@ -403,36 +403,57 @@ class ClientPeer {
403
403
  }
404
404
  }
405
405
 
406
- const JSON_BINARY_SEPARATOR_BYTE = 255;
406
+ const JSON_BINARY_DELIMITER = 255;
407
407
  const textEncoder = new TextEncoder();
408
408
  const textDecoder = new TextDecoder();
409
- async function encodePeerMessage(message) {
409
+ async function encodePeerMessage(message, options = {}) {
410
+ const jsonPart = stringifyJSON({ ...message, binary: void 0 });
410
411
  if (message.binary === void 0) {
411
- return stringifyJSON(message);
412
+ return options.prefix ? options.prefix + jsonPart : jsonPart;
412
413
  }
413
- const jsonBytes = textEncoder.encode(stringifyJSON(message));
414
+ const textBytes = textEncoder.encode(
415
+ options.prefix ? options.prefix + jsonPart : jsonPart
416
+ );
414
417
  const binaryBytes = message.binary instanceof Blob ? new Uint8Array(await message.binary.arrayBuffer()) : message.binary;
415
418
  const output = new Uint8Array(
416
- jsonBytes.length + 1 + binaryBytes.length
419
+ textBytes.length + 1 + binaryBytes.length
417
420
  );
418
- output.set(jsonBytes, 0);
419
- output[jsonBytes.length] = JSON_BINARY_SEPARATOR_BYTE;
420
- output.set(binaryBytes, jsonBytes.length + 1);
421
+ output.set(textBytes, 0);
422
+ output[textBytes.length] = JSON_BINARY_DELIMITER;
423
+ output.set(binaryBytes, textBytes.length + 1);
421
424
  return output;
422
425
  }
423
- function decodePeerMessage(data) {
424
- if (typeof data === "string") {
425
- return JSON.parse(data);
426
+ function decodePeerMessage(encoded, options = {}) {
427
+ if (typeof encoded === "string") {
428
+ if (options.prefix) {
429
+ if (!encoded.startsWith(options.prefix)) {
430
+ return { matched: false };
431
+ }
432
+ encoded = encoded.slice(options.prefix.length);
433
+ }
434
+ return { matched: true, message: JSON.parse(encoded) };
426
435
  }
427
- const separatorIndex = data.indexOf(JSON_BINARY_SEPARATOR_BYTE);
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]) {
440
+ return { matched: false };
441
+ }
442
+ }
443
+ encoded = encoded.subarray(prefixBytes.length);
444
+ }
445
+ const separatorIndex = encoded.indexOf(JSON_BINARY_DELIMITER);
428
446
  if (separatorIndex === -1) {
429
- return JSON.parse(textDecoder.decode(data));
447
+ return { matched: true, message: JSON.parse(textDecoder.decode(encoded)) };
430
448
  }
431
- const jsonBytes = data.subarray(0, separatorIndex);
432
- const binaryBytes = data.subarray(separatorIndex + 1);
449
+ const jsonBytes = encoded.subarray(0, separatorIndex);
450
+ const binaryBytes = encoded.subarray(separatorIndex + 1);
433
451
  return {
434
- ...JSON.parse(textDecoder.decode(jsonBytes)),
435
- binary: binaryBytes
452
+ matched: true,
453
+ message: {
454
+ ...JSON.parse(textDecoder.decode(jsonBytes)),
455
+ binary: binaryBytes
456
+ }
436
457
  };
437
458
  }
438
459
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@standardserver/peer",
3
3
  "type": "module",
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
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.1",
24
- "@standardserver/shared": "0.0.1"
23
+ "@standardserver/core": "0.0.3",
24
+ "@standardserver/shared": "0.0.3"
25
25
  },
26
26
  "scripts": {
27
27
  "build": "unbuild",