@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
@@ -191,7 +191,7 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
191
191
  const actorRef = this.actorRefForState(state);
192
192
  return {
193
193
  spotId: spotId,
194
- objectGeneration: state.locationGeneration ?? 0n,
194
+ objectGeneration: state.spotGeneration ?? 0n,
195
195
  meshName: this.actorMeshNames.get(actorId) ?? '',
196
196
  nodeRid: actorRef.nodeRid
197
197
  };
@@ -467,7 +467,8 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
467
467
  await registry.restore(transfer.adapterKey, actor, transfer.state, signal);
468
468
  }
469
469
  state.setLocationGeneration(authorityOwnerGeneration);
470
- if (spotId !== undefined) state.setJoinedSpot(spotId, undefined, membershipEpoch);
470
+ if (spotId !== undefined)
471
+ state.setJoinedSpot(spotId, undefined, membershipEpoch, spotGeneration);
471
472
  return actor;
472
473
  } catch (error) {
473
474
  if (nativeRef !== undefined) node.discardRelocatedActor?.(nativeRef);
@@ -486,17 +487,30 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
486
487
  }
487
488
 
488
489
  async abortRelocationActor(actorId: string): Promise<void> {
489
- await this.removeRelocationActor(actorId);
490
+ await this.releaseLocalActor(actorId);
490
491
  }
491
492
 
492
493
  async completeRelocationSource(
493
494
  actorId: string,
494
495
  sourceActorRef?: ZLinkBackendActorRef
495
496
  ): Promise<void> {
496
- await this.removeRelocationActor(actorId, sourceActorRef);
497
+ await this.releaseLocalActor(actorId, sourceActorRef);
497
498
  }
498
499
 
499
- private async removeRelocationActor(
500
+ async releaseSpotActorMembers(meshName: string, spotId?: RoutingId): Promise<void> {
501
+ const results = await Promise.allSettled(
502
+ [...this.states.values()]
503
+ .filter((state) => state.meshName === meshName && state.spotId === spotId)
504
+ .map((state) => this.releaseLocalActor(state.actorId))
505
+ );
506
+ const errors = results
507
+ .filter((result): result is PromiseRejectedResult => result.status === 'rejected')
508
+ .map((result) => result.reason);
509
+ if (errors.length === 1) throw errors[0];
510
+ if (errors.length > 1) throw new AggregateError(errors, 'Actor member cleanup failed.');
511
+ }
512
+
513
+ private async releaseLocalActor(
500
514
  actorId: string,
501
515
  exactNativeActorRef?: ZLinkBackendActorRef
502
516
  ): Promise<void> {
@@ -49,7 +49,8 @@ export class ZLinkSpotActorHandlerRegistryRuntime implements ZLinkActorHandlerRe
49
49
  );
50
50
  const resolvedPacketName = packetName ?? metadata?.packetName;
51
51
  if (metadata === undefined || resolvedPacketName === undefined) {
52
- throw new ZLinkConfigurationException(
52
+ throw createInternalFrameworkException(
53
+ ZLinkFrameworkInternalErrorKind.InvalidOperation,
53
54
  `Actor packet handler '${handlerType.name}' must declare a packet name.`
54
55
  );
55
56
  }
@@ -68,7 +69,8 @@ export class ZLinkSpotActorHandlerRegistryRuntime implements ZLinkActorHandlerRe
68
69
  addPacket(descriptor: ZLinkActorPacketDescriptor): this {
69
70
  const key = packetKey(descriptor.kind, descriptor.actorType, descriptor.packetName);
70
71
  if (this.packets.has(key)) {
71
- throw new ZLinkConfigurationException(
72
+ throw createInternalFrameworkException(
73
+ ZLinkFrameworkInternalErrorKind.InvalidOperation,
72
74
  `Actor packet '${descriptor.packetName}' for '${descriptor.actorType.name}' is already registered.`
73
75
  );
74
76
  }
@@ -86,12 +86,25 @@ export class ZLinkRuntimeAdmissionGate {
86
86
  );
87
87
  }
88
88
 
89
- async run<T>(meshName: string, operation: string, work: () => Promise<T>): Promise<T> {
90
- const claim = this.claim(meshName, operation);
89
+ run<T>(meshName: string, operation: string, work: () => T | Promise<T>): Promise<T> {
90
+ let claim: ZLinkApplicationWorkClaim | undefined;
91
91
  try {
92
- return await work();
93
- } finally {
94
- claim.close();
92
+ claim = this.claim(meshName, operation);
93
+ const result = work();
94
+ const close = claim.close;
95
+ return Promise.resolve(result).then(
96
+ (value) => {
97
+ close();
98
+ return value;
99
+ },
100
+ (error) => {
101
+ close();
102
+ throw error;
103
+ }
104
+ );
105
+ } catch (error) {
106
+ claim?.close();
107
+ return Promise.reject(error);
95
108
  }
96
109
  }
97
110
 
@@ -16,7 +16,7 @@ export interface IngressRecordPort {
16
16
  * ordinary Framework-owned ingress record closes after the last child terminal.
17
17
  */
18
18
  export class ApplicationIngressRecordOwner {
19
- private readonly stop = new AbortController();
19
+ private stop?: AbortController;
20
20
  private closed = false;
21
21
 
22
22
  private constructor(private readonly shared: SharedIngressRecordState) {}
@@ -46,17 +46,34 @@ export class ApplicationIngressRecordOwner {
46
46
  return job;
47
47
  }
48
48
 
49
- async acquire(
49
+ acquire(
50
50
  domain: ApplicationJobRecordDomain,
51
51
  signal?: AbortSignal
52
- ): Promise<ApplicationJobRecordLease> {
53
- this.requireOpen();
54
- const initial = this.shared.takeInitialPermit(domain);
55
- if (initial !== undefined) return initial;
52
+ ): ApplicationJobRecordLease | Promise<ApplicationJobRecordLease> {
53
+ try {
54
+ this.requireOpen();
55
+ const initial = this.shared.takeInitialPermit(domain);
56
+ if (initial !== undefined) return initial;
57
+ } catch (error) {
58
+ return Promise.reject(error);
59
+ }
56
60
 
57
- const waitSignal =
58
- signal === undefined ? this.stop.signal : AbortSignal.any([this.stop.signal, signal]);
59
- const permit = await this.shared.acquirePermit(waitSignal);
61
+ return this.acquireAdditional(domain, signal);
62
+ }
63
+
64
+ private async acquireAdditional(
65
+ domain: ApplicationJobRecordDomain,
66
+ signal?: AbortSignal
67
+ ): Promise<ApplicationJobRecordLease> {
68
+ const stop = (this.stop ??= new AbortController());
69
+ const waitSignal = signal === undefined ? stop.signal : AbortSignal.any([stop.signal, signal]);
70
+ let permit: ApplicationJobPermitPort;
71
+ try {
72
+ permit = await this.shared.acquirePermit(waitSignal);
73
+ } catch (error) {
74
+ if (error === ownerClosedError) throw ownerClosedError();
75
+ throw error;
76
+ }
60
77
  if (this.closed) {
61
78
  permit.releaseAfterInternalProcessing();
62
79
  throw ownerClosedError();
@@ -67,7 +84,8 @@ export class ApplicationIngressRecordOwner {
67
84
  close(): void {
68
85
  if (this.closed) return;
69
86
  this.closed = true;
70
- this.stop.abort(ownerClosedError());
87
+ // The queue forwards this reason; only a rejected acquisition constructs the error.
88
+ this.stop?.abort(ownerClosedError);
71
89
  this.shared.releaseOwner();
72
90
  }
73
91
 
@@ -79,14 +97,12 @@ export class ApplicationIngressRecordOwner {
79
97
  /** Queue-permit child of one shared raw ingress record. */
80
98
  export class ApplicationJobRecordLease implements ApplicationJobPermitPort {
81
99
  private ingressClosed = false;
82
- private permitReleased = false;
83
100
  private processingTerminal = false;
84
- private detachedForHandlerTurn = false;
85
- private jobReleased = false;
101
+ detachedForHandlerTurn = false;
86
102
 
87
103
  constructor(
88
104
  private readonly shared: SharedIngressRecordState,
89
- private readonly permit: ApplicationJobPermitPort
105
+ private permit: ApplicationJobPermitPort | undefined
90
106
  ) {}
91
107
 
92
108
  get origin(): ApplicationJobOrigin {
@@ -103,12 +119,12 @@ export class ApplicationJobRecordLease implements ApplicationJobPermitPort {
103
119
  }
104
120
 
105
121
  releaseBeforeHandler(): void {
106
- this.releasePermit(() => this.permit.releaseBeforeHandler());
122
+ this.permit?.releaseBeforeHandler();
107
123
  }
108
124
 
109
125
  releaseAfterInternalProcessing(): void {
110
126
  this.processingTerminal = true;
111
- this.releasePermit(() => this.permit.releaseAfterInternalProcessing());
127
+ this.permit?.releaseAfterInternalProcessing();
112
128
  this.releaseJobIfTerminal();
113
129
  }
114
130
 
@@ -122,16 +138,15 @@ export class ApplicationJobRecordLease implements ApplicationJobPermitPort {
122
138
  this.releaseJobIfTerminal();
123
139
  }
124
140
 
125
- private releasePermit(release: () => void): void {
126
- if (this.permitReleased) return;
127
- this.permitReleased = true;
128
- release();
129
- }
130
-
131
141
  private releaseJobIfTerminal(): void {
132
- if (this.jobReleased || !this.ingressClosed || !this.processingTerminal) return;
133
- this.jobReleased = true;
134
- this.shared.releaseJob();
142
+ const permit = this.permit;
143
+ if (permit === undefined || !this.ingressClosed || !this.processingTerminal) return;
144
+ this.permit = undefined;
145
+ try {
146
+ this.shared.releaseJob();
147
+ } finally {
148
+ permit.releaseStorage?.();
149
+ }
135
150
  }
136
151
  }
137
152
 
@@ -203,6 +218,7 @@ class SharedIngressRecordState {
203
218
  try {
204
219
  this.initialPermit?.releaseAfterInternalProcessing();
205
220
  } finally {
221
+ this.initialPermit?.releaseStorage?.();
206
222
  this.initialPermit = undefined;
207
223
  this.record.close();
208
224
  }
@@ -2,39 +2,69 @@ import { AsyncLocalStorage } from 'node:async_hooks';
2
2
 
3
3
  import type { ApplicationJobOrigin, ApplicationJobPermitPort } from './contracts';
4
4
 
5
- interface ApplicationJobPermitScope {
6
- readonly permit: ApplicationJobPermitPort;
7
- detached: boolean;
5
+ const applicationJobPermitScope = new AsyncLocalStorage<ApplicationJobPermitPort | undefined>();
6
+
7
+ function releasePermitTurn(): void {
8
+ const permit = applicationJobPermitScope.getStore();
9
+ if (permit !== undefined && !permit.detachedForHandlerTurn)
10
+ permit.releaseAfterInternalProcessing();
11
+ }
12
+
13
+ function releasePermitSuccess<TResult>(value: TResult): TResult {
14
+ releasePermitTurn();
15
+ return value;
8
16
  }
9
17
 
10
- const applicationJobPermitScope = new AsyncLocalStorage<ApplicationJobPermitScope>();
18
+ function releasePermitFailure(error: unknown): never {
19
+ releasePermitTurn();
20
+ throw error;
21
+ }
11
22
 
12
23
  /**
13
24
  * Carries the host-owned queue permit through internal async dispatch without
14
25
  * leaking capacity ownership into public handler contracts.
15
26
  */
16
- export async function runWithApplicationJobPermit<TResult>(
27
+ export function runWithApplicationJobPermit<TResult>(
17
28
  permit: ApplicationJobPermitPort,
18
- callback: () => Promise<TResult> | TResult
19
- ): Promise<TResult> {
20
- const scope: ApplicationJobPermitScope = { permit, detached: false };
21
- return applicationJobPermitScope.run(scope, async () => {
22
- try {
23
- return await callback();
24
- } finally {
25
- if (!scope.detached) permit.releaseAfterInternalProcessing();
29
+ callback: () => Promise<TResult>
30
+ ): Promise<TResult>;
31
+ export function runWithApplicationJobPermit<TResult, TFirst = undefined, TSecond = undefined>(
32
+ permit: ApplicationJobPermitPort,
33
+ callback: (first: TFirst, second: TSecond) => Promise<TResult> | TResult,
34
+ first?: TFirst,
35
+ second?: TSecond
36
+ ): TResult | Promise<TResult>;
37
+ export function runWithApplicationJobPermit<TResult, TFirst, TSecond>(
38
+ permit: ApplicationJobPermitPort,
39
+ callback: (first: TFirst, second: TSecond) => Promise<TResult> | TResult,
40
+ first?: TFirst,
41
+ second?: TSecond
42
+ ): TResult | Promise<TResult> {
43
+ const previous = applicationJobPermitScope.getStore();
44
+ applicationJobPermitScope.enterWith(permit);
45
+ try {
46
+ const result = callback(first as TFirst, second as TSecond);
47
+ if (result !== null && (typeof result === 'object' || typeof result === 'function')) {
48
+ return Promise.resolve(result).then(releasePermitSuccess, releasePermitFailure);
26
49
  }
27
- });
50
+ releasePermitTurn();
51
+ return result;
52
+ } catch (error) {
53
+ releasePermitTurn();
54
+ return Promise.reject(error);
55
+ } finally {
56
+ applicationJobPermitScope.enterWith(previous);
57
+ }
28
58
  }
29
59
 
30
60
  /** Releases the current job permit immediately before the first user callback. */
31
61
  export function releaseApplicationJobPermitBeforeHandler(): void {
32
- applicationJobPermitScope.getStore()?.permit.releaseBeforeHandler();
62
+ applicationJobPermitScope.getStore()?.releaseBeforeHandler();
33
63
  }
34
64
 
35
65
  /** @internal Returns an ingress permit after a durable queue takes record ownership. */
36
66
  export function releaseApplicationJobPermitForDurableHandoff(): void {
37
- applicationJobPermitScope.getStore()?.permit.releaseAfterInternalProcessing();
67
+ applicationJobPermitScope.getStore()?.releaseAfterInternalProcessing();
38
68
  }
39
69
 
40
70
  /** True while dispatch already owns the host-wide application job permit. */
@@ -44,7 +74,7 @@ export function hasApplicationJobPermit(): boolean {
44
74
 
45
75
  /** Keeps the ingress origin when a durable record later reacquires its permit. */
46
76
  export function currentApplicationJobOrigin(): ApplicationJobOrigin {
47
- return applicationJobPermitScope.getStore()!.permit.origin;
77
+ return applicationJobPermitScope.getStore()!.origin;
48
78
  }
49
79
 
50
80
  /** Re-enters the captured permit scope when a serial executor runs later. */
@@ -61,9 +91,8 @@ export function bindApplicationJobPermit<TResult, TArgument>(
61
91
  * detached owner must release it at handler entry or at a pre-start terminal.
62
92
  */
63
93
  export function detachApplicationJobPermit(): ApplicationJobPermitPort | undefined {
64
- const scope = applicationJobPermitScope.getStore();
65
- if (scope === undefined) return undefined;
66
- scope.permit.detachForHandlerTurn?.();
67
- scope.detached = true;
68
- return scope.permit;
94
+ const permit = applicationJobPermitScope.getStore();
95
+ if (permit === undefined) return undefined;
96
+ permit.detachForHandlerTurn();
97
+ return permit;
69
98
  }
@@ -2,14 +2,27 @@ export type ApplicationJobOrigin = 'local' | 'remote';
2
2
 
3
3
  export interface ApplicationJobPermitPort {
4
4
  readonly origin: ApplicationJobOrigin;
5
+ readonly detachedForHandlerTurn: boolean;
5
6
  markApplicationQueued(): void;
6
7
  /** Transfers ingress-record cleanup to a detached exact-target handler turn. */
7
- detachForHandlerTurn?(): void;
8
+ detachForHandlerTurn(): void;
8
9
  releaseBeforeHandler(): void;
9
10
  releaseAfterInternalProcessing(): void;
11
+ /** Returns reusable reservation storage only after its ingress lifetime ends. */
12
+ releaseStorage?(): void;
13
+ }
14
+
15
+ export interface ApplicationJobReceiveRotationPort {
16
+ reserve(): void;
17
+ take(): ApplicationJobPermitPort | undefined;
18
+ releaseUnused(): void;
10
19
  }
11
20
 
12
21
  export interface ApplicationJobQueuePort {
22
+ createReceiveRotation(
23
+ capacity: number,
24
+ origin: ApplicationJobOrigin
25
+ ): ApplicationJobReceiveRotationPort;
13
26
  acquire(
14
27
  signal: AbortSignal | undefined,
15
28
  origin: ApplicationJobOrigin
@@ -62,6 +62,7 @@ export type ZLinkBackendObjectPlacement =
62
62
  | { readonly kind: 'unavailable' };
63
63
 
64
64
  export interface ZLinkBackendMeshNode {
65
+ readonly routingId?: RoutingId;
65
66
  completeClosedInstance?(spotId: string, objectGeneration: bigint): void;
66
67
  setDispatchErrorReporter?(
67
68
  reporter: import('../../channels/dispatch-error-reporter').ZLinkDispatchErrorReporter,
@@ -125,7 +126,8 @@ export interface ZLinkBackendMeshNode {
125
126
  parts: ZLinkBackendMessageLike | readonly ZLinkBackendMessageLike[],
126
127
  deadlineUnixMs: bigint,
127
128
  sourceSpotId?: string,
128
- metadata?: ReadonlyMap<string, string>
129
+ metadata?: ReadonlyMap<string, string>,
130
+ onAdmitted?: () => void
129
131
  ): MeshOperationId;
130
132
  sendToInstanceSpot(
131
133
  route: ServiceInstanceRouteFence,
@@ -140,7 +142,8 @@ export interface ZLinkBackendMeshNode {
140
142
  timeoutMs?: number,
141
143
  sourceSpotId?: string,
142
144
  metadata?: ReadonlyMap<string, string>,
143
- instanceIntent?: boolean
145
+ instanceIntent?: boolean,
146
+ onAdmitted?: () => void
144
147
  ): MeshOperationId;
145
148
  registerUserSpotOperationHandler(handler: ServiceUserSpotOperationHandler): void;
146
149
  requestUserSpotCreate(
@@ -182,12 +185,16 @@ export interface ZLinkBackendMeshNode {
182
185
  readonly lifecycleGeneration: bigint;
183
186
  }): void;
184
187
  isObjectClientNodeDirectTarget?(targetRid: unknown): boolean;
188
+ observePeerRoute?(
189
+ targetRid: unknown
190
+ ): import('../../foundation/durable-service-request').PeerRouteObservation;
191
+ hasPeerRouteOrConnectionIntent?(targetRid: unknown, endpoint: string): boolean;
185
192
  isPeerRouteReady?(targetRid: unknown, lifecycleGeneration?: bigint): boolean;
186
193
  sendToNode(
187
194
  targetRid: unknown,
188
195
  parts: MessageLike | readonly MessageLike[],
189
196
  options?: { flags?: number }
190
- ): Promise<SubmitResult>;
197
+ ): SubmitResult | Promise<SubmitResult>;
191
198
  /**
192
199
  * Sends service-wire infrastructure frames directly to a peer. Relocation
193
200
  * Prepare may add NODE-INTERNAL sideband frames after its canonical frame.
@@ -208,12 +215,21 @@ export interface ZLinkBackendMeshNode {
208
215
  requestInfrastructureControlFrames?(
209
216
  targetRid: unknown,
210
217
  frames: readonly Uint8Array[],
211
- options?: { readonly timeoutMs?: number }
218
+ options?: {
219
+ readonly timeoutMs?: number;
220
+ readonly signal?: AbortSignal;
221
+ readonly onSubmitted?: (signal: AbortSignal) => Promise<void>;
222
+ }
212
223
  ): Promise<readonly Uint8Array[]>;
213
224
  requestToNode(
214
225
  targetRid: unknown,
215
226
  parts: MessageLike | readonly MessageLike[],
216
- options?: { flags?: number; timeoutMs?: number; applicationMetadata?: Buffer }
227
+ options?: {
228
+ flags?: number;
229
+ timeoutMs?: number;
230
+ applicationMetadata?: Buffer;
231
+ onAdmitted?: () => void;
232
+ }
217
233
  ): MeshOperationId;
218
234
  sendToChannel(
219
235
  channelName: string,
@@ -223,7 +239,12 @@ export interface ZLinkBackendMeshNode {
223
239
  requestToChannel(
224
240
  channelName: string,
225
241
  parts: MessageLike | readonly MessageLike[],
226
- options?: { flags?: number; timeoutMs?: number; applicationMetadata?: Buffer }
242
+ options?: {
243
+ flags?: number;
244
+ timeoutMs?: number;
245
+ applicationMetadata?: Buffer;
246
+ onAdmitted?: () => void;
247
+ }
227
248
  ): MeshOperationId;
228
249
  status(): MeshNodeStatus;
229
250
  peers(): MeshPeerEntry[];
@@ -349,7 +370,12 @@ export interface ZLinkBackendMeshNode {
349
370
  requestToActor(
350
371
  actor: ZLinkBackendActorRef,
351
372
  parts: MessageLike | readonly MessageLike[],
352
- options?: { flags?: number; timeoutMs?: number; applicationMetadata?: Buffer }
373
+ options?: {
374
+ flags?: number;
375
+ timeoutMs?: number;
376
+ applicationMetadata?: Buffer;
377
+ onAdmitted?: () => void;
378
+ }
353
379
  ): MeshOperationId;
354
380
  actorSendToActor(
355
381
  source: ZLinkBackendActorRef,
@@ -361,7 +387,12 @@ export interface ZLinkBackendMeshNode {
361
387
  source: ZLinkBackendActorRef,
362
388
  target: ZLinkBackendActorRef,
363
389
  parts: MessageLike | readonly MessageLike[],
364
- options?: { flags?: number; timeoutMs?: number; applicationMetadata?: Buffer }
390
+ options?: {
391
+ flags?: number;
392
+ timeoutMs?: number;
393
+ applicationMetadata?: Buffer;
394
+ onAdmitted?: () => void;
395
+ }
365
396
  ): MeshOperationId;
366
397
  sendActorBoundSession(
367
398
  actor: ZLinkBackendActorRef,
@@ -484,7 +515,11 @@ export interface ZLinkBackendDealerSocket extends ZLinkBackendConnectableSocket
484
515
  receiveTimeoutMs: number;
485
516
  maxMessageSize: number;
486
517
  send(message: Message | readonly Message[]): Promise<void>;
487
- request(message: Message | readonly Message[], timeoutMs?: number): Promise<readonly Message[]>;
518
+ request(
519
+ message: Message | readonly Message[],
520
+ timeoutMs?: number,
521
+ onAdmitted?: () => void
522
+ ): Promise<readonly Message[]>;
488
523
  recv(flags?: ZLinkBackendRecvFlags): Received | undefined;
489
524
  }
490
525
 
@@ -501,7 +536,7 @@ export interface ZLinkBackendSendOperation {
501
536
  export interface ZLinkBackendRequestOperation {
502
537
  message(message: MessageLike): ZLinkBackendRequestOperation;
503
538
  timeout(timeoutMs: number): ZLinkBackendRequestOperation;
504
- submit(): Promise<readonly Message[]>;
539
+ submit(onAdmitted?: () => void): Promise<readonly Message[]>;
505
540
  }
506
541
 
507
542
  export interface ZLinkBackendRouterSocket extends ZLinkBackendConnectableSocket {
@@ -519,7 +554,8 @@ export interface ZLinkBackendRouterSocket extends ZLinkBackendConnectableSocket
519
554
  request(
520
555
  routingId: RoutingId,
521
556
  message: Message | readonly Message[],
522
- timeoutMs?: number
557
+ timeoutMs?: number,
558
+ onAdmitted?: () => void
523
559
  ): Promise<readonly Message[]>;
524
560
  sendToSpot(
525
561
  targetNodeRid: RoutingId,
@@ -531,7 +567,8 @@ export interface ZLinkBackendRouterSocket extends ZLinkBackendConnectableSocket
531
567
  targetNodeRid: RoutingId,
532
568
  targetSpotId: RoutingId,
533
569
  parts: readonly Message[],
534
- timeoutMs?: number
570
+ timeoutMs?: number,
571
+ onAdmitted?: () => void
535
572
  ): Promise<readonly Message[]>;
536
573
  disconnectPeer(routingId: RoutingId): void;
537
574
  reply(routingId: RoutingId, replyToken: unknown): ZLinkBackendReplyOperation;
@@ -688,7 +725,8 @@ export interface ZLinkBackendSpot extends ZLinkBackendObject {
688
725
  requestToChannel(
689
726
  channelName: string,
690
727
  payload: Message | readonly Message[],
691
- timeoutMs?: number
728
+ timeoutMs?: number,
729
+ onAdmitted?: () => void
692
730
  ): Promise<readonly Message[]>;
693
731
  sendToChannel(channelName: string, payload: Message | readonly Message[]): Promise<void>;
694
732
  publish(
@@ -705,7 +743,8 @@ export interface ZLinkBackendSpot extends ZLinkBackendObject {
705
743
  targetRid: RoutingId,
706
744
  spotId: RoutingId,
707
745
  payload: Message | readonly Message[],
708
- timeoutMs?: number
746
+ timeoutMs?: number,
747
+ onAdmitted?: () => void
709
748
  ): Promise<readonly Message[]>;
710
749
  dispose(): Promise<void>;
711
750
  }