@zlink-systems/framework 0.11.0 → 0.13.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.
Files changed (119) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Configuration/EndpointNotation.d.ts +5 -4
  3. package/dist/contracts/Configuration/EndpointNotation.js +5 -4
  4. package/dist/contracts/Configuration/InternalDefaults.d.ts +0 -1
  5. package/dist/contracts/Configuration/InternalDefaults.js +1 -2
  6. package/dist/contracts/Configuration/RegistrationNormalizers.js +1 -2
  7. package/dist/contracts/Configuration/RegistrationTypes.d.ts +2 -5
  8. package/dist/contracts/Configuration/RegistrationValidators.js +0 -1
  9. package/dist/contracts/Errors/ZLinkFrameworkException.d.ts +6 -7
  10. package/dist/contracts/Errors/ZLinkFrameworkException.js +6 -7
  11. package/dist/runtime/actors/actor-client.js +1 -1
  12. package/dist/runtime/actors/actor-mailbox.js +1 -5
  13. package/dist/runtime/backend/contracts/index.d.ts +2 -0
  14. package/dist/runtime/backend/mesh-completion-table.d.ts +1 -3
  15. package/dist/runtime/backend/mesh-completion-table.js +11 -15
  16. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +11 -4
  17. package/dist/runtime/backend/mesh-dispatch-pump.js +201 -134
  18. package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +3 -4
  19. package/dist/runtime/backend/node/node-backend-adapter-factory.js +51 -37
  20. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -2
  21. package/dist/runtime/backend/node/node-backend-adapter-support.js +2 -2
  22. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +2 -2
  23. package/dist/runtime/backend/node/node-event-loop-poller.d.ts +16 -0
  24. package/dist/runtime/backend/node/node-event-loop-poller.js +49 -0
  25. package/dist/runtime/backend/node/node-raw-binding-port.js +24 -41
  26. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +8 -8
  27. package/dist/runtime/backend/node/node-raw-mesh-backend.js +100 -107
  28. package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +3 -2
  29. package/dist/runtime/backend/node/node-socket-backend-adapter.js +18 -67
  30. package/dist/runtime/backend/raw-binding-port.d.ts +1 -0
  31. package/dist/runtime/backend/runtime-values.d.ts +5 -1
  32. package/dist/runtime/channels/channel-dispatchers.js +2 -2
  33. package/dist/runtime/channels/channel-envelope.js +324 -121
  34. package/dist/runtime/channels/channel-multipart.d.ts +8 -1
  35. package/dist/runtime/channels/channel-outbound-operations.js +0 -2
  36. package/dist/runtime/channels/channel-receive-loops.d.ts +1 -3
  37. package/dist/runtime/channels/channel-receive-loops.js +25 -65
  38. package/dist/runtime/channels/channel-socket-registry.js +3 -1
  39. package/dist/runtime/channels/channel-transports.d.ts +2 -1
  40. package/dist/runtime/channels/channel-transports.js +12 -10
  41. package/dist/runtime/execution/serial-execution-queue.d.ts +5 -18
  42. package/dist/runtime/execution/serial-execution-queue.js +16 -80
  43. package/dist/runtime/foundation/event-loop-resources.d.ts +0 -3
  44. package/dist/runtime/foundation/event-loop-resources.js +2 -11
  45. package/dist/runtime/foundation/operation-registry.d.ts +2 -8
  46. package/dist/runtime/foundation/operation-registry.js +3 -21
  47. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +19 -7
  48. package/dist/runtime/foundation/raw-service-mesh-runtime.js +56 -10
  49. package/dist/runtime/foundation/service-mailbox.d.ts +1 -7
  50. package/dist/runtime/foundation/service-mailbox.js +3 -2
  51. package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -1
  52. package/dist/runtime/foundation/service-stateful-registry.d.ts +1 -1
  53. package/dist/runtime/foundation/service-stateful-registry.js +2 -2
  54. package/dist/runtime/foundation/service-stateful-runtime.js +14 -14
  55. package/dist/runtime/framework-errors-internal.d.ts +4 -4
  56. package/dist/runtime/framework-errors-internal.js +8 -10
  57. package/dist/runtime/host/actor-placement-coordinator.js +1 -1
  58. package/dist/runtime/host/index.js +1 -1
  59. package/dist/runtime/host/service-relocation-host-runtime.js +0 -4
  60. package/dist/runtime/host/spot-address-transport.js +1 -1
  61. package/dist/runtime/host/user-spot-creation-coordinator.js +1 -1
  62. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +0 -12
  63. package/dist/runtime/spots/spot-node-runtime-manager.js +6 -166
  64. package/dist/runtime/spots/spot-serial-turn-executor.js +1 -4
  65. package/dist/runtime/spots/spot-timer.d.ts +3 -0
  66. package/dist/runtime/spots/spot-timer.js +87 -18
  67. package/dist/runtime/streams/session-serial-executor.js +1 -3
  68. package/dist/runtime/streams/stream-session-runtime.d.ts +2 -2
  69. package/dist/runtime/streams/stream-session-runtime.js +13 -19
  70. package/dist/runtime/workers/index.d.ts +0 -1
  71. package/dist/runtime/workers/index.js +1 -9
  72. package/package.json +3 -3
  73. package/src/contracts/Configuration/EndpointNotation.ts +5 -4
  74. package/src/contracts/Configuration/InternalDefaults.ts +0 -1
  75. package/src/contracts/Configuration/RegistrationNormalizers.ts +2 -4
  76. package/src/contracts/Configuration/RegistrationTypes.ts +2 -5
  77. package/src/contracts/Configuration/RegistrationValidators.ts +0 -1
  78. package/src/contracts/Errors/ZLinkFrameworkException.ts +6 -7
  79. package/src/runtime/actors/actor-client.ts +1 -1
  80. package/src/runtime/actors/actor-mailbox.ts +1 -12
  81. package/src/runtime/backend/contracts/index.ts +2 -0
  82. package/src/runtime/backend/mesh-completion-table.ts +12 -23
  83. package/src/runtime/backend/mesh-dispatch-pump.ts +206 -138
  84. package/src/runtime/backend/node/node-backend-adapter-factory.ts +66 -35
  85. package/src/runtime/backend/node/node-backend-adapter-support.ts +4 -4
  86. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +2 -2
  87. package/src/runtime/backend/node/node-event-loop-poller.ts +55 -0
  88. package/src/runtime/backend/node/node-raw-binding-port.ts +30 -45
  89. package/src/runtime/backend/node/node-raw-mesh-backend.ts +97 -110
  90. package/src/runtime/backend/node/node-socket-backend-adapter.ts +23 -69
  91. package/src/runtime/backend/raw-binding-port.ts +1 -0
  92. package/src/runtime/backend/runtime-values.ts +7 -1
  93. package/src/runtime/channels/channel-dispatchers.ts +2 -2
  94. package/src/runtime/channels/channel-envelope.ts +379 -109
  95. package/src/runtime/channels/channel-multipart.ts +9 -1
  96. package/src/runtime/channels/channel-outbound-operations.ts +0 -1
  97. package/src/runtime/channels/channel-receive-loops.ts +24 -75
  98. package/src/runtime/channels/channel-socket-registry.ts +4 -1
  99. package/src/runtime/channels/channel-transports.ts +20 -10
  100. package/src/runtime/execution/serial-execution-queue.ts +16 -108
  101. package/src/runtime/foundation/event-loop-resources.ts +2 -11
  102. package/src/runtime/foundation/operation-registry.ts +2 -22
  103. package/src/runtime/foundation/raw-service-mesh-runtime.ts +74 -19
  104. package/src/runtime/foundation/service-mailbox.ts +3 -13
  105. package/src/runtime/foundation/service-runtime-contracts.ts +2 -1
  106. package/src/runtime/foundation/service-stateful-registry.ts +2 -2
  107. package/src/runtime/foundation/service-stateful-runtime.ts +14 -14
  108. package/src/runtime/framework-errors-internal.ts +8 -10
  109. package/src/runtime/host/actor-placement-coordinator.ts +1 -1
  110. package/src/runtime/host/index.ts +2 -1
  111. package/src/runtime/host/service-relocation-host-runtime.ts +0 -4
  112. package/src/runtime/host/spot-address-transport.ts +1 -1
  113. package/src/runtime/host/user-spot-creation-coordinator.ts +1 -1
  114. package/src/runtime/spots/spot-node-runtime-manager.ts +13 -233
  115. package/src/runtime/spots/spot-serial-turn-executor.ts +1 -8
  116. package/src/runtime/spots/spot-timer.ts +109 -18
  117. package/src/runtime/streams/session-serial-executor.ts +1 -7
  118. package/src/runtime/streams/stream-session-runtime.ts +13 -17
  119. package/src/runtime/workers/index.ts +2 -17
@@ -40,22 +40,7 @@ function encodeChannelEnvelopeParts(kind, channelName, packetName, payload, time
40
40
  const encoded = encodePayload(payload, (0, channel_framework_packets_1.codecsForFrameworkPacket)(messageName, codecs), messageName, 'payload');
41
41
  const flow = createFlow ? (0, flow_context_1.currentOrCreateFlow)('Application') : undefined;
42
42
  const envelopeCorrelationId = correlationIdForOutboundKind(kind, correlationId);
43
- const header = {
44
- formatMarker: exports.ZLINK_CHANNEL_FORMAT_MARKER,
45
- kind,
46
- channelName,
47
- messageName,
48
- contentType: encoded.contentType,
49
- correlationId: envelopeCorrelationId,
50
- deadline: timeoutMs === undefined ? null : new Date(Date.now() + timeoutMs).toISOString(),
51
- topic: topic ?? null,
52
- errorCode: null,
53
- errorMessage: null,
54
- metadata: applicationMetadataRecord(metadata),
55
- flowId: flow?.flowId,
56
- flowOrigin: flow?.flowOrigin
57
- };
58
- return [encodeChannelHeader(header), encoded.message];
43
+ return [encodeChannelHeader(kind, channelName, messageName, encoded.contentType, envelopeCorrelationId, timeoutMs === undefined ? null : new Date(Date.now() + timeoutMs).toISOString(), topic ?? null, null, null, undefined, applicationMetadataRecord(metadata), flow?.flowId, flow?.flowOrigin), encoded.message];
59
44
  }
60
45
  /**
61
46
  * Encodes an outbound channel envelope with a deadline that was established
@@ -71,60 +56,17 @@ function encodeChannelEnvelopePartsAtDeadline(kind, channelName, packetName, pay
71
56
  const encoded = encodePayload(payload, (0, channel_framework_packets_1.codecsForFrameworkPacket)(messageName, codecs), messageName, 'payload');
72
57
  const flow = createFlow ? (0, flow_context_1.currentOrCreateFlow)('Application') : undefined;
73
58
  const envelopeCorrelationId = correlationIdForOutboundKind(kind, correlationId);
74
- const header = {
75
- formatMarker: exports.ZLINK_CHANNEL_FORMAT_MARKER,
76
- kind,
77
- channelName,
78
- messageName,
79
- contentType: encoded.contentType,
80
- correlationId: envelopeCorrelationId,
81
- deadline: new Date(deadlineUnixMs).toISOString(),
82
- topic: topic ?? null,
83
- errorCode: null,
84
- errorMessage: null,
85
- metadata: applicationMetadataRecord(metadata),
86
- flowId: flow?.flowId,
87
- flowOrigin: flow?.flowOrigin
88
- };
89
- return [encodeChannelHeader(header), encoded.message];
59
+ return [encodeChannelHeader(kind, channelName, messageName, encoded.contentType, envelopeCorrelationId, new Date(deadlineUnixMs).toISOString(), topic ?? null, null, null, undefined, applicationMetadataRecord(metadata), flow?.flowId, flow?.flowOrigin), encoded.message];
90
60
  }
91
61
  function encodeChannelPublishEnvelopeParts(channelName, topic, packetName, payload, codecs, createFlow = true, metadata = EMPTY_OUTBOUND_METADATA) {
92
62
  const messageName = (0, packet_name_1.resolveFrameworkPacketName)(payload, packetName, 'Channel');
93
63
  const encoded = encodePayload(payload, (0, channel_framework_packets_1.codecsForFrameworkPacket)(messageName, codecs), messageName, 'payload');
94
64
  const flow = createFlow ? (0, flow_context_1.currentOrCreateFlow)('Application') : undefined;
95
- const header = {
96
- formatMarker: exports.ZLINK_CHANNEL_FORMAT_MARKER,
97
- kind: 4 /* ZLinkChannelMessageKind.Publish */,
98
- channelName,
99
- messageName,
100
- contentType: encoded.contentType,
101
- correlationId: null,
102
- deadline: null,
103
- topic,
104
- errorCode: null,
105
- errorMessage: null,
106
- metadata: applicationMetadataRecord(metadata),
107
- flowId: flow?.flowId,
108
- flowOrigin: flow?.flowOrigin
109
- };
110
- return [encodeChannelHeader(header), encoded.message];
65
+ return [encodeChannelHeader(4 /* ZLinkChannelMessageKind.Publish */, channelName, messageName, encoded.contentType, null, null, topic, null, null, undefined, applicationMetadataRecord(metadata), flow?.flowId, flow?.flowOrigin), encoded.message];
111
66
  }
112
67
  function encodeChannelReplyParts(request, payload, codecs) {
113
68
  const encoded = encodePayload(payload ?? Buffer.alloc(0), (0, channel_framework_packets_1.codecsForFrameworkPacket)(request.messageName, codecs), request.messageName, 'reply');
114
- const header = {
115
- formatMarker: exports.ZLINK_CHANNEL_FORMAT_MARKER,
116
- kind: 2 /* ZLinkChannelMessageKind.Response */,
117
- channelName: request.channelName,
118
- messageName: request.messageName,
119
- contentType: encoded.contentType,
120
- correlationId: request.correlationId,
121
- deadline: null,
122
- topic: null,
123
- metadata: {},
124
- flowId: request.flowId,
125
- flowOrigin: request.flowOrigin
126
- };
127
- return [encodeChannelHeader(header), encoded.message];
69
+ return [encodeChannelHeader(2 /* ZLinkChannelMessageKind.Response */, request.channelName, request.messageName, encoded.contentType, request.correlationId, null, null, undefined, undefined, undefined, EMPTY_APPLICATION_METADATA, request.flowId, request.flowOrigin), encoded.message];
128
70
  }
129
71
  /**
130
72
  * Reply metadata marker for errors the framework generated itself (never for
@@ -147,13 +89,12 @@ const ERROR_KIND_WIRE_NAMES = [
147
89
  'not_configured', // 3
148
90
  'rejected', // 4
149
91
  'unavailable', // 5
150
- 'capacity_exceeded', // 6
151
- 'deadline_exceeded', // 7
152
- 'shutting_down', // 8
153
- 'protocol_error', // 9
154
- 'invalid_operation', // 10
155
- 'data_lost', // 11
156
- 'internal_failure' // 12
92
+ 'deadline_exceeded', // 6
93
+ 'shutting_down', // 7
94
+ 'protocol_error', // 8
95
+ 'invalid_operation', // 9
96
+ 'data_lost', // 10
97
+ 'internal_failure' // 11
157
98
  ];
158
99
  const ERROR_KIND_BY_WIRE_NAME = new Map(ERROR_KIND_WIRE_NAMES.map((name, kind) => [name, kind]));
159
100
  function channelErrorCodeName(kind) {
@@ -164,22 +105,7 @@ function encodeChannelErrorReplyParts(request, error, metadata = {}) {
164
105
  ? error.kind
165
106
  : contracts_1.ZLinkFrameworkErrorKind.InternalFailure);
166
107
  const errorMessage = error instanceof Error ? error.message : String(error);
167
- const header = {
168
- formatMarker: exports.ZLINK_CHANNEL_FORMAT_MARKER,
169
- kind: 5 /* ZLinkChannelMessageKind.Error */,
170
- channelName: request.channelName,
171
- messageName: request.messageName,
172
- contentType: exports.JSON_CONTENT_TYPE,
173
- correlationId: request.correlationId,
174
- deadline: null,
175
- topic: null,
176
- errorCode,
177
- errorMessage,
178
- metadata,
179
- flowId: request.flowId,
180
- flowOrigin: request.flowOrigin
181
- };
182
- return [encodeChannelHeader(header), encodeJsonBytes(null)];
108
+ return [encodeChannelHeader(5 /* ZLinkChannelMessageKind.Error */, request.channelName, request.messageName, exports.JSON_CONTENT_TYPE, request.correlationId, null, null, errorCode, errorMessage, undefined, metadata, request.flowId, request.flowOrigin), encodeJsonBytes(null)];
183
109
  }
184
110
  function decodeChannelReply(parts, codecs) {
185
111
  const header = decodeChannelHeader(parts);
@@ -335,25 +261,145 @@ function isMessage(value) {
335
261
  function encodeJsonBytes(value, schema) {
336
262
  return Buffer.from((0, framework_json_v1_1.stringifyFrameworkJsonV1)(value, schema));
337
263
  }
338
- function encodeChannelHeader(header) {
339
- // Explicit construction: this runs for every outbound envelope, so avoid a
340
- // per-message spread of the whole header.
341
- return encodeJsonBytes({
342
- formatMarker: header.formatMarker,
343
- kind: header.kind,
344
- channelName: header.channelName,
345
- messageName: header.messageName,
346
- contentType: header.contentType,
347
- correlationId: header.correlationId,
348
- deadline: header.deadline,
349
- topic: header.topic,
350
- errorCode: header.errorCode,
351
- errorMessage: header.errorMessage,
352
- source: header.source,
353
- metadata: header.metadata,
354
- flowId: header.flowId,
355
- flowOrigin: header.flowOrigin === undefined ? undefined : encodeFlowOrigin(header.flowOrigin)
356
- });
264
+ function encodeChannelHeader(kind, channelName, messageName, contentType, correlationId, deadline, topic, errorCode, errorMessage, source, metadata, flowId, flowOrigin) {
265
+ // The wire has a fixed field order. Measure escaped UTF-8 first, then write
266
+ // each field once into the only header Buffer: no header object, whole JSON
267
+ // string, or post-encode byte copy exists on the outbound path.
268
+ const measure = new ChannelHeaderWriter();
269
+ writeChannelHeader(measure, kind, channelName, messageName, contentType, correlationId, deadline, topic, errorCode, errorMessage, source, metadata, flowId, flowOrigin);
270
+ const result = Buffer.alloc(measure.byteLength);
271
+ const writer = new ChannelHeaderWriter(result);
272
+ writeChannelHeader(writer, kind, channelName, messageName, contentType, correlationId, deadline, topic, errorCode, errorMessage, source, metadata, flowId, flowOrigin);
273
+ return result;
274
+ }
275
+ function writeChannelHeader(writer, kind, channelName, messageName, contentType, correlationId, deadline, topic, errorCode, errorMessage, source, metadata, flowId, flowOrigin) {
276
+ writer.append('{"formatMarker":');
277
+ writer.append(String(exports.ZLINK_CHANNEL_FORMAT_MARKER));
278
+ writer.append(',"kind":');
279
+ writer.append(String(kind));
280
+ writer.append(',"channelName":');
281
+ writer.string(channelName);
282
+ writer.append(',"messageName":');
283
+ writer.string(messageName);
284
+ writer.append(',"contentType":');
285
+ writer.string(contentType);
286
+ writer.append(',"correlationId":');
287
+ writer.nullableString(correlationId);
288
+ writer.append(',"deadline":');
289
+ writer.nullableString(deadline);
290
+ writer.append(',"topic":');
291
+ writer.nullableString(topic);
292
+ if (errorCode !== undefined) {
293
+ writer.append(',"errorCode":');
294
+ writer.nullableString(errorCode);
295
+ }
296
+ if (errorMessage !== undefined) {
297
+ writer.append(',"errorMessage":');
298
+ writer.nullableString(errorMessage);
299
+ }
300
+ if (source !== undefined) {
301
+ writer.append(',"source":');
302
+ writer.nullableString(source);
303
+ }
304
+ writer.append(',"metadata":{');
305
+ let first = true;
306
+ for (const name in metadata) {
307
+ if (!Object.prototype.hasOwnProperty.call(metadata, name))
308
+ continue;
309
+ if (!first)
310
+ writer.append(',');
311
+ first = false;
312
+ writer.string(name);
313
+ writer.append(':');
314
+ writer.string(metadata[name]);
315
+ }
316
+ writer.append('}');
317
+ if (flowId !== undefined) {
318
+ writer.append(',"flowId":');
319
+ writer.string(flowId);
320
+ }
321
+ if (flowOrigin !== undefined) {
322
+ writer.append(',"flowOrigin":');
323
+ writer.append(String(encodeFlowOrigin(flowOrigin)));
324
+ }
325
+ writer.append('}');
326
+ }
327
+ class ChannelHeaderWriter {
328
+ output;
329
+ offset = 0;
330
+ constructor(output) {
331
+ this.output = output;
332
+ }
333
+ get byteLength() {
334
+ return this.offset;
335
+ }
336
+ append(value) {
337
+ if (this.output === undefined) {
338
+ this.offset += Buffer.byteLength(value);
339
+ return;
340
+ }
341
+ this.offset += this.output.write(value, this.offset, 'utf8');
342
+ }
343
+ nullableString(value) {
344
+ if (value === null)
345
+ this.append('null');
346
+ else
347
+ this.string(value);
348
+ }
349
+ string(value) {
350
+ this.append('"');
351
+ let start = 0;
352
+ for (let index = 0; index < value.length; index += 1) {
353
+ const code = value.charCodeAt(index);
354
+ let escaped;
355
+ switch (code) {
356
+ case 0x08:
357
+ escaped = '\\b';
358
+ break;
359
+ case 0x09:
360
+ escaped = '\\t';
361
+ break;
362
+ case 0x0a:
363
+ escaped = '\\n';
364
+ break;
365
+ case 0x0c:
366
+ escaped = '\\f';
367
+ break;
368
+ case 0x0d:
369
+ escaped = '\\r';
370
+ break;
371
+ case 0x22:
372
+ escaped = '\\"';
373
+ break;
374
+ case 0x5c:
375
+ escaped = '\\\\';
376
+ break;
377
+ default:
378
+ if (code < 0x20) {
379
+ escaped = `\\u00${code.toString(16).padStart(2, '0')}`;
380
+ }
381
+ else if (code >= 0xd800 && code <= 0xdbff) {
382
+ const next = value.charCodeAt(index + 1);
383
+ if (next >= 0xdc00 && next <= 0xdfff) {
384
+ index += 1;
385
+ }
386
+ else {
387
+ escaped = `\\u${code.toString(16)}`;
388
+ }
389
+ }
390
+ else if (code >= 0xdc00 && code <= 0xdfff) {
391
+ escaped = `\\u${code.toString(16)}`;
392
+ }
393
+ }
394
+ if (escaped === undefined)
395
+ continue;
396
+ this.append(value.slice(start, index));
397
+ this.append(escaped);
398
+ start = index + 1;
399
+ }
400
+ this.append(value.slice(start));
401
+ this.append('"');
402
+ }
357
403
  }
358
404
  function encodeFlowOrigin(origin) {
359
405
  switch (origin) {
@@ -367,13 +413,173 @@ function decodeChannelHeader(parts, flowEnabled = true) {
367
413
  if (parts.length === 0) {
368
414
  throw new configuration_1.ZLinkConfigurationException('Channel envelope header part is missing.');
369
415
  }
370
- return validateChannelHeader(parseWireJson(parts[0].data().toString()), flowEnabled);
416
+ return validateChannelHeader(parseChannelHeaderBytes(parts[0].data()), flowEnabled);
371
417
  }
372
418
  function parseWireJson(payload, schema) {
373
419
  return (0, framework_json_v1_1.parseFrameworkJsonV1)(payload, {
374
420
  rejectPropertyName: isPrototypeKey
375
421
  }, schema);
376
422
  }
423
+ function parseChannelHeaderBytes(payload) {
424
+ return tryParseCanonicalChannelHeader(payload) ?? parseWireJson(payload.toString());
425
+ }
426
+ /**
427
+ * Accept the byte layout emitted by writeChannelHeader without materializing
428
+ * the enclosing JSON text. Any variation falls through to the established
429
+ * framework-json-v1 parser, which remains the sole authority for JSON
430
+ * failures, unknown properties, and prototype-key rejection.
431
+ */
432
+ function tryParseCanonicalChannelHeader(payload) {
433
+ const reader = new CanonicalChannelHeaderReader(payload);
434
+ if (!reader.consume('{"formatMarker":242,"kind":'))
435
+ return undefined;
436
+ const kind = reader.readSingleDigit();
437
+ if (kind === undefined || !reader.consume(',"channelName":'))
438
+ return undefined;
439
+ const channelName = reader.readString();
440
+ if (channelName === undefined || !reader.consume(',"messageName":'))
441
+ return undefined;
442
+ const messageName = reader.readString();
443
+ if (messageName === undefined || !reader.consume(',"contentType":'))
444
+ return undefined;
445
+ const contentType = reader.readString();
446
+ if (contentType === undefined || !reader.consume(',"correlationId":'))
447
+ return undefined;
448
+ const correlationId = reader.readNullableString();
449
+ if (correlationId === undefined || !reader.consume(',"deadline":'))
450
+ return undefined;
451
+ const deadline = reader.readNullableString();
452
+ if (deadline === undefined || !reader.consume(',"topic":'))
453
+ return undefined;
454
+ const topic = reader.readNullableString();
455
+ if (topic === undefined)
456
+ return undefined;
457
+ const header = {
458
+ formatMarker: exports.ZLINK_CHANNEL_FORMAT_MARKER,
459
+ kind,
460
+ channelName,
461
+ messageName,
462
+ contentType,
463
+ correlationId: correlationId === NULL_JSON_STRING ? null : correlationId,
464
+ deadline: deadline === NULL_JSON_STRING ? null : deadline,
465
+ topic: topic === NULL_JSON_STRING ? null : topic
466
+ };
467
+ if (!reader.readOptionalNullableString('errorCode', header))
468
+ return undefined;
469
+ if (!reader.readOptionalNullableString('errorMessage', header))
470
+ return undefined;
471
+ if (!reader.readOptionalNullableString('source', header))
472
+ return undefined;
473
+ if (!reader.consume(',"metadata":{}'))
474
+ return undefined;
475
+ header.metadata = {};
476
+ if (!reader.readOptionalString('flowId', header))
477
+ return undefined;
478
+ if (!reader.readOptionalSingleDigit('flowOrigin', header))
479
+ return undefined;
480
+ return reader.consume('}') && reader.atEnd() ? header : undefined;
481
+ }
482
+ const NULL_JSON_STRING = Symbol('null JSON string');
483
+ class CanonicalChannelHeaderReader {
484
+ bytes;
485
+ index = 0;
486
+ constructor(bytes) {
487
+ this.bytes = bytes;
488
+ }
489
+ atEnd() {
490
+ return this.index === this.bytes.length;
491
+ }
492
+ consume(value) {
493
+ if (this.index + value.length > this.bytes.length)
494
+ return false;
495
+ for (let offset = 0; offset < value.length; offset += 1) {
496
+ if (this.bytes[this.index + offset] !== value.charCodeAt(offset))
497
+ return false;
498
+ }
499
+ this.index += value.length;
500
+ return true;
501
+ }
502
+ readSingleDigit() {
503
+ if (this.index === this.bytes.length)
504
+ return undefined;
505
+ const value = this.bytes[this.index];
506
+ if (value < 0x30 || value > 0x39)
507
+ return undefined;
508
+ this.index += 1;
509
+ return value - 0x30;
510
+ }
511
+ readString() {
512
+ if (this.bytes[this.index] !== 0x22)
513
+ return undefined;
514
+ const start = this.index;
515
+ this.index += 1;
516
+ while (this.index < this.bytes.length) {
517
+ const value = this.bytes[this.index++];
518
+ if (value === 0x22) {
519
+ return JSON.parse(this.bytes.toString('utf8', start, this.index));
520
+ }
521
+ if (value < 0x20)
522
+ return undefined;
523
+ if (value !== 0x5c)
524
+ continue;
525
+ if (this.index === this.bytes.length)
526
+ return undefined;
527
+ const escaped = this.bytes[this.index++];
528
+ if (escaped === 0x75) {
529
+ for (let count = 0; count < 4; count += 1) {
530
+ if (this.index === this.bytes.length)
531
+ return undefined;
532
+ const digit = this.bytes[this.index++];
533
+ if (!isHexDigit(digit))
534
+ return undefined;
535
+ }
536
+ }
537
+ else if (escaped !== 0x22 && escaped !== 0x5c && escaped !== 0x2f
538
+ && escaped !== 0x62 && escaped !== 0x66 && escaped !== 0x6e
539
+ && escaped !== 0x72 && escaped !== 0x74) {
540
+ return undefined;
541
+ }
542
+ }
543
+ return undefined;
544
+ }
545
+ readNullableString() {
546
+ if (this.consume('null'))
547
+ return NULL_JSON_STRING;
548
+ return this.readString();
549
+ }
550
+ readOptionalNullableString(name, target) {
551
+ if (!this.consume(`,\"${name}\":`))
552
+ return true;
553
+ const value = this.readNullableString();
554
+ if (value === undefined)
555
+ return false;
556
+ target[name] = value === NULL_JSON_STRING ? null : value;
557
+ return true;
558
+ }
559
+ readOptionalString(name, target) {
560
+ if (!this.consume(`,\"${name}\":`))
561
+ return true;
562
+ const value = this.readString();
563
+ if (value === undefined)
564
+ return false;
565
+ target[name] = value;
566
+ return true;
567
+ }
568
+ readOptionalSingleDigit(name, target) {
569
+ if (!this.consume(`,\"${name}\":`))
570
+ return true;
571
+ const value = this.readSingleDigit();
572
+ if (value === undefined)
573
+ return false;
574
+ target[name] = value;
575
+ return true;
576
+ }
577
+ }
578
+ function isHexDigit(value) {
579
+ return (value >= 0x30 && value <= 0x39)
580
+ || (value >= 0x41 && value <= 0x46)
581
+ || (value >= 0x61 && value <= 0x66);
582
+ }
377
583
  function schemaForInboundChannelEnvelope(header) {
378
584
  const contract = (0, Attributes_1.readZLinkPacketJsonContract)(header.messageName);
379
585
  return header.kind === 2 /* ZLinkChannelMessageKind.Response */ ? contract?.reply : contract?.payload;
@@ -401,22 +607,19 @@ function validateChannelHeader(value, flowEnabled = true) {
401
607
  }
402
608
  const correlationId = requireNullableString(header.correlationId, 'correlationId');
403
609
  validateCorrelationForKind(kind, correlationId);
404
- return {
405
- formatMarker: exports.ZLINK_CHANNEL_FORMAT_MARKER,
406
- kind,
407
- channelName: requireString(header.channelName, 'channelName'),
408
- messageName: requireString(header.messageName, 'messageName'),
409
- contentType,
410
- correlationId,
411
- deadline: requireNullableString(header.deadline, 'deadline'),
412
- topic: requireNullableString(header.topic, 'topic'),
413
- errorCode: header.errorCode === undefined ? null : requireNullableString(header.errorCode, 'errorCode'),
414
- errorMessage: header.errorMessage === undefined ? null : requireNullableString(header.errorMessage, 'errorMessage'),
415
- source: header.source === undefined ? undefined : requireNullableString(header.source, 'source'),
416
- metadata: requireApplicationMetadata(header.metadata),
417
- flowId,
418
- flowOrigin
419
- };
610
+ requireString(header.channelName, 'channelName');
611
+ requireString(header.messageName, 'messageName');
612
+ requireNullableString(header.deadline, 'deadline');
613
+ requireNullableString(header.topic, 'topic');
614
+ // Parsing already gives this receive operation an owned object. Validate
615
+ // and normalize it here instead of allocating a second header per record.
616
+ header.errorCode = header.errorCode === undefined ? null : requireNullableString(header.errorCode, 'errorCode');
617
+ header.errorMessage = header.errorMessage === undefined ? null : requireNullableString(header.errorMessage, 'errorMessage');
618
+ header.source = header.source === undefined ? undefined : requireNullableString(header.source, 'source');
619
+ header.metadata = requireApplicationMetadata(header.metadata);
620
+ header.flowId = flowId;
621
+ header.flowOrigin = flowOrigin;
622
+ return header;
420
623
  }
421
624
  function correlationIdForOutboundKind(kind, correlationId) {
422
625
  if (kind === 1 /* ZLinkChannelMessageKind.Request */) {
@@ -6,8 +6,15 @@ export interface ZLinkMultipartOperation<TNext> {
6
6
  export interface ZLinkMultipartSubmitOperation extends ZLinkMultipartOperation<ZLinkMultipartSubmitOperation> {
7
7
  submit(): unknown;
8
8
  }
9
+ /**
10
+ * Binding submit()은 제출 스냅샷을 돌려준다. admission을 기다리려면 `.admitted`를
11
+ * await 한다. binding 타입과 구조적으로 호환되므로 import 하지 않는다.
12
+ */
13
+ export interface ZLinkMultipartSubmission {
14
+ readonly admitted: Promise<void>;
15
+ }
9
16
  export interface ZLinkMultipartAsyncSubmitOperation extends ZLinkMultipartOperation<ZLinkMultipartAsyncSubmitOperation> {
10
- submit(): Promise<void>;
17
+ submit(): ZLinkMultipartSubmission;
11
18
  }
12
19
  export type ZLinkMultipartReplyOperation = ZLinkMultipartSubmitOperation;
13
20
  export declare function appendParts<TNext extends ZLinkMultipartOperation<TNext>>(operation: ZLinkMultipartOperation<TNext>, parts: readonly MessageLike[]): TNext;
@@ -331,8 +331,6 @@ function requestTerminalResult(error, signal) {
331
331
  if (error instanceof contracts_1.ZLinkFrameworkException) {
332
332
  if (error.kind === contracts_1.ZLinkFrameworkErrorKind.ShuttingDown)
333
333
  return 'shutdown';
334
- if (error.kind === contracts_1.ZLinkFrameworkErrorKind.CapacityExceeded)
335
- return 'backpressured';
336
334
  }
337
335
  return 'failed';
338
336
  }
@@ -1,6 +1,7 @@
1
1
  import type { Message } from '../../contracts/Common/Message';
2
2
  import type { ZLinkBackendMessageLike as MessageLike } from '../backend/runtime-values';
3
3
  import type { ZLinkBackendRouterSocket, ZLinkBackendSpotRouteBridge, ZLinkBackendSubscriberSocket, ZLinkBackendReadablePoller, ZLinkChannelBackendAdapter } from '../backend/contracts';
4
+ import type { ZLinkMultipartAsyncSubmitOperation } from './channel-multipart';
4
5
  import type { ZLinkChannelEnvelopeHeader } from './channel-envelope';
5
6
  import { type ZLinkReceiveTaskErrorReporter } from './channel-receive-task-tracker';
6
7
  import { ApplicationJobQueue } from '../host/application-job-queue';
@@ -10,9 +11,6 @@ interface ZLinkMultipartOperation<TNext> {
10
11
  interface ZLinkMultipartSubmitOperation extends ZLinkMultipartOperation<ZLinkMultipartSubmitOperation> {
11
12
  submit(): unknown;
12
13
  }
13
- interface ZLinkMultipartAsyncSubmitOperation extends ZLinkMultipartOperation<ZLinkMultipartAsyncSubmitOperation> {
14
- submit(): Promise<void>;
15
- }
16
14
  type ZLinkMultipartReplyOperation = ZLinkMultipartSubmitOperation;
17
15
  interface ZLinkChannelRequestDispatchLoop {
18
16
  /** Spec 27 §4: with tracing Off, inbound flow fields are neither validated nor carried forward. */