@zlink-systems/framework 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Channels/IZLinkFanoutClient.d.ts +0 -6
  3. package/dist/contracts/RouteMesh/RuntimeTopology.d.ts +8 -0
  4. package/dist/internal.d.ts +1 -0
  5. package/dist/internal.js +1 -0
  6. package/dist/runtime/activation-admission.d.ts +29 -0
  7. package/dist/runtime/activation-admission.js +61 -0
  8. package/dist/runtime/actors/actor-context.js +6 -6
  9. package/dist/runtime/actors/actor-handoff.d.ts +9 -3
  10. package/dist/runtime/actors/actor-handoff.js +28 -17
  11. package/dist/runtime/actors/actor-local-native-join.js +2 -18
  12. package/dist/runtime/actors/actor-remote-joiner.d.ts +2 -2
  13. package/dist/runtime/actors/actor-remote-joiner.js +6 -8
  14. package/dist/runtime/actors/actor-runtime-contracts.d.ts +4 -2
  15. package/dist/runtime/actors/actor-source-transfer.d.ts +5 -5
  16. package/dist/runtime/actors/deferred-join-completion.d.ts +14 -0
  17. package/dist/runtime/actors/deferred-join-completion.js +20 -0
  18. package/dist/runtime/actors/index.d.ts +1 -1
  19. package/dist/runtime/actors/index.js +15 -5
  20. package/dist/runtime/admission.d.ts +5 -1
  21. package/dist/runtime/admission.js +4 -0
  22. package/dist/runtime/backend/contracts/index.d.ts +2 -10
  23. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -9
  24. package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +1 -2
  25. package/dist/runtime/backend/node/node-backend-adapter-factory.js +4 -18
  26. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +6 -3
  27. package/dist/runtime/backend/node/node-backend-adapter-support.js +12 -28
  28. package/dist/runtime/backend/node/node-event-loop-poller.d.ts +1 -1
  29. package/dist/runtime/backend/node/node-event-loop-poller.js +8 -2
  30. package/dist/runtime/backend/node/node-raw-binding-port.d.ts +1 -1
  31. package/dist/runtime/backend/node/node-raw-binding-port.js +11 -3
  32. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +12 -9
  33. package/dist/runtime/backend/node/node-raw-mesh-backend.js +61 -29
  34. package/dist/runtime/backend/node/node-socket-backend-adapter.js +1 -1
  35. package/dist/runtime/backend/raw-binding-port.d.ts +12 -0
  36. package/dist/runtime/channels/channel-clients.d.ts +0 -1
  37. package/dist/runtime/channels/channel-clients.js +0 -8
  38. package/dist/runtime/channels/channel-outbound-operations.js +2 -10
  39. package/dist/runtime/channels/channel-runtime-manager.d.ts +2 -5
  40. package/dist/runtime/channels/channel-runtime-manager.js +1 -12
  41. package/dist/runtime/channels/channel-socket-registry.d.ts +17 -4
  42. package/dist/runtime/channels/channel-socket-registry.js +49 -62
  43. package/dist/runtime/channels/channel-transports.d.ts +0 -3
  44. package/dist/runtime/channels/fanout-location-runtime.js +3 -9
  45. package/dist/runtime/execution/index.d.ts +18 -8
  46. package/dist/runtime/execution/index.js +55 -29
  47. package/dist/runtime/execution/serial-execution-queue.d.ts +5 -6
  48. package/dist/runtime/execution/serial-execution-queue.js +49 -15
  49. package/dist/runtime/foundation/listener-records.d.ts +11 -0
  50. package/dist/runtime/foundation/listener-records.js +20 -0
  51. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +10 -21
  52. package/dist/runtime/foundation/raw-service-mesh-runtime.js +66 -392
  53. package/dist/runtime/foundation/service-authority-payload-codec.d.ts +1 -0
  54. package/dist/runtime/foundation/service-authority-payload-codec.js +8 -0
  55. package/dist/runtime/foundation/service-maintenance-runtime.js +23 -2
  56. package/dist/runtime/foundation/service-relocation-coordinator.d.ts +9 -0
  57. package/dist/runtime/foundation/service-relocation-coordinator.js +14 -1
  58. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +8 -0
  59. package/dist/runtime/foundation/service-relocation-object-owner.js +16 -4
  60. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +6 -13
  61. package/dist/runtime/foundation/service-stateful-runtime.d.ts +10 -7
  62. package/dist/runtime/foundation/service-stateful-runtime.js +100 -60
  63. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +9 -4
  64. package/dist/runtime/foundation/service-stateful-wire-codec.js +153 -90
  65. package/dist/runtime/foundation/service-topology-registry.d.ts +1 -2
  66. package/dist/runtime/foundation/service-topology-registry.js +6 -30
  67. package/dist/runtime/host/actor-transfer-runtime.d.ts +17 -15
  68. package/dist/runtime/host/actor-transfer-runtime.js +73 -86
  69. package/dist/runtime/host/index.d.ts +6 -2
  70. package/dist/runtime/host/index.js +63 -37
  71. package/dist/runtime/host/remote-bound-session-relay.js +4 -3
  72. package/dist/runtime/host/route-mesh-runtime.d.ts +2 -0
  73. package/dist/runtime/host/route-mesh-runtime.js +7 -5
  74. package/dist/runtime/host/service-relocation-host-runtime.d.ts +50 -8
  75. package/dist/runtime/host/service-relocation-host-runtime.js +343 -270
  76. package/dist/runtime/host/spot-runtime-options-factory.d.ts +7 -4
  77. package/dist/runtime/host/spot-runtime-options-factory.js +4 -8
  78. package/dist/runtime/host/stateful-authority-route-runtime.js +6 -2
  79. package/dist/runtime/host/user-spot-creation-coordinator.d.ts +11 -3
  80. package/dist/runtime/host/user-spot-creation-coordinator.js +85 -87
  81. package/dist/runtime/locations/in-memory-provider-location-store.js +8 -6
  82. package/dist/runtime/locations/lifecycle.d.ts +1 -1
  83. package/dist/runtime/locations/lifecycle.js +2 -2
  84. package/dist/runtime/locations/resolvers.js +7 -2
  85. package/dist/runtime/locations/spot-location-claims.d.ts +2 -2
  86. package/dist/runtime/locations/spot-location-claims.js +3 -27
  87. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +1 -0
  88. package/dist/runtime/protocol/service_wire_codec.generated.js +5 -1
  89. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +1 -0
  90. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +3 -2
  91. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +3 -3
  92. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +4 -4
  93. package/dist/runtime/spots/formal-remote-actor-transfer-registry.d.ts +3 -3
  94. package/dist/runtime/spots/index.d.ts +25 -19
  95. package/dist/runtime/spots/index.js +207 -205
  96. package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
  97. package/dist/runtime/spots/spot-activation-registry.js +34 -31
  98. package/dist/runtime/spots/spot-activation-state.d.ts +2 -11
  99. package/dist/runtime/spots/spot-activation-state.js +4 -17
  100. package/dist/runtime/spots/spot-activation.d.ts +8 -6
  101. package/dist/runtime/spots/spot-activation.js +54 -49
  102. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -1
  103. package/dist/runtime/spots/spot-actor-admission-coordinator.js +1 -1
  104. package/dist/runtime/spots/spot-actor-join-dispatch.d.ts +2 -2
  105. package/dist/runtime/spots/spot-actor-join-dispatch.js +3 -5
  106. package/dist/runtime/spots/spot-actor-lifecycle-drain.js +2 -2
  107. package/dist/runtime/spots/spot-actor-membership.d.ts +4 -0
  108. package/dist/runtime/spots/spot-actor-membership.js +26 -12
  109. package/dist/runtime/spots/spot-entry-activation.d.ts +1 -2
  110. package/dist/runtime/spots/spot-entry-activation.js +0 -1
  111. package/dist/runtime/spots/spot-manager-public.js +1 -1
  112. package/dist/runtime/spots/spot-native-actor-join-admission.d.ts +1 -1
  113. package/dist/runtime/spots/spot-native-actor-join-admission.js +2 -2
  114. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +5 -5
  115. package/dist/runtime/spots/spot-node-runtime-manager.js +7 -11
  116. package/dist/runtime/spots/spot-outbound.js +1 -29
  117. package/dist/runtime/spots/spot-routed-actor-admission.d.ts +1 -0
  118. package/dist/runtime/spots/spot-routed-actor-admission.js +10 -0
  119. package/dist/runtime/spots/spot-routed-frame-dispatch.d.ts +2 -6
  120. package/dist/runtime/spots/spot-routed-frame-dispatch.js +2 -70
  121. package/dist/runtime/spots/spot-runtime-ports.d.ts +3 -5
  122. package/dist/runtime/spots/spot-serial-executor.d.ts +5 -0
  123. package/dist/runtime/spots/spot-serial-executor.js +8 -1
  124. package/dist/runtime/spots/spot-serial-turn-executor.d.ts +3 -0
  125. package/dist/runtime/spots/spot-serial-turn-executor.js +8 -4
  126. package/dist/runtime/streams/actor-session-binding-registry.d.ts +13 -15
  127. package/dist/runtime/streams/actor-session-binding-registry.js +19 -171
  128. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +3 -4
  129. package/dist/runtime/streams/bound-session-service.js +1 -18
  130. package/dist/runtime/streams/index.d.ts +2 -0
  131. package/dist/runtime/streams/index.js +19 -19
  132. package/dist/runtime/streams/session-serial-executor.js +2 -2
  133. package/package.json +3 -3
  134. package/src/contracts/Channels/IZLinkFanoutClient.ts +0 -7
  135. package/src/contracts/RouteMesh/RuntimeTopology.ts +10 -0
  136. package/src/internal.ts +1 -0
  137. package/src/runtime/activation-admission.ts +78 -0
  138. package/src/runtime/actors/actor-context.ts +6 -6
  139. package/src/runtime/actors/actor-handoff.ts +31 -23
  140. package/src/runtime/actors/actor-local-native-join.ts +3 -42
  141. package/src/runtime/actors/actor-remote-joiner.ts +6 -25
  142. package/src/runtime/actors/actor-runtime-contracts.ts +4 -10
  143. package/src/runtime/actors/actor-source-transfer.ts +5 -18
  144. package/src/runtime/actors/deferred-join-completion.ts +40 -0
  145. package/src/runtime/actors/index.ts +22 -9
  146. package/src/runtime/admission.ts +5 -1
  147. package/src/runtime/backend/contracts/index.ts +2 -13
  148. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +2 -10
  149. package/src/runtime/backend/node/node-backend-adapter-factory.ts +5 -25
  150. package/src/runtime/backend/node/node-backend-adapter-support.ts +9 -29
  151. package/src/runtime/backend/node/node-event-loop-poller.ts +14 -2
  152. package/src/runtime/backend/node/node-raw-binding-port.ts +17 -3
  153. package/src/runtime/backend/node/node-raw-mesh-backend.ts +65 -32
  154. package/src/runtime/backend/node/node-socket-backend-adapter.ts +2 -2
  155. package/src/runtime/backend/raw-binding-port.ts +13 -0
  156. package/src/runtime/channels/channel-clients.ts +0 -11
  157. package/src/runtime/channels/channel-outbound-operations.ts +3 -11
  158. package/src/runtime/channels/channel-runtime-manager.ts +4 -15
  159. package/src/runtime/channels/channel-socket-registry.ts +69 -71
  160. package/src/runtime/channels/channel-transports.ts +0 -3
  161. package/src/runtime/channels/fanout-location-runtime.ts +4 -16
  162. package/src/runtime/execution/index.ts +68 -30
  163. package/src/runtime/execution/serial-execution-queue.ts +52 -20
  164. package/src/runtime/foundation/listener-records.ts +21 -0
  165. package/src/runtime/foundation/raw-service-mesh-runtime.ts +66 -466
  166. package/src/runtime/foundation/service-authority-payload-codec.ts +10 -0
  167. package/src/runtime/foundation/service-maintenance-runtime.ts +30 -9
  168. package/src/runtime/foundation/service-relocation-coordinator.ts +13 -0
  169. package/src/runtime/foundation/service-relocation-object-owner.ts +18 -5
  170. package/src/runtime/foundation/service-session-binding-ingress-port.ts +6 -14
  171. package/src/runtime/foundation/service-stateful-runtime.ts +151 -89
  172. package/src/runtime/foundation/service-stateful-wire-codec.ts +203 -121
  173. package/src/runtime/foundation/service-topology-registry.ts +8 -48
  174. package/src/runtime/host/actor-transfer-runtime.ts +94 -166
  175. package/src/runtime/host/index.ts +119 -54
  176. package/src/runtime/host/remote-bound-session-relay.ts +4 -3
  177. package/src/runtime/host/route-mesh-runtime.ts +9 -5
  178. package/src/runtime/host/service-relocation-host-runtime.ts +495 -376
  179. package/src/runtime/host/spot-runtime-options-factory.ts +24 -13
  180. package/src/runtime/host/stateful-authority-route-runtime.ts +8 -4
  181. package/src/runtime/host/user-spot-creation-coordinator.ts +147 -142
  182. package/src/runtime/locations/in-memory-provider-location-store.ts +11 -7
  183. package/src/runtime/locations/lifecycle.ts +3 -2
  184. package/src/runtime/locations/resolvers.ts +19 -13
  185. package/src/runtime/locations/spot-location-claims.ts +5 -34
  186. package/src/runtime/protocol/service_wire_codec.generated.ts +9 -2
  187. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
  188. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +6 -6
  189. package/src/runtime/spots/formal-remote-actor-transfer-registry.ts +3 -3
  190. package/src/runtime/spots/index.ts +341 -295
  191. package/src/runtime/spots/spot-activation-registry.ts +41 -31
  192. package/src/runtime/spots/spot-activation-state.ts +4 -16
  193. package/src/runtime/spots/spot-activation.ts +102 -80
  194. package/src/runtime/spots/spot-actor-admission-coordinator.ts +2 -2
  195. package/src/runtime/spots/spot-actor-join-dispatch.ts +6 -7
  196. package/src/runtime/spots/spot-actor-lifecycle-drain.ts +20 -18
  197. package/src/runtime/spots/spot-actor-membership.ts +81 -17
  198. package/src/runtime/spots/spot-entry-activation.ts +0 -3
  199. package/src/runtime/spots/spot-manager-public.ts +8 -4
  200. package/src/runtime/spots/spot-native-actor-join-admission.ts +2 -2
  201. package/src/runtime/spots/spot-node-runtime-manager.ts +12 -18
  202. package/src/runtime/spots/spot-outbound.ts +4 -47
  203. package/src/runtime/spots/spot-routed-actor-admission.ts +20 -0
  204. package/src/runtime/spots/spot-routed-frame-dispatch.ts +6 -76
  205. package/src/runtime/spots/spot-runtime-ports.ts +6 -17
  206. package/src/runtime/spots/spot-serial-executor.ts +9 -1
  207. package/src/runtime/spots/spot-serial-turn-executor.ts +10 -4
  208. package/src/runtime/streams/actor-session-binding-registry.ts +20 -308
  209. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +2 -12
  210. package/src/runtime/streams/bound-session-service.ts +2 -36
  211. package/src/runtime/streams/index.ts +29 -27
  212. package/src/runtime/streams/session-serial-executor.ts +2 -2
  213. package/dist/runtime/actors/deferred-join-accepted-journal.d.ts +0 -47
  214. package/dist/runtime/actors/deferred-join-accepted-journal.js +0 -992
  215. package/src/runtime/actors/deferred-join-accepted-journal.ts +0 -1346
@@ -19,6 +19,19 @@ import {
19
19
  encodeCanonicalServiceWireText,
20
20
  encodeServiceWireRoutingId
21
21
  } from './service-wire-binary-primitives';
22
+ import {
23
+ decodeActorRequestCommand,
24
+ decodeActorSendCommand,
25
+ decodeMetadataFrame,
26
+ decodeSpotRequestCommand,
27
+ decodeSpotSendCommand,
28
+ encodeActorRequestCommand,
29
+ encodeActorSendCommand,
30
+ encodeApplicationPayloadEnvelopeV1,
31
+ encodeSpotRequestCommand,
32
+ encodeSpotSendCommand,
33
+ type ServiceWireDecoderContext
34
+ } from '../protocol/service_wire_codec.generated';
22
35
  import {
23
36
  decodeActorCreate49 as decodeGeneratedActorCreate49,
24
37
  decodeActorJoin28,
@@ -337,6 +350,7 @@ export type ServiceSessionRelocationRoute =
337
350
  readonly targetAuthorityOwnerGeneration: bigint;
338
351
  readonly targetNodeRid: string;
339
352
  readonly targetNodeGeneration: bigint;
353
+ readonly targetOwnerLeaseGeneration: bigint;
340
354
  };
341
355
  }
342
356
  | {
@@ -1015,8 +1029,10 @@ export type ServiceStatefulWireRecord =
1015
1029
  | {
1016
1030
  readonly kind: 'spotSend' | 'spotRequest';
1017
1031
  readonly correlation?: bigint;
1032
+ readonly operation: ServiceWireOperationId;
1033
+ readonly messageFollowHopCount: number;
1018
1034
  readonly sourceSpotId: string;
1019
- readonly target: ServiceDirectSpotRouteFence;
1035
+ readonly target: ServiceSpotRouteFence;
1020
1036
  }
1021
1037
  | {
1022
1038
  readonly kind: 'logicalMulticast';
@@ -1027,6 +1043,8 @@ export type ServiceStatefulWireRecord =
1027
1043
  | {
1028
1044
  readonly kind: 'actorSend' | 'actorRequest';
1029
1045
  readonly correlation?: bigint;
1046
+ readonly operation: ServiceWireOperationId;
1047
+ readonly messageFollowHopCount: number;
1030
1048
  readonly sourceActor?: ServiceActorRef;
1031
1049
  readonly target: ServiceActorRouteFence;
1032
1050
  readonly boundSession?: ServiceBoundSessionSource;
@@ -1137,20 +1155,68 @@ export interface ServiceStatefulReply {
1137
1155
  readonly tail?: ServiceStatefulReplyTail;
1138
1156
  }
1139
1157
 
1158
+ const STATEFUL_MESSAGE_CONTEXT: ServiceWireDecoderContext = {
1159
+ effectiveCompleteMessageBytesMinusActualEnvelopeOverhead: 0xffff_fdf6,
1160
+ effectiveCompleteMessageBytes: 0xffff_ffff
1161
+ };
1162
+ const STATEFUL_HEADER_PAYLOAD = {
1163
+ packetName: 'wire',
1164
+ contentType: 'application/json',
1165
+ payload: Buffer.from('{}')
1166
+ };
1167
+
1168
+ function generatedSpotFence(target: ServiceSpotRouteFence) {
1169
+ return {
1170
+ spot: { spotId: target.spot.spotId, objectGeneration: target.spot.generation },
1171
+ targetNodeRid: toGeneratedRoutingId(target.targetNodeRid, 'targetNodeRid'),
1172
+ targetNodeGeneration: target.targetNodeGeneration,
1173
+ expectedAuthorityOwnerGeneration: target.authorityOwnerGeneration,
1174
+ expectedOwnerLeaseGeneration: target.ownerLeaseGeneration
1175
+ };
1176
+ }
1177
+
1178
+ function generatedActorFence(target: ServiceActorRouteFence) {
1179
+ return {
1180
+ actor: { actorId: target.actor.actorId, objectGeneration: target.actor.generation },
1181
+ targetNodeRid: toGeneratedRoutingId(target.actor.nodeRid, 'targetNodeRid'),
1182
+ targetNodeGeneration: target.targetNodeGeneration,
1183
+ expectedAuthorityOwnerGeneration: target.authorityOwnerGeneration,
1184
+ expectedOwnerLeaseGeneration: target.ownerLeaseGeneration
1185
+ };
1186
+ }
1187
+
1140
1188
  export function encodeSpotHeader(
1141
1189
  kind: 'spotSend' | 'spotRequest',
1142
1190
  sourceSpotId: string,
1143
1191
  target: ServiceDirectSpotRouteFence,
1144
- correlation?: bigint
1192
+ correlation?: bigint,
1193
+ operation: ServiceWireOperationId = { high: 0n, low: 1n },
1194
+ messageFollowHopCount = 0,
1195
+ metadataFrame?: Uint8Array
1145
1196
  ): Buffer {
1146
- return concat(
1147
- prefix(
1148
- kind === 'spotSend' ? M6bServiceWireCommand.spotSend : M6bServiceWireCommand.spotRequest
1149
- ),
1150
- ...(kind === 'spotRequest' ? [u64(requirePositive(correlation, 'correlation'))] : []),
1151
- rid(sourceSpotId, 'sourceSpotId'),
1152
- directSpotFence(target)
1153
- );
1197
+ const common = {
1198
+ flags: metadataFrame === undefined ? 0 : M6bServiceWireFlag.metadata,
1199
+ operation,
1200
+ messageFollowHopCount,
1201
+ sourceSpotId,
1202
+ targetSpot: generatedSpotFence(target),
1203
+ payload: STATEFUL_HEADER_PAYLOAD,
1204
+ ...(metadataFrame === undefined
1205
+ ? {}
1206
+ : { metadata: decodeMetadataFrame(metadataFrame, STATEFUL_MESSAGE_CONTEXT) })
1207
+ };
1208
+ const frames =
1209
+ kind === 'spotSend'
1210
+ ? encodeSpotSendCommand({ command: kind, ...common }, STATEFUL_MESSAGE_CONTEXT)
1211
+ : encodeSpotRequestCommand(
1212
+ {
1213
+ command: kind,
1214
+ ...common,
1215
+ correlation: requirePositive(correlation, 'correlation')
1216
+ },
1217
+ STATEFUL_MESSAGE_CONTEXT
1218
+ );
1219
+ return Buffer.from(frames[0]!);
1154
1220
  }
1155
1221
 
1156
1222
  export function encodeActorHeader(
@@ -1158,28 +1224,46 @@ export function encodeActorHeader(
1158
1224
  target: ServiceActorRouteFence,
1159
1225
  correlation?: bigint,
1160
1226
  sourceActor?: ServiceActorRef,
1161
- boundSession?: ServiceBoundSessionSource
1227
+ boundSession?: ServiceBoundSessionSource,
1228
+ operation: ServiceWireOperationId = { high: 0n, low: 1n },
1229
+ messageFollowHopCount = 0
1162
1230
  ): Buffer {
1163
1231
  const flags =
1164
1232
  boundSession === undefined
1165
1233
  ? 0
1166
1234
  : M6bServiceWireFlag.boundSession | M6bServiceWireFlag.sourceSpotId;
1167
- return concat(
1168
- prefix(
1169
- kind === 'actorSend' ? M6bServiceWireCommand.actorSend : M6bServiceWireCommand.actorRequest,
1170
- flags
1171
- ),
1172
- ...(kind === 'actorRequest' ? [u64(requirePositive(correlation, 'correlation'))] : []),
1173
- optionalActor(sourceActor),
1174
- actorFence(target),
1235
+ const common = {
1236
+ flags,
1237
+ operation,
1238
+ messageFollowHopCount,
1239
+ sourceActor:
1240
+ sourceActor === undefined
1241
+ ? { actorId: null }
1242
+ : { actorId: sourceActor.actorId, generation: sourceActor.generation },
1243
+ targetActor: generatedActorFence(target),
1175
1244
  ...(boundSession === undefined
1176
- ? []
1177
- : [
1178
- rid(boundSession.sessionRid, 'sourceSessionRid'),
1179
- u64(boundSession.bindingGeneration),
1180
- u64(boundSession.sequence)
1181
- ])
1182
- );
1245
+ ? {}
1246
+ : {
1247
+ boundSessionTail: {
1248
+ sourceSessionRid: toGeneratedRoutingId(boundSession.sessionRid, 'sourceSessionRid'),
1249
+ sourceBindingGeneration: boundSession.bindingGeneration,
1250
+ sourceSessionSequence: boundSession.sequence
1251
+ }
1252
+ }),
1253
+ payload: STATEFUL_HEADER_PAYLOAD
1254
+ };
1255
+ const frames =
1256
+ kind === 'actorSend'
1257
+ ? encodeActorSendCommand({ command: kind, ...common }, STATEFUL_MESSAGE_CONTEXT)
1258
+ : encodeActorRequestCommand(
1259
+ {
1260
+ command: kind,
1261
+ ...common,
1262
+ correlation: requirePositive(correlation, 'correlation')
1263
+ },
1264
+ STATEFUL_MESSAGE_CONTEXT
1265
+ );
1266
+ return Buffer.from(frames[0]!);
1183
1267
  }
1184
1268
 
1185
1269
  export function encodeLogicalMulticastHeader(
@@ -1420,7 +1504,11 @@ export function encodeMessageFollowHeader(
1420
1504
  );
1421
1505
  }
1422
1506
 
1423
- export function decodeStatefulHeader(frame: Uint8Array): ServiceStatefulWireRecord {
1507
+ export function decodeStatefulHeader(
1508
+ frame: Uint8Array,
1509
+ payloadFrame?: Uint8Array,
1510
+ metadataFrame?: Uint8Array
1511
+ ): ServiceStatefulWireRecord {
1424
1512
  switch (frame[3]) {
1425
1513
  case M6bServiceWireCommand.userSpotCreate:
1426
1514
  return fromGeneratedUserSpotCreate(decodeGeneratedUserSpotCreate47(frame));
@@ -1428,52 +1516,98 @@ export function decodeStatefulHeader(frame: Uint8Array): ServiceStatefulWireReco
1428
1516
  return fromGeneratedUserSpotClose(decodeGeneratedUserSpotClose48(frame));
1429
1517
  case M6bServiceWireCommand.actorCreate:
1430
1518
  return fromGeneratedActorCreate(decodeGeneratedActorCreate49(frame));
1431
- }
1432
- const reader = new Reader(frame);
1433
- const command = reader.prefix();
1434
- switch (command.command) {
1435
1519
  case M6bServiceWireCommand.spotSend:
1436
- case M6bServiceWireCommand.spotRequest: {
1437
- requireFlags(command.flags, 0);
1438
- const request = command.command === M6bServiceWireCommand.spotRequest;
1439
- const correlation = request ? reader.nonZeroU64('correlation') : undefined;
1440
- const sourceSpotId = reader.rid('sourceSpotId');
1441
- const target = reader.directSpotFence();
1442
- reader.end();
1443
- return {
1444
- kind: request ? 'spotRequest' : 'spotSend',
1445
- ...(correlation === undefined ? {} : { correlation }),
1446
- sourceSpotId,
1447
- target
1448
- };
1449
- }
1520
+ case M6bServiceWireCommand.spotRequest:
1450
1521
  case M6bServiceWireCommand.actorSend:
1451
1522
  case M6bServiceWireCommand.actorRequest: {
1452
- const request = command.command === M6bServiceWireCommand.actorRequest;
1453
- const hasBinding = command.flags !== 0;
1454
- requireFlags(
1455
- command.flags,
1456
- hasBinding ? M6bServiceWireFlag.boundSession | M6bServiceWireFlag.sourceSpotId : 0
1457
- );
1458
- const correlation = request ? reader.nonZeroU64('correlation') : undefined;
1459
- const sourceActor = reader.optionalActor();
1460
- const target = reader.actorFence();
1461
- const boundSession = hasBinding
1462
- ? {
1463
- sessionRid: reader.rid('sourceSessionRid'),
1464
- bindingGeneration: reader.nonZeroU64('sourceBindingGeneration'),
1465
- sequence: reader.nonZeroU64('sourceSessionSequence')
1466
- }
1467
- : undefined;
1468
- reader.end();
1469
- return {
1470
- kind: request ? 'actorRequest' : 'actorSend',
1471
- ...(correlation === undefined ? {} : { correlation }),
1472
- ...(sourceActor === undefined ? {} : { sourceActor }),
1473
- target,
1474
- ...(boundSession === undefined ? {} : { boundSession })
1475
- };
1523
+ const frames = [
1524
+ frame,
1525
+ ...(metadataFrame === undefined ? [] : [metadataFrame]),
1526
+ payloadFrame ??
1527
+ encodeApplicationPayloadEnvelopeV1(STATEFUL_HEADER_PAYLOAD, STATEFUL_MESSAGE_CONTEXT)
1528
+ ];
1529
+ try {
1530
+ if (
1531
+ frame[3] === M6bServiceWireCommand.spotSend ||
1532
+ frame[3] === M6bServiceWireCommand.spotRequest
1533
+ ) {
1534
+ const decoded =
1535
+ frame[3] === M6bServiceWireCommand.spotSend
1536
+ ? decodeSpotSendCommand(frames, STATEFUL_MESSAGE_CONTEXT)
1537
+ : decodeSpotRequestCommand(frames, STATEFUL_MESSAGE_CONTEXT);
1538
+ return {
1539
+ kind: decoded.command,
1540
+ ...(decoded.command === 'spotRequest' ? { correlation: decoded.correlation } : {}),
1541
+ operation: decoded.operation,
1542
+ messageFollowHopCount: decoded.messageFollowHopCount,
1543
+ sourceSpotId: decoded.sourceSpotId,
1544
+ target: {
1545
+ spot: {
1546
+ spotId: decoded.targetSpot.spot.spotId,
1547
+ generation: decoded.targetSpot.spot.objectGeneration
1548
+ },
1549
+ targetNodeRid: fromGeneratedRoutingId(
1550
+ decoded.targetSpot.targetNodeRid,
1551
+ 'targetNodeRid'
1552
+ ),
1553
+ targetNodeGeneration: decoded.targetSpot.targetNodeGeneration,
1554
+ authorityOwnerGeneration: decoded.targetSpot.expectedAuthorityOwnerGeneration,
1555
+ ownerLeaseGeneration: decoded.targetSpot.expectedOwnerLeaseGeneration
1556
+ }
1557
+ };
1558
+ }
1559
+ const decoded =
1560
+ frame[3] === M6bServiceWireCommand.actorSend
1561
+ ? decodeActorSendCommand(frames, STATEFUL_MESSAGE_CONTEXT)
1562
+ : decodeActorRequestCommand(frames, STATEFUL_MESSAGE_CONTEXT);
1563
+ const source = decoded.sourceActor;
1564
+ return {
1565
+ kind: decoded.command,
1566
+ ...(decoded.command === 'actorRequest' ? { correlation: decoded.correlation } : {}),
1567
+ operation: decoded.operation,
1568
+ messageFollowHopCount: decoded.messageFollowHopCount,
1569
+ ...(source.actorId === null
1570
+ ? {}
1571
+ : {
1572
+ sourceActor: {
1573
+ nodeRid: '',
1574
+ actorId: source.actorId,
1575
+ generation: source.generation!
1576
+ }
1577
+ }),
1578
+ target: {
1579
+ actor: {
1580
+ nodeRid: fromGeneratedRoutingId(decoded.targetActor.targetNodeRid, 'targetNodeRid'),
1581
+ actorId: decoded.targetActor.actor.actorId,
1582
+ generation: decoded.targetActor.actor.objectGeneration
1583
+ },
1584
+ targetNodeGeneration: decoded.targetActor.targetNodeGeneration,
1585
+ authorityOwnerGeneration: decoded.targetActor.expectedAuthorityOwnerGeneration,
1586
+ ownerLeaseGeneration: decoded.targetActor.expectedOwnerLeaseGeneration
1587
+ },
1588
+ ...(decoded.boundSessionTail === undefined
1589
+ ? {}
1590
+ : {
1591
+ boundSession: {
1592
+ sessionRid: fromGeneratedRoutingId(
1593
+ decoded.boundSessionTail.sourceSessionRid,
1594
+ 'sourceSessionRid'
1595
+ ),
1596
+ bindingGeneration: decoded.boundSessionTail.sourceBindingGeneration,
1597
+ sequence: decoded.boundSessionTail.sourceSessionSequence
1598
+ }
1599
+ })
1600
+ };
1601
+ } catch (error) {
1602
+ throw new ServiceWireProtocolError(
1603
+ error instanceof Error ? error.message : 'Invalid stateful message.'
1604
+ );
1605
+ }
1476
1606
  }
1607
+ }
1608
+ const reader = new Reader(frame);
1609
+ const command = reader.prefix();
1610
+ switch (command.command) {
1477
1611
  case M6bServiceWireCommand.logicalMulticast: {
1478
1612
  requireFlags(command.flags, 0);
1479
1613
  const result = {
@@ -2124,20 +2258,6 @@ function actorAuthorityFence(value: ServiceBoundSessionActorAuthority): Buffer {
2124
2258
  );
2125
2259
  }
2126
2260
 
2127
- function spotFence(value: ServiceSpotRouteFence): Buffer {
2128
- return concat(
2129
- spotRef(value.spot),
2130
- rid(value.targetNodeRid, 'targetNodeRid'),
2131
- u64(value.targetNodeGeneration),
2132
- u64(value.authorityOwnerGeneration),
2133
- u64(value.ownerLeaseGeneration)
2134
- );
2135
- }
2136
-
2137
- function directSpotFence(value: ServiceDirectSpotRouteFence): Buffer {
2138
- return concat(spotFence(value), text16(value.storeVersion, 'storeVersion'));
2139
- }
2140
-
2141
2261
  function messageFollowRoute(value: ServiceMessageFollowRoute): Buffer {
2142
2262
  const body =
2143
2263
  value.kind === 'actor'
@@ -2205,12 +2325,6 @@ function actorRef(value: ServiceActorRef): Buffer {
2205
2325
  return concat(text8(value.actorId, 'actorId'), u64(value.generation));
2206
2326
  }
2207
2327
 
2208
- function optionalActor(value: ServiceActorRef | undefined): Buffer {
2209
- return value === undefined
2210
- ? Buffer.of(0)
2211
- : concat(text8(value.actorId, 'sourceActorId'), u64(value.generation));
2212
- }
2213
-
2214
2328
  function spotRef(value: ServiceSpotRef): Buffer {
2215
2329
  return concat(rid(value.spotId, 'spotId'), u64(value.generation));
2216
2330
  }
@@ -2409,20 +2523,6 @@ class Reader {
2409
2523
  };
2410
2524
  }
2411
2525
 
2412
- optionalActor(): ServiceActorRef | undefined {
2413
- const length = this.u8('sourceActorId.length');
2414
- if (length === 0) return undefined;
2415
- this.need(length, 'sourceActorId');
2416
- const bytes = this.bytes.subarray(this.offset, this.offset + length);
2417
- this.offset += length;
2418
- const actorId = decodeCanonicalServiceWireText(bytes, 'sourceActorId', fail);
2419
- return {
2420
- nodeRid: '',
2421
- actorId,
2422
- generation: this.nonZeroU64('sourceActorGeneration')
2423
- };
2424
- }
2425
-
2426
2526
  spotRef(): ServiceSpotRef {
2427
2527
  return {
2428
2528
  spotId: this.rid('spotId'),
@@ -2441,24 +2541,6 @@ class Reader {
2441
2541
  };
2442
2542
  }
2443
2543
 
2444
- spotFence(): ServiceSpotRouteFence {
2445
- const spot = this.spotRef();
2446
- return {
2447
- spot,
2448
- targetNodeRid: this.rid('targetNodeRid'),
2449
- targetNodeGeneration: this.nonZeroU64('targetNodeGeneration'),
2450
- authorityOwnerGeneration: this.nonZeroU64('authorityOwnerGeneration'),
2451
- ownerLeaseGeneration: this.nonZeroU64('ownerLeaseGeneration')
2452
- };
2453
- }
2454
-
2455
- directSpotFence(): ServiceDirectSpotRouteFence {
2456
- return {
2457
- ...this.spotFence(),
2458
- storeVersion: this.text16('storeVersion')
2459
- };
2460
- }
2461
-
2462
2544
  messageFollowRoute(name: string): ServiceMessageFollowRoute {
2463
2545
  const kind = this.u8(`${name}.objectKind`);
2464
2546
  const length = this.u16(`${name}.length`);
@@ -34,8 +34,9 @@ export interface ServiceNodeDescriptor {
34
34
 
35
35
  export interface AdmittedServicePeer {
36
36
  readonly descriptor: ServiceNodeDescriptor;
37
+ // The Core selected-route generation this admission belongs to (Core ROUTER
38
+ // §10.1), as an opaque token compared only for equality.
37
39
  readonly connectionId: string;
38
- readonly connectionDiscriminator: string;
39
40
  }
40
41
 
41
42
  export interface ServicePeerAdmissionExpectation {
@@ -98,13 +99,11 @@ export class ServiceTopologyRegistry {
98
99
  admit(
99
100
  descriptor: ServiceNodeDescriptor,
100
101
  connectionId: string,
101
- expected?: ServicePeerAdmissionExpectation,
102
- connectionDiscriminator = connectionId
102
+ expected?: ServicePeerAdmissionExpectation
103
103
  ): PeerAdmissionResult {
104
104
  try {
105
105
  validateDescriptor(descriptor);
106
106
  requireText(connectionId, 'connectionId');
107
- requireText(connectionDiscriminator, 'connectionDiscriminator');
108
107
  } catch (error) {
109
108
  return 'invalidDescriptor';
110
109
  }
@@ -146,34 +145,11 @@ export class ServiceTopologyRegistry {
146
145
  ) {
147
146
  return 'staleDescriptor';
148
147
  }
149
- if (
150
- current !== undefined &&
151
- current.descriptor.lifecycleGeneration === descriptor.lifecycleGeneration &&
152
- current.descriptor.descriptorRevision === descriptor.descriptorRevision &&
153
- sameServiceNodeDescriptor(current.descriptor, descriptor) &&
154
- current.connectionId !== connectionId &&
155
- // A fallback candidate is only a logical placeholder. Once the
156
- // monitor reports the physical connection, its evidence supersedes
157
- // candidate ordering so the request path uses the native route.
158
- !(
159
- isUnmonitoredConnectionId(current.connectionId) && !isUnmonitoredConnectionId(connectionId)
160
- ) &&
161
- compareConnectionCandidate(
162
- current.connectionDiscriminator,
163
- current.connectionId,
164
- connectionDiscriminator,
165
- connectionId
166
- ) <= 0
167
- ) {
168
- // Both manual directions can reach admission. The same comparison on
169
- // every retry keeps one physical candidate instead of replacing it in
170
- // arrival order.
171
- return 'staleDescriptor';
172
- }
148
+ // Core selects the one route per RID (Core ROUTER §10.1); an admission on
149
+ // that route replaces the admission of a route it replaced.
173
150
  this.peersByRid.set(descriptor.nodeRoutingId, {
174
151
  descriptor: cloneDescriptor(descriptor),
175
- connectionId,
176
- connectionDiscriminator
152
+ connectionId
177
153
  });
178
154
  this.remember(descriptor);
179
155
  this.rebuildSelections();
@@ -286,8 +262,7 @@ export class ServiceTopologyRegistry {
286
262
  () => {
287
263
  const local: AdmittedServicePeer = {
288
264
  descriptor: cloneDescriptor(this.local),
289
- connectionId: 'local',
290
- connectionDiscriminator: 'local'
265
+ connectionId: 'local'
291
266
  };
292
267
  return [local, ...this.peersByRid.values()]
293
268
  .map((peer) => ({
@@ -549,8 +524,7 @@ function cloneDescriptor(descriptor: ServiceNodeDescriptor): ServiceNodeDescript
549
524
  function clonePeer(peer: AdmittedServicePeer): AdmittedServicePeer {
550
525
  return {
551
526
  descriptor: cloneDescriptor(peer.descriptor),
552
- connectionId: peer.connectionId,
553
- connectionDiscriminator: peer.connectionDiscriminator
527
+ connectionId: peer.connectionId
554
528
  };
555
529
  }
556
530
 
@@ -582,20 +556,6 @@ function arraysEqual(left: readonly string[], right: readonly string[]): boolean
582
556
  return left.length === right.length && left.every((value, index) => value === right[index]);
583
557
  }
584
558
 
585
- function isUnmonitoredConnectionId(connectionId: string): boolean {
586
- return connectionId.startsWith('unmonitored:');
587
- }
588
-
589
- function compareConnectionCandidate(
590
- leftDiscriminator: string,
591
- leftId: string,
592
- rightDiscriminator: string,
593
- rightId: string
594
- ): number {
595
- const discriminator = compareOrdinal(leftDiscriminator, rightDiscriminator);
596
- return discriminator === 0 ? compareOrdinal(leftId, rightId) : discriminator;
597
- }
598
-
599
559
  function compareOrdinal(left: string, right: string): number {
600
560
  return left < right ? -1 : left > right ? 1 : 0;
601
561
  }