@zlink-systems/framework 0.30.0 → 0.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/LICENSE +150 -68
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/contracts/Actors/ZLinkActorClient.d.ts +2 -1
  4. package/dist/contracts/Channels/Calls.d.ts +2 -1
  5. package/dist/contracts/Common/ZLinkMessageMetadata.js +11 -5
  6. package/dist/contracts/Handlers/Attributes.d.ts +5 -13
  7. package/dist/contracts/Handlers/Attributes.js +7 -11
  8. package/dist/contracts/Handlers/JsonContract.d.ts +2 -46
  9. package/dist/contracts/Handlers/JsonContract.js +4 -153
  10. package/dist/contracts/Spots/Contracts.d.ts +2 -1
  11. package/dist/nest-integration.d.ts +1 -1
  12. package/dist/nest-integration.js +2 -1
  13. package/dist/runtime/actors/actor-client.d.ts +1 -1
  14. package/dist/runtime/actors/actor-client.js +14 -12
  15. package/dist/runtime/actors/actor-handoff.d.ts +1 -1
  16. package/dist/runtime/actors/actor-handoff.js +7 -4
  17. package/dist/runtime/actors/actor-join-relocation.d.ts +1 -0
  18. package/dist/runtime/actors/actor-local-native-join.js +9 -12
  19. package/dist/runtime/actors/actor-remote-wire.js +15 -0
  20. package/dist/runtime/actors/actor-routed-join-transport.d.ts +6 -2
  21. package/dist/runtime/actors/actor-routed-json-request.d.ts +2 -0
  22. package/dist/runtime/actors/index.d.ts +2 -1
  23. package/dist/runtime/actors/index.js +18 -6
  24. package/dist/runtime/actors/spot-actor-dispatch.js +2 -2
  25. package/dist/runtime/admission.d.ts +1 -1
  26. package/dist/runtime/admission.js +15 -5
  27. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +6 -8
  28. package/dist/runtime/application-jobs/application-ingress-record-owner.js +39 -22
  29. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +2 -1
  30. package/dist/runtime/application-jobs/application-job-queue-scope.js +37 -22
  31. package/dist/runtime/application-jobs/contracts.d.ts +10 -1
  32. package/dist/runtime/backend/contracts/index.d.ts +18 -9
  33. package/dist/runtime/backend/mesh-completion-table.d.ts +9 -1
  34. package/dist/runtime/backend/mesh-completion-table.js +149 -49
  35. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +3 -0
  36. package/dist/runtime/backend/mesh-dispatch-pump.js +32 -11
  37. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -2
  38. package/dist/runtime/backend/node/node-backend-adapter-support.js +16 -9
  39. package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
  40. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +5 -2
  41. package/dist/runtime/backend/node/node-raw-binding-port.js +42 -22
  42. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +13 -5
  43. package/dist/runtime/backend/node/node-raw-mesh-backend.js +69 -51
  44. package/dist/runtime/backend/node/node-socket-backend-adapter.js +6 -6
  45. package/dist/runtime/backend/raw-binding-port.d.ts +2 -2
  46. package/dist/runtime/backend/runtime-message.d.ts +1 -0
  47. package/dist/runtime/backend/runtime-message.js +5 -0
  48. package/dist/runtime/backend/runtime-values.d.ts +1 -0
  49. package/dist/runtime/backend/runtime-values.js +2 -1
  50. package/dist/runtime/channels/channel-clients.d.ts +1 -0
  51. package/dist/runtime/channels/channel-clients.js +58 -21
  52. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +3 -2
  53. package/dist/runtime/channels/channel-dispatch-pipeline.js +20 -11
  54. package/dist/runtime/channels/channel-dispatch-services.d.ts +1 -0
  55. package/dist/runtime/channels/channel-dispatch-services.js +45 -0
  56. package/dist/runtime/channels/channel-dispatchers.d.ts +1 -1
  57. package/dist/runtime/channels/channel-dispatchers.js +27 -26
  58. package/dist/runtime/channels/channel-envelope-inspection.d.ts +1 -2
  59. package/dist/runtime/channels/channel-envelope-inspection.js +1 -16
  60. package/dist/runtime/channels/channel-envelope.d.ts +1 -0
  61. package/dist/runtime/channels/channel-envelope.js +83 -8
  62. package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
  63. package/dist/runtime/channels/channel-outbound-operations.js +8 -8
  64. package/dist/runtime/channels/channel-runtime-manager.d.ts +6 -6
  65. package/dist/runtime/channels/channel-runtime-manager.js +12 -12
  66. package/dist/runtime/channels/channel-transports.d.ts +18 -15
  67. package/dist/runtime/channels/channel-transports.js +48 -31
  68. package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
  69. package/dist/runtime/channels/local-spot-route-transport.js +2 -1
  70. package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +2 -2
  71. package/dist/runtime/channels/router-socket-spot-route-transport.js +4 -4
  72. package/dist/runtime/channels/source-spot-router.d.ts +2 -2
  73. package/dist/runtime/channels/source-spot-router.js +4 -4
  74. package/dist/runtime/channels/spot-node-route-transport.d.ts +2 -2
  75. package/dist/runtime/channels/spot-node-route-transport.js +4 -4
  76. package/dist/runtime/channels/spot-route-bridge-transport.d.ts +2 -2
  77. package/dist/runtime/channels/spot-route-bridge-transport.js +4 -4
  78. package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +5 -4
  79. package/dist/runtime/channels/spot-route-dispatch-strategy.js +18 -18
  80. package/dist/runtime/execution/serial-execution-queue.d.ts +1 -0
  81. package/dist/runtime/execution/serial-execution-queue.js +1 -0
  82. package/dist/runtime/foundation/actor-join-recovery-codec.js +2 -2
  83. package/dist/runtime/foundation/durable-service-request.d.ts +14 -0
  84. package/dist/runtime/foundation/durable-service-request.js +98 -0
  85. package/dist/runtime/foundation/operation-identity.d.ts +1 -0
  86. package/dist/runtime/foundation/operation-identity.js +5 -1
  87. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +22 -5
  88. package/dist/runtime/foundation/raw-service-mesh-runtime.js +356 -232
  89. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +1 -0
  90. package/dist/runtime/foundation/service-relocation-object-owner.js +1 -0
  91. package/dist/runtime/foundation/service-relocation-runtime.d.ts +2 -0
  92. package/dist/runtime/foundation/service-relocation-runtime.js +13 -1
  93. package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -0
  94. package/dist/runtime/foundation/service-stateful-runtime.d.ts +4 -4
  95. package/dist/runtime/foundation/service-stateful-runtime.js +44 -103
  96. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +0 -5
  97. package/dist/runtime/foundation/service-topology-registry.d.ts +12 -2
  98. package/dist/runtime/foundation/service-topology-registry.js +61 -27
  99. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +3 -3
  100. package/dist/runtime/foundation/service-wire-m6a-codec.js +36 -38
  101. package/dist/runtime/handlers/handler-instance-scope.d.ts +8 -0
  102. package/dist/runtime/handlers/handler-instance-scope.js +54 -11
  103. package/dist/runtime/host/actor-runtime-options-factory.js +2 -2
  104. package/dist/runtime/host/application-job-queue.d.ts +19 -7
  105. package/dist/runtime/host/application-job-queue.js +150 -42
  106. package/dist/runtime/host/entry-actor-runtime.d.ts +1 -0
  107. package/dist/runtime/host/entry-actor-runtime.js +3 -0
  108. package/dist/runtime/host/index.d.ts +7 -1
  109. package/dist/runtime/host/index.js +142 -118
  110. package/dist/runtime/host/remote-bound-session-relay.js +2 -18
  111. package/dist/runtime/host/route-mesh-runtime.js +1 -1
  112. package/dist/runtime/host/service-relocation-control.d.ts +1 -0
  113. package/dist/runtime/host/service-relocation-control.js +10 -4
  114. package/dist/runtime/host/service-relocation-host-runtime.d.ts +6 -8
  115. package/dist/runtime/host/service-relocation-host-runtime.js +213 -241
  116. package/dist/runtime/host/spot-address-transport.js +3 -2
  117. package/dist/runtime/host/spot-runtime-options-factory.js +1 -0
  118. package/dist/runtime/locations/actor-location-claims.d.ts +2 -2
  119. package/dist/runtime/locations/actor-location-claims.js +34 -19
  120. package/dist/runtime/locations/lifecycle.d.ts +1 -2
  121. package/dist/runtime/locations/lifecycle.js +2 -5
  122. package/dist/runtime/locations/runtime.d.ts +1 -1
  123. package/dist/runtime/locations/runtime.js +24 -23
  124. package/dist/runtime/messaging/framework-json-v1.d.ts +4 -6
  125. package/dist/runtime/messaging/framework-json-v1.js +38 -294
  126. package/dist/runtime/messaging/packet-name.d.ts +1 -1
  127. package/dist/runtime/messaging/packet-name.js +8 -24
  128. package/dist/runtime/messaging/request-result.d.ts +2 -0
  129. package/dist/runtime/messaging/request-result.js +54 -0
  130. package/dist/runtime/messaging/submission-result.d.ts +1 -0
  131. package/dist/runtime/messaging/submission-result.js +5 -2
  132. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +15 -0
  133. package/dist/runtime/protocol/service_wire_codec.generated.js +144 -0
  134. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +9 -0
  135. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +14 -1
  136. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +7 -2
  137. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +33 -19
  138. package/dist/runtime/spots/index.d.ts +3 -0
  139. package/dist/runtime/spots/index.js +9 -2
  140. package/dist/runtime/spots/spot-activation.d.ts +1 -0
  141. package/dist/runtime/spots/spot-activation.js +17 -8
  142. package/dist/runtime/spots/spot-entry-activation.js +6 -2
  143. package/dist/runtime/spots/spot-handler-registry.d.ts +3 -1
  144. package/dist/runtime/spots/spot-handler-registry.js +18 -8
  145. package/dist/runtime/spots/spot-node-autoconnect.js +4 -3
  146. package/dist/runtime/spots/spot-outbound.d.ts +3 -0
  147. package/dist/runtime/spots/spot-outbound.js +24 -15
  148. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +1 -0
  149. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +1 -1
  150. package/dist/runtime/spots/spot-runtime-ports.d.ts +1 -0
  151. package/dist/runtime/spots/spot-subscription-dispatch.js +0 -3
  152. package/dist/runtime/spots/spot-timer.js +1 -0
  153. package/dist/runtime/streams/stream-session-runtime.d.ts +1 -1
  154. package/dist/runtime/streams/stream-session-runtime.js +13 -27
  155. package/package.json +2 -2
  156. package/src/contracts/Actors/ZLinkActorClient.ts +2 -1
  157. package/src/contracts/Channels/Calls.ts +2 -1
  158. package/src/contracts/Common/ZLinkMessageMetadata.ts +13 -8
  159. package/src/contracts/Handlers/Attributes.ts +14 -21
  160. package/src/contracts/Handlers/JsonContract.ts +8 -216
  161. package/src/contracts/Spots/Contracts.ts +2 -1
  162. package/src/nest-integration.ts +1 -0
  163. package/src/runtime/actors/actor-client.ts +40 -16
  164. package/src/runtime/actors/actor-handoff.ts +9 -4
  165. package/src/runtime/actors/actor-join-relocation.ts +1 -0
  166. package/src/runtime/actors/actor-local-native-join.ts +17 -26
  167. package/src/runtime/actors/actor-remote-wire.ts +17 -0
  168. package/src/runtime/actors/actor-routed-join-transport.ts +14 -4
  169. package/src/runtime/actors/actor-routed-json-request.ts +10 -2
  170. package/src/runtime/actors/index.ts +19 -5
  171. package/src/runtime/actors/spot-actor-dispatch.ts +4 -2
  172. package/src/runtime/admission.ts +18 -5
  173. package/src/runtime/application-jobs/application-ingress-record-owner.ts +41 -25
  174. package/src/runtime/application-jobs/application-job-queue-scope.ts +51 -22
  175. package/src/runtime/application-jobs/contracts.ts +14 -1
  176. package/src/runtime/backend/contracts/index.ts +53 -14
  177. package/src/runtime/backend/mesh-completion-table.ts +156 -57
  178. package/src/runtime/backend/mesh-dispatch-pump.ts +40 -10
  179. package/src/runtime/backend/node/node-backend-adapter-support.ts +17 -8
  180. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +12 -2
  181. package/src/runtime/backend/node/node-raw-binding-port.ts +57 -30
  182. package/src/runtime/backend/node/node-raw-mesh-backend.ts +128 -65
  183. package/src/runtime/backend/node/node-socket-backend-adapter.ts +21 -6
  184. package/src/runtime/backend/raw-binding-port.ts +7 -2
  185. package/src/runtime/backend/runtime-message.ts +6 -0
  186. package/src/runtime/backend/runtime-values.ts +1 -0
  187. package/src/runtime/channels/channel-clients.ts +90 -41
  188. package/src/runtime/channels/channel-dispatch-pipeline.ts +69 -34
  189. package/src/runtime/channels/channel-dispatch-services.ts +69 -1
  190. package/src/runtime/channels/channel-dispatchers.ts +29 -27
  191. package/src/runtime/channels/channel-envelope-inspection.ts +2 -16
  192. package/src/runtime/channels/channel-envelope.ts +133 -8
  193. package/src/runtime/channels/channel-outbound-operations.ts +22 -8
  194. package/src/runtime/channels/channel-runtime-manager.ts +29 -12
  195. package/src/runtime/channels/channel-transports.ts +128 -60
  196. package/src/runtime/channels/local-spot-route-transport.ts +3 -1
  197. package/src/runtime/channels/router-socket-spot-route-transport.ts +13 -4
  198. package/src/runtime/channels/source-spot-router.ts +8 -4
  199. package/src/runtime/channels/spot-node-route-transport.ts +8 -4
  200. package/src/runtime/channels/spot-route-bridge-transport.ts +6 -4
  201. package/src/runtime/channels/spot-route-dispatch-strategy.ts +47 -18
  202. package/src/runtime/execution/serial-execution-queue.ts +2 -0
  203. package/src/runtime/foundation/actor-join-recovery-codec.ts +2 -2
  204. package/src/runtime/foundation/durable-service-request.ts +137 -0
  205. package/src/runtime/foundation/operation-identity.ts +5 -1
  206. package/src/runtime/foundation/raw-service-mesh-runtime.ts +484 -293
  207. package/src/runtime/foundation/service-relocation-object-owner.ts +2 -0
  208. package/src/runtime/foundation/service-relocation-runtime.ts +18 -1
  209. package/src/runtime/foundation/service-runtime-contracts.ts +7 -1
  210. package/src/runtime/foundation/service-stateful-runtime.ts +67 -125
  211. package/src/runtime/foundation/service-stateful-wire-codec.ts +0 -5
  212. package/src/runtime/foundation/service-topology-registry.ts +91 -36
  213. package/src/runtime/foundation/service-wire-m6a-codec.ts +57 -38
  214. package/src/runtime/handlers/handler-instance-scope.ts +67 -16
  215. package/src/runtime/host/actor-runtime-options-factory.ts +13 -2
  216. package/src/runtime/host/application-job-queue.ts +175 -41
  217. package/src/runtime/host/entry-actor-runtime.ts +4 -0
  218. package/src/runtime/host/index.ts +201 -156
  219. package/src/runtime/host/remote-bound-session-relay.ts +2 -23
  220. package/src/runtime/host/route-mesh-runtime.ts +1 -1
  221. package/src/runtime/host/service-relocation-control.ts +11 -5
  222. package/src/runtime/host/service-relocation-host-runtime.ts +315 -291
  223. package/src/runtime/host/spot-address-transport.ts +4 -2
  224. package/src/runtime/host/spot-runtime-options-factory.ts +2 -0
  225. package/src/runtime/locations/actor-location-claims.ts +52 -30
  226. package/src/runtime/locations/lifecycle.ts +8 -26
  227. package/src/runtime/locations/runtime.ts +28 -24
  228. package/src/runtime/messaging/framework-json-v1.ts +5 -325
  229. package/src/runtime/messaging/packet-name.ts +5 -25
  230. package/src/runtime/messaging/request-result.ts +58 -0
  231. package/src/runtime/messaging/submission-result.ts +5 -1
  232. package/src/runtime/protocol/service_wire_codec.generated.ts +131 -1
  233. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
  234. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +43 -23
  235. package/src/runtime/spots/index.ts +14 -2
  236. package/src/runtime/spots/spot-activation.ts +28 -10
  237. package/src/runtime/spots/spot-entry-activation.ts +9 -2
  238. package/src/runtime/spots/spot-handler-registry.ts +41 -8
  239. package/src/runtime/spots/spot-node-autoconnect.ts +6 -2
  240. package/src/runtime/spots/spot-outbound.ts +36 -16
  241. package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +2 -1
  242. package/src/runtime/spots/spot-runtime-ports.ts +1 -0
  243. package/src/runtime/spots/spot-subscription-dispatch.ts +0 -3
  244. package/src/runtime/spots/spot-timer.ts +5 -1
  245. package/src/runtime/streams/stream-session-runtime.ts +12 -29
@@ -106,7 +106,7 @@ export class ZLinkEntrySpotActivation {
106
106
  private readonly spotSerialExecutor: ZLinkSpotSerialExecutor;
107
107
  private readonly timers: ZLinkSpotTimerRegistry;
108
108
  private readonly actorHandlers = new ZLinkSpotActorHandlerRegistryRuntime();
109
- private readonly handlers = new DefaultZLinkSpotHandlerRegistry(this.actorHandlers);
109
+ private readonly handlers: DefaultZLinkSpotHandlerRegistry;
110
110
  private readonly outbound: DefaultZLinkSpotOutbound;
111
111
  private readonly workerRuntime: ZLinkWorkerRuntime;
112
112
  private readonly lifecycleMetrics: ZLinkSpotLifecycleMetrics;
@@ -125,6 +125,10 @@ export class ZLinkEntrySpotActivation {
125
125
  'Entry Spot activation requires a detached task runner.'
126
126
  );
127
127
  }
128
+ this.handlers = new DefaultZLinkSpotHandlerRegistry(
129
+ this.actorHandlers,
130
+ options.providerResolver
131
+ );
128
132
  this.serial = new ZLinkSpotSerialTurnExecutor(false, options.nativeSpot.routingId);
129
133
  this.spotSerialExecutor = new ZLinkSpotSerialExecutor(
130
134
  this.serial,
@@ -328,7 +332,10 @@ export class ZLinkEntrySpotActivation {
328
332
  await cleanup(() => this.timers.dispose());
329
333
  await cleanup(() => this.spotSerialExecutor.close());
330
334
  await cleanup(() => disposeLifecycleHandlers(this.entrySpot, this.options.detachedTaskRunner));
331
- await cleanup(() => this.options.nativeSpot.dispose());
335
+ await cleanup(async () => {
336
+ await this.options.entryActorRuntime?.releaseMembers?.(this.options.spotNodeName);
337
+ await this.options.nativeSpot.dispose();
338
+ });
332
339
  if (this.initialized) {
333
340
  this.lifecycleMetrics.closed('entry');
334
341
  }
@@ -16,7 +16,12 @@ import type {
16
16
  ZLinkSpotPacketHandlerRegistration,
17
17
  ZLinkSpotSubscriptionHandlerRegistration
18
18
  } from '../../contracts/Configuration/RegistrationTypes';
19
- import { ZLinkConfigurationException } from '../configuration';
19
+ import type { ZLinkProviderResolver } from '../../contracts/Common/ZLinkProviderResolver';
20
+ import { prepareHandlerInstance } from '../handlers/handler-instance-scope';
21
+ import {
22
+ ZLinkFrameworkInternalErrorKind,
23
+ createInternalFrameworkException
24
+ } from '../framework-errors-internal';
20
25
  import { ZLinkActorPacketKind, ZLinkSpotActorHandlerRegistryRuntime } from '../actors';
21
26
  import { readZLinkDecoratorMetadata } from '../../contracts/Handlers/Attributes';
22
27
 
@@ -34,7 +39,10 @@ export class DefaultZLinkSpotHandlerRegistry<
34
39
  > implements ZLinkSpotHandlerRegistry {
35
40
  private readonly entries: ZLinkSpotHandlerRegistration[] = [];
36
41
 
37
- constructor(private readonly actorHandlers?: ZLinkSpotActorHandlerRegistryRuntime) {}
42
+ constructor(
43
+ private readonly actorHandlers?: ZLinkSpotActorHandlerRegistryRuntime,
44
+ private readonly providerResolver?: ZLinkProviderResolver
45
+ ) {}
38
46
 
39
47
  addHandler<THandler>(handlerType: Type<THandler>, packetName?: string): this {
40
48
  const metadata = readZLinkDecoratorMetadata(handlerType).find(
@@ -42,7 +50,8 @@ export class DefaultZLinkSpotHandlerRegistry<
42
50
  );
43
51
  const resolvedPacketName = packetName ?? metadata?.packetName;
44
52
  if (metadata === undefined || resolvedPacketName === undefined) {
45
- throw new ZLinkConfigurationException(
53
+ throw createInternalFrameworkException(
54
+ ZLinkFrameworkInternalErrorKind.InvalidOperation,
46
55
  `Actor packet handler '${handlerType.name}' must declare a packet name.`
47
56
  );
48
57
  }
@@ -62,7 +71,8 @@ export class DefaultZLinkSpotHandlerRegistry<
62
71
  (entry) => entry.kind === 'spotActorSend' || entry.kind === 'spotActorRequest'
63
72
  );
64
73
  if (metadata?.packetName === undefined) {
65
- throw new ZLinkConfigurationException(
74
+ throw createInternalFrameworkException(
75
+ ZLinkFrameworkInternalErrorKind.InvalidOperation,
66
76
  `Actor packet handler '${handlerType.name}' must declare a packet name.`
67
77
  );
68
78
  }
@@ -78,10 +88,21 @@ export class DefaultZLinkSpotHandlerRegistry<
78
88
  const declared = readZLinkDecoratorMetadata(handlerType).find(
79
89
  (entry) => entry.kind === 'packet'
80
90
  )?.packetName;
91
+ prepareHandlerInstance(this.providerResolver, handlerType);
92
+ const resolvedPacketName = packetName ?? declared ?? handlerType.name;
93
+ if (
94
+ this.entries.some(
95
+ (entry) => entry.kind === 'packet' && entry.packetName === resolvedPacketName
96
+ )
97
+ )
98
+ throw createInternalFrameworkException(
99
+ ZLinkFrameworkInternalErrorKind.InvalidOperation,
100
+ `SPOT packet '${resolvedPacketName}' is already registered.`
101
+ );
81
102
  this.entries.push({
82
103
  kind: 'packet',
83
104
  handlerType,
84
- packetName: packetName ?? declared ?? handlerType.name
105
+ packetName: resolvedPacketName
85
106
  });
86
107
  return this;
87
108
  }
@@ -96,6 +117,7 @@ export class DefaultZLinkSpotHandlerRegistry<
96
117
  actorType: Type<TActor>,
97
118
  packetName: string
98
119
  ): this {
120
+ prepareHandlerInstance(this.providerResolver, handlerType);
99
121
  this.entries.push({
100
122
  kind: kind === ZLinkActorPacketKind.Send ? 'actorSend' : 'actorRequest',
101
123
  handlerType,
@@ -139,10 +161,16 @@ export class DefaultZLinkSpotHandlerRegistry<
139
161
 
140
162
  addSubscribe(handlerType: Type, channelName: string, topic: string): this {
141
163
  if (channelName.trim().length === 0) {
142
- throw new ZLinkConfigurationException('SPOT subscribe channel name must not be empty.');
164
+ throw createInternalFrameworkException(
165
+ ZLinkFrameworkInternalErrorKind.InvalidOperation,
166
+ 'SPOT subscribe channel name must not be empty.'
167
+ );
143
168
  }
144
169
  if (topic.trim().length === 0) {
145
- throw new ZLinkConfigurationException('SPOT subscribe topic must not be empty.');
170
+ throw createInternalFrameworkException(
171
+ ZLinkFrameworkInternalErrorKind.InvalidOperation,
172
+ 'SPOT subscribe topic must not be empty.'
173
+ );
146
174
  }
147
175
  if (
148
176
  this.entries.some(
@@ -153,8 +181,12 @@ export class DefaultZLinkSpotHandlerRegistry<
153
181
  entry.topic === topic
154
182
  )
155
183
  ) {
156
- return this;
184
+ throw createInternalFrameworkException(
185
+ ZLinkFrameworkInternalErrorKind.InvalidOperation,
186
+ `SPOT subscription '${channelName}/${topic}' is already registered.`
187
+ );
157
188
  }
189
+ prepareHandlerInstance(this.providerResolver, handlerType);
158
190
  this.entries.push({ kind: 'subscribe', handlerType, channelName, topic });
159
191
  return this;
160
192
  }
@@ -164,6 +196,7 @@ export class DefaultZLinkSpotHandlerRegistry<
164
196
  }
165
197
 
166
198
  addSpotHandler(handlerType: Type): this {
199
+ prepareHandlerInstance(this.providerResolver, handlerType);
167
200
  this.entries.push({ kind: 'spotHandler', handlerType });
168
201
  return this;
169
202
  }
@@ -164,15 +164,19 @@ class ZLinkSpotNodeAutoConnectExecutor implements IZLinkAutoConnectExecutor {
164
164
  }
165
165
 
166
166
  async connect(target: ZLinkAutoConnectTarget): Promise<boolean> {
167
- if (this.manualConnections) return false;
168
167
  const key = connectionKey(target);
168
+ if (
169
+ !this.connectionIntents.has(key) &&
170
+ this.node.hasPeerRouteOrConnectionIntent?.(target.nodeRid, target.endpoint) === true
171
+ )
172
+ return false;
169
173
  const intent = await this.lane.run(() => this.prepareConnectCore(key));
170
174
  if (intent === undefined) return true;
171
175
  return await runDetachedSpotNodeAutoConnect(() => this.connectPeer(target, key, intent));
172
176
  }
173
177
 
174
178
  disconnect(target: ZLinkAutoConnectTarget): void {
175
- if (this.manualConnections) return;
179
+ if (!this.connectionIntents.has(connectionKey(target))) return;
176
180
  this.disconnectPeer(target);
177
181
  }
178
182
 
@@ -1,3 +1,4 @@
1
+ import { createZLinkRequest } from '../messaging/request-result';
1
2
  import {
2
3
  type RoutingId,
3
4
  type ZLinkChannelClient,
@@ -174,6 +175,7 @@ export class DefaultZLinkSpotOutbound implements ZLinkSpotOutbound {
174
175
  }
175
176
 
176
177
  export interface ZLinkSpotAddressCallOptions {
178
+ readonly onAdmitted?: () => void;
177
179
  readonly metadata?: ReadonlyMap<string, string>;
178
180
  readonly instanceSpot: boolean;
179
181
  readonly instanceSpotType?: string;
@@ -232,6 +234,7 @@ export interface ZLinkSpotRoutedSendOptions {
232
234
  }
233
235
 
234
236
  export interface ZLinkSpotRoutedRequestOptions extends ZLinkSpotRoutedSendOptions {
237
+ readonly onAdmitted?: () => void;
235
238
  readonly timeoutMs?: number;
236
239
  readonly signal?: AbortSignal;
237
240
  }
@@ -308,14 +311,13 @@ function createAddressedSpotRequestCall(
308
311
  sourceSpotProvider?: () => ZLinkBackendSpot | undefined
309
312
  ): ZLinkSpotRequestCall {
310
313
  const options = newAddressCallOptions();
311
- const begin = <TReply>(waitPolicy: 'async' | 'yield', signal?: AbortSignal) => {
312
- markSubmitted(options);
313
- rejectSameSpotAsyncRequest(serial, spotId, waitPolicy);
314
+ const begin = <TReply>(signal?: AbortSignal, onAdmitted?: () => void) => {
314
315
  return startRequestOnSerial<TReply>(serial, () => ({
315
316
  pending: transport.requestToSpotAddress<TReply>(spotId, request, {
316
317
  ...freezeAddressCallOptions(options, sourceSpotProvider?.()),
317
318
  timeoutMs: options.timeoutMs,
318
- signal
319
+ signal,
320
+ onAdmitted
319
321
  })
320
322
  }));
321
323
  };
@@ -356,12 +358,18 @@ function createAddressedSpotRequestCall(
356
358
  return this;
357
359
  },
358
360
  submit<TReply>(signal?: AbortSignal) {
359
- const pending = begin<TReply>('async', signal);
360
- return serial.isCurrentTurn ? pending : deliverOnSerial(serial, pending);
361
+ markSubmitted(options);
362
+ rejectSameSpotAsyncRequest(serial, spotId, 'async');
363
+ return createZLinkRequest(
364
+ (onAdmitted) => begin<TReply>(signal, onAdmitted),
365
+ (pending) => (serial.isCurrentTurn ? pending : deliverOnSerial(serial, pending))
366
+ );
361
367
  },
362
368
  yield<TReply>(signal?: AbortSignal) {
363
369
  const turn = requireZLinkYieldTurn();
364
- const pending = begin<TReply>('yield', signal);
370
+ markSubmitted(options);
371
+ rejectSameSpotAsyncRequest(serial, spotId, 'yield');
372
+ const pending = begin<TReply>(signal);
365
373
  return turn.yieldPromise(pending);
366
374
  }
367
375
  };
@@ -475,8 +483,12 @@ function wrapRequestCall(
475
483
  serial: ZLinkSpotSerialTurnExecutor,
476
484
  inner: ZLinkChannelRequestCall
477
485
  ): ZLinkChannelRequestCall {
478
- const begin = <TReply>(signal?: AbortSignal) =>
479
- startRequestOnSerial(serial, () => ({ pending: inner.submit<TReply>(signal) }));
486
+ const begin = <TReply>(signal?: AbortSignal, onAdmitted?: () => void) =>
487
+ startRequestOnSerial(serial, () => {
488
+ const pending = inner.submit<TReply>(signal);
489
+ if (onAdmitted !== undefined) void pending.admitted.then(onAdmitted, () => undefined);
490
+ return { pending };
491
+ });
480
492
  return {
481
493
  metadata(key: string | ZLinkMessageMetadata, value?: string) {
482
494
  if (typeof key === 'string') inner.metadata(key, value!);
@@ -488,8 +500,10 @@ function wrapRequestCall(
488
500
  return this;
489
501
  },
490
502
  submit<TReply>(signal?: AbortSignal) {
491
- const pending = begin<TReply>(signal);
492
- return serial.isCurrentTurn ? pending : deliverOnSerial(serial, pending);
503
+ return createZLinkRequest(
504
+ (onAdmitted) => begin<TReply>(signal, onAdmitted),
505
+ (pending) => (serial.isCurrentTurn ? pending : deliverOnSerial(serial, pending))
506
+ );
493
507
  },
494
508
  yield<TReply>(signal?: AbortSignal) {
495
509
  const turn = requireZLinkYieldTurn();
@@ -571,15 +585,15 @@ function wrapRoutedSpotRequestCall(
571
585
  ): ZLinkRequestCall & Pick<ZLinkChannelRequestCall, 'yield'> {
572
586
  let selectedTimeoutMs: number | undefined;
573
587
  const metadata = new Map<string, string>();
574
- const begin = <TReply>(waitPolicy: 'async' | 'yield', signal?: AbortSignal) => {
588
+ const begin = <TReply>(signal?: AbortSignal, onAdmitted?: () => void) => {
575
589
  // A request to the current Spot would wait behind the handler that owns
576
590
  // the same Spot claim. Reject it before resolving a route or submitting
577
591
  // transport work; one-way self-send remains a valid FIFO admission.
578
- rejectSameSpotAsyncRequest(serial, spot.spotId, waitPolicy);
579
592
  return startRequestOnSerial<TReply>(serial, () => ({
580
593
  pending: requestToSpotHandle<TReply>(transport, spot, request, {
581
594
  timeoutMs: selectedTimeoutMs,
582
595
  signal,
596
+ onAdmitted,
583
597
  metadata,
584
598
  spotRouterChannelIdForMesh,
585
599
  sourceSpot: sourceSpotProvider?.()
@@ -602,12 +616,16 @@ function wrapRoutedSpotRequestCall(
602
616
  return this;
603
617
  },
604
618
  submit<TReply>(signal?: AbortSignal) {
605
- const pending = begin<TReply>('async', signal);
606
- return serial.isCurrentTurn ? pending : deliverOnSerial(serial, pending);
619
+ rejectSameSpotAsyncRequest(serial, spot.spotId, 'async');
620
+ return createZLinkRequest(
621
+ (onAdmitted) => begin<TReply>(signal, onAdmitted),
622
+ (pending) => (serial.isCurrentTurn ? pending : deliverOnSerial(serial, pending))
623
+ );
607
624
  },
608
625
  yield<TReply>(signal?: AbortSignal) {
609
626
  const turn = requireZLinkYieldTurn();
610
- const pending = begin<TReply>('yield', signal);
627
+ rejectSameSpotAsyncRequest(serial, spot.spotId, 'yield');
628
+ const pending = begin<TReply>(signal);
611
629
  return turn.yieldPromise(pending);
612
630
  }
613
631
  };
@@ -628,6 +646,7 @@ function rejectSameSpotAsyncRequest(
628
646
  }
629
647
 
630
648
  export interface ZLinkSpotHandleCallOptions {
649
+ readonly onAdmitted?: () => void;
631
650
  readonly metadata?: ReadonlyMap<string, string>;
632
651
  readonly timeoutMs?: number;
633
652
  readonly signal?: AbortSignal;
@@ -672,6 +691,7 @@ export async function requestToSpotHandle<TReply = unknown>(
672
691
  packetName,
673
692
  timeoutMs: options.timeoutMs,
674
693
  signal: options.signal,
694
+ onAdmitted: options.onAdmitted,
675
695
  metadata: options.metadata
676
696
  };
677
697
  if (options.sourceSpot !== undefined && transport.requestFromSpotToSpot !== undefined) {
@@ -50,6 +50,7 @@ interface ZLinkRoutedSpotPacketDispatchOptions {
50
50
 
51
51
  interface ZLinkRoutedSpotPacketContext {
52
52
  readonly channelName: string;
53
+ readonly onAdmitted?: () => void;
53
54
  readonly contentType?: string;
54
55
  readonly workOptions?: ZLinkSerialWorkOptions;
55
56
  readonly admissionTimeoutMs?: number;
@@ -265,7 +266,7 @@ export class ZLinkRoutedSpotPacketDispatch {
265
266
  }
266
267
  await activation.serial.execute(
267
268
  runHandler,
268
- context.workOptions,
269
+ { ...context.workOptions, onAdmitted: context.onAdmitted },
269
270
  instanceIntent ? runHandler : undefined
270
271
  );
271
272
  }
@@ -22,6 +22,7 @@ import type {
22
22
  import type { ZLinkBackendSpotNode } from '../backend/contracts';
23
23
 
24
24
  export interface ZLinkEntryActorRuntime {
25
+ releaseMembers?(meshName: string): Promise<void>;
25
26
  resolveActor(actorId: string): ZLinkActor | undefined;
26
27
  commitActorTransaction(actor: ZLinkActor, onJoined: () => Promise<void>): Promise<void>;
27
28
  destroyActor(
@@ -68,9 +68,6 @@ export class ZLinkSpotSubscriptionDispatch {
68
68
  }
69
69
  const key = subscriptionKey(registration.channelName, registration.topic);
70
70
  const existing = this.handlers.get(key) ?? [];
71
- if (existing.some((entry) => entry.handlerType === registration.handlerType)) {
72
- continue;
73
- }
74
71
  existing.push(registration);
75
72
  this.handlers.set(key, existing);
76
73
  this.options.nativeSpot.setSubscription(registration.channelName, registration.topic);
@@ -19,7 +19,10 @@ import { ZLinkTimerOverrunPolicy } from '../../contracts';
19
19
  import { validateTimerRegistration } from '../../contracts/Configuration/TimerRegistrationValidator';
20
20
  import { throwIfAborted } from '../abort';
21
21
  import { ZLinkSpotSerialTurnExecutor } from './spot-serial-turn-executor';
22
- import { resolveLifecycleHandler } from '../handlers/handler-instance-scope';
22
+ import {
23
+ prepareHandlerInstance,
24
+ resolveLifecycleHandler
25
+ } from '../handlers/handler-instance-scope';
23
26
  import { createInboundFlow, runWithFlow } from '../diagnostics/flow-context';
24
27
  import type { ZLinkExecutionBarrier } from '../execution';
25
28
  import { ZLinkStateLane } from '../execution/state-lane';
@@ -135,6 +138,7 @@ export class ZLinkSpotTimerRegistry {
135
138
  ): Promise<ZLinkTimer> {
136
139
  validateTimerRegistration(name, periodMs, options);
137
140
  throwIfAborted(signal);
141
+ prepareHandlerInstance(providerResolver, handlerType);
138
142
  const handler = await resolveLifecycleHandler(spot, handlerType, providerResolver);
139
143
  const prepared = await this.lane.run(() => this.prepareAddCore(name));
140
144
  if (prepared.previous !== undefined) await prepared.previous.timer.cancel(signal);
@@ -95,29 +95,6 @@ const systemLivenessClock: ZLinkStreamLivenessClock = {
95
95
  clearTimer: (timer) => clearTimeout(timer as ReturnType<typeof setTimeout>)
96
96
  };
97
97
 
98
- class ZLinkStreamReceiveWake {
99
- private pending?: Promise<void>;
100
- private resolvePending?: () => void;
101
- private readonly finish = (): void => {
102
- const resolve = this.resolvePending;
103
- this.pending = undefined;
104
- this.resolvePending = undefined;
105
- resolve?.();
106
- };
107
-
108
- wait(): Promise<void> {
109
- if (this.pending !== undefined) return this.pending;
110
- this.pending = new Promise<void>((resolve) => {
111
- this.resolvePending = resolve;
112
- });
113
- return this.pending;
114
- }
115
-
116
- wake(): void {
117
- this.finish();
118
- }
119
- }
120
-
121
98
  export interface ZLinkStreamSessionContextFactory {
122
99
  createSessionContext(
123
100
  stream: ZLinkManagedStream,
@@ -928,7 +905,7 @@ export class ZLinkStreamSessionNodeRuntime {
928
905
  private readonly receiveAbortController = new AbortController();
929
906
  private receiveLoop: Promise<void> | undefined;
930
907
  private monitorLoop: Promise<void> | undefined;
931
- private readonly receiveWake = new ZLinkStreamReceiveWake();
908
+ private receiveWake: AbortController | undefined;
932
909
  private receiveWorkSinceYield = 0;
933
910
  constructor(
934
911
  private readonly options: ZLinkStreamSessionNodeRuntimeOptions & ZLinkStreamLivenessOptions
@@ -1455,14 +1432,20 @@ export class ZLinkStreamSessionNodeRuntime {
1455
1432
  }
1456
1433
 
1457
1434
  private async waitReceiveLoopWake(signal: AbortSignal): Promise<void> {
1458
- await Promise.race([
1459
- this.options.readablePoller.waitForReadable(signal),
1460
- this.receiveWake.wait()
1461
- ]);
1435
+ const wake = new AbortController();
1436
+ this.receiveWake = wake;
1437
+ try {
1438
+ // Readiness, internal wake and shutdown share one cancellable wait;
1439
+ // no losing Promise retains reactions across receive cycles.
1440
+ await this.options.readablePoller.waitForReadable(AbortSignal.any([signal, wake.signal]));
1441
+ } finally {
1442
+ wake.abort();
1443
+ this.receiveWake = undefined;
1444
+ }
1462
1445
  }
1463
1446
 
1464
1447
  private wakeReceiveLoop(): void {
1465
- this.receiveWake.wake();
1448
+ this.receiveWake?.abort();
1466
1449
  }
1467
1450
 
1468
1451
  private getOrCreateSession(routingId: unknown): ZLinkStreamSessionRuntime | undefined {