@zlink-systems/framework 0.25.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
@@ -1,3 +1,4 @@
1
+ import type { ZLinkListenerRecords } from '../foundation/listener-records';
1
2
  import type { ZLinkLocationOptionOverrides } from '../../contracts/Locations/Options';
2
3
  import type { RoutingId } from '../../contracts';
3
4
  import type { ZLinkProviderResolver } from '../../contracts/Common/ZLinkProviderResolver';
@@ -27,11 +28,6 @@ export declare class ZLinkChannelRuntimeManager {
27
28
  fanoutTopology(channelName: string): {
28
29
  descriptors: readonly import("../foundation").FanoutPublisherDescriptor[];
29
30
  };
30
- getFanoutListenerStatus(channelName: string): {
31
- channelName: string;
32
- endpoint: string;
33
- observedAt: Date;
34
- };
35
31
  observeClientServerTopology(channelName: string, changed: () => void): () => void;
36
32
  observeFanoutTopology(channelName: string, changed: () => void): () => void;
37
33
  configureLocationAutoConnect(runtime: ZLinkLocationRuntime, stores: ZLinkLocationRuntimeStores, options: ZLinkLocationOptionOverrides, events?: ZLinkLocationEventSink): void;
@@ -65,6 +61,7 @@ export declare class ZLinkChannelRuntimeManager {
65
61
  dispose(signal?: AbortSignal): Promise<void>;
66
62
  }
67
63
  export interface ZLinkChannelRuntimeManagerOptions {
64
+ readonly listenerRecords?: ZLinkListenerRecords;
68
65
  readonly internalRouteSendHandlers?: ReadonlyMap<string, ZLinkRouteRuntimeSendHandler>;
69
66
  readonly internalRouteRequestHandlers?: ReadonlyMap<string, ZLinkRouteRuntimeRequestHandler>;
70
67
  readonly monitoringAdapter?: ZLinkMonitoringBackendAdapter;
@@ -18,7 +18,7 @@ class ZLinkChannelRuntimeManager {
18
18
  this.registration = registration;
19
19
  const applicationJobQueue = options.applicationJobQueue ??
20
20
  new application_job_queue_1.ApplicationJobQueue((0, application_job_queue_1.resolveApplicationJobQueueConfiguration)());
21
- this.sockets = new channel_socket_registry_1.ZLinkChannelSocketRegistry(registration, adapter, context, options.monitoringAdapter, options.oneWayFailureSink, applicationJobQueue);
21
+ this.sockets = new channel_socket_registry_1.ZLinkChannelSocketRegistry(registration, adapter, context, options.monitoringAdapter, options.oneWayFailureSink, applicationJobQueue, options.listenerRecords);
22
22
  const codecs = {
23
23
  serializers: registration.messageSerializers
24
24
  };
@@ -65,17 +65,6 @@ class ZLinkChannelRuntimeManager {
65
65
  fanoutTopology(channelName) {
66
66
  return { descriptors: this.sockets.fanoutActiveTargets(channelName) };
67
67
  }
68
- getFanoutListenerStatus(channelName) {
69
- const endpoint = this.sockets.fanoutPublisherEndpoint(channelName);
70
- if (endpoint === undefined) {
71
- throw new configuration_1.ZLinkConfigurationException(`Fanout publisher '${channelName}' has not reported a bound listener.`);
72
- }
73
- return {
74
- channelName,
75
- endpoint,
76
- observedAt: new Date()
77
- };
78
- }
79
68
  observeClientServerTopology(channelName, changed) {
80
69
  const monitor = this.sockets.clientServerMonitoringSource(channelName);
81
70
  monitor.onEvent(changed);
@@ -1,3 +1,4 @@
1
+ import { ZLinkListenerRecords } from '../foundation/listener-records';
1
2
  import { type ZLinkClientServerServerDescriptor, type ZLinkFanoutPublisherDescriptor } from '../../contracts';
2
3
  import { type ZLinkFrameworkRegistration } from '../configuration';
3
4
  import type { ZLinkBackendContext, ZLinkBackendDealerSocket, ZLinkBackendPublisherSocket, ZLinkBackendRouterSocket, ZLinkBackendSocketMonitor, ZLinkBackendSubscriberSocket, ZLinkChannelBackendAdapter, ZLinkMonitoringBackendAdapter } from '../backend/contracts';
@@ -48,11 +49,14 @@ export declare class ZLinkChannelSocketRegistry {
48
49
  private readonly clientServerMonitorHandlers;
49
50
  private readonly fanoutMonitorHandlers;
50
51
  private readonly fanoutTopologyHandlers;
51
- constructor(registration: ZLinkFrameworkRegistration, adapter: ZLinkChannelBackendAdapter, context: ZLinkBackendContext, monitoringAdapter?: ZLinkMonitoringBackendAdapter | undefined, oneWayFailureSink?: ((error: unknown) => void) | undefined, applicationJobQueue?: ApplicationJobQueue | undefined);
52
+ private readonly listenerRecords;
53
+ constructor(registration: ZLinkFrameworkRegistration, adapter: ZLinkChannelBackendAdapter, context: ZLinkBackendContext, monitoringAdapter?: ZLinkMonitoringBackendAdapter | undefined, oneWayFailureSink?: ((error: unknown) => void) | undefined, applicationJobQueue?: ApplicationJobQueue | undefined, listenerRecords?: ZLinkListenerRecords);
52
54
  dispose(): Promise<void>;
53
55
  clientDealer(channelName: string): ZLinkBackendDealerSocket;
54
56
  channelRouter(channelName: string): ZLinkBackendRouterSocket;
55
57
  clientServerServerIdentity(channelName: string): ZLinkClientServerServerSocketIdentity;
58
+ fanoutPublisherEndpoint(channelName: string): string | undefined;
59
+ private recordListener;
56
60
  clientServerServerSocket(channelName: string): ZLinkBackendRouterSocket;
57
61
  clientServerServerWeight(channelName: string): number;
58
62
  setClientServerServerWeight(channelName: string, weight: number): void;
@@ -90,7 +94,6 @@ export declare class ZLinkChannelSocketRegistry {
90
94
  startLocalClientServerConnections(): void;
91
95
  clientServerMonitoringSource(channelName: string): ZLinkBackendSocketMonitor;
92
96
  clientServerActiveTargets(channelName: string): readonly Pick<ClientServerDiscoveryDescriptor, 'serverRoutingId' | 'weight' | 'state'>[];
93
- hasKnownClientServerTargets(channelName: string): boolean;
94
97
  fanoutActiveTargets(channelName: string): readonly import("../foundation/service-discovery-registry").FanoutPublisherDescriptor[];
95
98
  admitFanoutPublisher(descriptor: ZLinkFanoutPublisherDescriptor, connectionId: string): boolean;
96
99
  removeFanoutPublisher(descriptor: ZLinkFanoutPublisherDescriptor, connectionId: string): boolean;
@@ -130,7 +133,18 @@ export declare class ZLinkChannelSocketRegistry {
130
133
  private openConfiguredClientServerConnection;
131
134
  private admitConfiguredClientServerConnection;
132
135
  private drainClientServerControl;
133
- private requestClientServerEndpointTermination;
136
+ /**
137
+ * Ends the current logical admission of this connection: later replies of
138
+ * the fenced attempt no longer apply and its ready target is withdrawn.
139
+ */
140
+ private endClientServerAdmission;
141
+ /**
142
+ * A peer deadline or an invalid pushed control ends only the current logical
143
+ * admission. The connect intent stays with Core, which owns the endpoint
144
+ * reconnect (transport liveness §6); the service handshake starts again on
145
+ * the existing admission path.
146
+ */
147
+ private restartClientServerAdmission;
134
148
  private applyClientServerDescriptorUpdate;
135
149
  private ensureClientServerLivenessTimer;
136
150
  private drainSocketMonitors;
@@ -143,7 +157,6 @@ export declare class ZLinkChannelSocketRegistry {
143
157
  private pushClientServerDescriptorUpdate;
144
158
  private allocateClientServerProbeId;
145
159
  publisher(channelName: string): ZLinkBackendPublisherSocket;
146
- fanoutPublisherEndpoint(channelName: string): string | undefined;
147
160
  routeRouter(routerChannelId: string): ZLinkBackendRouterSocket;
148
161
  routeMeshSocket(routerChannelId: string): ZLinkBackendRouterSocket;
149
162
  routeMeshWeight(routerChannelId: string): number;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZLinkChannelSocketRegistry = void 0;
4
+ const listener_records_1 = require("../foundation/listener-records");
4
5
  const contracts_1 = require("../../contracts");
5
6
  const internal_event_contracts_1 = require("../diagnostics/internal-event-contracts");
6
7
  const configuration_1 = require("../configuration");
@@ -51,13 +52,15 @@ class ZLinkChannelSocketRegistry {
51
52
  clientServerMonitorHandlers = new Map();
52
53
  fanoutMonitorHandlers = new Map();
53
54
  fanoutTopologyHandlers = new Map();
54
- constructor(registration, adapter, context, monitoringAdapter, oneWayFailureSink, applicationJobQueue) {
55
+ listenerRecords;
56
+ constructor(registration, adapter, context, monitoringAdapter, oneWayFailureSink, applicationJobQueue, listenerRecords) {
55
57
  this.registration = registration;
56
58
  this.adapter = adapter;
57
59
  this.context = context;
58
60
  this.monitoringAdapter = monitoringAdapter;
59
61
  this.oneWayFailureSink = oneWayFailureSink;
60
62
  this.applicationJobQueue = applicationJobQueue;
63
+ this.listenerRecords = listenerRecords ?? new listener_records_1.ZLinkListenerRecords();
61
64
  }
62
65
  async dispose() {
63
66
  const clientServerConnections = [...new Set(this.clientServerConnections.values())];
@@ -177,14 +180,15 @@ class ZLinkChannelSocketRegistry {
177
180
  });
178
181
  }
179
182
  this.channelRouters.set(channelName, router);
183
+ const endpoint = advertisedEndpoint(router.lastEndpoint ?? channel.server.bind, channel.server.advertiseHost);
184
+ this.recordListener('clientServer', channelName, endpoint);
180
185
  if (!this.clientServerServerDescriptors.has(channelName)) {
181
- const boundEndpoint = router.lastEndpoint ?? channel.server.bind;
182
186
  this.clientServerServerDescriptors.set(channelName, {
183
187
  channelName,
184
188
  serverRid: identity.serverRid,
185
189
  lifecycleGeneration: identity.lifecycleGeneration,
186
190
  descriptorRevision: 1n,
187
- endpoint: advertisedEndpoint(boundEndpoint, channel.server.advertiseHost),
191
+ endpoint,
188
192
  weight: publicWeight,
189
193
  state: contracts_1.ZLinkFrameworkRuntimeState.Serving,
190
194
  securityIdentity: 'default',
@@ -196,20 +200,19 @@ class ZLinkChannelSocketRegistry {
196
200
  return router;
197
201
  }
198
202
  clientServerServerIdentity(channelName) {
199
- const router = this.channelRouter(channelName);
203
+ this.channelRouter(channelName);
200
204
  const identity = this.clientServerIdentities.get(channelName);
201
- const channel = this.registration.channels.get(channelName);
202
- if (identity === undefined || channel?.server === undefined) {
205
+ const endpoint = this.listenerRecords.endpoint('clientServer', channelName);
206
+ if (identity === undefined || endpoint === undefined) {
203
207
  throw new configuration_1.ZLinkConfigurationException(`Channel server '${channelName}' is not registered.`);
204
208
  }
205
- const boundEndpoint = router.lastEndpoint ?? channel.server.bind;
206
- if (boundEndpoint === undefined || boundEndpoint.length === 0) {
207
- throw new configuration_1.ZLinkConfigurationException(`Channel server '${channelName}' did not report its bound endpoint.`);
208
- }
209
- return {
210
- ...identity,
211
- endpoint: advertisedEndpoint(boundEndpoint, channel.server.advertiseHost)
212
- };
209
+ return { ...identity, endpoint };
210
+ }
211
+ fanoutPublisherEndpoint(channelName) {
212
+ return this.listenerRecords.endpoint('fanout', channelName);
213
+ }
214
+ recordListener(kind, name, endpoint) {
215
+ this.listenerRecords.record(kind, name, endpoint);
213
216
  }
214
217
  clientServerServerSocket(channelName) {
215
218
  return this.channelRouter(channelName);
@@ -275,8 +278,7 @@ class ZLinkChannelSocketRegistry {
275
278
  monitor,
276
279
  aliases: new Set([connectionId]),
277
280
  callbacksByAlias: new Map([[connectionId, callbacks]]),
278
- physicalConnectionId: Symbol(connectionId),
279
- terminationRequested: false
281
+ physicalConnectionId: Symbol(connectionId)
280
282
  };
281
283
  this.clientServerConnections.set(connectionId, connection);
282
284
  this.ensureClientServerLivenessTimer();
@@ -290,7 +292,7 @@ class ZLinkChannelSocketRegistry {
290
292
  const routingId = event.routingId === undefined ? undefined : String(event.routingId);
291
293
  if (event.nativeEvent === internal_event_contracts_1.ZLinkSocketNativeEventType.ConnectionReady) {
292
294
  // This single-endpoint DEALER also receives its disconnected ready-count snapshot.
293
- if (event.value === 0n || connection.terminationRequested)
295
+ if (event.value === 0n)
294
296
  return;
295
297
  connection.physicalConnectionId = Symbol(connectionId);
296
298
  connection.admissionAttempt = undefined;
@@ -304,24 +306,9 @@ class ZLinkChannelSocketRegistry {
304
306
  event.nativeEvent === internal_event_contracts_1.ZLinkSocketNativeEventType.HandshakeFailedNoDetail ||
305
307
  event.nativeEvent === internal_event_contracts_1.ZLinkSocketNativeEventType.HandshakeFailedProtocol ||
306
308
  event.nativeEvent === internal_event_contracts_1.ZLinkSocketNativeEventType.HandshakeFailedAuth) {
307
- if (connection.terminationRequested &&
308
- (event.remoteAddr !== connection.endpoint ||
309
- (event.nativeEvent !== internal_event_contracts_1.ZLinkSocketNativeEventType.Disconnected &&
310
- event.nativeEvent !== internal_event_contracts_1.ZLinkSocketNativeEventType.Closed)))
311
- return;
312
- connection.physicalConnectionId = Symbol(connectionId);
313
- connection.admissionAttempt = undefined;
314
- if (connection.readyConnectionId !== undefined) {
315
- this.removeReadyConnection(connection.readyConnectionId);
316
- }
317
- for (const currentCallbacks of [...connection.callbacksByAlias.values()]) {
318
- currentCallbacks.onTerminated(routingId, event.remoteAddr);
319
- }
320
- if (connection.terminationRequested) {
321
- connection.terminationRequested = false;
322
- // Explicit disconnect removes intent; restore it once after this endpoint closes.
323
- connection.dealer.connect(connection.endpoint);
324
- }
309
+ // Core owns the endpoint reconnect (transport liveness §6); the
310
+ // connect intent stays and the next READY starts a new admission.
311
+ this.endClientServerAdmission(connectionId, connection, routingId, event.remoteAddr);
325
312
  }
326
313
  });
327
314
  dealer.connect(endpoint);
@@ -588,9 +575,6 @@ class ZLinkChannelSocketRegistry {
588
575
  ? 1
589
576
  : 0);
590
577
  }
591
- hasKnownClientServerTargets(channelName) {
592
- return this.clientServerDiscovery.clientServerDescriptors(channelName).length > 0;
593
- }
594
578
  fanoutActiveTargets(channelName) {
595
579
  return this.clientServerDiscovery.fanoutEndpoints(channelName);
596
580
  }
@@ -689,7 +673,7 @@ class ZLinkChannelSocketRegistry {
689
673
  if (connection.deadlineAt === undefined)
690
674
  continue;
691
675
  if (nowMs >= connection.deadlineAt) {
692
- this.requestClientServerEndpointTermination(connectionId, connection);
676
+ this.restartClientServerAdmission(connectionId, connection);
693
677
  continue;
694
678
  }
695
679
  if (connection.nextProbeAt === undefined || nowMs < connection.nextProbeAt)
@@ -993,8 +977,6 @@ class ZLinkChannelSocketRegistry {
993
977
  }
994
978
  }
995
979
  drainClientServerControl(connectionId, connection) {
996
- if (connection.terminationRequested)
997
- return;
998
980
  for (;;) {
999
981
  if (!connection.readablePoller.wait(0))
1000
982
  return;
@@ -1025,7 +1007,7 @@ class ZLinkChannelSocketRegistry {
1025
1007
  this.applyClientServerDescriptorUpdate(connectionId, connection, record.admission);
1026
1008
  }
1027
1009
  catch (error) {
1028
- this.requestClientServerEndpointTermination(connectionId, connection);
1010
+ this.restartClientServerAdmission(connectionId, connection);
1029
1011
  this.oneWayFailureSink?.(error);
1030
1012
  return;
1031
1013
  }
@@ -1034,18 +1016,30 @@ class ZLinkChannelSocketRegistry {
1034
1016
  }
1035
1017
  }
1036
1018
  }
1037
- requestClientServerEndpointTermination(connectionId, connection) {
1038
- if (connection.terminationRequested)
1039
- return;
1040
- connection.terminationRequested = true;
1019
+ /**
1020
+ * Ends the current logical admission of this connection: later replies of
1021
+ * the fenced attempt no longer apply and its ready target is withdrawn.
1022
+ */
1023
+ endClientServerAdmission(connectionId, connection, routingId, endpoint) {
1041
1024
  connection.physicalConnectionId = Symbol(connectionId);
1042
1025
  connection.admissionAttempt = undefined;
1043
- this.removeReadyConnection(connectionId);
1044
- try {
1045
- connection.dealer.disconnect(connection.endpoint);
1026
+ if (connection.readyConnectionId !== undefined) {
1027
+ this.removeReadyConnection(connection.readyConnectionId);
1046
1028
  }
1047
- catch (error) {
1048
- this.oneWayFailureSink?.(error);
1029
+ for (const callbacks of [...connection.callbacksByAlias.values()]) {
1030
+ callbacks.onTerminated(routingId, endpoint);
1031
+ }
1032
+ }
1033
+ /**
1034
+ * A peer deadline or an invalid pushed control ends only the current logical
1035
+ * admission. The connect intent stays with Core, which owns the endpoint
1036
+ * reconnect (transport liveness §6); the service handshake starts again on
1037
+ * the existing admission path.
1038
+ */
1039
+ restartClientServerAdmission(connectionId, connection) {
1040
+ this.endClientServerAdmission(connectionId, connection, undefined, connection.endpoint);
1041
+ for (const callbacks of [...connection.callbacksByAlias.values()]) {
1042
+ callbacks.onTransportReady('', connection.endpoint);
1049
1043
  }
1050
1044
  }
1051
1045
  applyClientServerDescriptorUpdate(connectionId, connection, admission) {
@@ -1223,21 +1217,14 @@ class ZLinkChannelSocketRegistry {
1223
1217
  applyFanoutPublisherSocketOptions(publisher, channel);
1224
1218
  publisher.bind(channel.publisher.bind);
1225
1219
  this.publishers.set(channelName, publisher);
1220
+ const endpoint = (0, configuration_1.buildAdvertisedEndpoint)(publisher.lastEndpoint ?? channel.publisher.bind, channel.publisher.advertiseHost);
1221
+ if (endpoint !== undefined && endpoint.length > 0) {
1222
+ this.recordListener('fanout', channelName, endpoint);
1223
+ }
1226
1224
  this.fanoutPublisherNextBeacon.set(channelName, performance.now() + CLIENT_SERVER_PROBE_INTERVAL_MS);
1227
1225
  this.ensureClientServerLivenessTimer();
1228
1226
  return publisher;
1229
1227
  }
1230
- fanoutPublisherEndpoint(channelName) {
1231
- const channel = this.registration.channels.get(channelName);
1232
- const publisher = this.publishers.get(channelName);
1233
- const boundEndpoint = publisher?.lastEndpoint;
1234
- if (channel?.publisher === undefined ||
1235
- boundEndpoint === undefined ||
1236
- boundEndpoint.length === 0) {
1237
- return undefined;
1238
- }
1239
- return advertisedEndpoint(boundEndpoint, channel.publisher.advertiseHost);
1240
- }
1241
1228
  routeRouter(routerChannelId) {
1242
1229
  const existing = this.routeRouters.get(routerChannelId);
1243
1230
  if (existing !== undefined) {
@@ -1,7 +1,6 @@
1
1
  import { type ZLinkBackendMessageLike as MessageLike } from '../backend/runtime-values';
2
2
  import type { ZLinkBackendMeshNode, ZLinkBackendSpot } from '../backend/contracts';
3
3
  import { ZLinkFrameworkException } from '../../contracts';
4
- import type { ZLinkFanoutListenerStatus } from '../../contracts';
5
4
  import type { Message } from '../../contracts/Common/Message';
6
5
  import { type ZLinkSubmitResult } from '../messaging/submission-result';
7
6
  import type { ZLinkSpotRouteTarget } from '../spots/spot-routing-internal';
@@ -13,7 +12,6 @@ export interface ZLinkChannelClientTransport {
13
12
  request<TReply>(channelName: string, packetName: string | undefined, request: unknown, timeoutMs: number | undefined, signal?: AbortSignal, metadata?: ReadonlyMap<string, string>): Promise<TReply>;
14
13
  tryPublish?(channelName: string, topic: string, packetName: string | undefined, event: unknown, metadata?: ReadonlyMap<string, string>): ZLinkSubmitResult;
15
14
  publish(channelName: string, topic: string, packetName: string | undefined, event: unknown, signal?: AbortSignal, metadata?: ReadonlyMap<string, string>): ZLinkSubmitResult | Promise<ZLinkSubmitResult>;
16
- getFanoutListenerStatus?(channelName: string): ZLinkFanoutListenerStatus;
17
15
  }
18
16
  export type ZLinkChannelClientTransportSource = ZLinkChannelClientTransport | (() => ZLinkChannelClientTransport | undefined);
19
17
  export interface ZLinkSpotPublisherClientTransport {
@@ -43,7 +41,6 @@ interface ZLinkChannelTransportRuntime {
43
41
  request<TReply>(channelName: string, packetName: string | undefined, request: unknown, timeoutMs: number | undefined, signal?: AbortSignal, metadata?: ReadonlyMap<string, string>): Promise<TReply>;
44
42
  tryPublish(channelName: string, topic: string, packetName: string | undefined, event: unknown, metadata?: ReadonlyMap<string, string>): ZLinkSubmitResult;
45
43
  publish(channelName: string, topic: string, packetName: string | undefined, event: unknown, signal?: AbortSignal, metadata?: ReadonlyMap<string, string>): Promise<ZLinkSubmitResult>;
46
- getFanoutListenerStatus(channelName: string): ZLinkFanoutListenerStatus;
47
44
  canRouteChannel(routerChannelId: string): boolean;
48
45
  canRoutePacketChannel(routerChannelId: string): boolean;
49
46
  routeSubmit(routerChannelId: string, targetNodeRid: string, packetName: string | undefined, message: unknown, signal?: AbortSignal, metadata?: ReadonlyMap<string, string>): Promise<ZLinkSubmitResult>;
@@ -101,8 +101,9 @@ class ZLinkFanoutLocationRuntime {
101
101
  for (const [channelName, channel] of this.registration.channels) {
102
102
  if (channel.publisher === undefined)
103
103
  continue;
104
- const publisher = this.sockets.publisher(channelName);
105
- const endpoint = advertisedEndpoint(publisher.lastEndpoint ?? channel.publisher.bind ?? '', channel.publisher.advertiseHost);
104
+ // Opening the publisher binds it and fixes its advertised endpoint.
105
+ this.sockets.publisher(channelName);
106
+ const endpoint = this.sockets.fanoutPublisherEndpoint(channelName) ?? '';
106
107
  if (endpoint.length === 0) {
107
108
  throw new configuration_1.ZLinkConfigurationException(`Fanout publisher '${channelName}' did not report a bound endpoint.`);
108
109
  }
@@ -316,13 +317,6 @@ class ZLinkFanoutLocationRuntime {
316
317
  }
317
318
  }
318
319
  exports.ZLinkFanoutLocationRuntime = ZLinkFanoutLocationRuntime;
319
- function advertisedEndpoint(boundEndpoint, advertiseHost) {
320
- const result = (0, configuration_1.buildAdvertisedEndpoint)(boundEndpoint, advertiseHost);
321
- if (result === undefined) {
322
- throw new configuration_1.ZLinkConfigurationException(`Fanout publisher bound endpoint '${boundEndpoint}' cannot be advertised.`);
323
- }
324
- return result;
325
- }
326
320
  function fanoutConnectionId(descriptor) {
327
321
  return (`${descriptor.channelName}\0${String(descriptor.publisherRid)}\0` +
328
322
  descriptor.lifecycleGeneration.toString());
@@ -23,11 +23,14 @@ export declare class ZLinkSpotSerialTurn {
23
23
  private owner;
24
24
  private frameworkOperationsBlocked;
25
25
  constructor(postResume: (turn: ZLinkSpotSerialTurn, resume: () => void, reject: (reason: unknown) => void) => boolean, executionClaim: ZLinkExecutionBarrierClaim | undefined, yieldAllowed: boolean);
26
- bindExecutionClaim(claim: ZLinkExecutionBarrierClaim | undefined): void;
27
26
  get isSuspended(): boolean;
27
+ /** False when a seal that does not drain yielded turns won before this resume. */
28
+ resumeExecutionClaim(): boolean;
28
29
  releaseBoundExecutionClaim(): void;
29
30
  get suspended(): Promise<void>;
30
31
  bindOwner(owner: Promise<unknown>): void;
32
+ /** Settles when the whole turn ends by any path, including yielded continuations. */
33
+ get completion(): Promise<void>;
31
34
  blockFrameworkOperations(): void;
32
35
  ensureFrameworkOperationAllowed(): void;
33
36
  resetSuspension(): void;
@@ -51,9 +54,18 @@ export declare function captureZLinkExecutionTurn(): ZLinkCapturedExecutionTurn
51
54
  export declare function isCurrentZLinkSpotSerialTurn(executor: ZLinkSpotSerialTurnExecutorLike): boolean;
52
55
  export interface ZLinkExecutionBarrierSeal {
53
56
  readonly generation: bigint;
57
+ /**
58
+ * A Spot Close seal waits for yielded turns accepted before it and lets them
59
+ * resume (Spot address messaging §7 step 2); a relocation seal does not, and
60
+ * their continuation fails (execution gate §4).
61
+ */
62
+ readonly drainsYieldedTurns: boolean;
54
63
  }
55
64
  export interface ZLinkExecutionBarrierClaim {
56
65
  release(): void;
66
+ /** The turn yielded; it no longer runs until resume() admits it again. */
67
+ suspend(): void;
68
+ resume(): boolean;
57
69
  }
58
70
  /**
59
71
  * Seals application-lane admission and waits for every active Promise turn to
@@ -63,22 +75,20 @@ export interface ZLinkExecutionBarrierClaim {
63
75
  export declare class ZLinkExecutionBarrier {
64
76
  private generation;
65
77
  private activeClaims;
78
+ private suspendedClaims;
66
79
  private currentSeal;
67
80
  private readonly admissionWaiters;
68
81
  private readonly quiescenceWaiters;
69
82
  private committed;
83
+ get isSealed(): boolean;
70
84
  enter(): Promise<ZLinkExecutionBarrierClaim>;
71
- /**
72
- * Re-enters a previously yielded application turn only while admission is
73
- * open. A continuation must fail instead of waiting behind a relocation
74
- * seal that already won the turn-boundary race.
75
- */
76
- tryEnter(): ZLinkExecutionBarrierClaim | undefined;
77
- seal(): ZLinkExecutionBarrierSeal;
85
+ seal(drainsYieldedTurns?: boolean): ZLinkExecutionBarrierSeal;
78
86
  waitForQuiescence(seal: ZLinkExecutionBarrierSeal, signal?: AbortSignal): Promise<void>;
79
87
  abort(seal: ZLinkExecutionBarrierSeal): boolean;
80
88
  commit(seal: ZLinkExecutionBarrierSeal): boolean;
81
89
  isCurrent(seal: ZLinkExecutionBarrierSeal): boolean;
90
+ private isQuiescent;
91
+ private notifyQuiescence;
82
92
  private createClaim;
83
93
  private requireCurrent;
84
94
  }
@@ -43,15 +43,13 @@ class ZLinkSpotSerialTurn {
43
43
  this.executionClaim = executionClaim;
44
44
  this.yieldAllowed = yieldAllowed;
45
45
  }
46
- bindExecutionClaim(claim) {
47
- if (this.executionClaim !== undefined) {
48
- throw new Error('ZLink Spot serial turn already owns an execution claim.');
49
- }
50
- this.executionClaim = claim;
51
- }
52
46
  get isSuspended() {
53
47
  return this.suspendSignaled;
54
48
  }
49
+ /** False when a seal that does not drain yielded turns won before this resume. */
50
+ resumeExecutionClaim() {
51
+ return this.executionClaim?.resume() ?? true;
52
+ }
55
53
  releaseBoundExecutionClaim() {
56
54
  this.executionClaim?.release();
57
55
  this.executionClaim = undefined;
@@ -68,6 +66,10 @@ class ZLinkSpotSerialTurn {
68
66
  bindOwner(owner) {
69
67
  this.owner = owner;
70
68
  }
69
+ /** Settles when the whole turn ends by any path, including yielded continuations. */
70
+ get completion() {
71
+ return (this.owner ?? Promise.resolve()).then(() => undefined, () => undefined);
72
+ }
71
73
  blockFrameworkOperations() {
72
74
  this.frameworkOperationsBlocked = true;
73
75
  }
@@ -109,7 +111,7 @@ class ZLinkSpotSerialTurn {
109
111
  return;
110
112
  }
111
113
  this.suspendSignaled = true;
112
- this.releaseBoundExecutionClaim();
114
+ this.executionClaim?.suspend();
113
115
  this.suspendedResolve?.();
114
116
  }
115
117
  awaitResumePermit() {
@@ -175,10 +177,14 @@ function isCurrentZLinkSpotSerialTurn(executor) {
175
177
  class ZLinkExecutionBarrier {
176
178
  generation = 0n;
177
179
  activeClaims = 0;
180
+ suspendedClaims = 0;
178
181
  currentSeal;
179
182
  admissionWaiters = [];
180
183
  quiescenceWaiters = new Set();
181
184
  committed = false;
185
+ get isSealed() {
186
+ return this.currentSeal !== undefined || this.committed;
187
+ }
182
188
  async enter() {
183
189
  if (this.committed) {
184
190
  throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotMoving, 'ZLink execution barrier is committed.');
@@ -190,36 +196,28 @@ class ZLinkExecutionBarrier {
190
196
  }
191
197
  return this.createClaim();
192
198
  }
193
- /**
194
- * Re-enters a previously yielded application turn only while admission is
195
- * open. A continuation must fail instead of waiting behind a relocation
196
- * seal that already won the turn-boundary race.
197
- */
198
- tryEnter() {
199
- if (this.committed || this.currentSeal !== undefined) {
200
- return undefined;
201
- }
202
- return this.createClaim();
203
- }
204
- seal() {
199
+ seal(drainsYieldedTurns = false) {
205
200
  if (this.committed) {
206
201
  throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotMoving, 'ZLink execution barrier is committed.');
207
202
  }
208
203
  if (this.currentSeal !== undefined) {
209
204
  throw new Error('ZLink execution barrier is already sealed.');
210
205
  }
211
- const seal = Object.freeze({ generation: ++this.generation });
206
+ const seal = Object.freeze({ generation: ++this.generation, drainsYieldedTurns });
212
207
  this.currentSeal = seal;
213
208
  return seal;
214
209
  }
215
210
  async waitForQuiescence(seal, signal) {
216
211
  this.requireCurrent(seal);
217
- if (this.activeClaims === 0)
212
+ if (this.isQuiescent(seal))
218
213
  return;
219
214
  if (signal?.aborted === true)
220
215
  throw signal.reason;
221
216
  await new Promise((resolve, reject) => {
222
217
  const complete = () => {
218
+ if (!this.isQuiescent(seal))
219
+ return;
220
+ this.quiescenceWaiters.delete(complete);
223
221
  signal?.removeEventListener('abort', abort);
224
222
  resolve();
225
223
  };
@@ -255,20 +253,48 @@ class ZLinkExecutionBarrier {
255
253
  isCurrent(seal) {
256
254
  return this.currentSeal?.generation === seal.generation;
257
255
  }
256
+ isQuiescent(seal) {
257
+ return this.activeClaims === 0 && (!seal.drainsYieldedTurns || this.suspendedClaims === 0);
258
+ }
259
+ notifyQuiescence() {
260
+ for (const waiter of [...this.quiescenceWaiters])
261
+ waiter();
262
+ }
258
263
  createClaim() {
259
264
  this.activeClaims++;
260
- let released = false;
265
+ let state = 'active';
266
+ const release = () => {
267
+ if (state === 'released')
268
+ return;
269
+ if (state === 'active')
270
+ this.activeClaims--;
271
+ else
272
+ this.suspendedClaims--;
273
+ state = 'released';
274
+ this.notifyQuiescence();
275
+ };
261
276
  return {
262
- release: () => {
263
- if (released)
277
+ release,
278
+ suspend: () => {
279
+ if (state !== 'active')
264
280
  return;
265
- released = true;
281
+ state = 'suspended';
266
282
  this.activeClaims--;
267
- if (this.activeClaims === 0) {
268
- for (const waiter of this.quiescenceWaiters)
269
- waiter();
270
- this.quiescenceWaiters.clear();
283
+ this.suspendedClaims++;
284
+ this.notifyQuiescence();
285
+ },
286
+ resume: () => {
287
+ if (state !== 'suspended')
288
+ return state === 'active';
289
+ if (this.committed ||
290
+ (this.currentSeal !== undefined && !this.currentSeal.drainsYieldedTurns)) {
291
+ release();
292
+ return false;
271
293
  }
294
+ state = 'active';
295
+ this.suspendedClaims--;
296
+ this.activeClaims++;
297
+ return true;
272
298
  }
273
299
  };
274
300
  }
@@ -34,6 +34,7 @@ export declare class ZLinkSerialExecutionQueue {
34
34
  private readonly executeRecord;
35
35
  private readonly application;
36
36
  private readonly lifecycle;
37
+ private activeLifecycle?;
37
38
  private readonly ownerTimeBudget;
38
39
  private readonly lifecycleBurstLimit;
39
40
  private nextAcceptedSequence;
@@ -56,16 +57,14 @@ export declare class ZLinkSerialExecutionQueue {
56
57
  * It remains held through handler terminal completion.
57
58
  */
58
59
  submitPreAdmitted<T>(operation: () => Promise<T> | T, options?: ZLinkSerialWorkOptions, context?: unknown): Promise<T>;
59
- snapshot(): {
60
- readonly applicationMessages: number;
61
- readonly applicationBytes: number;
62
- readonly lifecycleMessages: number;
63
- readonly lifecycleBytes: number;
64
- };
60
+ /** Holds lifecycle FIFO through an operation result while its application turns can run. */
61
+ submitLifecycleOperation<T>(operation: () => Promise<T> | T): Promise<T>;
65
62
  get hasPendingWork(): boolean;
66
63
  whenIdle(): Promise<void>;
67
64
  /** Stops new submissions while allowing the accepted FIFO to finish. */
68
65
  close(): Promise<void>;
66
+ /** Stops admission within the lifecycle operation that owns this queue's close. */
67
+ closeAdmission(): void;
69
68
  private admit;
70
69
  private scheduleDrain;
71
70
  private drain;