@zlink-systems/framework 0.27.0 → 0.29.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 (191) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Actors/ZLinkActorClient.d.ts +1 -1
  3. package/dist/contracts/Channels/Calls.d.ts +1 -1
  4. package/dist/contracts/Configuration/Builders.d.ts +2 -1
  5. package/dist/contracts/Configuration/Configs.d.ts +0 -1
  6. package/dist/contracts/Configuration/InternalDefaults.d.ts +3 -0
  7. package/dist/contracts/Configuration/InternalDefaults.js +4 -1
  8. package/dist/contracts/Configuration/RegistrationBuilders.js +9 -0
  9. package/dist/contracts/Configuration/RegistrationNormalizers.d.ts +1 -0
  10. package/dist/contracts/Configuration/RegistrationNormalizers.js +16 -0
  11. package/dist/contracts/Configuration/RegistrationTypes.d.ts +3 -5
  12. package/dist/contracts/Configuration/RegistrationValidators.js +0 -2
  13. package/dist/contracts/Spots/Contracts.d.ts +1 -1
  14. package/dist/contracts/Streams/BoundSessionContracts.d.ts +1 -1
  15. package/dist/contracts/Streams/IZLinkSession.d.ts +2 -3
  16. package/dist/contracts/Streams/IZLinkSessionActor.d.ts +2 -2
  17. package/dist/runtime/actors/actor-client.js +7 -10
  18. package/dist/runtime/actors/actor-mailbox.d.ts +2 -2
  19. package/dist/runtime/actors/actor-mailbox.js +2 -2
  20. package/dist/runtime/actors/actor-request-deadline.d.ts +1 -3
  21. package/dist/runtime/actors/actor-request-deadline.js +4 -29
  22. package/dist/runtime/actors/actor-routed-join-transport.d.ts +2 -3
  23. package/dist/runtime/backend/contracts/index.d.ts +1 -4
  24. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -0
  25. package/dist/runtime/backend/node/node-backend-adapter-support.js +35 -4
  26. package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
  27. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +1 -2
  28. package/dist/runtime/backend/node/node-raw-binding-port.js +10 -27
  29. package/dist/runtime/backend/node/node-raw-mesh-backend.js +1 -3
  30. package/dist/runtime/backend/node/node-socket-backend-adapter.js +1 -1
  31. package/dist/runtime/channels/channel-clients.js +8 -10
  32. package/dist/runtime/channels/channel-envelope.d.ts +1 -1
  33. package/dist/runtime/channels/channel-envelope.js +4 -10
  34. package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
  35. package/dist/runtime/channels/channel-outbound-operations.js +20 -36
  36. package/dist/runtime/channels/channel-runtime-manager.d.ts +4 -4
  37. package/dist/runtime/channels/channel-runtime-manager.js +8 -8
  38. package/dist/runtime/channels/channel-socket-options.js +0 -10
  39. package/dist/runtime/channels/channel-socket-registry.d.ts +1 -1
  40. package/dist/runtime/channels/channel-socket-registry.js +3 -14
  41. package/dist/runtime/channels/channel-transports.d.ts +10 -14
  42. package/dist/runtime/channels/channel-transports.js +11 -14
  43. package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
  44. package/dist/runtime/channels/local-spot-route-transport.js +1 -3
  45. package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +1 -1
  46. package/dist/runtime/channels/router-socket-spot-route-transport.js +2 -2
  47. package/dist/runtime/channels/source-spot-router.d.ts +1 -1
  48. package/dist/runtime/channels/source-spot-router.js +2 -4
  49. package/dist/runtime/channels/spot-node-route-transport.d.ts +1 -1
  50. package/dist/runtime/channels/spot-node-route-transport.js +2 -3
  51. package/dist/runtime/channels/spot-route-bridge-transport.d.ts +1 -1
  52. package/dist/runtime/channels/spot-route-bridge-transport.js +2 -2
  53. package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +2 -4
  54. package/dist/runtime/channels/spot-route-dispatch-strategy.js +11 -12
  55. package/dist/runtime/execution/serial-execution-queue.d.ts +12 -3
  56. package/dist/runtime/execution/serial-execution-queue.js +116 -28
  57. package/dist/runtime/foundation/operation-registry.d.ts +3 -2
  58. package/dist/runtime/foundation/operation-registry.js +5 -1
  59. package/dist/runtime/foundation/raw-service-mesh-runtime.js +17 -11
  60. package/dist/runtime/foundation/service-authority-payload-codec.d.ts +0 -2
  61. package/dist/runtime/foundation/service-authority-payload-codec.js +0 -43
  62. package/dist/runtime/foundation/service-stateful-registry.d.ts +4 -3
  63. package/dist/runtime/foundation/service-stateful-registry.js +5 -2
  64. package/dist/runtime/foundation/service-stateful-runtime.d.ts +1 -8
  65. package/dist/runtime/foundation/service-stateful-runtime.js +78 -126
  66. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +0 -11
  67. package/dist/runtime/foundation/service-stateful-wire-codec.js +1 -23
  68. package/dist/runtime/foundation/service-topology-registry.d.ts +5 -0
  69. package/dist/runtime/foundation/service-topology-registry.js +16 -17
  70. package/dist/runtime/host/actor-packet-relay.d.ts +2 -2
  71. package/dist/runtime/host/actor-packet-relay.js +8 -10
  72. package/dist/runtime/host/index.js +1 -15
  73. package/dist/runtime/host/instance-activation-authority.d.ts +0 -1
  74. package/dist/runtime/host/instance-activation-authority.js +46 -97
  75. package/dist/runtime/host/remote-bound-session-relay.js +8 -8
  76. package/dist/runtime/host/spot-address-transport.d.ts +1 -9
  77. package/dist/runtime/host/spot-address-transport.js +47 -87
  78. package/dist/runtime/host/stateful-authority-route-runtime.d.ts +1 -0
  79. package/dist/runtime/host/stateful-authority-route-runtime.js +17 -9
  80. package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
  81. package/dist/runtime/locations/in-memory-authority-store.d.ts +2 -0
  82. package/dist/runtime/locations/in-memory-authority-store.js +22 -8
  83. package/dist/runtime/locations/in-memory-location-store.d.ts +1 -0
  84. package/dist/runtime/locations/in-memory-location-store.js +3 -0
  85. package/dist/runtime/locations/internal-store-contracts.d.ts +1 -1
  86. package/dist/runtime/locations/location-store-repository.d.ts +1 -0
  87. package/dist/runtime/locations/location-store-repository.js +98 -53
  88. package/dist/runtime/messaging/request-deadline.d.ts +3 -0
  89. package/dist/runtime/messaging/request-deadline.js +39 -0
  90. package/dist/runtime/messaging/submission-result.d.ts +2 -1
  91. package/dist/runtime/messaging/submission-result.js +11 -4
  92. package/dist/runtime/spots/spot-outbound.d.ts +3 -5
  93. package/dist/runtime/spots/spot-outbound.js +12 -15
  94. package/dist/runtime/spots/spot-serial-executor.js +4 -1
  95. package/dist/runtime/spots/spot-serial-turn-executor.d.ts +3 -0
  96. package/dist/runtime/spots/spot-serial-turn-executor.js +5 -0
  97. package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -2
  98. package/dist/runtime/streams/bound-actor-relay-sender.js +14 -14
  99. package/dist/runtime/streams/bound-session-service.js +1 -1
  100. package/dist/runtime/streams/index.d.ts +2 -3
  101. package/dist/runtime/streams/index.js +6 -5
  102. package/dist/runtime/streams/managed-stream.d.ts +2 -2
  103. package/dist/runtime/streams/managed-stream.js +3 -5
  104. package/dist/runtime/streams/native-fallback-bound-session.js +13 -16
  105. package/dist/runtime/streams/protocol.js +0 -9
  106. package/dist/runtime/streams/session-calls.d.ts +5 -7
  107. package/dist/runtime/streams/session-calls.js +6 -23
  108. package/dist/runtime/streams/session-context.d.ts +4 -8
  109. package/dist/runtime/streams/session-context.js +3 -32
  110. package/dist/runtime/streams/session-serial-executor.d.ts +0 -1
  111. package/dist/runtime/streams/session-serial-executor.js +0 -3
  112. package/dist/runtime/streams/stream-message-utils.d.ts +0 -1
  113. package/dist/runtime/streams/stream-message-utils.js +0 -20
  114. package/dist/runtime/streams/stream-session-runtime.d.ts +6 -3
  115. package/dist/runtime/streams/stream-session-runtime.js +40 -85
  116. package/package.json +3 -3
  117. package/src/contracts/Actors/ZLinkActorClient.ts +1 -1
  118. package/src/contracts/Channels/Calls.ts +1 -1
  119. package/src/contracts/Configuration/Builders.ts +2 -1
  120. package/src/contracts/Configuration/Configs.ts +0 -1
  121. package/src/contracts/Configuration/InternalDefaults.ts +4 -0
  122. package/src/contracts/Configuration/RegistrationBuilders.ts +13 -3
  123. package/src/contracts/Configuration/RegistrationNormalizers.ts +25 -0
  124. package/src/contracts/Configuration/RegistrationTypes.ts +3 -5
  125. package/src/contracts/Configuration/RegistrationValidators.ts +0 -4
  126. package/src/contracts/Spots/Contracts.ts +1 -1
  127. package/src/contracts/Streams/BoundSessionContracts.ts +1 -1
  128. package/src/contracts/Streams/IZLinkSession.ts +2 -3
  129. package/src/contracts/Streams/IZLinkSessionActor.ts +2 -6
  130. package/src/runtime/actors/actor-client.ts +9 -15
  131. package/src/runtime/actors/actor-mailbox.ts +7 -2
  132. package/src/runtime/actors/actor-request-deadline.ts +4 -49
  133. package/src/runtime/actors/actor-routed-join-transport.ts +3 -5
  134. package/src/runtime/backend/contracts/index.ts +1 -8
  135. package/src/runtime/backend/node/node-backend-adapter-support.ts +45 -5
  136. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +0 -2
  137. package/src/runtime/backend/node/node-raw-binding-port.ts +15 -41
  138. package/src/runtime/backend/node/node-raw-mesh-backend.ts +1 -7
  139. package/src/runtime/backend/node/node-socket-backend-adapter.ts +1 -1
  140. package/src/runtime/channels/channel-clients.ts +9 -19
  141. package/src/runtime/channels/channel-envelope.ts +16 -28
  142. package/src/runtime/channels/channel-outbound-operations.ts +36 -38
  143. package/src/runtime/channels/channel-runtime-manager.ts +6 -28
  144. package/src/runtime/channels/channel-socket-options.ts +0 -13
  145. package/src/runtime/channels/channel-socket-registry.ts +3 -17
  146. package/src/runtime/channels/channel-transports.ts +7 -33
  147. package/src/runtime/channels/local-spot-route-transport.ts +1 -5
  148. package/src/runtime/channels/router-socket-spot-route-transport.ts +2 -6
  149. package/src/runtime/channels/source-spot-router.ts +2 -9
  150. package/src/runtime/channels/spot-node-route-transport.ts +2 -7
  151. package/src/runtime/channels/spot-route-bridge-transport.ts +5 -12
  152. package/src/runtime/channels/spot-route-dispatch-strategy.ts +11 -30
  153. package/src/runtime/execution/serial-execution-queue.ts +117 -29
  154. package/src/runtime/foundation/operation-registry.ts +16 -9
  155. package/src/runtime/foundation/raw-service-mesh-runtime.ts +17 -14
  156. package/src/runtime/foundation/service-authority-payload-codec.ts +0 -46
  157. package/src/runtime/foundation/service-stateful-registry.ts +10 -5
  158. package/src/runtime/foundation/service-stateful-runtime.ts +103 -181
  159. package/src/runtime/foundation/service-stateful-wire-codec.ts +0 -25
  160. package/src/runtime/foundation/service-topology-registry.ts +30 -20
  161. package/src/runtime/host/actor-packet-relay.ts +8 -15
  162. package/src/runtime/host/index.ts +2 -26
  163. package/src/runtime/host/instance-activation-authority.ts +58 -125
  164. package/src/runtime/host/remote-bound-session-relay.ts +8 -16
  165. package/src/runtime/host/spot-address-transport.ts +107 -166
  166. package/src/runtime/host/stateful-authority-route-runtime.ts +22 -9
  167. package/src/runtime/locations/domain-store-contract.ts +5 -0
  168. package/src/runtime/locations/in-memory-authority-store.ts +42 -8
  169. package/src/runtime/locations/in-memory-location-store.ts +8 -0
  170. package/src/runtime/locations/internal-store-contracts.ts +1 -0
  171. package/src/runtime/locations/location-store-repository.ts +130 -68
  172. package/src/runtime/messaging/request-deadline.ts +58 -0
  173. package/src/runtime/messaging/submission-result.ts +18 -4
  174. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +1 -1
  175. package/src/runtime/spots/spot-outbound.ts +14 -24
  176. package/src/runtime/spots/spot-serial-executor.ts +4 -1
  177. package/src/runtime/spots/spot-serial-turn-executor.ts +10 -0
  178. package/src/runtime/streams/bound-actor-relay-sender.ts +12 -26
  179. package/src/runtime/streams/bound-session-service.ts +1 -1
  180. package/src/runtime/streams/index.ts +5 -5
  181. package/src/runtime/streams/managed-stream.ts +3 -13
  182. package/src/runtime/streams/native-fallback-bound-session.ts +13 -25
  183. package/src/runtime/streams/protocol.ts +0 -13
  184. package/src/runtime/streams/session-calls.ts +8 -34
  185. package/src/runtime/streams/session-context.ts +6 -47
  186. package/src/runtime/streams/session-serial-executor.ts +0 -8
  187. package/src/runtime/streams/stream-message-utils.ts +1 -27
  188. package/src/runtime/streams/stream-session-runtime.ts +54 -97
  189. package/dist/runtime/streams/session-requests.d.ts +0 -25
  190. package/dist/runtime/streams/session-requests.js +0 -101
  191. package/src/runtime/streams/session-requests.ts +0 -110
@@ -17,9 +17,14 @@ export class ZLinkActorSerialExecutor {
17
17
  constructor(
18
18
  private readonly actorId: string,
19
19
  private readonly sourceSpotId: unknown,
20
- options?: ZLinkSerialSchedulerOptions
20
+ options?: ZLinkSerialSchedulerOptions,
21
+ sharedOwner?: ZLinkSerialExecutionQueue
21
22
  ) {
22
- this.scheduler = new ZLinkSerialExecutionQueue((record) => this.runRecord(record), options);
23
+ this.scheduler = new ZLinkSerialExecutionQueue(
24
+ (record) => this.runRecord(record),
25
+ options,
26
+ sharedOwner
27
+ );
23
28
  }
24
29
 
25
30
  execute<T>(operation: () => Promise<T> | T, workOptions?: ZLinkSerialWorkOptions): Promise<T> {
@@ -1,49 +1,4 @@
1
- import { awaitWithAbort } from '../abort';
2
- import {
3
- createInternalFrameworkException,
4
- ZLinkFrameworkInternalErrorKind
5
- } from '../framework-errors-internal';
6
-
7
- export function remainingActorRequestTimeout(
8
- actorId: string,
9
- deadlineMs: number | undefined
10
- ): number | undefined {
11
- if (deadlineMs === undefined) return undefined;
12
- const remaining = deadlineMs - performance.now();
13
- if (remaining <= 0) {
14
- throw createInternalFrameworkException(
15
- ZLinkFrameworkInternalErrorKind.DeadlineExceeded,
16
- `Actor request '${actorId}' exceeded its deadline.`
17
- );
18
- }
19
- return Math.max(1, Math.ceil(remaining));
20
- }
21
-
22
- /** Only actual Store, delivery-gate, and handoff waits acquire a deadline handle. */
23
- export async function waitActorReply<T>(
24
- reply: Promise<T>,
25
- actorId: string,
26
- deadlineMs: number | undefined,
27
- signal?: AbortSignal
28
- ): Promise<T> {
29
- if (deadlineMs === undefined) return await awaitWithAbort(reply, signal);
30
- let timer: ReturnType<typeof setTimeout> | undefined;
31
- const timeout = new Promise<never>((_resolve, reject) => {
32
- const remaining = remainingActorRequestTimeout(actorId, deadlineMs);
33
- timer = setTimeout(
34
- () =>
35
- reject(
36
- createInternalFrameworkException(
37
- ZLinkFrameworkInternalErrorKind.DeadlineExceeded,
38
- `Actor request '${actorId}' exceeded its deadline.`
39
- )
40
- ),
41
- remaining
42
- );
43
- });
44
- try {
45
- return await awaitWithAbort(Promise.race([reply, timeout]), signal);
46
- } finally {
47
- clearTimeout(timer);
48
- }
49
- }
1
+ export {
2
+ remainingRequestTimeout as remainingActorRequestTimeout,
3
+ waitRequestReply as waitActorReply
4
+ } from '../messaging/request-deadline';
@@ -18,20 +18,18 @@ export interface ZLinkActorRoutedJoinTransport {
18
18
  routerChannelId: string,
19
19
  targetNodeRid: string,
20
20
  packetName: string | undefined,
21
- message: unknown,
22
- signal?: AbortSignal
21
+ message: unknown
23
22
  ): Promise<ZLinkSubmitResult>;
24
23
  submitInfrastructure?(
25
24
  routerChannelId: string,
26
25
  targetNodeRid: string,
27
26
  packetName: string | undefined,
28
- message: unknown,
29
- signal?: AbortSignal
27
+ message: unknown
30
28
  ): Promise<ZLinkSubmitResult>;
31
29
  sendToSpot(
32
30
  spotRouteTarget: ZLinkSpotRouteTarget,
33
31
  message: unknown,
34
- options: { readonly packetName?: string; readonly signal?: AbortSignal }
32
+ options: { readonly packetName?: string }
35
33
  ): Promise<ZLinkSubmitResult>;
36
34
  requestRawToSpot?(
37
35
  spotRouteTarget: ZLinkSpotRouteTarget,
@@ -492,7 +492,6 @@ export interface ZLinkBackendDealerSocket extends ZLinkBackendConnectableSocket
492
492
  sendHighWaterMark: number;
493
493
  receiveHighWaterMark: number;
494
494
  receiveTimeoutMs: number;
495
- sendTimeoutMs: number;
496
495
  maxMessageSize: number;
497
496
  send(message: Message | readonly Message[]): Promise<void>;
498
497
  request(message: Message | readonly Message[], timeoutMs?: number): Promise<readonly Message[]>;
@@ -523,7 +522,6 @@ export interface ZLinkBackendRouterSocket extends ZLinkBackendConnectableSocket
523
522
  sendHighWaterMark: number;
524
523
  receiveHighWaterMark: number;
525
524
  receiveTimeoutMs: number;
526
- sendTimeoutMs: number;
527
525
  maxMessageSize: number;
528
526
  setRoutingId(routingId: RoutingId): void;
529
527
  recv(flags?: ZLinkBackendRecvFlags): Received | undefined;
@@ -577,7 +575,6 @@ export interface ZLinkBackendStreamPacket {
577
575
  }
578
576
 
579
577
  export interface ZLinkBackendStreamSocket extends ZLinkBackendSocket {
580
- readonly sendTimeoutMs: number;
581
578
  readonly sendHighWaterMark: number;
582
579
  /** Framework stream ingress uses this bound for packet payload validation. */
583
580
  maxMessageSize: number;
@@ -588,11 +585,7 @@ export interface ZLinkBackendStreamSocket extends ZLinkBackendSocket {
588
585
  payload: Message | readonly Message[],
589
586
  flags: ZLinkBackendSendFlags
590
587
  ): boolean;
591
- submit(
592
- routingId: RoutingId,
593
- payload: Message | readonly Message[],
594
- timeoutMs?: number
595
- ): Promise<void>;
588
+ submit(routingId: RoutingId, payload: Message | readonly Message[]): Promise<void>;
596
589
  disconnectPeer(routingId: RoutingId): void;
597
590
  bindActor(
598
591
  sessionRid: RoutingId,
@@ -1,5 +1,9 @@
1
1
  import { constants as osConstants } from 'node:os';
2
- import { requireOneWayCompletion, ZLinkSubmitStatus } from '../../messaging/submission-result';
2
+ import { waitRequestReply } from '../../messaging/request-deadline';
3
+ import {
4
+ requireClassicFanoutCompletion,
5
+ ZLinkSubmitStatus
6
+ } from '../../messaging/submission-result';
3
7
  import { loadBinding } from '../node-backend-adapter';
4
8
  import { SubmitResult, ZLinkBackendResultError } from '../runtime-values';
5
9
  const nativeErrnoValues = osConstants.errno;
@@ -92,7 +96,7 @@ export function submitBindingPublish(
92
96
  (translated.result === SubmitResult.Backpressured ||
93
97
  translated.result === SubmitResult.NotAdmitted)
94
98
  ) {
95
- requireOneWayCompletion(
99
+ requireClassicFanoutCompletion(
96
100
  { status: ZLinkSubmitStatus.Backpressured },
97
101
  'Classic fanout publish'
98
102
  );
@@ -119,6 +123,7 @@ export async function submitBindingAsyncSend(
119
123
  operation: ZLinkBindingAsyncSendOperation,
120
124
  payload: unknown
121
125
  ): Promise<void> {
126
+ let submission: import('@zlink-systems/zlink').SendSubmission;
122
127
  try {
123
128
  let current: ZLinkBindingAsyncSendSubmitOperation | undefined;
124
129
  const parts = Array.isArray(payload) ? payload : [payload];
@@ -127,9 +132,16 @@ export async function submitBindingAsyncSend(
127
132
  current = current === undefined ? operation.message(nativePart) : current.message(nativePart);
128
133
  }
129
134
  current ??= operation.message(Buffer.alloc(0));
130
- await current.submit().admitted;
135
+ submission = current.submit();
131
136
  } catch (error) {
132
- throw translateBindingResultError(error);
137
+ throw translateBindingResultError(error, 'submit');
138
+ }
139
+ if (submission.result === SubmitResult.Backpressured) {
140
+ try {
141
+ await submission.admitted;
142
+ } catch (error) {
143
+ throw translateBindingResultError(error, 'completion');
144
+ }
133
145
  }
134
146
  }
135
147
 
@@ -156,6 +168,7 @@ export async function submitBindingRequest(
156
168
  payload: unknown,
157
169
  timeoutMs: number | undefined
158
170
  ): Promise<readonly unknown[]> {
171
+ const deadlineMs = timeoutMs === undefined ? undefined : performance.now() + timeoutMs;
159
172
  try {
160
173
  let current: ZLinkBindingRequestSubmitOperation | undefined;
161
174
  if (Array.isArray(payload)) {
@@ -171,12 +184,39 @@ export async function submitBindingRequest(
171
184
  if (timeoutMs !== undefined) {
172
185
  current = current.timeout(timeoutMs);
173
186
  }
174
- return await current.submit().reply;
187
+ return await bindingRequestReply(current.submit(), deadlineMs);
175
188
  } catch (error) {
176
189
  throw translateBindingResultError(error);
177
190
  }
178
191
  }
179
192
 
193
+ export async function bindingRequestReply(
194
+ submission: import('@zlink-systems/zlink').RequestSubmission,
195
+ deadlineMs: number | undefined
196
+ ): Promise<import('@zlink-systems/zlink').Message[]> {
197
+ const reply = submission.reply;
198
+ if (submission.result === SubmitResult.Backpressured) {
199
+ try {
200
+ const [, replies] = await waitRequestReply(
201
+ Promise.all([submission.admitted, reply]),
202
+ 'Request',
203
+ deadlineMs
204
+ );
205
+ return replies;
206
+ } catch (error) {
207
+ void reply.then(closeBindingReply, () => undefined);
208
+ throw error;
209
+ }
210
+ }
211
+ return reply;
212
+ }
213
+
214
+ export function closeBindingReply(
215
+ replies: readonly import('@zlink-systems/zlink').Message[]
216
+ ): void {
217
+ for (const reply of replies) reply.close();
218
+ }
219
+
180
220
  /**
181
221
  * Closes a binding handle once. An already closed or terminated handle counts as
182
222
  * closed. A busy close propagates to the caller.
@@ -24,10 +24,8 @@ export class ZLinkDealerChannelClientTransport implements ZLinkChannelClientTran
24
24
  channelName: string,
25
25
  packetName: string | undefined,
26
26
  message: Message,
27
- signal?: AbortSignal,
28
27
  metadata: ReadonlyMap<string, string> = EMPTY_METADATA
29
28
  ): Promise<ZLinkSubmitResult> {
30
- throwIfAborted(signal);
31
29
  // Call-scoped flow (spec 27 §4): the envelope flow pair does not outlive
32
30
  // this outbound call.
33
31
  await runWithOutboundFlow(
@@ -7,7 +7,6 @@ import {
7
7
  createDealerSocket,
8
8
  createRouterSocket,
9
9
  ReceiveFlowState,
10
- SubmitResult,
11
10
  type Context,
12
11
  type DealerSocket,
13
12
  type MonitorEvent,
@@ -18,11 +17,13 @@ import {
18
17
  type RequestOperation,
19
18
  type RequestSubmitOperation,
20
19
  type RouterSocket,
21
- type SendOperation,
22
- type SendSubmitOperation,
23
20
  type Socket
24
21
  } from '@zlink-systems/zlink';
25
- import { translateBindingResultError } from './node-backend-adapter-support';
22
+ import {
23
+ translateBindingResultError,
24
+ bindingRequestReply,
25
+ submitBindingAsyncSend
26
+ } from './node-backend-adapter-support';
26
27
  import { isEndpointCloseIgnorableError } from './node-socket-backend-adapter';
27
28
  import { ZLinkNodeEventLoopPoller } from './node-event-loop-poller';
28
29
  import type {
@@ -266,15 +267,10 @@ class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLink
266
267
  this.connect(endpoint);
267
268
  }
268
269
 
269
- async send(targetRid: string, parts: readonly Uint8Array[]): Promise<void> {
270
+ send(targetRid: string, parts: readonly Uint8Array[]): Promise<void> {
270
271
  this.requireOpen();
271
- const submission = appendSendParts(
272
- this.socket.send(bindingRoutingId(targetRid)),
273
- parts
274
- ).submit();
275
- if (submission.result === SubmitResult.Backpressured) {
276
- await submission.admitted;
277
- }
272
+ requireParts(parts);
273
+ return submitBindingAsyncSend(this.socket.send(bindingRoutingId(targetRid)), parts);
278
274
  }
279
275
 
280
276
  async request(
@@ -283,6 +279,7 @@ class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLink
283
279
  timeoutMs: number
284
280
  ): Promise<readonly Buffer[]> {
285
281
  this.requireOpen();
282
+ const deadlineMs = performance.now() + timeoutMs;
286
283
  let submission: ReturnType<RequestSubmitOperation['submit']>;
287
284
  try {
288
285
  submission = appendRequestParts(this.socket.request(bindingRoutingId(targetRid)), parts)
@@ -292,7 +289,7 @@ class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLink
292
289
  throw translateBindingResultError(error, 'submit');
293
290
  }
294
291
  try {
295
- const replies = await requestReply(submission);
292
+ const replies = await bindingRequestReply(submission, deadlineMs);
296
293
  return copyAndClose(replies);
297
294
  } catch (error) {
298
295
  throw translateBindingResultError(error, 'completion');
@@ -338,16 +335,15 @@ class NodeRawDealerPort extends NodeRawSocketPort<DealerSocket> implements ZLink
338
335
  this.socket.setRoutingId(bindingRoutingId(routingId));
339
336
  }
340
337
 
341
- async send(parts: readonly Uint8Array[]): Promise<void> {
338
+ send(parts: readonly Uint8Array[]): Promise<void> {
342
339
  this.requireOpen();
343
- const submission = appendSendParts(this.socket.send(), parts).submit();
344
- if (submission.result === SubmitResult.Backpressured) {
345
- await submission.admitted;
346
- }
340
+ requireParts(parts);
341
+ return submitBindingAsyncSend(this.socket.send(), parts);
347
342
  }
348
343
 
349
344
  async request(parts: readonly Uint8Array[], timeoutMs: number): Promise<readonly Buffer[]> {
350
345
  this.requireOpen();
346
+ const deadlineMs = performance.now() + timeoutMs;
351
347
  let submission: ReturnType<RequestSubmitOperation['submit']>;
352
348
  try {
353
349
  submission = appendRequestParts(this.socket.request(), parts).timeout(timeoutMs).submit();
@@ -355,7 +351,7 @@ class NodeRawDealerPort extends NodeRawSocketPort<DealerSocket> implements ZLink
355
351
  throw translateBindingResultError(error, 'submit');
356
352
  }
357
353
  try {
358
- const replies = await requestReply(submission);
354
+ const replies = await bindingRequestReply(submission, deadlineMs);
359
355
  return copyAndClose(replies);
360
356
  } catch (error) {
361
357
  throw translateBindingResultError(error, 'completion');
@@ -368,16 +364,6 @@ class NodeRawDealerPort extends NodeRawSocketPort<DealerSocket> implements ZLink
368
364
  }
369
365
  }
370
366
 
371
- async function requestReply(
372
- submission: ReturnType<RequestSubmitOperation['submit']>
373
- ): Promise<Message[]> {
374
- if (submission.result === SubmitResult.Backpressured) {
375
- const [, replies] = await Promise.all([submission.admitted, submission.reply]);
376
- return replies;
377
- }
378
- return submission.reply;
379
- }
380
-
381
367
  class NodeRawMonitorPort implements ZLinkRawMonitorPort {
382
368
  private closed = false;
383
369
 
@@ -410,18 +396,6 @@ class NodeRawMonitorPort implements ZLinkRawMonitorPort {
410
396
  }
411
397
  }
412
398
 
413
- function appendSendParts(
414
- operation: SendOperation,
415
- parts: readonly Uint8Array[]
416
- ): SendSubmitOperation {
417
- requireParts(parts);
418
- let next = operation.message(parts[0]);
419
- for (let index = 1; index < parts.length; index += 1) {
420
- next = next.message(parts[index]);
421
- }
422
- return next;
423
- }
424
-
425
399
  function appendRequestParts(
426
400
  operation: RequestOperation,
427
401
  parts: readonly Uint8Array[]
@@ -297,19 +297,13 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
297
297
  selectObjectPlacement(stableType: string): ZLinkBackendObjectPlacement {
298
298
  const runtime = this.requireRuntime();
299
299
  const localNodeRid = runtime.topology.localDescriptor().nodeRoutingId;
300
- const status = runtime.topology.objectPlacementStatus(
300
+ const { status, descriptor } = runtime.topology.selectObjectPlacementWithStatus(
301
301
  stableType,
302
302
  (candidate) =>
303
303
  candidate.nodeRoutingId === localNodeRid ||
304
304
  runtime.isPeerRouteReady(candidate.nodeRoutingId)
305
305
  );
306
306
  if (status !== 'available') return { kind: status };
307
- const descriptor = runtime.topology.selectObjectPlacement(
308
- stableType,
309
- (candidate) =>
310
- candidate.nodeRoutingId === localNodeRid ||
311
- runtime.isPeerRouteReady(candidate.nodeRoutingId)
312
- );
313
307
  return descriptor === undefined
314
308
  ? { kind: 'unavailable' }
315
309
  : {
@@ -194,7 +194,7 @@ export function wrapSocket<T extends { close(): void }>(
194
194
  }
195
195
  return submitBindingAsyncSend(operation, payload);
196
196
  },
197
- submit(routingId: unknown, payload: unknown, _timeoutMs?: number): Promise<void> {
197
+ submit(routingId: unknown, payload: unknown): Promise<void> {
198
198
  if (!hasStream) throw new TypeError('Async stream send requires a STREAM socket.');
199
199
  return submitBindingAsyncSend(
200
200
  (nativeInstance as T & { send(routingId: unknown): ZLinkBindingAsyncSendOperation }).send(
@@ -20,6 +20,7 @@ import {
20
20
  import {
21
21
  requireOneWayCompletion,
22
22
  requirePublishCompletion,
23
+ requireClassicFanoutCompletion,
23
24
  throwAlreadySubmitted,
24
25
  ZLinkSubmitStatus,
25
26
  type ZLinkSubmitResult
@@ -176,14 +177,13 @@ export class DefaultZLinkRouteClient implements ZLinkRouteClient {
176
177
  sendToNode(meshName: string, targetNodeRid: string, message: unknown): ZLinkSendCall {
177
178
  return new DefaultZLinkSendCall(
178
179
  () => this.requireMesh(meshName),
179
- async (packetName, metadata, signal) =>
180
+ async (packetName, metadata) =>
180
181
  normalizeSubmitResult(
181
182
  await this.requireTransport().submit(
182
183
  meshName,
183
184
  targetNodeRid,
184
185
  packetName,
185
186
  message,
186
- signal,
187
187
  metadata
188
188
  )
189
189
  )
@@ -210,7 +210,7 @@ export class DefaultZLinkRouteClient implements ZLinkRouteClient {
210
210
  sendToChannel(channelName: string, message: unknown): ZLinkSendCall {
211
211
  return new DefaultZLinkSendCall(
212
212
  () => this.requireChannelRoute(channelName),
213
- async (packetName, metadata, signal) => {
213
+ async (packetName, metadata) => {
214
214
  const route = this.requireChannelRoute(channelName);
215
215
  if (route.kind === 'route-mesh') {
216
216
  return normalizeSubmitResult(
@@ -219,19 +219,12 @@ export class DefaultZLinkRouteClient implements ZLinkRouteClient {
219
219
  channelName,
220
220
  packetName,
221
221
  message,
222
- signal,
223
222
  metadata
224
223
  )
225
224
  );
226
225
  }
227
226
  return normalizeSubmitResult(
228
- await this.requireChannelTransport().send(
229
- channelName,
230
- packetName,
231
- message,
232
- signal,
233
- metadata
234
- )
227
+ await this.requireChannelTransport().send(channelName, packetName, message, metadata)
235
228
  );
236
229
  }
237
230
  );
@@ -271,9 +264,8 @@ export class DefaultZLinkRouteClient implements ZLinkRouteClient {
271
264
  () => {
272
265
  this.requireSpotTransport();
273
266
  },
274
- async (_packetName, metadata, signal) => {
267
+ async (_packetName, metadata) => {
275
268
  await sendToSpotHandle(this.requireSpotTransport(), spot, message, {
276
- signal,
277
269
  metadata,
278
270
  spotRouterChannelIdForMesh: this.spotRouterChannelIdForMesh
279
271
  });
@@ -431,8 +423,7 @@ class DefaultZLinkSendCall implements ZLinkSendCall {
431
423
  private readonly validate: () => void,
432
424
  private readonly submitter: (
433
425
  packetName: string | undefined,
434
- metadata: ReadonlyMap<string, string>,
435
- signal?: AbortSignal
426
+ metadata: ReadonlyMap<string, string>
436
427
  ) => Promise<ZLinkSubmitResult>
437
428
  ) {}
438
429
 
@@ -450,12 +441,11 @@ class DefaultZLinkSendCall implements ZLinkSendCall {
450
441
  return this;
451
442
  }
452
443
 
453
- async submit(signal?: AbortSignal): Promise<void> {
444
+ async submit(): Promise<void> {
454
445
  ensureNotExecuted(this.executed);
455
446
  this.validate();
456
447
  this.executed = true;
457
- throwIfAborted(signal);
458
- const result = await this.submitter(undefined, new Map(this.selectedMetadata), signal);
448
+ const result = await this.submitter(undefined, new Map(this.selectedMetadata));
459
449
  requireOneWayCompletion(result, 'One-way send');
460
450
  }
461
451
  }
@@ -580,6 +570,6 @@ class DefaultZLinkFanoutPublishCall implements ZLinkFanoutPublishCall {
580
570
  this.executed = true;
581
571
  throwIfAborted(signal);
582
572
  const result = await this.submitter(signal);
583
- requireOneWayCompletion(result, 'Classic fanout publish');
573
+ requireClassicFanoutCompletion(result, 'Classic fanout publish');
584
574
  }
585
575
  }
@@ -86,33 +86,18 @@ export function encodeChannelEnvelopeParts(
86
86
  createFlow = true,
87
87
  metadata: ReadonlyMap<string, string> = EMPTY_OUTBOUND_METADATA
88
88
  ): readonly MessageLike[] {
89
- const messageName = resolveFrameworkPacketName(payload, packetName, 'Channel');
90
- const encoded = encodePayload(
89
+ return encodeChannelEnvelopePartsAtDeadline(
90
+ kind,
91
+ channelName,
92
+ packetName,
91
93
  payload,
92
- codecsForFrameworkPacket(messageName, codecs),
93
- messageName,
94
- 'payload'
94
+ timeoutMs === undefined ? undefined : Date.now() + timeoutMs,
95
+ topic,
96
+ codecs,
97
+ correlationId,
98
+ createFlow,
99
+ metadata
95
100
  );
96
- const flow = createFlow ? currentOrCreateFlow('Application') : undefined;
97
- const envelopeCorrelationId = correlationIdForOutboundKind(kind, correlationId);
98
- return [
99
- encodeChannelHeader(
100
- kind,
101
- channelName,
102
- messageName,
103
- encoded.contentType,
104
- envelopeCorrelationId,
105
- timeoutMs === undefined ? null : new Date(Date.now() + timeoutMs).toISOString(),
106
- topic ?? null,
107
- null,
108
- null,
109
- undefined,
110
- applicationMetadataRecord(metadata),
111
- flow?.flowId,
112
- flow?.flowOrigin
113
- ),
114
- encoded.message
115
- ];
116
101
  }
117
102
 
118
103
  /**
@@ -126,14 +111,17 @@ export function encodeChannelEnvelopePartsAtDeadline(
126
111
  channelName: string,
127
112
  packetName: string | undefined,
128
113
  payload: unknown,
129
- deadlineUnixMs: number,
114
+ deadlineUnixMs: number | undefined,
130
115
  topic?: string,
131
116
  codecs?: ZLinkChannelEnvelopeCodecRegistry,
132
117
  correlationId?: string,
133
118
  createFlow = true,
134
119
  metadata: ReadonlyMap<string, string> = EMPTY_OUTBOUND_METADATA
135
120
  ): readonly MessageLike[] {
136
- if (!Number.isSafeInteger(deadlineUnixMs) || deadlineUnixMs <= 0) {
121
+ if (
122
+ deadlineUnixMs !== undefined &&
123
+ (!Number.isSafeInteger(deadlineUnixMs) || deadlineUnixMs <= 0)
124
+ ) {
137
125
  throw new RangeError('deadlineUnixMs must be a positive safe integer.');
138
126
  }
139
127
  const messageName = resolveFrameworkPacketName(payload, packetName, 'Channel');
@@ -152,7 +140,7 @@ export function encodeChannelEnvelopePartsAtDeadline(
152
140
  messageName,
153
141
  encoded.contentType,
154
142
  envelopeCorrelationId,
155
- new Date(deadlineUnixMs).toISOString(),
143
+ deadlineUnixMs === undefined ? null : new Date(deadlineUnixMs).toISOString(),
156
144
  topic ?? null,
157
145
  null,
158
146
  null,