@zlink-systems/framework 0.29.0 → 0.30.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 (168) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Configuration/Builders.d.ts +1 -2
  3. package/dist/contracts/Configuration/Configs.d.ts +0 -5
  4. package/dist/contracts/Configuration/RegistrationBuilders.js +6 -4
  5. package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -6
  6. package/dist/contracts/Configuration/RegistrationValidators.js +4 -4
  7. package/dist/contracts/Configuration/index.d.ts +1 -1
  8. package/dist/internal.d.ts +1 -0
  9. package/dist/internal.js +3 -1
  10. package/dist/runtime/actors/actor-handoff.d.ts +3 -2
  11. package/dist/runtime/actors/actor-handoff.js +9 -4
  12. package/dist/runtime/actors/actor-runtime-contracts.d.ts +1 -0
  13. package/dist/runtime/actors/index.d.ts +2 -0
  14. package/dist/runtime/actors/index.js +21 -6
  15. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +3 -1
  16. package/dist/runtime/application-jobs/application-ingress-record-owner.js +6 -1
  17. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +3 -1
  18. package/dist/runtime/application-jobs/application-job-queue-scope.js +5 -0
  19. package/dist/runtime/application-jobs/contracts.d.ts +5 -1
  20. package/dist/runtime/backend/contracts/index.d.ts +10 -19
  21. package/dist/runtime/backend/mesh-completion-table.d.ts +6 -4
  22. package/dist/runtime/backend/mesh-completion-table.js +28 -18
  23. package/dist/runtime/backend/mesh-dispatch-pump.js +21 -25
  24. package/dist/runtime/backend/node/node-backend-adapter-factory.js +6 -1
  25. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +3 -3
  26. package/dist/runtime/backend/node/node-backend-adapter-support.js +24 -29
  27. package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +1 -9
  28. package/dist/runtime/backend/node/node-mesh-backend-adapter.js +1 -1
  29. package/dist/runtime/backend/node/node-raw-binding-port.js +11 -6
  30. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +10 -12
  31. package/dist/runtime/backend/node/node-raw-mesh-backend.js +64 -98
  32. package/dist/runtime/backend/node/node-socket-backend-adapter.js +10 -5
  33. package/dist/runtime/backend/raw-binding-port.d.ts +9 -2
  34. package/dist/runtime/channels/channel-receive-loops.js +3 -3
  35. package/dist/runtime/channels/channel-runtime-lifecycle.js +2 -1
  36. package/dist/runtime/channels/channel-socket-registry.d.ts +10 -3
  37. package/dist/runtime/channels/channel-socket-registry.js +59 -82
  38. package/dist/runtime/diagnostics/message-flow.d.ts +1 -0
  39. package/dist/runtime/diagnostics/message-flow.js +3 -3
  40. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +15 -1
  41. package/dist/runtime/foundation/raw-service-mesh-runtime.js +193 -64
  42. package/dist/runtime/foundation/service-liveness-registry.d.ts +20 -8
  43. package/dist/runtime/foundation/service-liveness-registry.js +57 -44
  44. package/dist/runtime/foundation/service-mailbox.d.ts +3 -0
  45. package/dist/runtime/foundation/service-mailbox.js +2 -1
  46. package/dist/runtime/foundation/service-stateful-runtime.d.ts +7 -6
  47. package/dist/runtime/foundation/service-stateful-runtime.js +60 -41
  48. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +5 -2
  49. package/dist/runtime/foundation/service-stateful-wire-codec.js +43 -61
  50. package/dist/runtime/foundation/service-topology-registry.d.ts +5 -3
  51. package/dist/runtime/foundation/service-topology-registry.js +9 -4
  52. package/dist/runtime/handlers/handler-instance-scope.js +1 -1
  53. package/dist/runtime/host/actor-packet-relay.js +7 -7
  54. package/dist/runtime/host/actor-placement-coordinator.d.ts +2 -1
  55. package/dist/runtime/host/actor-placement-coordinator.js +2 -1
  56. package/dist/runtime/host/actor-runtime-options-factory.d.ts +2 -1
  57. package/dist/runtime/host/actor-runtime-options-factory.js +2 -1
  58. package/dist/runtime/host/application-job-queue.d.ts +11 -4
  59. package/dist/runtime/host/application-job-queue.js +66 -10
  60. package/dist/runtime/host/entry-actor-runtime.js +1 -1
  61. package/dist/runtime/host/index.d.ts +1 -1
  62. package/dist/runtime/host/index.js +18 -13
  63. package/dist/runtime/host/instance-activation-authority.d.ts +2 -1
  64. package/dist/runtime/host/instance-activation-authority.js +89 -25
  65. package/dist/runtime/host/service-relocation-host-runtime.js +2 -2
  66. package/dist/runtime/host/spot-address-transport.d.ts +1 -0
  67. package/dist/runtime/host/spot-address-transport.js +25 -12
  68. package/dist/runtime/host/spot-runtime-options-factory.js +2 -2
  69. package/dist/runtime/host/user-spot-creation-coordinator.d.ts +1 -0
  70. package/dist/runtime/host/user-spot-creation-coordinator.js +1 -0
  71. package/dist/runtime/locations/domain-store-contract.d.ts +3 -2
  72. package/dist/runtime/locations/in-memory-authority-store.d.ts +5 -2
  73. package/dist/runtime/locations/in-memory-authority-store.js +107 -14
  74. package/dist/runtime/locations/in-memory-location-store.d.ts +3 -3
  75. package/dist/runtime/locations/in-memory-location-store.js +31 -13
  76. package/dist/runtime/locations/internal-location-contracts.d.ts +8 -0
  77. package/dist/runtime/locations/location-store-repository.d.ts +4 -2
  78. package/dist/runtime/locations/location-store-repository.js +209 -33
  79. package/dist/runtime/locations/resolvers.d.ts +2 -1
  80. package/dist/runtime/locations/resolvers.js +10 -1
  81. package/dist/runtime/messaging/submission-result.d.ts +1 -1
  82. package/dist/runtime/messaging/submission-result.js +2 -2
  83. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +2 -0
  84. package/dist/runtime/spots/index.d.ts +4 -3
  85. package/dist/runtime/spots/index.js +14 -14
  86. package/dist/runtime/spots/spot-activation.d.ts +2 -1
  87. package/dist/runtime/spots/spot-activation.js +4 -4
  88. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +2 -1
  89. package/dist/runtime/spots/spot-actor-admission-coordinator.js +11 -10
  90. package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +4 -1
  91. package/dist/runtime/spots/spot-actor-packet-dispatch.js +7 -5
  92. package/dist/runtime/spots/spot-actor-packet-drain.js +2 -0
  93. package/dist/runtime/spots/spot-actor-packet-relay-dispatch.js +1 -0
  94. package/dist/runtime/spots/spot-entry-activation.d.ts +1 -0
  95. package/dist/runtime/spots/spot-entry-activation.js +6 -1
  96. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +3 -1
  97. package/dist/runtime/spots/spot-node-runtime-manager.js +10 -11
  98. package/dist/runtime/spots/spot-routing-internal.d.ts +6 -0
  99. package/dist/runtime/spots/spot-runtime-ports.d.ts +2 -1
  100. package/dist/runtime/spots/spot-serial-executor.d.ts +1 -0
  101. package/dist/runtime/spots/spot-serial-executor.js +10 -1
  102. package/dist/runtime/streams/stream-session-runtime.js +1 -1
  103. package/package.json +3 -3
  104. package/src/contracts/Configuration/Builders.ts +1 -2
  105. package/src/contracts/Configuration/Configs.ts +0 -6
  106. package/src/contracts/Configuration/RegistrationBuilders.ts +8 -12
  107. package/src/contracts/Configuration/RegistrationTypes.ts +1 -6
  108. package/src/contracts/Configuration/RegistrationValidators.ts +9 -10
  109. package/src/contracts/Configuration/index.ts +1 -6
  110. package/src/internal.ts +1 -0
  111. package/src/runtime/actors/actor-handoff.ts +13 -4
  112. package/src/runtime/actors/actor-runtime-contracts.ts +4 -0
  113. package/src/runtime/actors/index.ts +77 -42
  114. package/src/runtime/application-jobs/application-ingress-record-owner.ts +12 -2
  115. package/src/runtime/application-jobs/application-job-queue-scope.ts +6 -1
  116. package/src/runtime/application-jobs/contracts.ts +14 -1
  117. package/src/runtime/backend/contracts/index.ts +10 -18
  118. package/src/runtime/backend/mesh-completion-table.ts +36 -19
  119. package/src/runtime/backend/mesh-dispatch-pump.ts +19 -22
  120. package/src/runtime/backend/node/node-backend-adapter-factory.ts +12 -5
  121. package/src/runtime/backend/node/node-backend-adapter-support.ts +31 -29
  122. package/src/runtime/backend/node/node-mesh-backend-adapter.ts +3 -10
  123. package/src/runtime/backend/node/node-raw-binding-port.ts +19 -10
  124. package/src/runtime/backend/node/node-raw-mesh-backend.ts +81 -111
  125. package/src/runtime/backend/node/node-socket-backend-adapter.ts +12 -8
  126. package/src/runtime/backend/raw-binding-port.ts +12 -2
  127. package/src/runtime/channels/channel-receive-loops.ts +3 -3
  128. package/src/runtime/channels/channel-runtime-lifecycle.ts +7 -1
  129. package/src/runtime/channels/channel-socket-registry.ts +84 -130
  130. package/src/runtime/diagnostics/message-flow.ts +1 -1
  131. package/src/runtime/foundation/raw-service-mesh-runtime.ts +268 -70
  132. package/src/runtime/foundation/service-liveness-registry.ts +68 -59
  133. package/src/runtime/foundation/service-mailbox.ts +7 -1
  134. package/src/runtime/foundation/service-stateful-runtime.ts +109 -77
  135. package/src/runtime/foundation/service-stateful-wire-codec.ts +55 -79
  136. package/src/runtime/foundation/service-topology-registry.ts +13 -7
  137. package/src/runtime/handlers/handler-instance-scope.ts +2 -1
  138. package/src/runtime/host/actor-packet-relay.ts +7 -0
  139. package/src/runtime/host/actor-placement-coordinator.ts +8 -2
  140. package/src/runtime/host/actor-runtime-options-factory.ts +7 -0
  141. package/src/runtime/host/application-job-queue.ts +77 -10
  142. package/src/runtime/host/entry-actor-runtime.ts +1 -0
  143. package/src/runtime/host/index.ts +30 -7
  144. package/src/runtime/host/instance-activation-authority.ts +132 -27
  145. package/src/runtime/host/service-relocation-host-runtime.ts +2 -0
  146. package/src/runtime/host/spot-address-transport.ts +45 -22
  147. package/src/runtime/host/spot-runtime-options-factory.ts +2 -0
  148. package/src/runtime/host/user-spot-creation-coordinator.ts +8 -0
  149. package/src/runtime/locations/domain-store-contract.ts +6 -2
  150. package/src/runtime/locations/in-memory-authority-store.ts +153 -12
  151. package/src/runtime/locations/in-memory-location-store.ts +39 -13
  152. package/src/runtime/locations/internal-location-contracts.ts +10 -0
  153. package/src/runtime/locations/location-store-repository.ts +295 -36
  154. package/src/runtime/locations/resolvers.ts +25 -2
  155. package/src/runtime/messaging/submission-result.ts +2 -2
  156. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +2 -0
  157. package/src/runtime/spots/index.ts +16 -0
  158. package/src/runtime/spots/spot-activation.ts +5 -0
  159. package/src/runtime/spots/spot-actor-admission-coordinator.ts +13 -0
  160. package/src/runtime/spots/spot-actor-packet-dispatch.ts +10 -0
  161. package/src/runtime/spots/spot-actor-packet-drain.ts +2 -0
  162. package/src/runtime/spots/spot-actor-packet-relay-dispatch.ts +1 -0
  163. package/src/runtime/spots/spot-entry-activation.ts +7 -0
  164. package/src/runtime/spots/spot-node-runtime-manager.ts +14 -12
  165. package/src/runtime/spots/spot-routing-internal.ts +14 -0
  166. package/src/runtime/spots/spot-runtime-ports.ts +2 -0
  167. package/src/runtime/spots/spot-serial-executor.ts +10 -4
  168. package/src/runtime/streams/stream-session-runtime.ts +1 -1
@@ -477,12 +477,12 @@ class ZLinkSpotActivationLifecycle {
477
477
  async cleanupFailedIncarnation(activation) {
478
478
  await this.cleanupActivation(activation, activation.meshName, false, undefined, contracts_1.ZLinkSpotCloseReason.ExplicitClose, undefined, true);
479
479
  }
480
- async dispatchActorPacket(activation, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin) {
481
- return await this.actorAdmission.dispatchActorPacket(activation, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin);
480
+ async dispatchActorPacket(origin, activation, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin) {
481
+ return await this.actorAdmission.dispatchActorPacket(origin, activation, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin);
482
482
  }
483
483
  /** @internal Dispatches a held Actor record after its handoff owner releases it. */
484
- dispatchActorPacketDirect(activation, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef) {
485
- return this.actorAdmission.dispatchActorPacketDirect(activation, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef);
484
+ dispatchActorPacketDirect(origin, activation, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef) {
485
+ return this.actorAdmission.dispatchActorPacketDirect(origin, activation, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef);
486
486
  }
487
487
  /** @internal Atomically restores one durable Actor packet prefix. */
488
488
  admitActorPacketPrefix(activation, actorId, records) {
@@ -1,3 +1,4 @@
1
+ import type { ApplicationJobOrigin } from '../application-jobs/contracts';
1
2
  import type { ActorRef } from '../../contracts';
2
3
  import type { Message } from '../../contracts/Common/Message';
3
4
  import type { ZLinkMessageFollowOrigin } from '../foundation/service-runtime-contracts';
@@ -10,7 +11,7 @@ type AdmissionOptions = Pick<ZLinkSpotActivationLifecycleOptions, 'actorHandoffR
10
11
  export declare class ZLinkSpotActorAdmissionCoordinator {
11
12
  private readonly options;
12
13
  constructor(options: AdmissionOptions);
13
- dispatchActorPacket(activation: ZLinkSpotActivation, actorId: string, parts: readonly Message[], returnResponse?: boolean, remoteBoundSessionTarget?: ZLinkRemoteBoundSessionTarget, fallbackActorRef?: ActorRef, requestTerminal?: (response: unknown) => Promise<void> | void, messageFollowOrigin?: ZLinkMessageFollowOrigin): Promise<unknown>;
14
+ dispatchActorPacket(origin: ApplicationJobOrigin, activation: ZLinkSpotActivation, actorId: string, parts: readonly Message[], returnResponse?: boolean, remoteBoundSessionTarget?: ZLinkRemoteBoundSessionTarget, fallbackActorRef?: ActorRef, requestTerminal?: (response: unknown) => Promise<void> | void, messageFollowOrigin?: ZLinkMessageFollowOrigin): Promise<unknown>;
14
15
  attachNativeActorJoinDispatch(activation: ZLinkSpotActivation, nativeSpot: ZLinkBackendSpot | undefined): ZLinkSpotActorJoinDispatch | undefined;
15
16
  private dispatchActorPacketInActorTurn;
16
17
  private commitTransferredActorTransaction;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZLinkSpotActorAdmissionCoordinator = void 0;
4
+ const application_job_queue_scope_1 = require("../application-jobs/application-job-queue-scope");
4
5
  const actor_handoff_1 = require("../actors/actor-handoff");
5
6
  const routing_id_1 = require("../routing-id");
6
7
  const spot_actor_join_dispatch_1 = require("./spot-actor-join-dispatch");
@@ -10,11 +11,11 @@ class ZLinkSpotActorAdmissionCoordinator {
10
11
  constructor(options) {
11
12
  this.options = options;
12
13
  }
13
- async dispatchActorPacket(activation, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin) {
14
- const handoff = this.options.actorHandoffRuntime?.capture(actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, undefined, messageFollowOrigin, (replayedParts, replayReturnResponse, replayRemoteBoundSessionTarget, replayFallbackActorRef) => this.dispatchActorPacketDirect(activation, actorId, replayedParts, replayReturnResponse, replayRemoteBoundSessionTarget, replayFallbackActorRef));
14
+ async dispatchActorPacket(origin, activation, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin) {
15
+ const handoff = this.options.actorHandoffRuntime?.capture(origin, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, undefined, messageFollowOrigin, (replayedParts, replayReturnResponse, replayRemoteBoundSessionTarget, replayFallbackActorRef) => this.dispatchActorPacketDirect(origin, activation, actorId, replayedParts, replayReturnResponse, replayRemoteBoundSessionTarget, replayFallbackActorRef));
15
16
  if (handoff !== undefined)
16
17
  return await handoff;
17
- return await this.dispatchActorPacketDirect(activation, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal);
18
+ return await this.dispatchActorPacketDirect(origin, activation, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal);
18
19
  }
19
20
  attachNativeActorJoinDispatch(activation, nativeSpot) {
20
21
  if (nativeSpot === undefined)
@@ -39,7 +40,7 @@ class ZLinkSpotActorAdmissionCoordinator {
39
40
  commitTransferredActor: (actor, backlog, sealedSession) => this.commitTransferredActorTransaction(activation, actor, backlog, sealedSession)
40
41
  },
41
42
  packets: {
42
- handle: (delivery) => this.dispatchActorPacket(activation, delivery.actorId, delivery.parts, delivery.returnResponse, delivery.remoteBoundSessionTarget, delivery.fallbackActorRef),
43
+ handle: (delivery) => this.dispatchActorPacket('remote', activation, delivery.actorId, delivery.parts, delivery.returnResponse, delivery.remoteBoundSessionTarget, delivery.fallbackActorRef),
43
44
  bindRemoteSession: (actor, sourceNodeRid, sourceSessionRid) => {
44
45
  const node = this.options.nativeSpotNodeProvider?.(activation.meshName);
45
46
  if (node === undefined || (0, routing_id_1.routingIdsEqual)(sourceNodeRid, node.routingId))
@@ -63,8 +64,8 @@ class ZLinkSpotActorAdmissionCoordinator {
63
64
  return nativeDispatch;
64
65
  }
65
66
  /** @internal Dispatches a coordinator-owned replay without recapturing it. */
66
- dispatchActorPacketDirect(activation, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal) {
67
- return activation.executeActor(actorId, (actorSerial) => this.dispatchActorPacketInActorTurn(activation, actorSerial, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal));
67
+ dispatchActorPacketDirect(origin, activation, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal) {
68
+ return activation.executeActor(actorId, (actorSerial) => this.dispatchActorPacketInActorTurn(origin, activation, actorSerial, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal));
68
69
  }
69
70
  /**
70
71
  * Atomically restores one durable packet prefix at the Actor FIFO tail.
@@ -75,7 +76,7 @@ class ZLinkSpotActorAdmissionCoordinator {
75
76
  */
76
77
  admitActorPacketPrefix(activation, actorId, records) {
77
78
  const terminals = activation.admitActorDurablePrefix(actorId, records.map((record) => ({
78
- operation: (executeChild) => record.drain((parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef) => executeChild((actorSerial) => this.dispatchActorPacketInActorTurn(activation, actorSerial, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef))),
79
+ operation: (executeChild) => record.drain((parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef) => executeChild((actorSerial) => this.dispatchActorPacketInActorTurn((0, application_job_queue_scope_1.currentApplicationJobOrigin)(), activation, actorSerial, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef))),
79
80
  preparation: record.preparation,
80
81
  workOptions: { payloadBytes: record.payloadBytes }
81
82
  })));
@@ -89,7 +90,7 @@ class ZLinkSpotActorAdmissionCoordinator {
89
90
  });
90
91
  return { terminal };
91
92
  }
92
- dispatchActorPacketInActorTurn(activation, actorSerial, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal) {
93
+ dispatchActorPacketInActorTurn(origin, activation, actorSerial, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal) {
93
94
  return new spot_actor_packet_dispatch_1.ZLinkSpotActorPacketDispatch({
94
95
  spot: activation.spot,
95
96
  spotId: () => String(activation.spotId),
@@ -107,7 +108,7 @@ class ZLinkSpotActorAdmissionCoordinator {
107
108
  messageSerializers: this.options.messageSerializers,
108
109
  dispatchErrors: this.options.dispatchErrors,
109
110
  routeToActorJoinPrewarm: this.options.routeToActorJoinPrewarm
110
- }).dispatch(actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal);
111
+ }).dispatch(origin, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal);
111
112
  }
112
113
  async commitTransferredActorTransaction(activation, actor, backlog, sealedSession) {
113
114
  const transfer = this.options.actorTransferRuntime;
@@ -140,7 +141,7 @@ class ZLinkSpotActorAdmissionCoordinator {
140
141
  }
141
142
  }
142
143
  async replayActorBacklog(activation, actor, backlog) {
143
- return await (0, actor_handoff_1.replayActorHandoffBacklog)(backlog, (parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef) => this.dispatchActorPacketDirect(activation, actor.context.actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef), (index) => this.options.runtimeEventPublisher?.publish({
144
+ return await (0, actor_handoff_1.replayActorHandoffBacklog)(backlog, (parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef) => this.dispatchActorPacketDirect('remote', activation, actor.context.actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef), (index) => this.options.runtimeEventPublisher?.publish({
144
145
  sourceName: 'zlink.framework.actor-handoff',
145
146
  timestamp: new Date(),
146
147
  marker: 'backlog_enqueued',
@@ -1,3 +1,4 @@
1
+ import type { ApplicationJobOrigin } from '../application-jobs/contracts';
1
2
  import type { ActorRef, RoutingId, ZLinkActor, ZLinkMessageSerializer, ZLinkSpot } from '../../contracts';
2
3
  import type { Message } from '../../contracts/Common/Message';
3
4
  import type { ZLinkRemoteBoundSessionTarget } from '../actors';
@@ -17,6 +18,7 @@ export interface ZLinkActorRequestTerminal {
17
18
  }
18
19
  /** One admitted Actor packet and the routing context that must move with it. */
19
20
  export interface ZLinkActorPacketDelivery {
21
+ readonly origin: ApplicationJobOrigin;
20
22
  readonly actorId: string;
21
23
  readonly parts: readonly Message[];
22
24
  readonly returnResponse: boolean;
@@ -35,6 +37,7 @@ export interface ZLinkActorPacketDelivery {
35
37
  * unchanged.
36
38
  */
37
39
  export type ZLinkRouteToActorJoinPrewarm = (actorId: string, objectGeneration: bigint, arrival: {
40
+ readonly origin: ApplicationJobOrigin;
38
41
  readonly header: Buffer;
39
42
  readonly payload: Buffer;
40
43
  readonly returnResponse: boolean;
@@ -69,7 +72,7 @@ interface ZLinkSpotActorPacketDispatchOptions {
69
72
  export declare class ZLinkSpotActorPacketDispatch {
70
73
  private readonly options;
71
74
  constructor(options: ZLinkSpotActorPacketDispatchOptions);
72
- dispatch(actorId: string, parts: readonly Message[], returnResponse?: boolean, remoteBoundSessionTarget?: ZLinkRemoteBoundSessionTarget, fallbackActorRef?: ActorRef, requestTerminal?: ZLinkActorRequestTerminal): Promise<unknown>;
75
+ dispatch(origin: ApplicationJobOrigin, actorId: string, parts: readonly Message[], returnResponse?: boolean, remoteBoundSessionTarget?: ZLinkRemoteBoundSessionTarget, fallbackActorRef?: ActorRef, requestTerminal?: ZLinkActorRequestTerminal): Promise<unknown>;
73
76
  dispatchDelivery(delivery: ZLinkActorPacketDelivery): Promise<unknown>;
74
77
  private handleMissingActor;
75
78
  /**
@@ -17,8 +17,9 @@ class ZLinkSpotActorPacketDispatch {
17
17
  constructor(options) {
18
18
  this.options = options;
19
19
  }
20
- dispatch(actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal) {
20
+ dispatch(origin, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal) {
21
21
  return this.dispatchDelivery({
22
+ origin,
22
23
  actorId,
23
24
  parts,
24
25
  returnResponse,
@@ -71,7 +72,7 @@ class ZLinkSpotActorPacketDispatch {
71
72
  }
72
73
  const actor = this.options.resolveActor(actorId);
73
74
  if (actor === undefined) {
74
- return this.handleMissingActor(actorId, parts, header, messageKind, action, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal);
75
+ return this.handleMissingActor(delivery.origin, actorId, parts, header, messageKind, action, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal);
75
76
  }
76
77
  if (header.name === actors_1.ZLINK_REMOTE_ACTOR_SESSION_DISCONNECTED_PACKET) {
77
78
  await this.options.onDisconnectActor(actor);
@@ -81,7 +82,7 @@ class ZLinkSpotActorPacketDispatch {
81
82
  return this.dispatchActorPacket(actor, actorId, decodePayload, header, messageKind, action, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, requestDeadlineUnixMs, (0, serial_work_size_1.zlinkSerialWorkOptions)(parts[1].data().byteLength, (0, serial_work_size_1.zlinkMetadataByteLength)(header.metadata)));
82
83
  });
83
84
  }
84
- async handleMissingActor(actorId, parts, header, messageKind, action, returnResponse, fallbackBoundSessionTarget, fallbackActorRef, requestTerminal) {
85
+ async handleMissingActor(origin, actorId, parts, header, messageKind, action, returnResponse, fallbackBoundSessionTarget, fallbackActorRef, requestTerminal) {
85
86
  if (this.options.routeToActorJoinPrewarm !== undefined &&
86
87
  fallbackActorRef !== undefined &&
87
88
  parts.length >= 2 &&
@@ -90,7 +91,7 @@ class ZLinkSpotActorPacketDispatch {
90
91
  // forever with no reply route. Fall through to the existing
91
92
  // missing-actor handling for that shape instead.
92
93
  (messageKind !== ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.ActorRequest || requestTerminal !== undefined)) {
93
- const parked = this.parkForActorJoinPrewarm(actorId, parts, messageKind, returnResponse, fallbackBoundSessionTarget, fallbackActorRef, requestTerminal);
94
+ const parked = this.parkForActorJoinPrewarm(origin, actorId, parts, messageKind, returnResponse, fallbackBoundSessionTarget, fallbackActorRef, requestTerminal);
94
95
  if (parked !== undefined)
95
96
  return parked;
96
97
  }
@@ -126,7 +127,7 @@ class ZLinkSpotActorPacketDispatch {
126
127
  * arrival survives independently of the original {@link Message}
127
128
  * lifetime.
128
129
  */
129
- parkForActorJoinPrewarm(actorId, parts, messageKind, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal) {
130
+ parkForActorJoinPrewarm(origin, actorId, parts, messageKind, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal) {
130
131
  const isRequest = messageKind === ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.ActorRequest;
131
132
  let resolve = () => undefined;
132
133
  let reject = () => undefined;
@@ -154,6 +155,7 @@ class ZLinkSpotActorPacketDispatch {
154
155
  }
155
156
  }, { prepare: requestTerminal.prepare });
156
157
  const route = this.options.routeToActorJoinPrewarm(actorId, fallbackActorRef.objectGeneration, {
158
+ origin,
157
159
  header: Buffer.from(parts[0].data()),
158
160
  payload: Buffer.from(parts[1].data()),
159
161
  returnResponse,
@@ -83,6 +83,7 @@ class ZLinkSpotActorPacketDrain {
83
83
  }
84
84
  else {
85
85
  await this.options.actorPacketHandler({
86
+ origin: 'remote',
86
87
  actorId,
87
88
  parts,
88
89
  returnResponse: false,
@@ -131,6 +132,7 @@ class ZLinkSpotActorPacketDrain {
131
132
  async dispatchNoBindActorRequest(info, actorId, parts, actorRef) {
132
133
  try {
133
134
  const response = await this.options.actorPacketHandler?.({
135
+ origin: 'remote',
134
136
  actorId,
135
137
  parts,
136
138
  returnResponse: true,
@@ -69,6 +69,7 @@ class ZLinkSpotActorPacketRelayDispatch {
69
69
  actorPacketRelay.messageFollowContext !== undefined &&
70
70
  remoteBoundSessionTarget !== undefined;
71
71
  const response = await this.options.actorPacketHandler({
72
+ origin: 'remote',
72
73
  actorId: actorPacketRelay.actorId,
73
74
  parts: [header, payload],
74
75
  returnResponse: !followedBoundSessionReply,
@@ -89,6 +89,7 @@ export declare class ZLinkEntrySpotActivation {
89
89
  */
90
90
  commitServiceActorJoin(actor: ZLinkActor, handoffBacklog?: readonly ZLinkActorHandoffPacket[], signal?: AbortSignal): Promise<void>;
91
91
  executeActor<T>(actorId: string, operation: () => Promise<T>): Promise<T>;
92
+ terminateActor(actorId: string, terminal: () => Promise<void>): Promise<void>;
92
93
  /**
93
94
  * Entry Spot membership does not have an application admission callback.
94
95
  * The shared core round-trip therefore accepts a valid returning Actor and
@@ -220,6 +220,9 @@ class ZLinkEntrySpotActivation {
220
220
  executeActor(actorId, operation) {
221
221
  return this.spotSerialExecutor.executeActor(actorId, operation);
222
222
  }
223
+ terminateActor(actorId, terminal) {
224
+ return this.spotSerialExecutor.terminateActor(actorId, terminal);
225
+ }
223
226
  /**
224
227
  * Entry Spot membership does not have an application admission callback.
225
228
  * The shared core round-trip therefore accepts a valid returning Actor and
@@ -284,7 +287,8 @@ class ZLinkEntrySpotActivation {
284
287
  }
285
288
  async dispatchActorPacket(delivery) {
286
289
  const { actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, messageFollowOrigin } = delivery;
287
- const handoff = this.options.actorHandoffRuntime?.capture(actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, undefined, messageFollowOrigin, (replayedParts, replayReturnResponse, replayRemoteBoundSessionTarget, replayFallbackActorRef) => this.spotSerialExecutor.executeActor(actorId, () => this.dispatchActorPacketInsideMailbox({
290
+ const handoff = this.options.actorHandoffRuntime?.capture(delivery.origin, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, undefined, messageFollowOrigin, (replayedParts, replayReturnResponse, replayRemoteBoundSessionTarget, replayFallbackActorRef) => this.spotSerialExecutor.executeActor(actorId, () => this.dispatchActorPacketInsideMailbox({
291
+ origin: delivery.origin,
288
292
  actorId,
289
293
  parts: replayedParts,
290
294
  returnResponse: replayReturnResponse,
@@ -297,6 +301,7 @@ class ZLinkEntrySpotActivation {
297
301
  }
298
302
  async replayActorBacklog(actor, backlog) {
299
303
  return await (0, actor_handoff_1.replayActorHandoffBacklog)(backlog, (parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef) => this.spotSerialExecutor.executeActor(actor.context.actorId, () => this.dispatchActorPacketInsideMailbox({
304
+ origin: 'remote',
300
305
  actorId: actor.context.actorId,
301
306
  parts,
302
307
  returnResponse,
@@ -1,3 +1,4 @@
1
+ import type { ApplicationJobOrigin } from '../application-jobs/contracts';
1
2
  import { type ActorRef, type RoutingId, type ZLinkActor, type ZLinkChannelClient, type ZLinkFanoutClient, type ZLinkMeshNodeDescriptor, type ZLinkMessage, type ZLinkMessageSerializer, type ZLinkSpotPublisherClient, ZLinkFrameworkRuntimeState } from '../../contracts';
2
3
  import type { Message } from '../../contracts/Common/Message';
3
4
  import type { ZLinkProviderResolver } from '../../contracts/Common/ZLinkProviderResolver';
@@ -104,6 +105,7 @@ export declare class ZLinkSpotNodeRuntimeManager {
104
105
  get primaryMeshCompletions(): ZLinkMeshCompletionTable | undefined;
105
106
  notifyEntrySpotActorCreated(nodeRid: RoutingId, actor: ZLinkActor, createRequest: ZLinkMessage, signal?: AbortSignal): Promise<import('../../contracts').ZLinkActorCreateResponse | undefined>;
106
107
  notifyPrimaryEntrySpotActorJoined(actor: ZLinkActor, signal?: AbortSignal): Promise<void>;
108
+ terminateActorActivation(actor: ZLinkActor, terminal: () => Promise<void>): Promise<void>;
107
109
  notifyPrimaryEntrySpotActorLeft(actor: ZLinkActor, signal?: AbortSignal, actorRef?: ActorRef, membershipEpoch?: bigint): Promise<void>;
108
110
  notifyPrimaryEntrySpotActorDisconnected(actor: ZLinkActor, signal?: AbortSignal): Promise<void>;
109
111
  notifyEntrySpotActorDisconnected(meshName: string, actor: ZLinkActor, signal?: AbortSignal): Promise<void>;
@@ -115,7 +117,7 @@ export declare class ZLinkSpotNodeRuntimeManager {
115
117
  private ensureEntryActivation;
116
118
  private initializeEntrySpot;
117
119
  private primaryEntryActivation;
118
- dispatchEntryActorPacket(actorId: string, parts: readonly Message[], returnResponse?: boolean, remoteBoundSessionTarget?: ZLinkRemoteBoundSessionTarget, fallbackActorRef?: ActorRef, requestTerminal?: (response: unknown) => Promise<void> | void, messageFollowOrigin?: ZLinkMessageFollowOrigin): Promise<unknown>;
120
+ dispatchEntryActorPacket(origin: ApplicationJobOrigin, actorId: string, parts: readonly Message[], returnResponse?: boolean, remoteBoundSessionTarget?: ZLinkRemoteBoundSessionTarget, fallbackActorRef?: ActorRef, requestTerminal?: (response: unknown) => Promise<void> | void, messageFollowOrigin?: ZLinkMessageFollowOrigin): Promise<unknown>;
119
121
  dispatchEntryActorJoin(meshName: string, actor: ZLinkActor, handoffBacklog?: readonly ZLinkActorHandoffPacket[]): Promise<void>;
120
122
  executeEntryActor<T>(meshName: string, actorId: string, operation: () => Promise<T>): Promise<T>;
121
123
  publish(meshName: string, channelName: string, topic: string, packetName: string | undefined, event: Message, signal?: AbortSignal, metadata?: ReadonlyMap<string, string>): Promise<ZLinkSubmitResult>;
@@ -17,7 +17,6 @@ const channel_clients_1 = require("../channels/channel-clients");
17
17
  const channel_envelope_1 = require("../channels/channel-envelope");
18
18
  const configuration_1 = require("../configuration");
19
19
  const flow_context_1 = require("../diagnostics/flow-context");
20
- const execution_1 = require("../execution");
21
20
  const service_runtime_contracts_1 = require("../foundation/service-runtime-contracts");
22
21
  const framework_errors_internal_1 = require("../framework-errors-internal");
23
22
  const application_job_queue_1 = require("../host/application-job-queue");
@@ -146,6 +145,7 @@ class ZLinkSpotNodeRuntimeManager {
146
145
  routingId,
147
146
  receiveTimeoutMs: spotNode.router?.receiveTimeoutMs,
148
147
  applicationJobQueue: this.applicationJobQueue,
148
+ infrastructureTaskRunner: this.options.detachedTaskRunner,
149
149
  applicationJobReceiveFlowFailureSink: this.options.applicationJobReceiveFlowFailureSink,
150
150
  peerAdmissionSealed: () => this.options.peerAdmissionSealed?.(spotNodeName) ?? false
151
151
  });
@@ -177,6 +177,7 @@ class ZLinkSpotNodeRuntimeManager {
177
177
  let pump;
178
178
  const completions = new mesh_completion_table_1.ZLinkMeshCompletionTable();
179
179
  try {
180
+ node.setCompletionHandler((terminal, materialize) => completions.complete(terminal, materialize));
180
181
  node.setBind(bind);
181
182
  if (spotNode.router?.advertiseHost !== undefined) {
182
183
  node.setAdvertiseHost(spotNode.router.advertiseHost);
@@ -542,6 +543,12 @@ class ZLinkSpotNodeRuntimeManager {
542
543
  const activation = this.primaryEntryActivation();
543
544
  return activation?.notifyJoinActor(actor, signal) ?? Promise.resolve();
544
545
  }
546
+ terminateActorActivation(actor, terminal) {
547
+ const activation = this.entryActivations.get(actor.context.meshName);
548
+ return activation === undefined
549
+ ? terminal()
550
+ : activation.terminateActor(actor.context.actorId, terminal);
551
+ }
545
552
  notifyPrimaryEntrySpotActorLeft(actor, signal, actorRef, membershipEpoch) {
546
553
  const activation = this.primaryEntryActivation();
547
554
  return (activation?.notifyLeaveActor(actor, signal, actorRef, membershipEpoch) ?? Promise.resolve());
@@ -598,15 +605,6 @@ class ZLinkSpotNodeRuntimeManager {
598
605
  this.meshCompletions.clear();
599
606
  }
600
607
  async dispatchMeshRecord(meshName, owner, record) {
601
- if (record.kind === service_runtime_contracts_1.ReceiveKind.Completion) {
602
- (0, execution_1.requireZLinkInfrastructureExecutionArea)();
603
- const completions = this.meshCompletions.get(meshName);
604
- if (completions === undefined) {
605
- throw new configuration_1.ZLinkConfigurationException(`MeshNode '${meshName}' received a completion before its completion table was registered.`);
606
- }
607
- completions.complete(record);
608
- return;
609
- }
610
608
  const node = this.meshNodes.get(meshName);
611
609
  const targetsEntrySpot = owner.spotId === null ||
612
610
  (node !== undefined &&
@@ -739,7 +737,7 @@ class ZLinkSpotNodeRuntimeManager {
739
737
  primaryEntryActivation() {
740
738
  return this.entryActivations.values().next().value;
741
739
  }
742
- async dispatchEntryActorPacket(actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin) {
740
+ async dispatchEntryActorPacket(origin, actorId, parts, returnResponse = false, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin) {
743
741
  let activation = this.primaryEntryActivation();
744
742
  if (activation === undefined) {
745
743
  const candidates = this.options.primaryMeshName === undefined
@@ -768,6 +766,7 @@ class ZLinkSpotNodeRuntimeManager {
768
766
  throw new configuration_1.ZLinkConfigurationException('Entry Spot actor packet dispatch requires an Entry Spot.');
769
767
  }
770
768
  return await activation.dispatchActorPacket({
769
+ origin,
771
770
  actorId,
772
771
  parts,
773
772
  returnResponse,
@@ -1,6 +1,7 @@
1
1
  import type { RoutingId } from '../../contracts/Common';
2
2
  import type { ZLinkFrameworkRuntimeState, ZLinkSpotKind } from '../../contracts';
3
3
  export interface ZLinkSpotRouteResolver {
4
+ resolve(spotId: RoutingId, signal: AbortSignal | undefined, instanceIntent: true): Promise<ZLinkSpotRouteTarget | ZLinkInstanceReactivationRoute>;
4
5
  resolve(spotId: RoutingId, signal?: AbortSignal): Promise<ZLinkSpotRouteTarget>;
5
6
  invalidate?(spotId: RoutingId): void;
6
7
  }
@@ -26,3 +27,8 @@ export interface ZLinkSpotRouteTarget {
26
27
  /** Current state of the owning MeshNode, when the route was resolved from Location Store. */
27
28
  readonly targetNodeState?: ZLinkFrameworkRuntimeState;
28
29
  }
30
+ export interface ZLinkInstanceReactivationRoute extends Pick<ZLinkSpotRouteTarget, 'spotId' | 'spotKind' | 'stableType'> {
31
+ readonly kind: 'coldActivation';
32
+ readonly meshName: string;
33
+ readonly stableType: string;
34
+ }
@@ -1,3 +1,4 @@
1
+ import type { ApplicationJobOrigin } from '../application-jobs/contracts';
1
2
  import type { ActorRef, RoutingId, ZLinkActor, ZLinkActorJoinOperationId, ZLinkSpot } from '../../contracts';
2
3
  import type { Message } from '../../contracts/Common/Message';
3
4
  import type { ZLinkMessageFollowOrigin } from '../foundation/service-runtime-contracts';
@@ -44,5 +45,5 @@ export interface ZLinkSpotBoundSessionRuntime {
44
45
  sendActorError(actorId: string, packetName: string, requestSeq: bigint, error: unknown, metadata: ReadonlyMap<string, string>, fallbackBoundSessionTarget?: ZLinkRemoteBoundSessionTarget, actorRef?: ActorRef, signal?: AbortSignal): Promise<void>;
45
46
  }
46
47
  export interface ZLinkSpotActorHandoffRuntime {
47
- capture(actorId: string, parts: readonly Message[], returnResponse?: boolean, remoteBoundSessionTarget?: ZLinkRemoteBoundSessionTarget, fallbackActorRef?: ActorRef, deadlineUnixMs?: number, messageFollowOrigin?: ZLinkMessageFollowOrigin, provisionalReplay?: ZLinkActorHandoffDispatch): Promise<unknown> | undefined;
48
+ capture(origin: ApplicationJobOrigin, actorId: string, parts: readonly Message[], returnResponse?: boolean, remoteBoundSessionTarget?: ZLinkRemoteBoundSessionTarget, fallbackActorRef?: ActorRef, deadlineUnixMs?: number, messageFollowOrigin?: ZLinkMessageFollowOrigin, provisionalReplay?: ZLinkActorHandoffDispatch): Promise<unknown> | undefined;
48
49
  }
@@ -26,6 +26,7 @@ export declare class ZLinkSpotSerialExecutor {
26
26
  executeTimer<T>(timerName: string, operation: () => Promise<T> | T, workOptions?: ZLinkSerialWorkOptions): Promise<T>;
27
27
  isTimerExecuting(timerName: string): boolean;
28
28
  executeLifecycle<T>(operation: () => Promise<T> | T, workOptions?: ZLinkSerialWorkOptions): Promise<T>;
29
+ terminateActor(actorId: string, terminal: () => Promise<void>): Promise<void>;
29
30
  /**
30
31
  * Makes all child queues unreachable and completes them in one synchronous
31
32
  * ownership turn. Already accepted work remains drainable.
@@ -42,7 +42,8 @@ class ZLinkSpotSerialExecutor {
42
42
  return this.spotSerial.execute(operation, workOptions);
43
43
  }
44
44
  executeActor(actorId, operation, workOptions) {
45
- return this.actorExecutor(actorId).execute(() => operation(this.actorSerial(actorId)), workOptions);
45
+ const serial = this.actorSerial(actorId);
46
+ return this.actorExecutor(actorId).execute(() => operation(serial), workOptions);
46
47
  }
47
48
  /** @internal Restores a durable Actor FIFO prefix without starting it. */
48
49
  admitActorDurablePrefix(actorId, records) {
@@ -65,6 +66,14 @@ class ZLinkSpotSerialExecutor {
65
66
  executeLifecycle(operation, workOptions) {
66
67
  return this.spotSerial.execute(operation, { ...workOptions, lane: 'lifecycle' });
67
68
  }
69
+ async terminateActor(actorId, terminal) {
70
+ const executor = this.actorExecutor(actorId);
71
+ await executor.close();
72
+ await terminal();
73
+ if (this.actorExecutors.get(actorId) === executor)
74
+ this.actorExecutors.delete(actorId);
75
+ this.actorSerials.delete(actorId);
76
+ }
68
77
  /**
69
78
  * Makes all child queues unreachable and completes them in one synchronous
70
79
  * ownership turn. Already accepted work remains drainable.
@@ -759,7 +759,7 @@ class ZLinkStreamSessionNodeRuntime {
759
759
  let packet;
760
760
  let packetTransferred = false;
761
761
  try {
762
- permit = await this.options.applicationJobQueue.acquire(signal);
762
+ permit = await this.options.applicationJobQueue.acquire(signal, 'remote');
763
763
  if (this.isReceiveStopped(signal)) {
764
764
  permit.releaseAfterInternalProcessing();
765
765
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zlink-systems/framework",
3
- "version": "0.29.0",
3
+ "version": "0.30.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,7 +19,7 @@
19
19
  "dependencies": {
20
20
  "@opentelemetry/api": "^1.9.1",
21
21
  "@opentelemetry/api-logs": "^0.221.0",
22
- "@zlink-systems/stream-wire": "0.29.0",
23
- "@zlink-systems/zlink": "1.17.0"
22
+ "@zlink-systems/stream-wire": "0.30.0",
23
+ "@zlink-systems/zlink": "1.19.0"
24
24
  }
25
25
  }
@@ -7,7 +7,6 @@ import type { ZLinkDispatchOptionsBuilder, ZLinkInboundDispatchOptions } from '.
7
7
  import type { ZLinkLocationOptions, ZLinkLocationStore, ZLinkRelocationStore } from '../Locations';
8
8
  import type { RoutingId, Type } from '../Common';
9
9
  import type { ZLinkWorkerOptions } from './RegistrationTypes';
10
- import type { ZLinkSpotPublisherConfig } from './Configs';
11
10
  import type {
12
11
  ZLinkActorFactoryBuilder,
13
12
  ZLinkInstanceSpotFactoryBuilder,
@@ -120,7 +119,6 @@ export interface ZLinkMeshNodeBuilder {
120
119
  setActivationConcurrency(limit: number): this;
121
120
  setInstanceSpotIdleTimeout(timeoutMs: number): this;
122
121
  configureRouterSocket(): ZLinkMeshNodeSocketConfig;
123
- configureSpotPublisher(): ZLinkSpotPublisherConfig;
124
122
  peerConnections(): ZLinkMeshPeerConnections;
125
123
  setDefaultRequestTimeout(timeoutMs: number): this;
126
124
  objects(): ZLinkMeshObjectRoleBuilder;
@@ -180,6 +178,7 @@ export interface ZLinkFanoutChannelBuilder {
180
178
  routingId(routingId: string): this;
181
179
  setRoutingIdPrefix(prefix: string): this;
182
180
  setNoDrop(noDrop?: boolean): this;
181
+ setSendTimeout(timeoutMs: number): this;
183
182
  enableSubscriber(): this;
184
183
  subscribe(topic: string): this;
185
184
  connect(endpoint: string): this;
@@ -19,9 +19,3 @@ export interface ZLinkOutboundRouteConfig {
19
19
  targetNodeRid: RoutingId;
20
20
  endpoint: string;
21
21
  }
22
-
23
- export interface ZLinkSpotPublisherConfig {
24
- sendHighWaterMark: number;
25
- sendTimeoutMs?: number;
26
- lingerMs?: number;
27
- }
@@ -27,7 +27,6 @@ import type {
27
27
  ZLinkSession,
28
28
  ZLinkSessionFactory,
29
29
  ZLinkSpot,
30
- ZLinkSpotPublisherConfig,
31
30
  ZLinkStreamCompressionBuilder,
32
31
  ZLinkStreamCompressionCodec,
33
32
  ZLinkStreamNodeBuilder,
@@ -53,6 +52,7 @@ import type { ZLinkEndpointConnections } from './Connections';
53
52
  import { requireMessageFlowLogMode, requireTraceSampleRate } from './DiagnosticsValidation';
54
53
  import { normalizeEndpoint } from './EndpointNotation';
55
54
  import { requirePublicFanoutTopic } from './FanoutTopic';
55
+ import { requireValidSendTimeoutMs } from './SendTimeoutValidation';
56
56
  import { DEFAULT_STREAM_NODE_MAX_MESSAGE_SIZE } from './InternalDefaults';
57
57
  import {
58
58
  type ZLinkActorFactoryBuilder,
@@ -519,6 +519,12 @@ class DefaultFanoutChannelBuilder implements ZLinkFanoutChannelBuilder {
519
519
  return this;
520
520
  }
521
521
 
522
+ setSendTimeout(timeoutMs: number): this {
523
+ requireValidSendTimeoutMs(`Fanout channel '${this.name}' send timeout`, timeoutMs);
524
+ this.channel.sendTimeoutMs = timeoutMs;
525
+ return this;
526
+ }
527
+
522
528
  enableSubscriber(endpoint?: string): this {
523
529
  this.selectSubscriberMode(endpoint === undefined ? 'automatic' : 'manual');
524
530
  this.channel.subscriber ??= { manualConnections: [] };
@@ -984,11 +990,6 @@ class DefaultMeshNodeBuilder implements ZLinkMeshNodeBuilder {
984
990
  return this.node.router as ZLinkMeshNodeSocketConfig;
985
991
  }
986
992
 
987
- configureSpotPublisher(): ZLinkSpotPublisherConfig {
988
- this.node.publisherConfig ??= {};
989
- return this.node.publisherConfig as ZLinkSpotPublisherConfig;
990
- }
991
-
992
993
  peerConnections(): ZLinkMeshPeerConnections {
993
994
  this.node.router ??= {};
994
995
  return new DefaultMeshPeerConnections(this.node.router);
@@ -1576,6 +1577,7 @@ interface MutableChannelOptions {
1576
1577
  routingId?: string;
1577
1578
  routingIdPrefix?: string;
1578
1579
  noDrop?: boolean;
1580
+ sendTimeoutMs?: number;
1579
1581
  publisher?: MutablePublisherCapabilityOptions;
1580
1582
  publishHandlers?: ZLinkChannelPublishHandlerRegistration[];
1581
1583
  subscriptions?: string[];
@@ -1607,7 +1609,6 @@ interface MutableClientCapabilityOptions {
1607
1609
  }
1608
1610
 
1609
1611
  interface MutablePublisherCapabilityOptions {
1610
- sendTimeoutMs?: number;
1611
1612
  bind?: string;
1612
1613
  bindHost?: string;
1613
1614
  advertiseHost?: string;
@@ -1668,11 +1669,6 @@ interface MutableSpotNodeOptions {
1668
1669
  routeSendHandlers?: Array<{ packetName: string; handlerType: Type }>;
1669
1670
  routeRequestHandlers?: Array<{ packetName: string; handlerType: Type }>;
1670
1671
  requestTimeoutMs?: number;
1671
- publisherConfig?: {
1672
- sendHighWaterMark?: number;
1673
- sendTimeoutMs?: number;
1674
- lingerMs?: number;
1675
- };
1676
1672
  }
1677
1673
 
1678
1674
  interface MutableObjectFactoryRegistration<T, TImplementation = T, TOptions = unknown> {
@@ -166,6 +166,7 @@ export interface ZLinkChannelOptions {
166
166
  readonly routingId?: string;
167
167
  readonly routingIdPrefix?: string;
168
168
  readonly noDrop?: boolean;
169
+ readonly sendTimeoutMs?: number;
169
170
  readonly requestTimeoutMs?: number;
170
171
  readonly client?: ZLinkClientCapabilityOptions;
171
172
  readonly publisher?: ZLinkPublisherCapabilityOptions;
@@ -196,7 +197,6 @@ export interface ZLinkClientCapabilityOptions {
196
197
  }
197
198
 
198
199
  export interface ZLinkPublisherCapabilityOptions {
199
- readonly sendTimeoutMs?: number;
200
200
  readonly bind?: string;
201
201
  readonly bindHost?: string;
202
202
  readonly advertiseHost?: string;
@@ -297,11 +297,6 @@ export interface ZLinkSpotNodeOptions {
297
297
  readonly routeSendHandlers?: readonly ZLinkRouteMeshSendHandlerRegistration[];
298
298
  readonly routeRequestHandlers?: readonly ZLinkRouteMeshRequestHandlerRegistration[];
299
299
  readonly requestTimeoutMs?: number;
300
- readonly publisherConfig?: {
301
- readonly sendHighWaterMark?: number;
302
- readonly sendTimeoutMs?: number;
303
- readonly lingerMs?: number;
304
- };
305
300
  readonly entrySpotTimerHandlers?: readonly ZLinkEntrySpotTimerHandlerRegistration[];
306
301
  readonly entrySpotPacketHandlers?: readonly ZLinkEntrySpotPacketHandlerRegistration[];
307
302
  readonly entrySpotSubscriptionHandlers?: readonly ZLinkEntrySpotSubscriptionHandlerRegistration[];
@@ -217,9 +217,12 @@ function validateChannelCapabilities(
217
217
  if (channel.noDrop !== undefined && typeof channel.noDrop !== 'boolean') {
218
218
  throw new ZLinkConfigurationException(`Channel '${channelName}' NoDrop must be a boolean.`);
219
219
  }
220
- if (channel.noDrop !== undefined && channel.publisher === undefined) {
220
+ if (
221
+ (channel.noDrop !== undefined || channel.sendTimeoutMs !== undefined) &&
222
+ channel.publisher === undefined
223
+ ) {
221
224
  throw new ZLinkConfigurationException(
222
- `Channel '${channelName}' NoDrop requires a publisher role.`
225
+ `Channel '${channelName}': NoDrop and send timeout require the publisher role.`
223
226
  );
224
227
  }
225
228
  if (channel.server !== undefined) {
@@ -235,11 +238,11 @@ function validateChannelCapabilities(
235
238
  requirePeerWeight(`channel '${channelName}' server weight`, channel.server.weight);
236
239
  requireSocketOptions(`channel '${channelName}' server`, channel.server);
237
240
  }
241
+ requireValidSendTimeoutMs(
242
+ `channel '${channelName}' publisher sendTimeoutMs`,
243
+ channel.sendTimeoutMs
244
+ );
238
245
  if (channel.publisher !== undefined) {
239
- requireValidSendTimeoutMs(
240
- `channel '${channelName}' publisher sendTimeoutMs`,
241
- channel.publisher.sendTimeoutMs
242
- );
243
246
  requireEndpoint(`channel '${channelName}' publisher`, channel.publisher.bind);
244
247
  validateListenerNetworkIdentity(
245
248
  `channel '${channelName}' publisher`,
@@ -345,10 +348,6 @@ function validateSpotNodes(registration: ZLinkFrameworkRegistration): void {
345
348
  `SpotNode '${spotNodeName}' instanceSpotIdleTimeoutMs`,
346
349
  spotNode.instanceSpotIdleTimeoutMs
347
350
  );
348
- requireValidSendTimeoutMs(
349
- `SpotNode '${spotNodeName}' publisher sendTimeoutMs`,
350
- spotNode.publisherConfig?.sendTimeoutMs
351
- );
352
351
  validateSpotNodeFactories(spotNodeName, spotNode);
353
352
  validateSpotNodeTimers(spotNode);
354
353
  if (
@@ -20,12 +20,7 @@ export type {
20
20
  ZLinkStreamSocketConfig,
21
21
  ZLinkStreamNodeBuilder
22
22
  } from './Builders';
23
- export type {
24
- ZLinkOutboundRouteConfig,
25
- ZLinkRouteConfig,
26
- ZLinkSocketConfig,
27
- ZLinkSpotPublisherConfig
28
- } from './Configs';
23
+ export type { ZLinkOutboundRouteConfig, ZLinkRouteConfig, ZLinkSocketConfig } from './Configs';
29
24
  export * from './Connections';
30
25
  export * from './ObjectRoles';
31
26
  export type {