@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,4 +1,6 @@
1
1
  import { DEFAULT_REQUEST_TIMEOUT_MS } from '../../contracts/Configuration/Registration';
2
+ import { createZLinkRequest } from '../messaging/request-result';
3
+ import type { ZLinkRequest } from '../../contracts/Handlers/Attributes';
2
4
  import type {
3
5
  ZLinkChannelClient,
4
6
  ZLinkChannelRequestCall,
@@ -23,6 +25,7 @@ import {
23
25
  requireClassicFanoutCompletion,
24
26
  throwAlreadySubmitted,
25
27
  ZLinkSubmitStatus,
28
+ submittedResult,
26
29
  type ZLinkSubmitResult
27
30
  } from '../messaging/submission-result';
28
31
  import type {
@@ -165,7 +168,17 @@ export class DefaultZLinkFanoutClient implements ZLinkFanoutClient {
165
168
  }
166
169
  }
167
170
 
171
+ interface PreparedNodeSend {
172
+ readonly validate: () => void;
173
+ readonly submit: (
174
+ packetName: string | undefined,
175
+ metadata: ReadonlyMap<string, string>,
176
+ message?: unknown
177
+ ) => ZLinkSubmitResult | Promise<ZLinkSubmitResult>;
178
+ }
179
+
168
180
  export class DefaultZLinkRouteClient implements ZLinkRouteClient {
181
+ private readonly nodeSends = new Map<string, Map<string, PreparedNodeSend>>();
169
182
  constructor(
170
183
  private readonly registration: ZLinkFrameworkRegistration,
171
184
  private readonly transport?: ZLinkRouteClientTransport,
@@ -175,25 +188,28 @@ export class DefaultZLinkRouteClient implements ZLinkRouteClient {
175
188
  ) {}
176
189
 
177
190
  sendToNode(meshName: string, targetNodeRid: string, message: unknown): ZLinkSendCall {
178
- return new DefaultZLinkSendCall(
179
- () => this.requireMesh(meshName),
180
- async (packetName, metadata) =>
181
- normalizeSubmitResult(
182
- await this.requireTransport().submit(
183
- meshName,
184
- targetNodeRid,
185
- packetName,
186
- message,
187
- metadata
191
+ let targets = this.nodeSends.get(meshName);
192
+ if (targets === undefined) this.nodeSends.set(meshName, (targets = new Map()));
193
+ let prepared = targets.get(targetNodeRid);
194
+ if (prepared === undefined) {
195
+ prepared = {
196
+ validate: () => {
197
+ this.requireMesh(meshName);
198
+ },
199
+ submit: (packetName, metadata, payload) =>
200
+ normalizeSubmitResult(
201
+ this.requireTransport().submit(meshName, targetNodeRid, packetName, payload, metadata)
188
202
  )
189
- )
190
- );
203
+ };
204
+ targets.set(targetNodeRid, prepared);
205
+ }
206
+ return new DefaultZLinkSendCall(prepared.validate, prepared.submit, message);
191
207
  }
192
208
 
193
209
  requestToNode(meshName: string, targetNodeRid: string, request: unknown): ZLinkRequestCall {
194
210
  return new DefaultZLinkRequestCall(
195
211
  () => this.requireMesh(meshName),
196
- (packetName, timeoutMs, metadata, signal) =>
212
+ (packetName, timeoutMs, metadata, signal, onAdmitted) =>
197
213
  this.requireTransport().request(
198
214
  meshName,
199
215
  targetNodeRid,
@@ -201,7 +217,8 @@ export class DefaultZLinkRouteClient implements ZLinkRouteClient {
201
217
  request,
202
218
  timeoutMs,
203
219
  signal,
204
- metadata
220
+ metadata,
221
+ onAdmitted
205
222
  ),
206
223
  this.defaultRequestTimeout(meshName)
207
224
  );
@@ -233,7 +250,7 @@ export class DefaultZLinkRouteClient implements ZLinkRouteClient {
233
250
  requestToChannel(channelName: string, request: unknown): ZLinkChannelRequestCall {
234
251
  return new DefaultZLinkRequestCall(
235
252
  () => this.requireChannelRoute(channelName),
236
- (packetName, timeoutMs, metadata, signal) => {
253
+ (packetName, timeoutMs, metadata, signal, onAdmitted) => {
237
254
  const route = this.requireChannelRoute(channelName);
238
255
  if (route.kind === 'route-mesh') {
239
256
  return this.requireTransport().requestToChannel(
@@ -243,7 +260,8 @@ export class DefaultZLinkRouteClient implements ZLinkRouteClient {
243
260
  request,
244
261
  timeoutMs,
245
262
  signal,
246
- metadata
263
+ metadata,
264
+ onAdmitted
247
265
  );
248
266
  }
249
267
  return this.requireChannelTransport().request(
@@ -252,7 +270,8 @@ export class DefaultZLinkRouteClient implements ZLinkRouteClient {
252
270
  request,
253
271
  timeoutMs,
254
272
  signal,
255
- metadata
273
+ metadata,
274
+ onAdmitted
256
275
  );
257
276
  },
258
277
  this.defaultRequestTimeoutForChannel(channelName)
@@ -279,11 +298,12 @@ export class DefaultZLinkRouteClient implements ZLinkRouteClient {
279
298
  () => {
280
299
  this.requireSpotTransport();
281
300
  },
282
- (_packetName, timeoutMs, metadata, signal) =>
301
+ (_packetName, timeoutMs, metadata, signal, onAdmitted) =>
283
302
  requestToSpotHandle(this.requireSpotTransport(), spot, request, {
284
303
  timeoutMs,
285
304
  signal,
286
305
  metadata,
306
+ onAdmitted,
287
307
  spotRouterChannelIdForMesh: this.spotRouterChannelIdForMesh
288
308
  }),
289
309
  this.registration.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS
@@ -416,21 +436,24 @@ export class DefaultZLinkSpotPublisherClient implements ZLinkSpotPublisherClient
416
436
  }
417
437
 
418
438
  class DefaultZLinkSendCall implements ZLinkSendCall {
419
- private readonly selectedMetadata = new Map<string, string>();
439
+ private selectedMetadata?: Map<string, string>;
420
440
  private executed = false;
421
441
 
422
442
  constructor(
423
443
  private readonly validate: () => void,
424
444
  private readonly submitter: (
425
445
  packetName: string | undefined,
426
- metadata: ReadonlyMap<string, string>
427
- ) => Promise<ZLinkSubmitResult>
446
+ metadata: ReadonlyMap<string, string>,
447
+ message?: unknown
448
+ ) => ZLinkSubmitResult | Promise<ZLinkSubmitResult>,
449
+ private readonly message?: unknown
428
450
  ) {}
429
451
 
430
452
  metadata(key: string, value: string): this;
431
453
  metadata(metadata: ZLinkMessageMetadata): this;
432
454
  metadata(keyOrMetadata: string | ZLinkMessageMetadata, value?: string): this {
433
455
  ensureNotExecuted(this.executed);
456
+ this.selectedMetadata ??= new Map<string, string>();
434
457
  if (typeof keyOrMetadata === 'string') {
435
458
  this.selectedMetadata.set(keyOrMetadata, value!);
436
459
  } else {
@@ -441,12 +464,22 @@ class DefaultZLinkSendCall implements ZLinkSendCall {
441
464
  return this;
442
465
  }
443
466
 
444
- async submit(): Promise<void> {
445
- ensureNotExecuted(this.executed);
446
- this.validate();
447
- this.executed = true;
448
- const result = await this.submitter(undefined, new Map(this.selectedMetadata));
449
- requireOneWayCompletion(result, 'One-way send');
467
+ submit(): Promise<void> {
468
+ try {
469
+ ensureNotExecuted(this.executed);
470
+ this.validate();
471
+ this.executed = true;
472
+ const result = this.submitter(
473
+ undefined,
474
+ this.selectedMetadata ?? EMPTY_CALL_METADATA,
475
+ this.message
476
+ );
477
+ if (result instanceof Promise) return result.then(completeOneWaySend);
478
+ completeOneWaySend(result);
479
+ return completedOneWaySend;
480
+ } catch (error) {
481
+ return Promise.reject(error);
482
+ }
450
483
  }
451
484
  }
452
485
 
@@ -456,13 +489,24 @@ function ensureNotExecuted(executed: boolean): void {
456
489
  }
457
490
  }
458
491
 
459
- function normalizeSubmitResult(result: void | ZLinkSubmitResult): ZLinkSubmitResult {
460
- return result ?? { status: ZLinkSubmitStatus.Submitted };
492
+ const EMPTY_CALL_METADATA: ReadonlyMap<string, string> = new Map();
493
+ const completedOneWaySend = Promise.resolve();
494
+
495
+ function completeOneWaySend(result: ZLinkSubmitResult): void {
496
+ requireOneWayCompletion(result, 'One-way send');
497
+ }
498
+
499
+ function normalizeSubmitResult(
500
+ result: void | ZLinkSubmitResult | Promise<void | ZLinkSubmitResult>
501
+ ): ZLinkSubmitResult | Promise<ZLinkSubmitResult> {
502
+ return result instanceof Promise
503
+ ? result.then((value) => value ?? submittedResult)
504
+ : (result ?? submittedResult);
461
505
  }
462
506
 
463
507
  class DefaultZLinkRequestCall implements ZLinkChannelRequestCall {
464
508
  private timeoutMs?: number;
465
- private readonly selectedMetadata = new Map<string, string>();
509
+ private selectedMetadata?: Map<string, string>;
466
510
  private readonly turn: ZLinkSpotSerialTurn | undefined = captureZLinkSpotSerialTurn();
467
511
 
468
512
  constructor(
@@ -471,7 +515,8 @@ class DefaultZLinkRequestCall implements ZLinkChannelRequestCall {
471
515
  packetName: string | undefined,
472
516
  timeoutMs: number | undefined,
473
517
  metadata: ReadonlyMap<string, string>,
474
- signal?: AbortSignal
518
+ signal?: AbortSignal,
519
+ onAdmitted?: () => void
475
520
  ) => Promise<TReply>,
476
521
  private readonly defaultRequestTimeoutMs?: number
477
522
  ) {}
@@ -479,6 +524,7 @@ class DefaultZLinkRequestCall implements ZLinkChannelRequestCall {
479
524
  metadata(key: string, value: string): this;
480
525
  metadata(metadata: ZLinkMessageMetadata): this;
481
526
  metadata(keyOrMetadata: string | ZLinkMessageMetadata, value?: string): this {
527
+ this.selectedMetadata ??= new Map<string, string>();
482
528
  if (typeof keyOrMetadata === 'string') {
483
529
  this.selectedMetadata.set(keyOrMetadata, value!);
484
530
  } else {
@@ -494,15 +540,18 @@ class DefaultZLinkRequestCall implements ZLinkChannelRequestCall {
494
540
  return this;
495
541
  }
496
542
 
497
- async submit<TReply>(signal?: AbortSignal): Promise<TReply> {
498
- throwIfAborted(signal);
499
- this.validate();
500
- return this.submitter<TReply>(
501
- undefined,
502
- this.timeoutMs ?? this.defaultRequestTimeoutMs,
503
- new Map(this.selectedMetadata),
504
- signal
505
- );
543
+ submit<TReply>(signal?: AbortSignal): ZLinkRequest<TReply> {
544
+ return createZLinkRequest((onAdmitted) => {
545
+ throwIfAborted(signal);
546
+ this.validate();
547
+ return this.submitter<TReply>(
548
+ undefined,
549
+ this.timeoutMs ?? this.defaultRequestTimeoutMs,
550
+ this.selectedMetadata === undefined ? EMPTY_CALL_METADATA : new Map(this.selectedMetadata),
551
+ signal,
552
+ onAdmitted
553
+ );
554
+ });
506
555
  }
507
556
 
508
557
  async yield<TReply>(signal?: AbortSignal): Promise<TReply> {
@@ -512,7 +561,7 @@ class DefaultZLinkRequestCall implements ZLinkChannelRequestCall {
512
561
  const pending = this.submitter<TReply>(
513
562
  undefined,
514
563
  this.timeoutMs ?? this.defaultRequestTimeoutMs,
515
- new Map(this.selectedMetadata),
564
+ this.selectedMetadata === undefined ? EMPTY_CALL_METADATA : new Map(this.selectedMetadata),
516
565
  signal
517
566
  );
518
567
  return turn.yieldPromise(pending);
@@ -26,7 +26,6 @@ import {
26
26
  import { invokeZLinkHandlerFilters } from '../handlers';
27
27
  import {
28
28
  decodeChannelPayload,
29
- ZLinkChannelMessageKind,
30
29
  type ZLinkChannelEnvelope,
31
30
  type ZLinkChannelEnvelopeCodecRegistry
32
31
  } from './channel-envelope';
@@ -74,8 +73,8 @@ interface ZLinkRequestDispatch<TContext extends ZLinkMessageContext> {
74
73
  readonly context: TContext;
75
74
  readonly signal?: AbortSignal;
76
75
  readonly missingHandlerMessage: string;
77
- readonly writeReply: (reply: unknown) => Promise<void>;
78
- readonly writeError: (error: unknown) => Promise<void>;
76
+ readonly writeReply: (reply: unknown) => void | Promise<void>;
77
+ readonly writeError: (error: unknown) => void | Promise<void>;
79
78
  }
80
79
 
81
80
  export class ZLinkChannelDispatchPipeline {
@@ -113,17 +112,27 @@ export class ZLinkChannelDispatchPipeline {
113
112
  this.options.dispatchErrors.flow.flowCreationEnabled(),
114
113
  undefined
115
114
  );
116
- const invocation = await runWithFlow(flow, () =>
117
- this.invoke(
118
- dispatch.envelope,
119
- dispatch.codecs,
120
- dispatch.handler!,
121
- dispatch.context,
122
- dispatch.fields,
123
- dispatch.signal
124
- )
125
- );
126
- if (invocation.handlerInvoked) {
115
+ const invocation = await (flow === undefined
116
+ ? this.invoke(
117
+ dispatch.envelope,
118
+ dispatch.codecs,
119
+ dispatch.handler,
120
+ dispatch.context,
121
+ dispatch.fields,
122
+ dispatch.signal
123
+ )
124
+ : runWithFlow(flow, () =>
125
+ this.invoke(
126
+ dispatch.envelope,
127
+ dispatch.codecs,
128
+ dispatch.handler!,
129
+ dispatch.context,
130
+ dispatch.fields,
131
+ dispatch.signal
132
+ )
133
+ ));
134
+
135
+ if (invocation !== HANDLER_FILTER_REJECTED) {
127
136
  this.trace(ZLinkMessageFlowOutcome.Completed, dispatch.fields);
128
137
  }
129
138
  } catch (error) {
@@ -165,23 +174,33 @@ export class ZLinkChannelDispatchPipeline {
165
174
  this.options.dispatchErrors.flow.flowCreationEnabled(),
166
175
  undefined
167
176
  );
168
- const invocation = await runWithFlow(flow, () =>
169
- this.invoke(
170
- dispatch.envelope,
171
- dispatch.codecs,
172
- dispatch.handler!,
173
- dispatch.context,
174
- dispatch.fields,
175
- dispatch.signal
176
- )
177
- );
178
- if (!invocation.handlerInvoked) {
177
+ const invocation = await (flow === undefined
178
+ ? this.invoke(
179
+ dispatch.envelope,
180
+ dispatch.codecs,
181
+ dispatch.handler,
182
+ dispatch.context,
183
+ dispatch.fields,
184
+ dispatch.signal
185
+ )
186
+ : runWithFlow(flow, () =>
187
+ this.invoke(
188
+ dispatch.envelope,
189
+ dispatch.codecs,
190
+ dispatch.handler!,
191
+ dispatch.context,
192
+ dispatch.fields,
193
+ dispatch.signal
194
+ )
195
+ ));
196
+
197
+ if (invocation === HANDLER_FILTER_REJECTED) {
179
198
  throw createInternalFrameworkException(
180
199
  ZLinkFrameworkInternalErrorKind.RequestRejected,
181
200
  `A handler filter rejected '${this.options.channelName}:${dispatch.fields.packetName}'.`
182
201
  );
183
202
  }
184
- reply = invocation.value;
203
+ reply = invocation;
185
204
  } catch (error) {
186
205
  try {
187
206
  await dispatch.writeError(error);
@@ -206,7 +225,8 @@ export class ZLinkChannelDispatchPipeline {
206
225
  }
207
226
 
208
227
  try {
209
- await dispatch.writeReply(reply);
228
+ const written = dispatch.writeReply(reply);
229
+ if (written !== undefined) await written;
210
230
  this.trace(ZLinkMessageFlowOutcome.Replied, dispatch.fields);
211
231
  } catch (error) {
212
232
  // Spec 26 §3.1: a failed reply write means the reply delivery path is
@@ -240,9 +260,7 @@ export class ZLinkChannelDispatchPipeline {
240
260
  readonly writeProtocolError?: (error: ZLinkFrameworkException) => Promise<void>;
241
261
  }): Promise<void> {
242
262
  const { info } = input;
243
- const isRequest =
244
- info.kind === ZLinkChannelMessageKind.Request ||
245
- (info.kind === undefined && input.transportRequest);
263
+ const isRequest = input.transportRequest;
246
264
  let replied = false;
247
265
  if (isRequest && input.writeProtocolError !== undefined && info.correlationId !== undefined) {
248
266
  const protocolError = new ZLinkFrameworkException(
@@ -271,22 +289,37 @@ export class ZLinkChannelDispatchPipeline {
271
289
  });
272
290
  }
273
291
 
274
- private async invoke<TContext extends ZLinkMessageContext, TResult>(
292
+ private invoke<TContext extends ZLinkMessageContext, TResult>(
275
293
  envelope: ZLinkChannelEnvelope,
276
294
  codecs: ZLinkChannelEnvelopeCodecRegistry | undefined,
277
295
  handler: ZLinkChannelDispatchHandler<TContext, TResult>,
278
296
  context: TContext,
279
297
  fields: ZLinkChannelDispatchFields,
280
298
  signal?: AbortSignal
281
- ): Promise<{ readonly handlerInvoked: boolean; readonly value?: TResult }> {
299
+ ):
300
+ | TResult
301
+ | undefined
302
+ | typeof HANDLER_FILTER_REJECTED
303
+ | Promise<TResult | undefined | typeof HANDLER_FILTER_REJECTED> {
282
304
  releaseApplicationJobPermitBeforeHandler();
283
305
  if (this.filters.length === 0) {
284
306
  // Fast path for the dominant unfiltered dispatch: skip the filter
285
307
  // context object and chain machinery entirely.
286
308
  const payload = decodeChannelPayload(envelope, codecs);
287
309
  this.trace(ZLinkMessageFlowOutcome.Dispatched, fields);
288
- return { handlerInvoked: true, value: await handler.handle(payload, context) };
310
+ return handler.handle(payload, context);
289
311
  }
312
+ return this.invokeFiltered(envelope, codecs, handler, context, fields, signal);
313
+ }
314
+
315
+ private async invokeFiltered<TContext extends ZLinkMessageContext, TResult>(
316
+ envelope: ZLinkChannelEnvelope,
317
+ codecs: ZLinkChannelEnvelopeCodecRegistry | undefined,
318
+ handler: ZLinkChannelDispatchHandler<TContext, TResult>,
319
+ context: TContext,
320
+ fields: ZLinkChannelDispatchFields,
321
+ signal?: AbortSignal
322
+ ): Promise<TResult | undefined | typeof HANDLER_FILTER_REJECTED> {
290
323
  let value: TResult | undefined;
291
324
  const handlerInvoked = await invokeZLinkHandlerFilters(
292
325
  this.filters,
@@ -300,7 +333,7 @@ export class ZLinkChannelDispatchPipeline {
300
333
  },
301
334
  signal
302
335
  );
303
- return { handlerInvoked, value };
336
+ return handlerInvoked ? value : HANDLER_FILTER_REJECTED;
304
337
  }
305
338
 
306
339
  private createFilterContext(
@@ -401,6 +434,8 @@ export class ZLinkChannelDispatchPipeline {
401
434
  }
402
435
  }
403
436
 
437
+ const HANDLER_FILTER_REJECTED = Symbol('handler-filter-rejected');
438
+
404
439
  const DEFAULT_UNHANDLED_DISPATCH: ZLinkUnhandledDispatchOptions = {
405
440
  request: ZLinkUnhandledDispatchAction.ReplyError,
406
441
  send: ZLinkUnhandledDispatchAction.LogAndDrop,
@@ -26,7 +26,11 @@ import {
26
26
  import type { ZLinkRuntimeTaskErrorSink } from '../execution';
27
27
  import { ZLinkDispatchErrorReporter } from './dispatch-error-reporter';
28
28
  import { invokeZLinkHandlerFilters } from '../handlers';
29
- import { runInHandlerInstanceScope } from '../handlers/handler-instance-scope';
29
+ import {
30
+ runInHandlerInstanceScope,
31
+ prepareHandlerInstance,
32
+ handlerInstanceCleanup
33
+ } from '../handlers/handler-instance-scope';
30
34
  import { handlerFilterScope } from './handler-filter-scope';
31
35
  import type {
32
36
  ZLinkChannelRequestHandler,
@@ -109,6 +113,17 @@ export class ZLinkChannelDispatchServices {
109
113
  }
110
114
 
111
115
  channelRequestHandler(handlerType: Type): ZLinkChannelRequestHandler {
116
+ const activate =
117
+ this.registration.filterTypes.length === 0
118
+ ? prepareHandlerInstance(
119
+ this.providerResolver,
120
+ handlerType as Type<ZLinkChannelRequestHandler>
121
+ )
122
+ : undefined;
123
+ if (activate !== undefined)
124
+ return {
125
+ handle: (payload, context) => this.invokeScopeFreeHandler(activate, payload, context)
126
+ };
112
127
  return {
113
128
  handle: (payload, context) =>
114
129
  this.withHandlerScope(context, async (scope) => {
@@ -119,6 +134,17 @@ export class ZLinkChannelDispatchServices {
119
134
  }
120
135
 
121
136
  channelSendHandler(handlerType: Type): ZLinkChannelSendHandler {
137
+ const activate =
138
+ this.registration.filterTypes.length === 0
139
+ ? prepareHandlerInstance(
140
+ this.providerResolver,
141
+ handlerType as Type<ZLinkChannelSendHandler>
142
+ )
143
+ : undefined;
144
+ if (activate !== undefined)
145
+ return {
146
+ handle: (payload, context) => this.invokeScopeFreeHandler(activate, payload, context)
147
+ };
122
148
  return {
123
149
  handle: (payload, context) =>
124
150
  this.withHandlerScope(context, async (scope) => {
@@ -129,6 +155,17 @@ export class ZLinkChannelDispatchServices {
129
155
  }
130
156
 
131
157
  routeRequestHandler(handlerType: Type): ZLinkRouteRuntimeRequestHandler {
158
+ const activate =
159
+ this.registration.filterTypes.length === 0
160
+ ? prepareHandlerInstance(
161
+ this.providerResolver,
162
+ handlerType as Type<ZLinkRouteRuntimeRequestHandler>
163
+ )
164
+ : undefined;
165
+ if (activate !== undefined)
166
+ return {
167
+ handle: (payload, context) => this.invokeScopeFreeHandler(activate, payload, context)
168
+ };
132
169
  return {
133
170
  handle: (payload, context) =>
134
171
  this.withHandlerScope(context, async (scope) => {
@@ -139,6 +176,17 @@ export class ZLinkChannelDispatchServices {
139
176
  }
140
177
 
141
178
  routeSendHandler(handlerType: Type): ZLinkRouteRuntimeSendHandler {
179
+ const activate =
180
+ this.registration.filterTypes.length === 0
181
+ ? prepareHandlerInstance(
182
+ this.providerResolver,
183
+ handlerType as Type<ZLinkRouteRuntimeSendHandler>
184
+ )
185
+ : undefined;
186
+ if (activate !== undefined)
187
+ return {
188
+ handle: (payload, context) => this.invokeScopeFreeHandler(activate, payload, context)
189
+ };
142
190
  return {
143
191
  handle: (payload, context) =>
144
192
  this.withHandlerScope(context, async (scope) => {
@@ -148,6 +196,26 @@ export class ZLinkChannelDispatchServices {
148
196
  };
149
197
  }
150
198
 
199
+ private invokeScopeFreeHandler<TContext extends ZLinkMessageContext, TResult>(
200
+ activate: () => { handle(payload: unknown, context: TContext): TResult | Promise<TResult> },
201
+ payload: unknown,
202
+ context: TContext
203
+ ): TResult | Promise<TResult> {
204
+ const handler = activate();
205
+ const cleanup = handlerInstanceCleanup(handler);
206
+ if (cleanup === undefined) return handler.handle(payload, context);
207
+ let result: TResult | Promise<TResult>;
208
+ try {
209
+ result = handler.handle(payload, context);
210
+ } catch (error) {
211
+ const disposed = cleanup.call(handler);
212
+ return Promise.resolve(disposed).then(() => {
213
+ throw error;
214
+ });
215
+ }
216
+ return Promise.resolve(result).finally(() => cleanup.call(handler));
217
+ }
218
+
151
219
  private async invokeHandlerFilters(
152
220
  context: ZLinkHandlerFilterContext,
153
221
  next: () => Promise<void>,