@zlink-systems/framework 0.30.0 → 0.30.1

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 (245) hide show
  1. package/LICENSE +150 -68
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/contracts/Actors/ZLinkActorClient.d.ts +2 -1
  4. package/dist/contracts/Channels/Calls.d.ts +2 -1
  5. package/dist/contracts/Common/ZLinkMessageMetadata.js +11 -5
  6. package/dist/contracts/Handlers/Attributes.d.ts +5 -13
  7. package/dist/contracts/Handlers/Attributes.js +7 -11
  8. package/dist/contracts/Handlers/JsonContract.d.ts +2 -46
  9. package/dist/contracts/Handlers/JsonContract.js +4 -153
  10. package/dist/contracts/Spots/Contracts.d.ts +2 -1
  11. package/dist/nest-integration.d.ts +1 -1
  12. package/dist/nest-integration.js +2 -1
  13. package/dist/runtime/actors/actor-client.d.ts +1 -1
  14. package/dist/runtime/actors/actor-client.js +14 -12
  15. package/dist/runtime/actors/actor-handoff.d.ts +1 -1
  16. package/dist/runtime/actors/actor-handoff.js +7 -4
  17. package/dist/runtime/actors/actor-join-relocation.d.ts +1 -0
  18. package/dist/runtime/actors/actor-local-native-join.js +9 -12
  19. package/dist/runtime/actors/actor-remote-wire.js +15 -0
  20. package/dist/runtime/actors/actor-routed-join-transport.d.ts +6 -2
  21. package/dist/runtime/actors/actor-routed-json-request.d.ts +2 -0
  22. package/dist/runtime/actors/index.d.ts +2 -1
  23. package/dist/runtime/actors/index.js +18 -6
  24. package/dist/runtime/actors/spot-actor-dispatch.js +2 -2
  25. package/dist/runtime/admission.d.ts +1 -1
  26. package/dist/runtime/admission.js +15 -5
  27. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +6 -8
  28. package/dist/runtime/application-jobs/application-ingress-record-owner.js +39 -22
  29. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +2 -1
  30. package/dist/runtime/application-jobs/application-job-queue-scope.js +37 -22
  31. package/dist/runtime/application-jobs/contracts.d.ts +10 -1
  32. package/dist/runtime/backend/contracts/index.d.ts +18 -9
  33. package/dist/runtime/backend/mesh-completion-table.d.ts +9 -1
  34. package/dist/runtime/backend/mesh-completion-table.js +149 -49
  35. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +3 -0
  36. package/dist/runtime/backend/mesh-dispatch-pump.js +32 -11
  37. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -2
  38. package/dist/runtime/backend/node/node-backend-adapter-support.js +16 -9
  39. package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
  40. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +5 -2
  41. package/dist/runtime/backend/node/node-raw-binding-port.js +42 -22
  42. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +13 -5
  43. package/dist/runtime/backend/node/node-raw-mesh-backend.js +69 -51
  44. package/dist/runtime/backend/node/node-socket-backend-adapter.js +6 -6
  45. package/dist/runtime/backend/raw-binding-port.d.ts +2 -2
  46. package/dist/runtime/backend/runtime-message.d.ts +1 -0
  47. package/dist/runtime/backend/runtime-message.js +5 -0
  48. package/dist/runtime/backend/runtime-values.d.ts +1 -0
  49. package/dist/runtime/backend/runtime-values.js +2 -1
  50. package/dist/runtime/channels/channel-clients.d.ts +1 -0
  51. package/dist/runtime/channels/channel-clients.js +58 -21
  52. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +3 -2
  53. package/dist/runtime/channels/channel-dispatch-pipeline.js +20 -11
  54. package/dist/runtime/channels/channel-dispatch-services.d.ts +1 -0
  55. package/dist/runtime/channels/channel-dispatch-services.js +45 -0
  56. package/dist/runtime/channels/channel-dispatchers.d.ts +1 -1
  57. package/dist/runtime/channels/channel-dispatchers.js +27 -26
  58. package/dist/runtime/channels/channel-envelope-inspection.d.ts +1 -2
  59. package/dist/runtime/channels/channel-envelope-inspection.js +1 -16
  60. package/dist/runtime/channels/channel-envelope.d.ts +1 -0
  61. package/dist/runtime/channels/channel-envelope.js +83 -8
  62. package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
  63. package/dist/runtime/channels/channel-outbound-operations.js +8 -8
  64. package/dist/runtime/channels/channel-runtime-manager.d.ts +6 -6
  65. package/dist/runtime/channels/channel-runtime-manager.js +12 -12
  66. package/dist/runtime/channels/channel-transports.d.ts +18 -15
  67. package/dist/runtime/channels/channel-transports.js +48 -31
  68. package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
  69. package/dist/runtime/channels/local-spot-route-transport.js +2 -1
  70. package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +2 -2
  71. package/dist/runtime/channels/router-socket-spot-route-transport.js +4 -4
  72. package/dist/runtime/channels/source-spot-router.d.ts +2 -2
  73. package/dist/runtime/channels/source-spot-router.js +4 -4
  74. package/dist/runtime/channels/spot-node-route-transport.d.ts +2 -2
  75. package/dist/runtime/channels/spot-node-route-transport.js +4 -4
  76. package/dist/runtime/channels/spot-route-bridge-transport.d.ts +2 -2
  77. package/dist/runtime/channels/spot-route-bridge-transport.js +4 -4
  78. package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +5 -4
  79. package/dist/runtime/channels/spot-route-dispatch-strategy.js +18 -18
  80. package/dist/runtime/execution/serial-execution-queue.d.ts +1 -0
  81. package/dist/runtime/execution/serial-execution-queue.js +1 -0
  82. package/dist/runtime/foundation/actor-join-recovery-codec.js +2 -2
  83. package/dist/runtime/foundation/durable-service-request.d.ts +14 -0
  84. package/dist/runtime/foundation/durable-service-request.js +98 -0
  85. package/dist/runtime/foundation/operation-identity.d.ts +1 -0
  86. package/dist/runtime/foundation/operation-identity.js +5 -1
  87. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +22 -5
  88. package/dist/runtime/foundation/raw-service-mesh-runtime.js +356 -232
  89. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +1 -0
  90. package/dist/runtime/foundation/service-relocation-object-owner.js +1 -0
  91. package/dist/runtime/foundation/service-relocation-runtime.d.ts +2 -0
  92. package/dist/runtime/foundation/service-relocation-runtime.js +13 -1
  93. package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -0
  94. package/dist/runtime/foundation/service-stateful-runtime.d.ts +4 -4
  95. package/dist/runtime/foundation/service-stateful-runtime.js +44 -103
  96. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +0 -5
  97. package/dist/runtime/foundation/service-topology-registry.d.ts +12 -2
  98. package/dist/runtime/foundation/service-topology-registry.js +61 -27
  99. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +3 -3
  100. package/dist/runtime/foundation/service-wire-m6a-codec.js +36 -38
  101. package/dist/runtime/handlers/handler-instance-scope.d.ts +8 -0
  102. package/dist/runtime/handlers/handler-instance-scope.js +54 -11
  103. package/dist/runtime/host/actor-runtime-options-factory.js +2 -2
  104. package/dist/runtime/host/application-job-queue.d.ts +19 -7
  105. package/dist/runtime/host/application-job-queue.js +150 -42
  106. package/dist/runtime/host/entry-actor-runtime.d.ts +1 -0
  107. package/dist/runtime/host/entry-actor-runtime.js +3 -0
  108. package/dist/runtime/host/index.d.ts +7 -1
  109. package/dist/runtime/host/index.js +142 -118
  110. package/dist/runtime/host/remote-bound-session-relay.js +2 -18
  111. package/dist/runtime/host/route-mesh-runtime.js +1 -1
  112. package/dist/runtime/host/service-relocation-control.d.ts +1 -0
  113. package/dist/runtime/host/service-relocation-control.js +10 -4
  114. package/dist/runtime/host/service-relocation-host-runtime.d.ts +6 -8
  115. package/dist/runtime/host/service-relocation-host-runtime.js +213 -241
  116. package/dist/runtime/host/spot-address-transport.js +3 -2
  117. package/dist/runtime/host/spot-runtime-options-factory.js +1 -0
  118. package/dist/runtime/locations/actor-location-claims.d.ts +2 -2
  119. package/dist/runtime/locations/actor-location-claims.js +34 -19
  120. package/dist/runtime/locations/lifecycle.d.ts +1 -2
  121. package/dist/runtime/locations/lifecycle.js +2 -5
  122. package/dist/runtime/locations/runtime.d.ts +1 -1
  123. package/dist/runtime/locations/runtime.js +24 -23
  124. package/dist/runtime/messaging/framework-json-v1.d.ts +4 -6
  125. package/dist/runtime/messaging/framework-json-v1.js +38 -294
  126. package/dist/runtime/messaging/packet-name.d.ts +1 -1
  127. package/dist/runtime/messaging/packet-name.js +8 -24
  128. package/dist/runtime/messaging/request-result.d.ts +2 -0
  129. package/dist/runtime/messaging/request-result.js +54 -0
  130. package/dist/runtime/messaging/submission-result.d.ts +1 -0
  131. package/dist/runtime/messaging/submission-result.js +5 -2
  132. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +15 -0
  133. package/dist/runtime/protocol/service_wire_codec.generated.js +144 -0
  134. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +9 -0
  135. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +14 -1
  136. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +7 -2
  137. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +33 -19
  138. package/dist/runtime/spots/index.d.ts +3 -0
  139. package/dist/runtime/spots/index.js +9 -2
  140. package/dist/runtime/spots/spot-activation.d.ts +1 -0
  141. package/dist/runtime/spots/spot-activation.js +17 -8
  142. package/dist/runtime/spots/spot-entry-activation.js +6 -2
  143. package/dist/runtime/spots/spot-handler-registry.d.ts +3 -1
  144. package/dist/runtime/spots/spot-handler-registry.js +18 -8
  145. package/dist/runtime/spots/spot-node-autoconnect.js +4 -3
  146. package/dist/runtime/spots/spot-outbound.d.ts +3 -0
  147. package/dist/runtime/spots/spot-outbound.js +24 -15
  148. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +1 -0
  149. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +1 -1
  150. package/dist/runtime/spots/spot-runtime-ports.d.ts +1 -0
  151. package/dist/runtime/spots/spot-subscription-dispatch.js +0 -3
  152. package/dist/runtime/spots/spot-timer.js +1 -0
  153. package/dist/runtime/streams/stream-session-runtime.d.ts +1 -1
  154. package/dist/runtime/streams/stream-session-runtime.js +13 -27
  155. package/package.json +2 -2
  156. package/src/contracts/Actors/ZLinkActorClient.ts +2 -1
  157. package/src/contracts/Channels/Calls.ts +2 -1
  158. package/src/contracts/Common/ZLinkMessageMetadata.ts +13 -8
  159. package/src/contracts/Handlers/Attributes.ts +14 -21
  160. package/src/contracts/Handlers/JsonContract.ts +8 -216
  161. package/src/contracts/Spots/Contracts.ts +2 -1
  162. package/src/nest-integration.ts +1 -0
  163. package/src/runtime/actors/actor-client.ts +40 -16
  164. package/src/runtime/actors/actor-handoff.ts +9 -4
  165. package/src/runtime/actors/actor-join-relocation.ts +1 -0
  166. package/src/runtime/actors/actor-local-native-join.ts +17 -26
  167. package/src/runtime/actors/actor-remote-wire.ts +17 -0
  168. package/src/runtime/actors/actor-routed-join-transport.ts +14 -4
  169. package/src/runtime/actors/actor-routed-json-request.ts +10 -2
  170. package/src/runtime/actors/index.ts +19 -5
  171. package/src/runtime/actors/spot-actor-dispatch.ts +4 -2
  172. package/src/runtime/admission.ts +18 -5
  173. package/src/runtime/application-jobs/application-ingress-record-owner.ts +41 -25
  174. package/src/runtime/application-jobs/application-job-queue-scope.ts +51 -22
  175. package/src/runtime/application-jobs/contracts.ts +14 -1
  176. package/src/runtime/backend/contracts/index.ts +53 -14
  177. package/src/runtime/backend/mesh-completion-table.ts +156 -57
  178. package/src/runtime/backend/mesh-dispatch-pump.ts +40 -10
  179. package/src/runtime/backend/node/node-backend-adapter-support.ts +17 -8
  180. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +12 -2
  181. package/src/runtime/backend/node/node-raw-binding-port.ts +57 -30
  182. package/src/runtime/backend/node/node-raw-mesh-backend.ts +128 -65
  183. package/src/runtime/backend/node/node-socket-backend-adapter.ts +21 -6
  184. package/src/runtime/backend/raw-binding-port.ts +7 -2
  185. package/src/runtime/backend/runtime-message.ts +6 -0
  186. package/src/runtime/backend/runtime-values.ts +1 -0
  187. package/src/runtime/channels/channel-clients.ts +90 -41
  188. package/src/runtime/channels/channel-dispatch-pipeline.ts +69 -34
  189. package/src/runtime/channels/channel-dispatch-services.ts +69 -1
  190. package/src/runtime/channels/channel-dispatchers.ts +29 -27
  191. package/src/runtime/channels/channel-envelope-inspection.ts +2 -16
  192. package/src/runtime/channels/channel-envelope.ts +133 -8
  193. package/src/runtime/channels/channel-outbound-operations.ts +22 -8
  194. package/src/runtime/channels/channel-runtime-manager.ts +29 -12
  195. package/src/runtime/channels/channel-transports.ts +128 -60
  196. package/src/runtime/channels/local-spot-route-transport.ts +3 -1
  197. package/src/runtime/channels/router-socket-spot-route-transport.ts +13 -4
  198. package/src/runtime/channels/source-spot-router.ts +8 -4
  199. package/src/runtime/channels/spot-node-route-transport.ts +8 -4
  200. package/src/runtime/channels/spot-route-bridge-transport.ts +6 -4
  201. package/src/runtime/channels/spot-route-dispatch-strategy.ts +47 -18
  202. package/src/runtime/execution/serial-execution-queue.ts +2 -0
  203. package/src/runtime/foundation/actor-join-recovery-codec.ts +2 -2
  204. package/src/runtime/foundation/durable-service-request.ts +137 -0
  205. package/src/runtime/foundation/operation-identity.ts +5 -1
  206. package/src/runtime/foundation/raw-service-mesh-runtime.ts +484 -293
  207. package/src/runtime/foundation/service-relocation-object-owner.ts +2 -0
  208. package/src/runtime/foundation/service-relocation-runtime.ts +18 -1
  209. package/src/runtime/foundation/service-runtime-contracts.ts +7 -1
  210. package/src/runtime/foundation/service-stateful-runtime.ts +67 -125
  211. package/src/runtime/foundation/service-stateful-wire-codec.ts +0 -5
  212. package/src/runtime/foundation/service-topology-registry.ts +91 -36
  213. package/src/runtime/foundation/service-wire-m6a-codec.ts +57 -38
  214. package/src/runtime/handlers/handler-instance-scope.ts +67 -16
  215. package/src/runtime/host/actor-runtime-options-factory.ts +13 -2
  216. package/src/runtime/host/application-job-queue.ts +175 -41
  217. package/src/runtime/host/entry-actor-runtime.ts +4 -0
  218. package/src/runtime/host/index.ts +201 -156
  219. package/src/runtime/host/remote-bound-session-relay.ts +2 -23
  220. package/src/runtime/host/route-mesh-runtime.ts +1 -1
  221. package/src/runtime/host/service-relocation-control.ts +11 -5
  222. package/src/runtime/host/service-relocation-host-runtime.ts +315 -291
  223. package/src/runtime/host/spot-address-transport.ts +4 -2
  224. package/src/runtime/host/spot-runtime-options-factory.ts +2 -0
  225. package/src/runtime/locations/actor-location-claims.ts +52 -30
  226. package/src/runtime/locations/lifecycle.ts +8 -26
  227. package/src/runtime/locations/runtime.ts +28 -24
  228. package/src/runtime/messaging/framework-json-v1.ts +5 -325
  229. package/src/runtime/messaging/packet-name.ts +5 -25
  230. package/src/runtime/messaging/request-result.ts +58 -0
  231. package/src/runtime/messaging/submission-result.ts +5 -1
  232. package/src/runtime/protocol/service_wire_codec.generated.ts +131 -1
  233. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
  234. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +43 -23
  235. package/src/runtime/spots/index.ts +14 -2
  236. package/src/runtime/spots/spot-activation.ts +28 -10
  237. package/src/runtime/spots/spot-entry-activation.ts +9 -2
  238. package/src/runtime/spots/spot-handler-registry.ts +41 -8
  239. package/src/runtime/spots/spot-node-autoconnect.ts +6 -2
  240. package/src/runtime/spots/spot-outbound.ts +36 -16
  241. package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +2 -1
  242. package/src/runtime/spots/spot-runtime-ports.ts +1 -0
  243. package/src/runtime/spots/spot-subscription-dispatch.ts +0 -3
  244. package/src/runtime/spots/spot-timer.ts +5 -1
  245. package/src/runtime/streams/stream-session-runtime.ts +12 -29
@@ -1,3 +1,4 @@
1
+ import { requestDurableService } from '../../foundation/durable-service-request';
1
2
  import {
2
3
  decodeStreamWireFrame,
3
4
  decodeStreamWireHeader,
@@ -19,7 +20,11 @@ import {
19
20
  import { randomBytes } from 'node:crypto';
20
21
  import type { ZLinkMeshCompletionHandler } from '../mesh-completion-table';
21
22
  import { setImmediate as yieldToIO } from 'node:timers/promises';
22
- import { type RoutingId, ZLinkFrameworkException } from '../../../contracts';
23
+ import {
24
+ type RoutingId,
25
+ ZLinkFrameworkException,
26
+ ZLinkFrameworkErrorKind
27
+ } from '../../../contracts';
23
28
 
24
29
  import type { Message as FrameworkMessage } from '../../../contracts/Common/Message';
25
30
  import { ZLinkConfigurationException } from '../../../contracts/Configuration/ConfigurationException';
@@ -172,7 +177,7 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
172
177
  }
173
178
  >();
174
179
  private completionHandler?: ZLinkMeshCompletionHandler;
175
- private readonly routingId: string;
180
+ readonly routingId: string;
176
181
  private readonly lifecycleGeneration: bigint;
177
182
  private bindEndpoint?: string;
178
183
  private advertiseHost?: string;
@@ -342,7 +347,8 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
342
347
  parts: MessageLike | readonly MessageLike[],
343
348
  deadlineUnixMs: bigint,
344
349
  sourceSpotId?: string,
345
- metadata?: ReadonlyMap<string, string>
350
+ metadata?: ReadonlyMap<string, string>,
351
+ onAdmitted?: () => void
346
352
  ): MeshOperationId {
347
353
  return this.observeStateful(
348
354
  OperationKind.InstanceSpotRequest,
@@ -351,7 +357,8 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
351
357
  encodeMultipartApplicationFrame(parts),
352
358
  deadlineUnixMs,
353
359
  sourceSpotId,
354
- metadata === undefined ? undefined : encodeServiceMetadataFrame(metadata)
360
+ metadata === undefined ? undefined : encodeServiceMetadataFrame(metadata),
361
+ onAdmitted
355
362
  )
356
363
  );
357
364
  }
@@ -411,15 +418,7 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
411
418
  }
412
419
  }
413
420
  },
414
- onPeerDisconnected: (nodeRoutingId, endpoint) => {
415
- for (const [intentId, peer] of this.peerIntents) {
416
- if (
417
- peer.endpoint === endpoint &&
418
- (peer.nodeRoutingId === undefined || peer.nodeRoutingId === nodeRoutingId)
419
- ) {
420
- this.peerIntents.delete(intentId);
421
- }
422
- }
421
+ onPeerDisconnected: (_nodeRoutingId, endpoint) => {
423
422
  for (const handler of this.peerDisconnectedHandlers) handler(endpoint);
424
423
  }
425
424
  });
@@ -630,20 +629,38 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
630
629
  return this.requireRuntime().isObjectClientNodeDirectTarget(String(targetRid));
631
630
  }
632
631
 
632
+ observePeerRoute(targetRid: unknown) {
633
+ return this.requireRuntime().observePeerRoute(String(targetRid));
634
+ }
635
+
636
+ hasPeerRouteOrConnectionIntent(targetRid: unknown, endpoint: string): boolean {
637
+ const rid = String(targetRid);
638
+ if (this.requireRuntime().hasSelectedPeerRoute(rid)) return true;
639
+ for (const intent of this.peerIntents.values()) {
640
+ if (
641
+ intent.nodeRoutingId === rid ||
642
+ (intent.nodeRoutingId === undefined && intent.endpoint === endpoint)
643
+ )
644
+ return true;
645
+ }
646
+ return false;
647
+ }
648
+
633
649
  isPeerRouteReady(targetRid: unknown, lifecycleGeneration?: bigint): boolean {
634
650
  return this.requireRuntime().isPeerRouteReady(String(targetRid), lifecycleGeneration);
635
651
  }
636
652
 
637
- async sendToNode(
653
+ sendToNode(
638
654
  targetRid: unknown,
639
655
  parts: MessageLike | readonly MessageLike[]
640
- ): Promise<SubmitResultValue> {
641
- return (await this.requireRuntime().sendToNode(
656
+ ): SubmitResultValue | Promise<SubmitResultValue> {
657
+ const submitted = this.requireRuntime().sendToNode(
642
658
  String(targetRid),
643
659
  encodeMultipartApplicationFrame(parts)
644
- ))
645
- ? SubmitResult.Ok
646
- : SubmitResult.NotConnected;
660
+ );
661
+ return submitted instanceof Promise
662
+ ? submitted.then(nodeSendResult)
663
+ : nodeSendResult(submitted);
647
664
  }
648
665
 
649
666
  async sendInfrastructureControl(
@@ -673,24 +690,33 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
673
690
  async requestInfrastructureControlFrames(
674
691
  targetRid: unknown,
675
692
  frames: readonly Uint8Array[],
676
- options?: { readonly timeoutMs?: number }
693
+ options?: {
694
+ readonly timeoutMs?: number;
695
+ readonly signal?: AbortSignal;
696
+ readonly onSubmitted?: (signal: AbortSignal) => Promise<void>;
697
+ }
677
698
  ): Promise<readonly Uint8Array[]> {
678
- return await this.requireRuntime().requestService(
699
+ return requestDurableService(
700
+ this.requireRuntime(),
679
701
  String(targetRid),
680
- frames.map((frame) => Buffer.from(frame)),
681
- options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS
702
+ frames,
703
+ performance.now() + (options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS),
704
+ 'relocation control',
705
+ options?.signal,
706
+ options?.onSubmitted
682
707
  );
683
708
  }
684
709
 
685
710
  requestToNode(
686
711
  targetRid: unknown,
687
712
  parts: MessageLike | readonly MessageLike[],
688
- options?: { readonly timeoutMs?: number }
713
+ options?: { readonly timeoutMs?: number; readonly onAdmitted?: () => void }
689
714
  ): MeshOperationId {
690
715
  const pending = this.requireRuntime().requestToNode(
691
716
  String(targetRid),
692
717
  encodeMultipartApplicationFrame(parts),
693
- options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS
718
+ options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
719
+ options?.onAdmitted
694
720
  );
695
721
  return this.observeCompletion(pending.id, OperationKind.NodeRequest, pending.promise);
696
722
  }
@@ -705,12 +731,13 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
705
731
  requestToChannel(
706
732
  channelName: string,
707
733
  parts: MessageLike | readonly MessageLike[],
708
- options?: { readonly timeoutMs?: number }
734
+ options?: { readonly timeoutMs?: number; readonly onAdmitted?: () => void }
709
735
  ): MeshOperationId {
710
736
  const pending = this.requireRuntime().requestToChannel(
711
737
  channelName,
712
738
  encodeMultipartApplicationFrame(parts),
713
- options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS
739
+ options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
740
+ options?.onAdmitted
714
741
  );
715
742
  return this.observeCompletion(pending.id, OperationKind.ChannelRequest, pending.promise);
716
743
  }
@@ -1173,7 +1200,8 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
1173
1200
  timeoutMs: number = DEFAULT_REQUEST_TIMEOUT_MS,
1174
1201
  sourceSpotId?: string,
1175
1202
  metadata?: ReadonlyMap<string, string>,
1176
- instanceIntent = false
1203
+ instanceIntent = false,
1204
+ onAdmitted?: () => void
1177
1205
  ): MeshOperationId {
1178
1206
  return this.observeStateful(
1179
1207
  OperationKind.InstanceSpotRequest,
@@ -1183,7 +1211,8 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
1183
1211
  timeoutMs,
1184
1212
  sourceSpotId,
1185
1213
  metadata === undefined ? undefined : encodeServiceMetadataFrame(metadata),
1186
- instanceIntent
1214
+ instanceIntent,
1215
+ onAdmitted
1187
1216
  )
1188
1217
  );
1189
1218
  }
@@ -1328,7 +1357,7 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
1328
1357
  requestToActor(
1329
1358
  actor: ZLinkBackendActorRef,
1330
1359
  parts: MessageLike | readonly MessageLike[],
1331
- options?: { readonly timeoutMs?: number }
1360
+ options?: { readonly timeoutMs?: number; readonly onAdmitted?: () => void }
1332
1361
  ): MeshOperationId {
1333
1362
  return this.observeStateful(
1334
1363
  OperationKind.ActorRequest,
@@ -1337,7 +1366,10 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
1337
1366
  this.peerGeneration(String(actor.nodeRid)),
1338
1367
  actor.generation,
1339
1368
  encodeMultipart(parts),
1340
- options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS
1369
+ options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
1370
+ undefined,
1371
+ undefined,
1372
+ options?.onAdmitted
1341
1373
  )
1342
1374
  );
1343
1375
  }
@@ -1360,7 +1392,7 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
1360
1392
  source: ZLinkBackendActorRef,
1361
1393
  target: ZLinkBackendActorRef,
1362
1394
  parts: MessageLike | readonly MessageLike[],
1363
- options?: { readonly timeoutMs?: number }
1395
+ options?: { readonly timeoutMs?: number; readonly onAdmitted?: () => void }
1364
1396
  ): MeshOperationId {
1365
1397
  return this.observeStateful(
1366
1398
  OperationKind.ActorRequest,
@@ -1370,7 +1402,9 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
1370
1402
  target.generation,
1371
1403
  encodeMultipart(parts),
1372
1404
  options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
1373
- source
1405
+ source,
1406
+ undefined,
1407
+ options?.onAdmitted
1374
1408
  )
1375
1409
  );
1376
1410
  }
@@ -1443,7 +1477,8 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
1443
1477
  source: ServiceSpotState,
1444
1478
  target: ServiceDirectSpotRouteFence,
1445
1479
  parts: MessageLike | readonly MessageLike[],
1446
- timeoutMs: number
1480
+ timeoutMs: number,
1481
+ onAdmitted?: () => void
1447
1482
  ): MeshOperationId {
1448
1483
  return this.observeStateful(
1449
1484
  OperationKind.SpotRequest,
@@ -1451,7 +1486,8 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
1451
1486
  source.ref.spotId,
1452
1487
  target,
1453
1488
  encodeMultipart(parts),
1454
- timeoutMs
1489
+ timeoutMs,
1490
+ onAdmitted
1455
1491
  )
1456
1492
  );
1457
1493
  }
@@ -1475,6 +1511,11 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
1475
1511
  }
1476
1512
 
1477
1513
  setSpotSubscription(state: ServiceSpotState, channelName: string, topicFilter: string): void {
1514
+ if (!this.channels.has(channelName))
1515
+ throw new ZLinkFrameworkException(
1516
+ ZLinkFrameworkErrorKind.InvalidOperation,
1517
+ `Spot does not participate in subscription channel '${channelName}'.`
1518
+ );
1478
1519
  this.requireStateful().setSubscription(state, channelName, topicFilter);
1479
1520
  }
1480
1521
 
@@ -1719,7 +1760,11 @@ class RawServiceSpot implements ServiceSpot {
1719
1760
  requestToChannel(
1720
1761
  channelName: string,
1721
1762
  parts: MessageLike | readonly MessageLike[],
1722
- options?: { readonly flags?: number; readonly timeoutMs?: number }
1763
+ options?: {
1764
+ readonly flags?: number;
1765
+ readonly timeoutMs?: number;
1766
+ readonly onAdmitted?: () => void;
1767
+ }
1723
1768
  ): MeshOperationId {
1724
1769
  this.requireOpen();
1725
1770
  return this.backend.requestToChannel(channelName, parts, options);
@@ -1755,6 +1800,7 @@ class RawServiceSpot implements ServiceSpot {
1755
1800
  parts: MessageLike | readonly MessageLike[],
1756
1801
  options?: {
1757
1802
  readonly timeoutMs?: number;
1803
+ readonly onAdmitted?: () => void;
1758
1804
  readonly routeFence?: ServiceDirectSpotRouteFence;
1759
1805
  readonly entrySpot?: boolean;
1760
1806
  }
@@ -1773,7 +1819,8 @@ class RawServiceSpot implements ServiceSpot {
1773
1819
  this.state,
1774
1820
  routeFence,
1775
1821
  parts,
1776
- options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS
1822
+ options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
1823
+ options?.onAdmitted
1777
1824
  );
1778
1825
  }
1779
1826
 
@@ -1823,6 +1870,10 @@ class RawServiceSpot implements ServiceSpot {
1823
1870
  }
1824
1871
  }
1825
1872
 
1873
+ function nodeSendResult(submitted: boolean): SubmitResultValue {
1874
+ return submitted ? SubmitResult.Ok : SubmitResult.NotConnected;
1875
+ }
1876
+
1826
1877
  function requireDirectSpotRouteFence(
1827
1878
  route: ServiceDirectSpotRouteFence | undefined,
1828
1879
  targetNodeRid: string,
@@ -1970,7 +2021,10 @@ class RawStreamSessionService implements StreamSessionService {
1970
2021
  const target = this.sessionTargets.get(sessionRid);
1971
2022
  if (target === undefined) return false;
1972
2023
  const operation = this.stream.send(target as unknown as BindingRoutingId);
1973
- const parts = decodeMultipartBuffers(decodeApplicationPayloadView(payload).payload);
2024
+ const parts = decodeMultipartParts(
2025
+ decodeApplicationPayloadView(payload).payload,
2026
+ borrowMultipartPart
2027
+ );
1974
2028
  if (parts.length === 0) return false;
1975
2029
  const actorSlot = await serviceSessionBindingIngressPortIfRegistered(this)?.actorSlot(
1976
2030
  actorId,
@@ -2584,45 +2638,54 @@ function decodeApplicationEnvelope(frame: Uint8Array) {
2584
2638
  }
2585
2639
 
2586
2640
  function decodeMultipart(payload: Uint8Array): FrameworkMessage[] {
2587
- const buffers = decodeMultipartBuffers(payload);
2588
- const parts = new Array<FrameworkMessage>(buffers.length);
2589
- let materialized = 0;
2590
- try {
2591
- for (; materialized < buffers.length; materialized += 1) {
2592
- parts[materialized] = ZLinkBufferMessage.fromOwned(buffers[materialized]!);
2593
- }
2594
- return parts;
2595
- } catch (error) {
2596
- for (let index = 0; index < materialized; index += 1) parts[index]!.close();
2597
- throw error;
2598
- }
2641
+ return decodeMultipartParts(payload, ZLinkBufferMessage.fromOwned, closeMultipartMessage);
2599
2642
  }
2600
2643
 
2601
- function decodeMultipartBuffers(payload: Uint8Array): Buffer[] {
2644
+ function closeMultipartMessage(part: FrameworkMessage): void {
2645
+ part.close();
2646
+ }
2647
+
2648
+ function borrowMultipartPart(part: Buffer): Buffer {
2649
+ return part;
2650
+ }
2651
+
2652
+ function decodeMultipartParts<T>(
2653
+ payload: Uint8Array,
2654
+ materialize: (part: Buffer) => T,
2655
+ release?: (part: T) => void
2656
+ ): T[] {
2602
2657
  const bytes = Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength);
2603
2658
  if (bytes.length < 4) throw new ServiceWireProtocolError('Truncated multipart payload.');
2604
2659
  const count = bytes.readUInt32BE(0);
2605
2660
  if (count === 0 || count > Math.floor((bytes.length - 4) / 4)) {
2606
2661
  throw new ServiceWireProtocolError('Invalid multipart part count.');
2607
2662
  }
2608
- const result = new Array<Buffer>(count);
2663
+ const result = new Array<T>(count);
2609
2664
  let offset = 4;
2610
- for (let index = 0; index < count; index++) {
2611
- if (bytes.length - offset < 4) {
2612
- throw new ServiceWireProtocolError('Truncated multipart part length.');
2665
+ let index = 0;
2666
+ try {
2667
+ for (; index < count; index++) {
2668
+ if (bytes.length - offset < 4) {
2669
+ throw new ServiceWireProtocolError('Truncated multipart part length.');
2670
+ }
2671
+ const length = bytes.readUInt32BE(offset);
2672
+ offset += 4;
2673
+ if (bytes.length - offset < length) {
2674
+ throw new ServiceWireProtocolError('Truncated multipart part.');
2675
+ }
2676
+ result[index] = materialize(bytes.subarray(offset, offset + length));
2677
+ offset += length;
2613
2678
  }
2614
- const length = bytes.readUInt32BE(offset);
2615
- offset += 4;
2616
- if (bytes.length - offset < length) {
2617
- throw new ServiceWireProtocolError('Truncated multipart part.');
2679
+ if (offset !== bytes.length) {
2680
+ throw new ServiceWireProtocolError('Multipart payload has trailing bytes.');
2618
2681
  }
2619
- result[index] = bytes.subarray(offset, offset + length);
2620
- offset += length;
2621
- }
2622
- if (offset !== bytes.length) {
2623
- throw new ServiceWireProtocolError('Multipart payload has trailing bytes.');
2682
+ return result;
2683
+ } catch (error) {
2684
+ if (release !== undefined) {
2685
+ for (let retained = 0; retained < index; retained++) release(result[retained]!);
2686
+ }
2687
+ throw error;
2624
2688
  }
2625
- return result;
2626
2689
  }
2627
2690
 
2628
2691
  function messageBytesView(value: MessageLike): Uint8Array {
@@ -208,22 +208,34 @@ export function wrapSocket<T extends { close(): void }>(
208
208
  },
209
209
  request(...args: unknown[]): unknown {
210
210
  if (hasRoutedPeer) {
211
- const [routingId, payload, timeoutMs] = args as [unknown, unknown, number | undefined];
211
+ const [routingId, payload, timeoutMs, onAdmitted] = args as [
212
+ unknown,
213
+ unknown,
214
+ number | undefined,
215
+ (() => void) | undefined
216
+ ];
212
217
  return submitBindingRequest(
213
218
  (
214
219
  nativeInstance as T & { request(routingId: unknown): ZLinkBindingRequestOperation }
215
220
  ).request(toNativeRoutingId(routingId)),
216
221
  payload,
217
- timeoutMs
222
+ timeoutMs,
223
+ undefined,
224
+ onAdmitted
218
225
  );
219
226
  }
220
227
  if (hasRequest) {
221
- const [payload, timeoutMs] = args as [unknown, number | undefined];
228
+ const [payload, timeoutMs, onAdmitted] = args as [
229
+ unknown,
230
+ number | undefined,
231
+ (() => void) | undefined
232
+ ];
222
233
  return submitBindingRequest(
223
234
  (nativeInstance as T & { request(): ZLinkBindingRequestOperation }).request(),
224
235
  payload,
225
236
  timeoutMs,
226
- adapter.receiveAdmission?.recordReceived
237
+ adapter.receiveAdmission?.recordReceived,
238
+ onAdmitted
227
239
  );
228
240
  }
229
241
  throw new TypeError('Backend request requires a DEALER or ROUTER socket.');
@@ -302,7 +314,8 @@ export function wrapSocket<T extends { close(): void }>(
302
314
  targetRid: unknown,
303
315
  targetSpot: unknown,
304
316
  payload: unknown,
305
- timeoutMs?: number
317
+ timeoutMs?: number,
318
+ onAdmitted?: () => void
306
319
  ): Promise<readonly unknown[]> {
307
320
  return submitBindingRequest(
308
321
  (
@@ -311,7 +324,9 @@ export function wrapSocket<T extends { close(): void }>(
311
324
  }
312
325
  ).requestToSpot(toNativeRoutingId(targetRid), toNativeRoutingId(targetSpot)),
313
326
  payload,
314
- timeoutMs
327
+ timeoutMs,
328
+ undefined,
329
+ onAdmitted
315
330
  );
316
331
  },
317
332
  disconnectPeer(routingId: unknown): void {
@@ -67,7 +67,8 @@ export interface ZLinkRawRouterPort extends ZLinkRawSocketPort {
67
67
  targetRid: string,
68
68
  parts: readonly Uint8Array[],
69
69
  timeoutMs: number,
70
- recordReceived?: () => void
70
+ recordReceived?: () => void,
71
+ onAdmitted?: () => void
71
72
  ): Promise<readonly Buffer[]>;
72
73
  receive(dontWait?: boolean): ZLinkRawReceivedRecord | undefined;
73
74
  /** The selected route of every RID. The socket's one route observer calls it. */
@@ -77,7 +78,11 @@ export interface ZLinkRawRouterPort extends ZLinkRawSocketPort {
77
78
  export interface ZLinkRawDealerPort extends ZLinkRawSocketPort {
78
79
  setRoutingId(routingId: string): void;
79
80
  send(parts: readonly Uint8Array[]): Promise<void>;
80
- request(parts: readonly Uint8Array[], timeoutMs: number): Promise<readonly Buffer[]>;
81
+ request(
82
+ parts: readonly Uint8Array[],
83
+ timeoutMs: number,
84
+ onAdmitted?: () => void
85
+ ): Promise<readonly Buffer[]>;
81
86
  receive(dontWait?: boolean): ZLinkRawReceivedRecord | undefined;
82
87
  }
83
88
 
@@ -17,6 +17,12 @@ export class ZLinkBufferMessage implements Message {
17
17
  return new ZLinkBufferMessage(bytes);
18
18
  }
19
19
 
20
+ static retainPayload(message: Message): Buffer {
21
+ // Binding data() Buffers retain their storage after the message handle closes.
22
+ // Preserve that ownership at runtime boundaries without copying the payload.
23
+ return message.data();
24
+ }
25
+
20
26
  data(): Buffer {
21
27
  return this.bytes;
22
28
  }
@@ -39,6 +39,7 @@ export type SubmitResult = (typeof SubmitResult)[keyof typeof SubmitResult];
39
39
  export type ZLinkBackendSendFlags = number;
40
40
  export type ZLinkBackendRecvFlags = number;
41
41
  export const ZLINK_BACKEND_SEND_NONE: ZLinkBackendSendFlags = 0;
42
+ export const ZLINK_BACKEND_SEND_DONT_WAIT: ZLinkBackendSendFlags = 1;
42
43
  export const ZLINK_BACKEND_RECV_DONT_WAIT: ZLinkBackendRecvFlags = 1;
43
44
 
44
45
  export class ZLinkBackendResultError extends Error {