@zlink-systems/framework 0.24.0 → 0.26.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 (215) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Channels/IZLinkFanoutClient.d.ts +0 -6
  3. package/dist/contracts/RouteMesh/RuntimeTopology.d.ts +8 -0
  4. package/dist/internal.d.ts +1 -0
  5. package/dist/internal.js +1 -0
  6. package/dist/runtime/activation-admission.d.ts +29 -0
  7. package/dist/runtime/activation-admission.js +61 -0
  8. package/dist/runtime/actors/actor-context.js +6 -6
  9. package/dist/runtime/actors/actor-handoff.d.ts +9 -3
  10. package/dist/runtime/actors/actor-handoff.js +28 -17
  11. package/dist/runtime/actors/actor-local-native-join.js +2 -18
  12. package/dist/runtime/actors/actor-remote-joiner.d.ts +2 -2
  13. package/dist/runtime/actors/actor-remote-joiner.js +6 -8
  14. package/dist/runtime/actors/actor-runtime-contracts.d.ts +4 -2
  15. package/dist/runtime/actors/actor-source-transfer.d.ts +5 -5
  16. package/dist/runtime/actors/deferred-join-completion.d.ts +14 -0
  17. package/dist/runtime/actors/deferred-join-completion.js +20 -0
  18. package/dist/runtime/actors/index.d.ts +1 -1
  19. package/dist/runtime/actors/index.js +15 -5
  20. package/dist/runtime/admission.d.ts +5 -1
  21. package/dist/runtime/admission.js +4 -0
  22. package/dist/runtime/backend/contracts/index.d.ts +2 -10
  23. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -9
  24. package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +1 -2
  25. package/dist/runtime/backend/node/node-backend-adapter-factory.js +4 -18
  26. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +6 -3
  27. package/dist/runtime/backend/node/node-backend-adapter-support.js +12 -28
  28. package/dist/runtime/backend/node/node-event-loop-poller.d.ts +1 -1
  29. package/dist/runtime/backend/node/node-event-loop-poller.js +8 -2
  30. package/dist/runtime/backend/node/node-raw-binding-port.d.ts +1 -1
  31. package/dist/runtime/backend/node/node-raw-binding-port.js +11 -3
  32. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +12 -9
  33. package/dist/runtime/backend/node/node-raw-mesh-backend.js +61 -29
  34. package/dist/runtime/backend/node/node-socket-backend-adapter.js +1 -1
  35. package/dist/runtime/backend/raw-binding-port.d.ts +12 -0
  36. package/dist/runtime/channels/channel-clients.d.ts +0 -1
  37. package/dist/runtime/channels/channel-clients.js +0 -8
  38. package/dist/runtime/channels/channel-outbound-operations.js +2 -10
  39. package/dist/runtime/channels/channel-runtime-manager.d.ts +2 -5
  40. package/dist/runtime/channels/channel-runtime-manager.js +1 -12
  41. package/dist/runtime/channels/channel-socket-registry.d.ts +17 -4
  42. package/dist/runtime/channels/channel-socket-registry.js +49 -62
  43. package/dist/runtime/channels/channel-transports.d.ts +0 -3
  44. package/dist/runtime/channels/fanout-location-runtime.js +3 -9
  45. package/dist/runtime/execution/index.d.ts +18 -8
  46. package/dist/runtime/execution/index.js +55 -29
  47. package/dist/runtime/execution/serial-execution-queue.d.ts +5 -6
  48. package/dist/runtime/execution/serial-execution-queue.js +49 -15
  49. package/dist/runtime/foundation/listener-records.d.ts +11 -0
  50. package/dist/runtime/foundation/listener-records.js +20 -0
  51. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +10 -21
  52. package/dist/runtime/foundation/raw-service-mesh-runtime.js +66 -392
  53. package/dist/runtime/foundation/service-authority-payload-codec.d.ts +1 -0
  54. package/dist/runtime/foundation/service-authority-payload-codec.js +8 -0
  55. package/dist/runtime/foundation/service-maintenance-runtime.js +23 -2
  56. package/dist/runtime/foundation/service-relocation-coordinator.d.ts +9 -0
  57. package/dist/runtime/foundation/service-relocation-coordinator.js +14 -1
  58. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +8 -0
  59. package/dist/runtime/foundation/service-relocation-object-owner.js +16 -4
  60. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +6 -13
  61. package/dist/runtime/foundation/service-stateful-runtime.d.ts +10 -7
  62. package/dist/runtime/foundation/service-stateful-runtime.js +100 -60
  63. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +9 -4
  64. package/dist/runtime/foundation/service-stateful-wire-codec.js +153 -90
  65. package/dist/runtime/foundation/service-topology-registry.d.ts +1 -2
  66. package/dist/runtime/foundation/service-topology-registry.js +6 -30
  67. package/dist/runtime/host/actor-transfer-runtime.d.ts +17 -15
  68. package/dist/runtime/host/actor-transfer-runtime.js +73 -86
  69. package/dist/runtime/host/index.d.ts +6 -2
  70. package/dist/runtime/host/index.js +63 -37
  71. package/dist/runtime/host/remote-bound-session-relay.js +4 -3
  72. package/dist/runtime/host/route-mesh-runtime.d.ts +2 -0
  73. package/dist/runtime/host/route-mesh-runtime.js +7 -5
  74. package/dist/runtime/host/service-relocation-host-runtime.d.ts +50 -8
  75. package/dist/runtime/host/service-relocation-host-runtime.js +343 -270
  76. package/dist/runtime/host/spot-runtime-options-factory.d.ts +7 -4
  77. package/dist/runtime/host/spot-runtime-options-factory.js +4 -8
  78. package/dist/runtime/host/stateful-authority-route-runtime.js +6 -2
  79. package/dist/runtime/host/user-spot-creation-coordinator.d.ts +11 -3
  80. package/dist/runtime/host/user-spot-creation-coordinator.js +85 -87
  81. package/dist/runtime/locations/in-memory-provider-location-store.js +8 -6
  82. package/dist/runtime/locations/lifecycle.d.ts +1 -1
  83. package/dist/runtime/locations/lifecycle.js +2 -2
  84. package/dist/runtime/locations/resolvers.js +7 -2
  85. package/dist/runtime/locations/spot-location-claims.d.ts +2 -2
  86. package/dist/runtime/locations/spot-location-claims.js +3 -27
  87. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +1 -0
  88. package/dist/runtime/protocol/service_wire_codec.generated.js +5 -1
  89. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +1 -0
  90. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +3 -2
  91. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +3 -3
  92. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +4 -4
  93. package/dist/runtime/spots/formal-remote-actor-transfer-registry.d.ts +3 -3
  94. package/dist/runtime/spots/index.d.ts +25 -19
  95. package/dist/runtime/spots/index.js +207 -205
  96. package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
  97. package/dist/runtime/spots/spot-activation-registry.js +34 -31
  98. package/dist/runtime/spots/spot-activation-state.d.ts +2 -11
  99. package/dist/runtime/spots/spot-activation-state.js +4 -17
  100. package/dist/runtime/spots/spot-activation.d.ts +8 -6
  101. package/dist/runtime/spots/spot-activation.js +54 -49
  102. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -1
  103. package/dist/runtime/spots/spot-actor-admission-coordinator.js +1 -1
  104. package/dist/runtime/spots/spot-actor-join-dispatch.d.ts +2 -2
  105. package/dist/runtime/spots/spot-actor-join-dispatch.js +3 -5
  106. package/dist/runtime/spots/spot-actor-lifecycle-drain.js +2 -2
  107. package/dist/runtime/spots/spot-actor-membership.d.ts +4 -0
  108. package/dist/runtime/spots/spot-actor-membership.js +26 -12
  109. package/dist/runtime/spots/spot-entry-activation.d.ts +1 -2
  110. package/dist/runtime/spots/spot-entry-activation.js +0 -1
  111. package/dist/runtime/spots/spot-manager-public.js +1 -1
  112. package/dist/runtime/spots/spot-native-actor-join-admission.d.ts +1 -1
  113. package/dist/runtime/spots/spot-native-actor-join-admission.js +2 -2
  114. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +5 -5
  115. package/dist/runtime/spots/spot-node-runtime-manager.js +7 -11
  116. package/dist/runtime/spots/spot-outbound.js +1 -29
  117. package/dist/runtime/spots/spot-routed-actor-admission.d.ts +1 -0
  118. package/dist/runtime/spots/spot-routed-actor-admission.js +10 -0
  119. package/dist/runtime/spots/spot-routed-frame-dispatch.d.ts +2 -6
  120. package/dist/runtime/spots/spot-routed-frame-dispatch.js +2 -70
  121. package/dist/runtime/spots/spot-runtime-ports.d.ts +3 -5
  122. package/dist/runtime/spots/spot-serial-executor.d.ts +5 -0
  123. package/dist/runtime/spots/spot-serial-executor.js +8 -1
  124. package/dist/runtime/spots/spot-serial-turn-executor.d.ts +3 -0
  125. package/dist/runtime/spots/spot-serial-turn-executor.js +8 -4
  126. package/dist/runtime/streams/actor-session-binding-registry.d.ts +13 -15
  127. package/dist/runtime/streams/actor-session-binding-registry.js +19 -171
  128. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +3 -4
  129. package/dist/runtime/streams/bound-session-service.js +1 -18
  130. package/dist/runtime/streams/index.d.ts +2 -0
  131. package/dist/runtime/streams/index.js +19 -19
  132. package/dist/runtime/streams/session-serial-executor.js +2 -2
  133. package/package.json +3 -3
  134. package/src/contracts/Channels/IZLinkFanoutClient.ts +0 -7
  135. package/src/contracts/RouteMesh/RuntimeTopology.ts +10 -0
  136. package/src/internal.ts +1 -0
  137. package/src/runtime/activation-admission.ts +78 -0
  138. package/src/runtime/actors/actor-context.ts +6 -6
  139. package/src/runtime/actors/actor-handoff.ts +31 -23
  140. package/src/runtime/actors/actor-local-native-join.ts +3 -42
  141. package/src/runtime/actors/actor-remote-joiner.ts +6 -25
  142. package/src/runtime/actors/actor-runtime-contracts.ts +4 -10
  143. package/src/runtime/actors/actor-source-transfer.ts +5 -18
  144. package/src/runtime/actors/deferred-join-completion.ts +40 -0
  145. package/src/runtime/actors/index.ts +22 -9
  146. package/src/runtime/admission.ts +5 -1
  147. package/src/runtime/backend/contracts/index.ts +2 -13
  148. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +2 -10
  149. package/src/runtime/backend/node/node-backend-adapter-factory.ts +5 -25
  150. package/src/runtime/backend/node/node-backend-adapter-support.ts +9 -29
  151. package/src/runtime/backend/node/node-event-loop-poller.ts +14 -2
  152. package/src/runtime/backend/node/node-raw-binding-port.ts +17 -3
  153. package/src/runtime/backend/node/node-raw-mesh-backend.ts +65 -32
  154. package/src/runtime/backend/node/node-socket-backend-adapter.ts +2 -2
  155. package/src/runtime/backend/raw-binding-port.ts +13 -0
  156. package/src/runtime/channels/channel-clients.ts +0 -11
  157. package/src/runtime/channels/channel-outbound-operations.ts +3 -11
  158. package/src/runtime/channels/channel-runtime-manager.ts +4 -15
  159. package/src/runtime/channels/channel-socket-registry.ts +69 -71
  160. package/src/runtime/channels/channel-transports.ts +0 -3
  161. package/src/runtime/channels/fanout-location-runtime.ts +4 -16
  162. package/src/runtime/execution/index.ts +68 -30
  163. package/src/runtime/execution/serial-execution-queue.ts +52 -20
  164. package/src/runtime/foundation/listener-records.ts +21 -0
  165. package/src/runtime/foundation/raw-service-mesh-runtime.ts +66 -466
  166. package/src/runtime/foundation/service-authority-payload-codec.ts +10 -0
  167. package/src/runtime/foundation/service-maintenance-runtime.ts +30 -9
  168. package/src/runtime/foundation/service-relocation-coordinator.ts +13 -0
  169. package/src/runtime/foundation/service-relocation-object-owner.ts +18 -5
  170. package/src/runtime/foundation/service-session-binding-ingress-port.ts +6 -14
  171. package/src/runtime/foundation/service-stateful-runtime.ts +151 -89
  172. package/src/runtime/foundation/service-stateful-wire-codec.ts +203 -121
  173. package/src/runtime/foundation/service-topology-registry.ts +8 -48
  174. package/src/runtime/host/actor-transfer-runtime.ts +94 -166
  175. package/src/runtime/host/index.ts +119 -54
  176. package/src/runtime/host/remote-bound-session-relay.ts +4 -3
  177. package/src/runtime/host/route-mesh-runtime.ts +9 -5
  178. package/src/runtime/host/service-relocation-host-runtime.ts +495 -376
  179. package/src/runtime/host/spot-runtime-options-factory.ts +24 -13
  180. package/src/runtime/host/stateful-authority-route-runtime.ts +8 -4
  181. package/src/runtime/host/user-spot-creation-coordinator.ts +147 -142
  182. package/src/runtime/locations/in-memory-provider-location-store.ts +11 -7
  183. package/src/runtime/locations/lifecycle.ts +3 -2
  184. package/src/runtime/locations/resolvers.ts +19 -13
  185. package/src/runtime/locations/spot-location-claims.ts +5 -34
  186. package/src/runtime/protocol/service_wire_codec.generated.ts +9 -2
  187. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
  188. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +6 -6
  189. package/src/runtime/spots/formal-remote-actor-transfer-registry.ts +3 -3
  190. package/src/runtime/spots/index.ts +341 -295
  191. package/src/runtime/spots/spot-activation-registry.ts +41 -31
  192. package/src/runtime/spots/spot-activation-state.ts +4 -16
  193. package/src/runtime/spots/spot-activation.ts +102 -80
  194. package/src/runtime/spots/spot-actor-admission-coordinator.ts +2 -2
  195. package/src/runtime/spots/spot-actor-join-dispatch.ts +6 -7
  196. package/src/runtime/spots/spot-actor-lifecycle-drain.ts +20 -18
  197. package/src/runtime/spots/spot-actor-membership.ts +81 -17
  198. package/src/runtime/spots/spot-entry-activation.ts +0 -3
  199. package/src/runtime/spots/spot-manager-public.ts +8 -4
  200. package/src/runtime/spots/spot-native-actor-join-admission.ts +2 -2
  201. package/src/runtime/spots/spot-node-runtime-manager.ts +12 -18
  202. package/src/runtime/spots/spot-outbound.ts +4 -47
  203. package/src/runtime/spots/spot-routed-actor-admission.ts +20 -0
  204. package/src/runtime/spots/spot-routed-frame-dispatch.ts +6 -76
  205. package/src/runtime/spots/spot-runtime-ports.ts +6 -17
  206. package/src/runtime/spots/spot-serial-executor.ts +9 -1
  207. package/src/runtime/spots/spot-serial-turn-executor.ts +10 -4
  208. package/src/runtime/streams/actor-session-binding-registry.ts +20 -308
  209. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +2 -12
  210. package/src/runtime/streams/bound-session-service.ts +2 -36
  211. package/src/runtime/streams/index.ts +29 -27
  212. package/src/runtime/streams/session-serial-executor.ts +2 -2
  213. package/dist/runtime/actors/deferred-join-accepted-journal.d.ts +0 -47
  214. package/dist/runtime/actors/deferred-join-accepted-journal.js +0 -992
  215. package/src/runtime/actors/deferred-join-accepted-journal.ts +0 -1346
@@ -14,6 +14,7 @@ export interface ZLinkSpotCloseOperation {
14
14
  readonly started: boolean;
15
15
  }
16
16
  export declare class ZLinkSpotActivationRegistry {
17
+ private readonly isCommittedClose;
17
18
  private nextId;
18
19
  private readonly activations;
19
20
  private readonly staged;
@@ -23,14 +24,15 @@ export declare class ZLinkSpotActivationRegistry {
23
24
  private readonly emptyWaiters;
24
25
  private readonly lifecycleMetrics;
25
26
  private activeScan;
26
- constructor(metrics?: import('../diagnostics').ZLinkRuntimeMetrics);
27
+ constructor(metrics?: import('../diagnostics').ZLinkRuntimeMetrics, isCommittedClose?: (meshName: string, spotId: RoutingId) => boolean);
27
28
  allocateSpotId(meshName: string): RoutingId;
28
29
  resolve(meshName: string, spotId: RoutingId): ZLinkSpotActivation | undefined;
29
30
  resolveUnique(spotId: RoutingId): ZLinkSpotActivation | undefined;
30
31
  has(meshName: string, spotId: RoutingId): boolean;
31
- canClose(meshName: string, spotId: RoutingId): boolean;
32
32
  list(meshName: string): readonly ZLinkSpotInfo[];
33
33
  activeActivations(): readonly ZLinkSpotActivation[];
34
+ activationForClose(meshName: string, spotId: RoutingId): ZLinkSpotActivation | undefined;
35
+ finishClose(meshName: string, spotId: RoutingId): void;
34
36
  hasActiveActivations(): boolean;
35
37
  nextActiveActivationBatch(limit?: number): readonly ZLinkSpotActivation[];
36
38
  closingOperation(meshName: string, spotId: RoutingId): ZLinkSpotCloseOperation | undefined;
@@ -3,13 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZLinkSpotActivationRegistry = exports.ZLinkSpotActivation = void 0;
4
4
  const framework_errors_internal_1 = require("../framework-errors-internal");
5
5
  const contracts_1 = require("../../contracts");
6
- const spot_activation_state_1 = require("./spot-activation-state");
7
6
  const configuration_1 = require("../configuration");
8
7
  const abort_1 = require("../abort");
9
8
  const spot_lifecycle_metrics_1 = require("./spot-lifecycle-metrics");
10
- var spot_activation_state_2 = require("./spot-activation-state");
11
- Object.defineProperty(exports, "ZLinkSpotActivation", { enumerable: true, get: function () { return spot_activation_state_2.ZLinkSpotActivation; } });
9
+ var spot_activation_state_1 = require("./spot-activation-state");
10
+ Object.defineProperty(exports, "ZLinkSpotActivation", { enumerable: true, get: function () { return spot_activation_state_1.ZLinkSpotActivation; } });
12
11
  class ZLinkSpotActivationRegistry {
12
+ isCommittedClose;
13
13
  nextId = 1;
14
14
  activations = new Map();
15
15
  staged = new Set();
@@ -19,7 +19,8 @@ class ZLinkSpotActivationRegistry {
19
19
  emptyWaiters = new Set();
20
20
  lifecycleMetrics;
21
21
  activeScan;
22
- constructor(metrics) {
22
+ constructor(metrics, isCommittedClose = () => false) {
23
+ this.isCommittedClose = isCommittedClose;
23
24
  this.lifecycleMetrics = new spot_lifecycle_metrics_1.ZLinkSpotLifecycleMetrics(metrics);
24
25
  }
25
26
  allocateSpotId(meshName) {
@@ -32,12 +33,16 @@ class ZLinkSpotActivationRegistry {
32
33
  }
33
34
  resolve(meshName, spotId) {
34
35
  const key = spotActivationKey(meshName, spotId);
35
- return this.closing.has(key) || this.failedClose.has(key) || this.staged.has(key)
36
+ return this.isCommittedClose(meshName, spotId) ||
37
+ this.closing.has(key) ||
38
+ this.failedClose.has(key) ||
39
+ this.staged.has(key)
36
40
  ? undefined
37
41
  : this.activations.get(key);
38
42
  }
39
43
  resolveUnique(spotId) {
40
44
  const matches = [...this.activations.values()].filter((activation) => String(activation.spotId) === String(spotId) &&
45
+ !this.isCommittedClose(activation.meshName, activation.spotId) &&
41
46
  !this.staged.has(spotActivationKey(activation.meshName, activation.spotId)) &&
42
47
  !this.closing.has(spotActivationKey(activation.meshName, activation.spotId)) &&
43
48
  !this.failedClose.has(spotActivationKey(activation.meshName, activation.spotId)));
@@ -45,25 +50,22 @@ class ZLinkSpotActivationRegistry {
45
50
  }
46
51
  has(meshName, spotId) {
47
52
  const key = spotActivationKey(meshName, spotId);
48
- return (!this.staged.has(key) &&
53
+ return (!this.isCommittedClose(meshName, spotId) &&
54
+ !this.staged.has(key) &&
49
55
  !this.closing.has(key) &&
50
56
  !this.failedClose.has(key) &&
51
57
  this.activations.has(key));
52
58
  }
53
- canClose(meshName, spotId) {
54
- const key = spotActivationKey(meshName, spotId);
55
- return (!this.staged.has(key) &&
56
- !this.closing.has(key) &&
57
- !this.failedClose.has(key) &&
58
- this.activations.get(key)?.canClose() === true);
59
- }
60
59
  list(meshName) {
61
60
  return [...this.activations.values()]
62
61
  .filter((activation) => {
63
62
  if (activation.meshName !== meshName)
64
63
  return false;
65
64
  const key = spotActivationKey(activation.meshName, activation.spotId);
66
- return !this.staged.has(key) && !this.closing.has(key) && !this.failedClose.has(key);
65
+ return (!this.isCommittedClose(meshName, activation.spotId) &&
66
+ !this.staged.has(key) &&
67
+ !this.closing.has(key) &&
68
+ !this.failedClose.has(key));
67
69
  })
68
70
  .map((activation) => String(activation.spotId))
69
71
  .sort((left, right) => left.localeCompare(right))
@@ -72,6 +74,17 @@ class ZLinkSpotActivationRegistry {
72
74
  activeActivations() {
73
75
  return [...this.activations.values()];
74
76
  }
77
+ activationForClose(meshName, spotId) {
78
+ return this.activations.get(spotActivationKey(meshName, spotId));
79
+ }
80
+ finishClose(meshName, spotId) {
81
+ const key = spotActivationKey(meshName, spotId);
82
+ if (this.activations.delete(key))
83
+ this.lifecycleMetrics.closed('user');
84
+ this.staged.delete(key);
85
+ this.failedClose.delete(key);
86
+ this.resolveEmptyWaiters();
87
+ }
75
88
  hasActiveActivations() {
76
89
  return this.activations.size > 0;
77
90
  }
@@ -165,30 +178,14 @@ class ZLinkSpotActivationRegistry {
165
178
  }
166
179
  const operation = {};
167
180
  let completed = false;
168
- let occupiedAfterQuiescence = false;
169
181
  const ready = Promise.resolve()
170
182
  .then(() => close(activation))
171
183
  .then(() => {
172
184
  completed = true;
173
- })
174
- .catch((error) => {
175
- // The seal's post-quiescence recheck (spot-activation.ts
176
- // closeAfterSeal) found a new join and released the seal instead of
177
- // closing. The activation is already back to normal operation, so
178
- // this is a "did not close" outcome, not a close failure.
179
- if (error instanceof spot_activation_state_1.ZLinkSpotCloseOccupiedError) {
180
- occupiedAfterQuiescence = true;
181
- return;
182
- }
183
- throw error;
184
185
  })
185
186
  .finally(() => {
186
187
  if (this.closing.get(key) === operation) {
187
188
  this.closing.delete(key);
188
- if (occupiedAfterQuiescence) {
189
- this.resolveEmptyWaiters();
190
- return;
191
- }
192
189
  if (completed || resourcesReleased(activation)) {
193
190
  this.activations.delete(key);
194
191
  this.staged.delete(key);
@@ -201,13 +198,19 @@ class ZLinkSpotActivationRegistry {
201
198
  this.resolveEmptyWaiters();
202
199
  }
203
200
  })
204
- .then(() => !occupiedAfterQuiescence);
201
+ .then(() => true);
205
202
  Object.assign(operation, { activation, ready, started: true });
206
203
  this.closing.set(key, operation);
207
204
  return operation;
208
205
  }
209
206
  getOrBegin(meshName, spotType, spotId, create) {
210
207
  const key = spotActivationKey(meshName, spotId);
208
+ if (this.isCommittedClose(meshName, spotId)) {
209
+ return {
210
+ owner: false,
211
+ ready: Promise.reject((0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RequestRejected, `Spot '${String(spotId)}' is Closing.`))
212
+ };
213
+ }
211
214
  const closing = this.closing.get(key);
212
215
  if (closing !== undefined) {
213
216
  return {
@@ -12,6 +12,7 @@ import { ZLinkExecutionBarrier, type ZLinkExecutionBarrierSeal } from '../execut
12
12
  import type { ZLinkTimerRelocationState } from './spot-timer';
13
13
  export type ZLinkSpotActivationDomain = {
14
14
  readonly kind: 'user';
15
+ readonly objectGeneration?: bigint;
15
16
  readonly executionMode: ZLinkUserSpotExecutionMode;
16
17
  readonly relocationCoordinationMode: ZLinkSpotRelocationCoordinationMode;
17
18
  } | {
@@ -39,16 +40,6 @@ export interface ZLinkSpotRelocationCapture {
39
40
  readonly seal: ZLinkExecutionBarrierSeal;
40
41
  readonly timers: readonly ZLinkTimerRelocationState[];
41
42
  }
42
- /**
43
- * Internal signal that a close seal reached quiescence but the activation
44
- * became occupied again while it waited (an actor join queued ahead of the
45
- * close finished after the eager pre-seal occupancy check). This is not a
46
- * close failure: the seal is released, the Spot stays open, and the caller
47
- * reports `close(...)` as `false` instead of throwing.
48
- */
49
- export declare class ZLinkSpotCloseOccupiedError extends Error {
50
- constructor(spotId: RoutingId);
51
- }
52
43
  export declare class ZLinkSpotActivation {
53
44
  readonly meshName: string;
54
45
  readonly spotId: RoutingId;
@@ -81,7 +72,7 @@ export declare class ZLinkSpotActivation {
81
72
  completeConsumedRelocationBoundary(outcome: ZLinkSpotRelocationReadyOutcome): Promise<void>;
82
73
  notifyRelocatedBoundary(): Promise<void>;
83
74
  executeActor<T>(actorId: string, operation: (serial: ZLinkSpotSerialTurnExecutor) => Promise<T> | T): Promise<T>;
84
- sealExecution(): ZLinkExecutionBarrierSeal;
75
+ sealExecution(drainsYieldedTurns?: boolean): ZLinkExecutionBarrierSeal;
85
76
  waitForExecutionQuiescence(seal: ZLinkExecutionBarrierSeal, signal?: AbortSignal): Promise<void>;
86
77
  abortExecutionSeal(seal: ZLinkExecutionBarrierSeal): boolean;
87
78
  commitExecutionSeal(seal: ZLinkExecutionBarrierSeal): boolean;
@@ -1,25 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ZLinkSpotActivation = exports.ZLinkSpotCloseOccupiedError = void 0;
3
+ exports.ZLinkSpotActivation = void 0;
4
4
  const framework_errors_internal_1 = require("../framework-errors-internal");
5
5
  const contracts_1 = require("../../contracts");
6
6
  const configuration_1 = require("../configuration");
7
7
  const abort_1 = require("../abort");
8
8
  const spot_serial_executor_1 = require("./spot-serial-executor");
9
9
  const execution_1 = require("../execution");
10
- /**
11
- * Internal signal that a close seal reached quiescence but the activation
12
- * became occupied again while it waited (an actor join queued ahead of the
13
- * close finished after the eager pre-seal occupancy check). This is not a
14
- * close failure: the seal is released, the Spot stays open, and the caller
15
- * reports `close(...)` as `false` instead of throwing.
16
- */
17
- class ZLinkSpotCloseOccupiedError extends Error {
18
- constructor(spotId) {
19
- super(`Spot '${String(spotId)}' became occupied while its close seal reached quiescence.`);
20
- }
21
- }
22
- exports.ZLinkSpotCloseOccupiedError = ZLinkSpotCloseOccupiedError;
23
10
  class ZLinkSpotActivation {
24
11
  meshName;
25
12
  spotId;
@@ -68,7 +55,7 @@ class ZLinkSpotActivation {
68
55
  this.actorDispatch = options.actorDispatch;
69
56
  }
70
57
  get objectGeneration() {
71
- return this.domain.kind === 'instance' ? this.domain.objectGeneration : undefined;
58
+ return this.domain.objectGeneration;
72
59
  }
73
60
  get executionMode() {
74
61
  return this.domain.kind === 'user'
@@ -171,8 +158,8 @@ class ZLinkSpotActivation {
171
158
  admitActorDurablePrefix(actorId, records) {
172
159
  return this.serialExecutor.admitActorDurablePrefix(actorId, records);
173
160
  }
174
- sealExecution() {
175
- return this.executionBarrier.seal();
161
+ sealExecution(drainsYieldedTurns = false) {
162
+ return this.executionBarrier.seal(drainsYieldedTurns);
176
163
  }
177
164
  waitForExecutionQuiescence(seal, signal) {
178
165
  return this.executionBarrier.waitForQuiescence(seal, signal);
@@ -6,7 +6,7 @@ import type { ZLinkSpotActorRequestHandlerRegistration, ZLinkSpotActorSendHandle
6
6
  import { ZLinkSpotCloseReason, ZLinkSpotRelocationCoordinationMode, ZLinkUserSpotExecutionMode } from '../../contracts';
7
7
  import type { Message } from '../../contracts/Common/Message';
8
8
  import type { ZLinkMessageFollowOrigin } from '../foundation/service-runtime-contracts';
9
- import type { ZLinkBackendReceived, ZLinkBackendSpot, ZLinkBackendSpotNode, ZLinkBackendTopicMessage } from '../backend/contracts';
9
+ import type { ZLinkBackendSpot, ZLinkBackendSpotNode, ZLinkBackendTopicMessage } from '../backend/contracts';
10
10
  import { ZLinkDispatchErrorReporter } from '../channels';
11
11
  import { type ZLinkRemoteBoundSessionTarget } from '../actors';
12
12
  import { ZLinkWorkerRuntime } from '../workers';
@@ -39,12 +39,12 @@ export interface ZLinkSpotActivationLifecycleOptions {
39
39
  readonly channelMeshNameForChannel?: (channelName: string) => string | undefined;
40
40
  readonly providerResolver?: ZLinkProviderResolver;
41
41
  readonly dispatchErrors?: ZLinkDispatchErrorReporter;
42
+ readonly closeErrorSink?: import('../diagnostics/dispatch-error-port').ZLinkDispatchErrorSink;
42
43
  readonly runtimeEventPublisher?: ZLinkRuntimeEventPublisher;
43
44
  readonly workerRuntime: ZLinkWorkerRuntime;
44
45
  readonly messageSerializers?: ReadonlyMap<string, ZLinkMessageSerializer>;
45
46
  readonly locationClaim: ZLinkSpotLocationClaim;
46
47
  readonly createNativeSpot?: (meshName: string, spotId: RoutingId, authority?: ZLinkNativeSpotAuthority) => ZLinkBackendSpot | undefined;
47
- readonly createReceived?: () => ZLinkBackendReceived;
48
48
  readonly createTopicMessage?: () => ZLinkBackendTopicMessage;
49
49
  readonly nativeSpotNodeProvider?: (meshName: string) => ZLinkBackendSpotNode | undefined;
50
50
  readonly actorResolver?: (actorId: string) => ZLinkActor | undefined;
@@ -55,7 +55,9 @@ export interface ZLinkSpotActivationLifecycleOptions {
55
55
  readonly admission?: ZLinkRuntimeAdmissionGate;
56
56
  readonly statefulExecutionAllowed?: () => boolean;
57
57
  readonly leaveActor: (spotId: RoutingId, actor: ZLinkActor, signal?: AbortSignal, meshName?: string) => Promise<void>;
58
- readonly closeSpot: (meshName: string, spotId: RoutingId, signal?: AbortSignal, reason?: ZLinkSpotCloseReason) => Promise<boolean>;
58
+ /** Starts a context Close request after its calling turn has ended. */
59
+ readonly requestContextClose: (activation: ZLinkSpotActivation, objectGeneration: bigint, signal?: AbortSignal) => Promise<boolean>;
60
+ readonly isSpotClosing: (activation: ZLinkSpotActivation) => boolean;
59
61
  readonly registerActivation: (activation: ZLinkSpotActivation) => void;
60
62
  readonly routeToActorJoinPrewarm?: ZLinkRouteToActorJoinPrewarm;
61
63
  readonly releaseLocation: (activation: ZLinkSpotActivation, meshName: string, spotId: RoutingId) => Promise<void>;
@@ -75,12 +77,12 @@ export declare class ZLinkSpotActivationLifecycle {
75
77
  materializeRelocation<TSpot extends ZLinkSpot | ZLinkInstanceSpot>(meshName: string, objectKind: 'user_spot' | 'instance_spot', stableType: string, implementation: Type<TSpot>, spotId: RoutingId, objectGeneration: bigint, authorityOwnerGeneration: bigint, signal?: AbortSignal): Promise<ZLinkSpotActivation>;
76
78
  materializeInstance<TSpot extends ZLinkInstanceSpot>(meshName: string, instanceType: string, implementation: Type<TSpot>, spotId: RoutingId, objectGeneration: bigint, signal?: AbortSignal): Promise<ZLinkSpotActivation>;
77
79
  discardInstance(activation: ZLinkSpotActivation): Promise<void>;
78
- resourcesReleased(activation: ZLinkSpotActivation): boolean;
79
80
  create<TSpot extends ZLinkSpot>(meshName: string, spotType: Type<TSpot>, spotId: RoutingId, request: Message, signal?: AbortSignal, authority?: ZLinkNativeSpotAuthority): Promise<ZLinkLocalSpotCreateResult>;
80
81
  private createWithoutNativeSpot;
81
82
  private contextClose;
82
- close(activation: ZLinkSpotActivation, signal?: AbortSignal, reason?: ZLinkSpotCloseReason): Promise<void>;
83
- closeAfterSeal(activation: ZLinkSpotActivation, seal: import('../execution').ZLinkExecutionBarrierSeal, signal?: AbortSignal, reason?: ZLinkSpotCloseReason, deadline?: Date): Promise<void>;
83
+ sealForClose(activation: ZLinkSpotActivation, seal: import('../execution').ZLinkExecutionBarrierSeal, signal?: AbortSignal): Promise<void>;
84
+ /** Returns the OnClosing failure, which cleanup records and does not rethrow. */
85
+ cleanupClosedActivation(activation: ZLinkSpotActivation, reason?: ZLinkSpotCloseReason, deadline?: Date): Promise<unknown>;
84
86
  dispatchActorPacket(activation: ZLinkSpotActivation, actorId: string, parts: readonly Message[], returnResponse?: boolean, remoteBoundSessionTarget?: ZLinkRemoteBoundSessionTarget, fallbackActorRef?: ActorRef, requestTerminal?: (response: unknown) => Promise<void> | void, messageFollowOrigin?: ZLinkMessageFollowOrigin): Promise<unknown>;
85
87
  private runCreateLifecycle;
86
88
  private cleanupActivation;
@@ -4,6 +4,7 @@ exports.ZLinkSpotActivationLifecycle = void 0;
4
4
  const contracts_1 = require("../../contracts");
5
5
  const abort_1 = require("../abort");
6
6
  const configuration_1 = require("../configuration");
7
+ const framework_errors_internal_1 = require("../framework-errors-internal");
7
8
  const actors_1 = require("../actors");
8
9
  const handler_instance_scope_1 = require("../handlers/handler-instance-scope");
9
10
  const payload_codec_1 = require("../messaging/payload-codec");
@@ -72,7 +73,7 @@ class ZLinkSpotActivationLifecycle {
72
73
  providerResolver: this.options.providerResolver,
73
74
  runtimeEventPublisher: this.options.runtimeEventPublisher,
74
75
  workerRuntime: this.options.workerRuntime,
75
- close: this.contextClose(meshName, spotId, () => activation)
76
+ close: this.contextClose(objectGeneration, () => activation)
76
77
  };
77
78
  const context = objectKind === 'user_spot'
78
79
  ? (0, spot_context_1.createSpotContext)({
@@ -110,6 +111,7 @@ class ZLinkSpotActivationLifecycle {
110
111
  domain: objectKind === 'user_spot'
111
112
  ? {
112
113
  kind: 'user',
114
+ objectGeneration,
113
115
  executionMode,
114
116
  relocationCoordinationMode: this.options.userSpotRelocationCoordinationMode?.(meshName, implementation) ?? contracts_1.ZLinkSpotRelocationCoordinationMode.FrameworkManaged
115
117
  }
@@ -171,7 +173,7 @@ class ZLinkSpotActivationLifecycle {
171
173
  providerResolver: this.options.providerResolver,
172
174
  runtimeEventPublisher: this.options.runtimeEventPublisher,
173
175
  workerRuntime: this.options.workerRuntime,
174
- close: this.contextClose(meshName, spotId, () => activation)
176
+ close: this.contextClose(objectGeneration, () => activation)
175
177
  });
176
178
  instance = await (0, spot_provider_1.createFreshProviderInstance)(implementation, this.options.providerResolver, context);
177
179
  Object.defineProperty(instance, 'context', {
@@ -241,13 +243,6 @@ class ZLinkSpotActivationLifecycle {
241
243
  throw new AggregateError(errors, `Instance Spot '${String(activation.spotId)}' cleanup failed.`);
242
244
  }
243
245
  }
244
- resourcesReleased(activation) {
245
- const state = this.cleanupStates.get(activation);
246
- return (state?.timersDisposed === true &&
247
- state.handlersDisposed === true &&
248
- state.nativeDisposed === true &&
249
- state.locationReleased === true);
250
- }
251
246
  async create(meshName, spotType, spotId, request, signal, authority) {
252
247
  const executionMode = this.options.userSpotExecutionMode?.(meshName, spotType) ??
253
248
  contracts_1.ZLinkUserSpotExecutionMode.SpotWide;
@@ -315,7 +310,7 @@ class ZLinkSpotActivationLifecycle {
315
310
  },
316
311
  ensureOperationAllowed: () => activation?.ensureContextOperationAllowed(),
317
312
  leaveActor: (actor, contextSignal) => this.options.leaveActor(spotId, actor, contextSignal, meshName),
318
- close: this.contextClose(meshName, spotId, () => activation)
313
+ close: this.contextClose(spotGeneration, () => activation)
319
314
  });
320
315
  try {
321
316
  spot = await (0, spot_provider_1.createFreshProviderInstance)(spotType, this.options.providerResolver, context);
@@ -331,6 +326,7 @@ class ZLinkSpotActivationLifecycle {
331
326
  spotId,
332
327
  domain: {
333
328
  kind: 'user',
329
+ objectGeneration: spotGeneration,
334
330
  executionMode,
335
331
  relocationCoordinationMode: this.options.userSpotRelocationCoordinationMode?.(meshName, spotType) ??
336
332
  contracts_1.ZLinkSpotRelocationCoordinationMode.FrameworkManaged
@@ -408,7 +404,7 @@ class ZLinkSpotActivationLifecycle {
408
404
  },
409
405
  ensureOperationAllowed: () => activation?.ensureContextOperationAllowed(),
410
406
  leaveActor: (actor, contextSignal) => this.options.leaveActor(spotId, actor, contextSignal, meshName),
411
- close: this.contextClose(meshName, spotId, () => activation)
407
+ close: this.contextClose(objectGeneration, () => activation)
412
408
  });
413
409
  spot = await (0, spot_provider_1.createFreshProviderInstance)(spotType, this.options.providerResolver, context);
414
410
  Object.defineProperty(spot, 'context', {
@@ -421,6 +417,7 @@ class ZLinkSpotActivationLifecycle {
421
417
  spotId,
422
418
  domain: {
423
419
  kind: 'user',
420
+ objectGeneration,
424
421
  executionMode,
425
422
  relocationCoordinationMode: this.options.userSpotRelocationCoordinationMode?.(meshName, spotType) ??
426
423
  contracts_1.ZLinkSpotRelocationCoordinationMode.FrameworkManaged
@@ -437,31 +434,16 @@ class ZLinkSpotActivationLifecycle {
437
434
  });
438
435
  return await this.runCreateLifecycle(activation, spotType, request, locationClaim, undefined, signal);
439
436
  }
440
- contextClose(meshName, spotId, activationProvider) {
441
- return async (signal) => {
437
+ contextClose(objectGeneration, activationProvider) {
438
+ return (signal) => {
442
439
  const activation = activationProvider();
443
- // Native callbacks can cross a promise boundary that does not retain
444
- // the serial turn context. Queue the close before calling the manager
445
- // so the callback never waits for work behind its own serial turn.
446
- if (activation?.serial.isExecuting === true && !activation.serial.isCurrentTurn) {
447
- activation.requestClose();
448
- const retry = activation.serial.post(() => this.options.closeSpot(meshName, spotId, signal));
449
- this.options.detachedTaskRunner?.runDetached(`spot close ${String(spotId)}`, async () => {
450
- await retry;
451
- });
452
- if (this.options.detachedTaskRunner === undefined) {
453
- void retry.catch(() => undefined);
454
- }
455
- return true;
440
+ if (activation === undefined) {
441
+ throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.InvalidOperation, 'Spot context Close requires its active generation.');
456
442
  }
457
- return await this.options.closeSpot(meshName, spotId, signal);
443
+ return this.options.requestContextClose(activation, objectGeneration, signal);
458
444
  };
459
445
  }
460
- async close(activation, signal, reason = contracts_1.ZLinkSpotCloseReason.ExplicitClose) {
461
- const seal = activation.sealExecution();
462
- await this.closeAfterSeal(activation, seal, signal, reason);
463
- }
464
- async closeAfterSeal(activation, seal, signal, reason = contracts_1.ZLinkSpotCloseReason.ExplicitClose, deadline) {
446
+ async sealForClose(activation, seal, signal) {
465
447
  try {
466
448
  await activation.waitForExecutionQuiescence(seal, signal);
467
449
  }
@@ -469,19 +451,13 @@ class ZLinkSpotActivationLifecycle {
469
451
  activation.abortExecutionSeal(seal);
470
452
  throw error;
471
453
  }
472
- // The eager occupancy check that authorized this seal (startClose ->
473
- // canClose()) ran before quiescence, so it can miss an actor join that
474
- // was already queued on the serial executor at that moment. Recheck now
475
- // that every turn admitted before the seal has finished, and release the
476
- // seal instead of closing an occupied Spot.
477
- if (!activation.canClose(reason)) {
478
- activation.abortExecutionSeal(seal);
479
- throw new spot_activation_state_1.ZLinkSpotCloseOccupiedError(activation.spotId);
480
- }
481
454
  if (!activation.commitExecutionSeal(seal)) {
482
455
  throw new Error(`Spot '${String(activation.spotId)}' close seal is stale.`);
483
456
  }
484
- await this.cleanupActivation(activation, activation.meshName, true, signal, reason, deadline);
457
+ }
458
+ /** Returns the OnClosing failure, which cleanup records and does not rethrow. */
459
+ async cleanupClosedActivation(activation, reason = contracts_1.ZLinkSpotCloseReason.ExplicitClose, deadline) {
460
+ return await this.cleanupActivation(activation, activation.meshName, true, undefined, reason, deadline, true);
485
461
  }
486
462
  async dispatchActorPacket(activation, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin) {
487
463
  return await this.actorAdmission.dispatchActorPacket(activation, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin);
@@ -536,25 +512,28 @@ class ZLinkSpotActivationLifecycle {
536
512
  throw error;
537
513
  }
538
514
  }
539
- async cleanupActivation(activation, locationMeshName, notifyClosing, signal, reason = contracts_1.ZLinkSpotCloseReason.ExplicitClose, deadline) {
515
+ async cleanupActivation(activation, locationMeshName, notifyClosing, signal, reason = contracts_1.ZLinkSpotCloseReason.ExplicitClose, deadline, owningLifecycle = false) {
540
516
  (0, abort_1.throwIfAborted)(signal);
541
517
  const state = this.cleanupStates.get(activation) ?? {
542
518
  closingAttempted: false,
543
519
  timersDisposed: false,
520
+ serialDisposed: false,
544
521
  handlersDisposed: false,
522
+ actorDispatchDisposed: false,
545
523
  nativeDisposed: false,
546
524
  locationReleased: false
547
525
  };
548
526
  this.cleanupStates.set(activation, state);
549
527
  if (state.inFlight !== undefined)
550
528
  return await state.inFlight;
551
- state.inFlight = this.runCleanup(activation, locationMeshName, notifyClosing, reason, state, deadline).finally(() => {
529
+ state.inFlight = this.runCleanup(activation, locationMeshName, notifyClosing, reason, state, deadline, owningLifecycle).finally(() => {
552
530
  state.inFlight = undefined;
553
531
  });
554
532
  return await state.inFlight;
555
533
  }
556
- async runCleanup(activation, locationMeshName, notifyClosing, reason, state, deadline) {
534
+ async runCleanup(activation, locationMeshName, notifyClosing, reason, state, deadline, owningLifecycle = false) {
557
535
  const errors = [];
536
+ let closingFailure;
558
537
  const cleanup = async (operation, completed) => {
559
538
  try {
560
539
  await operation();
@@ -566,26 +545,51 @@ class ZLinkSpotActivationLifecycle {
566
545
  };
567
546
  if (notifyClosing && !state.closingAttempted) {
568
547
  state.closingAttempted = true;
569
- await cleanup(() => (0, spot_closing_1.invokeSpotClosing)(activation.spot.onClosing?.bind(activation.spot), reason, deadline), () => undefined);
548
+ try {
549
+ // OnClosing is user code: it runs as a Framework turn through the
550
+ // execution gate while the Close lifecycle item keeps its FIFO slot.
551
+ await activation.serial.postBarrierTurn(() => (0, spot_closing_1.invokeSpotClosing)(activation.spot.onClosing?.bind(activation.spot), reason, deadline));
552
+ }
553
+ catch (error) {
554
+ // An OnClosing failure is diagnostic and cleanup continues. It is
555
+ // returned so host shutdown can classify its teardown outcome.
556
+ this.options.closeErrorSink?.reportRuntimeTaskException(`spot ${String(activation.spotId)} onClosing`, error);
557
+ closingFailure = error;
558
+ }
570
559
  }
571
560
  if (!state.timersDisposed) {
572
561
  await cleanup(() => activation.timers.dispose(), () => {
573
562
  state.timersDisposed = true;
574
563
  });
575
564
  }
576
- await cleanup(() => activation.serialExecutor.close(), () => undefined);
565
+ if (!state.serialDisposed && state.timersDisposed) {
566
+ await cleanup(() => owningLifecycle
567
+ ? activation.serialExecutor.closeChildren()
568
+ : activation.serialExecutor.close(), () => {
569
+ state.serialDisposed = true;
570
+ });
571
+ }
577
572
  if (!state.handlersDisposed) {
578
573
  await cleanup(() => (0, handler_instance_scope_1.disposeLifecycleHandlers)(activation.spot), () => {
579
574
  state.handlersDisposed = true;
580
575
  });
581
576
  }
577
+ if (!state.actorDispatchDisposed) {
578
+ await cleanup(() => activation.actorDispatch?.dispose(), () => {
579
+ state.actorDispatchDisposed = true;
580
+ });
581
+ }
582
582
  if (!state.nativeDisposed) {
583
- await cleanup(() => activation.actorDispatch?.dispose(), () => undefined);
584
583
  await cleanup(() => activation.nativeSpot?.dispose(), () => {
585
584
  state.nativeDisposed = true;
586
585
  });
587
586
  }
588
- if (!state.locationReleased) {
587
+ if (!state.locationReleased &&
588
+ state.timersDisposed &&
589
+ state.serialDisposed &&
590
+ state.handlersDisposed &&
591
+ state.actorDispatchDisposed &&
592
+ state.nativeDisposed) {
589
593
  await cleanup(() => this.options.releaseLocation(activation, locationMeshName, activation.spotId), () => {
590
594
  state.locationReleased = true;
591
595
  });
@@ -595,6 +599,7 @@ class ZLinkSpotActivationLifecycle {
595
599
  if (errors.length > 1) {
596
600
  throw new AggregateError(errors, `Spot '${activation.spotId}' cleanup failed.`);
597
601
  }
602
+ return closingFailure;
598
603
  }
599
604
  decodeCreateReply(reply) {
600
605
  if (reply === undefined) {
@@ -6,7 +6,7 @@ import { type ZLinkRemoteBoundSessionTarget } from '../actors';
6
6
  import type { ZLinkSpotActivationLifecycleOptions } from './spot-activation';
7
7
  import { ZLinkSpotActivation } from './spot-activation-state';
8
8
  import { ZLinkSpotActorJoinDispatch } from './spot-actor-join-dispatch';
9
- type AdmissionOptions = Pick<ZLinkSpotActivationLifecycleOptions, 'actorHandoffRuntime' | 'admission' | 'actorResolver' | 'actorTransferRuntime' | 'boundSessionRuntime' | 'detachedTaskRunner' | 'dispatchErrors' | 'locationClaim' | 'messageSerializers' | 'nativeSpotNodeProvider' | 'createReceived' | 'createTopicMessage' | 'providerResolver' | 'runtimeEventPublisher' | 'routeToActorJoinPrewarm'>;
9
+ type AdmissionOptions = Pick<ZLinkSpotActivationLifecycleOptions, 'actorHandoffRuntime' | 'admission' | 'actorResolver' | 'actorTransferRuntime' | 'boundSessionRuntime' | 'detachedTaskRunner' | 'dispatchErrors' | 'locationClaim' | 'messageSerializers' | 'nativeSpotNodeProvider' | 'createTopicMessage' | 'providerResolver' | 'runtimeEventPublisher' | 'routeToActorJoinPrewarm' | 'isSpotClosing'>;
10
10
  export declare class ZLinkSpotActorAdmissionCoordinator {
11
11
  private readonly options;
12
12
  constructor(options: AdmissionOptions);
@@ -21,9 +21,9 @@ class ZLinkSpotActorAdmissionCoordinator {
21
21
  return undefined;
22
22
  const nativeDispatch = new spot_actor_join_dispatch_1.ZLinkSpotActorJoinDispatch({
23
23
  nativeSpot,
24
- createReceived: requireBackendValueFactory(this.options.createReceived, 'Received'),
25
24
  createTopicMessage: requireBackendValueFactory(this.options.createTopicMessage, 'TopicMessage'),
26
25
  serial: activation.serial,
26
+ isSpotClosing: () => this.options.isSpotClosing(activation),
27
27
  actors: {
28
28
  resolveActor: (actorId) => activation.hasDepartedActor(actorId)
29
29
  ? undefined
@@ -1,6 +1,6 @@
1
1
  import type { RoutingId, ZLinkActor, ZLinkMessage, ZLinkMessageSerializer, ZLinkSpotActorJoinResult } from '../../contracts';
2
2
  import type { ZLinkProviderResolver } from '../../contracts/Common/ZLinkProviderResolver';
3
- import type { ZLinkBackendActorRef, ZLinkBackendActorRecvInfo, ZLinkBackendReceived, ZLinkBackendSpot, ZLinkBackendTopicMessage } from '../backend/contracts';
3
+ import type { ZLinkBackendActorRef, ZLinkBackendActorRecvInfo, ZLinkBackendSpot, ZLinkBackendTopicMessage } from '../backend/contracts';
4
4
  import type { Message } from '../../contracts/Common/Message';
5
5
  import type { RequestResult } from '../backend/runtime-values';
6
6
  type RuntimeMessage = Message;
@@ -47,9 +47,9 @@ export interface ZLinkDetachedTaskRunner {
47
47
  }
48
48
  interface ZLinkSpotActorJoinDispatchOptions {
49
49
  readonly nativeSpot: ZLinkBackendSpot;
50
- readonly createReceived: () => ZLinkBackendReceived;
51
50
  readonly createTopicMessage: () => ZLinkBackendTopicMessage;
52
51
  readonly serial: ZLinkSpotSerialTurnExecutor;
52
+ readonly isSpotClosing?: () => boolean;
53
53
  readonly actors: ZLinkSpotActorAdmissionRuntime;
54
54
  readonly packets?: ZLinkSpotActorPacketRuntime;
55
55
  readonly boundSessionRuntime?: ZLinkSpotBoundSessionRuntime;
@@ -54,10 +54,9 @@ class ZLinkSpotActorJoinDispatch {
54
54
  dispatchErrors: options.dispatchErrors
55
55
  });
56
56
  this.routedFrames = new spot_routed_frame_dispatch_1.ZLinkSpotRoutedFrameDispatch({
57
- nativeSpot: options.nativeSpot,
58
- createReceived: options.createReceived,
59
57
  nativeSpotId: this.nativeSpotId,
60
58
  serial: options.serial,
59
+ isSpotClosing: options.isSpotClosing,
61
60
  resolveActor: actors.resolveActor,
62
61
  getTarget: () => actors.getTarget(),
63
62
  defaultAccept: actors.defaultAccept,
@@ -78,8 +77,7 @@ class ZLinkSpotActorJoinDispatch {
78
77
  messageSerializers: options.messageSerializers,
79
78
  providerResolver: options.providerResolver,
80
79
  dispatchErrors: options.dispatchErrors,
81
- claimApplicationWork: options.claimApplicationWork,
82
- waitIdle: waitSpotDispatchIdle
80
+ claimApplicationWork: options.claimApplicationWork
83
81
  });
84
82
  this.subscriptions = new spot_subscription_dispatch_1.ZLinkSpotSubscriptionDispatch({
85
83
  nativeSpot: options.nativeSpot,
@@ -175,7 +173,7 @@ class ZLinkSpotActorJoinDispatch {
175
173
  await waitSpotDispatchIdle();
176
174
  return;
177
175
  }
178
- await this.nativeActorJoinAdmission.admit(request);
176
+ await this.options.serial.executeLifecycleOperation(() => this.nativeActorJoinAdmission.admit(request, this.options.isSpotClosing?.() === true));
179
177
  }
180
178
  }
181
179
  }
@@ -26,7 +26,7 @@ class ZLinkSpotActorLifecycleDrain {
26
26
  }
27
27
  if (actorRef === null || actorRef === undefined)
28
28
  continue;
29
- await this.options.serial.execute(() => {
29
+ await this.options.serial.executeLifecycleOperation(() => this.options.serial.execute(() => {
30
30
  const actor = this.options.resolveActor(actorId);
31
31
  if (actor === undefined) {
32
32
  return undefined;
@@ -44,7 +44,7 @@ class ZLinkSpotActorLifecycleDrain {
44
44
  return target.onDisconnectActor?.(actor);
45
45
  }
46
46
  return undefined;
47
- });
47
+ }));
48
48
  }
49
49
  }
50
50
  }