@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
@@ -336,7 +336,8 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
336
336
  instanceSpot: call.instanceSpot,
337
337
  timeoutMs: deadline.requireRemaining(),
338
338
  signal: deadline.signal,
339
- metadata: call.metadata
339
+ metadata: call.metadata,
340
+ onAdmitted: call.onAdmitted
340
341
  }),
341
342
  deadline.signal
342
343
  );
@@ -416,7 +417,8 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
416
417
  encoded,
417
418
  deadlineUnixMs,
418
419
  call.sourceSpot === undefined ? undefined : String(call.sourceSpot.routingId),
419
- call.metadata
420
+ call.metadata,
421
+ call.onAdmitted
420
422
  ),
421
423
  deadline.signal
422
424
  );
@@ -333,6 +333,8 @@ export class ZLinkSpotRuntimeOptionsFactory {
333
333
  );
334
334
  },
335
335
  actorTransferRuntime,
336
+ releaseActorMembers: (meshName, spotId) =>
337
+ this.options.actorManager()?.releaseSpotActorMembers(meshName, spotId) ?? Promise.resolve(),
336
338
  boundSessionRuntime: this.options.boundSessionRelay.boundSessions,
337
339
  actorHandoffRuntime: this.options.actorHandoff,
338
340
  metrics: this.options.metrics,
@@ -12,6 +12,10 @@ import { ZLinkSpotKind } from '../../contracts/Spots';
12
12
  import { ZLinkLocationKeyCodec } from './key-codec';
13
13
  import { encodeAuthorityKey } from './authority-key-codec';
14
14
  import { routingIdsEqual } from '../routing-id';
15
+ import {
16
+ decodeActorAuthorityIdentity,
17
+ rewriteActorAuthorityRoute
18
+ } from '../actors/actor-authority-publication';
15
19
  import type { IZLinkLocationLifecycleRuntime, ZLinkOwnershipLostEvent } from './lifecycle-runtime';
16
20
 
17
21
  export enum ZLinkActorClaimStatus {
@@ -203,41 +207,59 @@ export class ZLinkActorLocationClaims {
203
207
  return { status: ZLinkActorClaimStatus.Claimed, claimed, generation: result.generation };
204
208
  }
205
209
 
206
- async notifyJoinedSpot(
210
+ async commitMembership(
207
211
  actorType: string,
208
- actorId: string,
209
- _spotMeshName: string,
212
+ actorRef: ActorRef,
213
+ authorityOwnerGeneration: bigint,
210
214
  spotId: RoutingId,
211
215
  spotGeneration: bigint,
212
- membershipEpoch: bigint,
216
+ spotKind: ZLinkSpotKind.Entry | ZLinkSpotKind.User,
213
217
  ownerNodeGeneration: bigint
214
218
  ): Promise<void> {
215
- await this.renew(actorType, actorId, (row) => ({
216
- ...row,
217
- spotKind: ZLinkSpotKind.User,
218
- spotId,
219
- spotGeneration,
220
- membershipEpoch,
221
- ownerNodeGeneration
222
- }));
223
- }
224
-
225
- async notifyLeftSpot(
226
- actorType: string,
227
- actorId: string,
228
- entrySpotId: RoutingId,
229
- entrySpotGeneration: bigint,
230
- membershipEpoch: bigint,
231
- ownerNodeGeneration: bigint
232
- ): Promise<void> {
233
- await this.renew(actorType, actorId, (row) => ({
234
- ...row,
235
- spotKind: ZLinkSpotKind.Entry,
236
- spotId: entrySpotId,
237
- spotGeneration: entrySpotGeneration,
238
- membershipEpoch,
239
- ownerNodeGeneration
240
- }));
219
+ const actorId = actorRef.actorId;
220
+ const store = this.authorityStore;
221
+ const owner = this.runtime.currentOwnerToken;
222
+ if (store === undefined || owner === undefined) {
223
+ throw new Error('Actor membership commit requires Location Store authority and owner.');
224
+ }
225
+ const key = encodeAuthorityKey('actor', actorId);
226
+ const current = await store.readAuthority(key);
227
+ if (
228
+ !matchesActorAuthority(current, actorRef, owner) ||
229
+ current.allocation.stableType !== actorType ||
230
+ current.authorityOwnerGeneration !== authorityOwnerGeneration ||
231
+ current.allocation.descriptorLifecycleGeneration !== ownerNodeGeneration
232
+ ) {
233
+ throw new Error(`Actor '${actorId}' membership authority fence does not match.`);
234
+ }
235
+ const identity = decodeActorAuthorityIdentity(current.payload, current.objectGeneration);
236
+ if (
237
+ identity === undefined ||
238
+ identity.actorType !== actorType ||
239
+ identity.ownerNodeGeneration !== ownerNodeGeneration ||
240
+ identity.owner.ownerId !== owner.ownerId ||
241
+ identity.owner.leaseGeneration !== owner.leaseGeneration ||
242
+ !routingIdsEqual(identity.actor.nodeRid, actorRef.nodeRid) ||
243
+ identity.meshName !== actorRef.meshName
244
+ ) {
245
+ throw new Error(`Actor '${actorId}' membership authority identity does not match.`);
246
+ }
247
+ const result = await store.compareExchangeAuthority(key, current.storeVersion, {
248
+ kind: 'put',
249
+ generationTransition: 'preserve',
250
+ payload: rewriteActorAuthorityRoute(
251
+ current.payload,
252
+ actorRef,
253
+ String(spotId),
254
+ spotGeneration,
255
+ spotKind
256
+ )
257
+ });
258
+ if (result.kind !== 'stored') {
259
+ throw new Error(
260
+ `Actor '${actorId}' membership commit was rejected with status ${result.kind}.`
261
+ );
262
+ }
241
263
  }
242
264
 
243
265
  async release(_actorType: string, actorId: string, actorRef?: ActorRef): Promise<void> {
@@ -118,40 +118,22 @@ export class ZLinkLocationLifecycle {
118
118
  );
119
119
  }
120
120
 
121
- async notifyActorJoinedSpot(
121
+ async commitActorMembership(
122
122
  actorType: string,
123
- actorId: string,
124
- spotMeshName: string,
123
+ actorRef: ActorRef,
124
+ authorityOwnerGeneration: bigint,
125
125
  spotId: RoutingId,
126
126
  spotGeneration: bigint,
127
- membershipEpoch: bigint,
127
+ spotKind: ZLinkSpotKind.Entry | ZLinkSpotKind.User,
128
128
  ownerNodeGeneration: bigint
129
129
  ): Promise<void> {
130
- await this.actorClaims.notifyJoinedSpot(
130
+ await this.actorClaims.commitMembership(
131
131
  actorType,
132
- actorId,
133
- spotMeshName,
132
+ actorRef,
133
+ authorityOwnerGeneration,
134
134
  spotId,
135
135
  spotGeneration,
136
- membershipEpoch,
137
- ownerNodeGeneration
138
- );
139
- }
140
-
141
- async notifyActorLeftSpot(
142
- actorType: string,
143
- actorId: string,
144
- entrySpotId: RoutingId,
145
- entrySpotGeneration: bigint,
146
- membershipEpoch: bigint,
147
- ownerNodeGeneration: bigint
148
- ): Promise<void> {
149
- await this.actorClaims.notifyLeftSpot(
150
- actorType,
151
- actorId,
152
- entrySpotId,
153
- entrySpotGeneration,
154
- membershipEpoch,
136
+ spotKind,
155
137
  ownerNodeGeneration
156
138
  );
157
139
  }
@@ -162,7 +162,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
162
162
  readonly name: string;
163
163
  }[];
164
164
  private readonly rewriteAuthorityPayloadForOwner?: ZLinkLocationRuntimeOptions['rewriteAuthorityPayloadForOwner'];
165
- private nextLeaseRenewAtMs?: number;
165
+ private leaseOperationStartedAtMs = 0;
166
166
  private ownerToken?: ZLinkLocationOwnerToken;
167
167
  private lastOwnerToken?: ZLinkLocationOwnerToken;
168
168
  private ownerLeaseDeadlineMs?: number;
@@ -342,12 +342,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
342
342
  const claim = this.renewOwnerLeaseOnce(signal, shutdownSignal);
343
343
  this.heartbeatRenewal = claim;
344
344
  try {
345
- const claimed = await claim;
346
- if (claimed) {
347
- this.scheduleHeartbeat();
348
- return;
349
- }
350
- this.nextLeaseRenewAtMs = this.monotonicNowMs() + this.options.ownerLeaseRenewIntervalMs;
345
+ await claim;
351
346
  this.scheduleHeartbeat();
352
347
  } catch (error) {
353
348
  this.started = false;
@@ -362,7 +357,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
362
357
  this.clearTimer(this.heartbeatTimer);
363
358
  this.heartbeatTimer = undefined;
364
359
  }
365
- this.nextLeaseRenewAtMs = undefined;
360
+ this.leaseOperationStartedAtMs = 0;
366
361
  this.ownerLeaseDeadlineMs = undefined;
367
362
  await this.cleanupOwner(signal);
368
363
  }
@@ -422,6 +417,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
422
417
  const wasOwnerLeaseUsable = this.ownerLeaseUsable;
423
418
  try {
424
419
  const renewStartedAtMs = this.monotonicNowMs();
420
+ this.leaseOperationStartedAtMs = renewStartedAtMs;
425
421
  const result = await withTimeout(
426
422
  (renewSignal) =>
427
423
  this.stores.ownerLeaseStore.renewOwnerLease(
@@ -475,10 +471,15 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
475
471
  shutdownSignal?: () => AbortSignal
476
472
  ): Promise<boolean> {
477
473
  const claimStartedAtMs = this.monotonicNowMs();
478
- const timeoutDeadline = performance.now() + this.options.ownerLeaseRenewTimeoutMs;
474
+ this.leaseOperationStartedAtMs = claimStartedAtMs;
475
+ const timeoutStartedAtMs = performance.now();
479
476
  let claim: Awaited<ReturnType<ZLinkOwnerLeaseStore['claimOwnerLease']>>;
480
477
  try {
481
- claim = await this.claimOwnerLeaseWithConfirmation(timeoutDeadline, signal, shutdownSignal);
478
+ claim = await this.claimOwnerLeaseWithConfirmation(
479
+ timeoutStartedAtMs,
480
+ signal,
481
+ shutdownSignal
482
+ );
482
483
  } catch (error) {
483
484
  if (signal?.aborted === true) throw error;
484
485
  if (error instanceof ZLinkOwnerLeaseClaimError) throw error;
@@ -508,7 +509,6 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
508
509
  claim.storeNow
509
510
  );
510
511
  this.lastError = undefined;
511
- this.nextLeaseRenewAtMs = this.monotonicNowMs() + this.options.ownerLeaseRenewIntervalMs;
512
512
  for (const handler of this.ownerLeaseRenewedHandlers) {
513
513
  handler({
514
514
  kind: 'renewed',
@@ -525,7 +525,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
525
525
  }
526
526
 
527
527
  private async claimOwnerLeaseWithConfirmation(
528
- timeoutDeadline: number,
528
+ timeoutStartedAtMs: number,
529
529
  signal?: AbortSignal,
530
530
  shutdownSignal?: () => AbortSignal
531
531
  ): Promise<Awaited<ReturnType<ZLinkOwnerLeaseStore['claimOwnerLease']>>> {
@@ -540,7 +540,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
540
540
  this.options.ownerLeaseTtlMs,
541
541
  claimSignal
542
542
  )),
543
- remainingTimeoutMs(timeoutDeadline),
543
+ remainingTimeoutMs(timeoutStartedAtMs, this.options.ownerLeaseRenewTimeoutMs),
544
544
  signal
545
545
  );
546
546
  } catch (error) {
@@ -550,7 +550,9 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
550
550
  try {
551
551
  await withTimeout(
552
552
  () => request!,
553
- cleanupSignal === undefined ? remainingTimeoutMs(timeoutDeadline) : undefined,
553
+ cleanupSignal === undefined
554
+ ? remainingTimeoutMs(timeoutStartedAtMs, this.options.ownerLeaseRenewTimeoutMs)
555
+ : undefined,
554
556
  cleanupSignal
555
557
  );
556
558
  } catch (completionError) {
@@ -567,7 +569,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
567
569
  }
568
570
  const confirmed = await this.confirmOwnerLease(
569
571
  error,
570
- timeoutDeadline,
572
+ timeoutStartedAtMs,
571
573
  signal,
572
574
  shutdownSignal
573
575
  );
@@ -577,13 +579,13 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
577
579
  if (claim.kind !== 'conflict') return claim;
578
580
  const conflict = new ZLinkOwnerLeaseClaimError(claim.kind);
579
581
  return (
580
- (await this.confirmOwnerLease(conflict, timeoutDeadline, signal, shutdownSignal)) ?? claim
582
+ (await this.confirmOwnerLease(conflict, timeoutStartedAtMs, signal, shutdownSignal)) ?? claim
581
583
  );
582
584
  }
583
585
 
584
586
  private async confirmOwnerLease(
585
587
  originalError: unknown,
586
- timeoutDeadline: number,
588
+ timeoutStartedAtMs: number,
587
589
  signal?: AbortSignal,
588
590
  shutdownSignal?: () => AbortSignal
589
591
  ): Promise<
@@ -593,7 +595,9 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
593
595
  const cancelled = signal?.aborted === true;
594
596
  const cleanupSignal = cancelled ? shutdownSignal?.() : undefined;
595
597
  const confirmationTimeoutMs =
596
- cleanupSignal === undefined ? remainingTimeoutMs(timeoutDeadline) : undefined;
598
+ cleanupSignal === undefined
599
+ ? remainingTimeoutMs(timeoutStartedAtMs, this.options.ownerLeaseRenewTimeoutMs)
600
+ : undefined;
597
601
  if (confirmationTimeoutMs !== undefined && confirmationTimeoutMs <= 0) throw originalError;
598
602
  let confirmed: Awaited<ReturnType<ZLinkOwnerLeaseStore['readOwnerLease']>>;
599
603
  try {
@@ -615,7 +619,9 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
615
619
  await withTimeout(
616
620
  (releaseSignal) =>
617
621
  this.stores.ownerLeaseStore.releaseOwnerLease(confirmed.token, releaseSignal),
618
- cleanupSignal === undefined ? remainingTimeoutMs(timeoutDeadline) : undefined,
622
+ cleanupSignal === undefined
623
+ ? remainingTimeoutMs(timeoutStartedAtMs, this.options.ownerLeaseRenewTimeoutMs)
624
+ : undefined,
619
625
  cleanupSignal
620
626
  );
621
627
  } catch (releaseError) {
@@ -1250,8 +1256,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
1250
1256
  if (!this.started) {
1251
1257
  return;
1252
1258
  }
1253
- const scheduledAt =
1254
- this.nextLeaseRenewAtMs ?? this.monotonicNowMs() + this.options.ownerLeaseRenewIntervalMs;
1259
+ const scheduledAt = this.leaseOperationStartedAtMs + this.options.ownerLeaseRenewIntervalMs;
1255
1260
  const delayMs = Math.max(0, scheduledAt - this.monotonicNowMs());
1256
1261
  this.heartbeatTimer = this.setTimer(() => {
1257
1262
  this.heartbeatTimer = undefined;
@@ -1259,7 +1264,6 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
1259
1264
  for (const scope of this.leaseScopes) {
1260
1265
  this.metrics?.recordOwnerLeaseRenewLateness(lateness, scope.kind, scope.name);
1261
1266
  }
1262
- this.nextLeaseRenewAtMs = this.monotonicNowMs() + this.options.ownerLeaseRenewIntervalMs;
1263
1267
  if (
1264
1268
  this.ownerLeaseDeadlineMs !== undefined &&
1265
1269
  this.monotonicNowMs() >= this.ownerLeaseDeadlineMs
@@ -1413,8 +1417,8 @@ class OwnerLeaseRenewTimeoutError extends Error {
1413
1417
  }
1414
1418
  }
1415
1419
 
1416
- function remainingTimeoutMs(timeoutDeadline: number): number {
1417
- return Math.max(0, timeoutDeadline - performance.now());
1420
+ function remainingTimeoutMs(timeoutStartedAtMs: number, timeoutMs: number): number {
1421
+ return Math.max(0, timeoutMs - (performance.now() - timeoutStartedAtMs));
1418
1422
  }
1419
1423
 
1420
1424
  function errorMessage(error: unknown): string {
@@ -1,326 +1,6 @@
1
- import type { ZLinkJsonSchema } from '../../contracts/Handlers/JsonContract';
1
+ import * as profile from '@zlink-systems/stream-wire/internal/json';
2
2
 
3
- export const FRAMEWORK_JSON_V1_PROFILE = 'framework-json-v1';
4
-
5
- const SIGNED_64_MIN = -(1n << 63n);
6
- const UNSIGNED_64_MAX = (1n << 64n) - 1n;
7
-
8
- export interface FrameworkJsonParseOptions {
9
- readonly rejectPropertyName?: (name: string) => boolean;
10
- }
11
-
12
- export function stringifyFrameworkJsonV1(value: unknown, schema?: ZLinkJsonSchema): string {
13
- if (value === undefined || typeof value === 'function' || typeof value === 'symbol') {
14
- throw new TypeError('framework-json-v1 payload is not a JSON value.');
15
- }
16
- const encoded = JSON.stringify(value, frameworkJsonV1Replacer);
17
- if (schema !== undefined) {
18
- validateFrameworkJsonV1Value(JSON.parse(encoded), schema, '$', false);
19
- }
20
- return encoded;
21
- }
22
-
23
- // Module-level so JSON.stringify does not allocate a fresh closure per
24
- // encoded message. On the root call `this` is the {'': value} wrapper, so
25
- // this[key] resolves the raw (pre-toJSON) source for every key including ''.
26
- function frameworkJsonV1Replacer(
27
- this: Record<string, unknown>,
28
- key: string,
29
- item: unknown
30
- ): unknown {
31
- const source = this[key];
32
- if (typeof source === 'number' && !Number.isFinite(source)) {
33
- throw new TypeError('framework-json-v1 only accepts finite JSON numbers.');
34
- }
35
- if (typeof source === 'bigint') {
36
- if (source < SIGNED_64_MIN || source > UNSIGNED_64_MAX) {
37
- throw new RangeError('framework-json-v1 64-bit integer is outside the supported range.');
38
- }
39
- return source.toString(10);
40
- }
41
- if (source instanceof Uint8Array) {
42
- return Buffer.from(source.buffer, source.byteOffset, source.byteLength).toString('base64');
43
- }
44
- if (source instanceof Date) {
45
- throw new TypeError('framework-json-v1 does not implicitly encode Date values.');
46
- }
47
- if (
48
- typeof source === 'object' &&
49
- source !== null &&
50
- typeof (source as { readonly toJSON?: unknown }).toJSON === 'function'
51
- ) {
52
- throw new TypeError('framework-json-v1 does not implicitly invoke custom toJSON methods.');
53
- }
54
- return item;
55
- }
56
-
57
- export function parseFrameworkJsonV1(
58
- text: string,
59
- options: FrameworkJsonParseOptions = {},
60
- schema?: ZLinkJsonSchema
61
- ): unknown {
62
- if (text.charCodeAt(0) === 0xfeff) {
63
- throw new SyntaxError('framework-json-v1 does not allow a UTF-8 BOM.');
64
- }
65
- new JsonPropertyScanner(text, options).scan();
66
- const parsed = JSON.parse(text);
67
- return schema === undefined ? parsed : validateFrameworkJsonV1Value(parsed, schema, '$', true);
68
- }
69
-
70
- // Sticky pattern shared across scans; matching happens synchronously so the
71
- // mutable lastIndex never crosses calls.
72
- const NUMBER_TOKEN_PATTERN = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/uy;
73
-
74
- const BASE64_PATTERN = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u;
75
- const INT32_MIN = -2_147_483_648;
76
- const INT32_MAX = 2_147_483_647;
77
- const UINT32_MAX = 4_294_967_295;
78
-
79
- function validateFrameworkJsonV1Value(
80
- value: unknown,
81
- schema: ZLinkJsonSchema,
82
- path: string,
83
- decode: boolean
84
- ): unknown {
85
- switch (schema.type) {
86
- case 'boolean':
87
- if (typeof value !== 'boolean') schemaFailure(path, 'a boolean');
88
- return value;
89
- case 'string':
90
- if (typeof value !== 'string') schemaFailure(path, 'a string');
91
- return value;
92
- case 'number':
93
- if (typeof value !== 'number' || !Number.isFinite(value))
94
- schemaFailure(path, 'a finite number');
95
- return value;
96
- case 'int32':
97
- if (
98
- !Number.isInteger(value) ||
99
- (value as number) < INT32_MIN ||
100
- (value as number) > INT32_MAX
101
- ) {
102
- schemaFailure(path, 'an int32 JSON number');
103
- }
104
- return value;
105
- case 'uint32':
106
- if (!Number.isInteger(value) || (value as number) < 0 || (value as number) > UINT32_MAX) {
107
- schemaFailure(path, 'a uint32 JSON number');
108
- }
109
- return value;
110
- case 'int64':
111
- return validateDecimalInteger(value, path, true, decode);
112
- case 'uint64':
113
- return validateDecimalInteger(value, path, false, decode);
114
- case 'bytes': {
115
- if (typeof value !== 'string' || !BASE64_PATTERN.test(value)) {
116
- schemaFailure(path, 'padded RFC 4648 base64');
117
- }
118
- const bytes = Buffer.from(value as string, 'base64');
119
- if (bytes.toString('base64') !== value)
120
- schemaFailure(path, 'canonical padded RFC 4648 base64');
121
- return decode ? Uint8Array.from(bytes) : value;
122
- }
123
- case 'enum':
124
- if (typeof value !== 'string' || !schema.names.includes(value)) {
125
- schemaFailure(path, `one of ${schema.names.join(', ')}`);
126
- }
127
- return value;
128
- case 'nullable':
129
- return value === null
130
- ? null
131
- : validateFrameworkJsonV1Value(value, schema.value, path, decode);
132
- case 'array':
133
- if (!Array.isArray(value)) schemaFailure(path, 'an array');
134
- return (value as unknown[]).map((item, index) =>
135
- validateFrameworkJsonV1Value(item, schema.items, `${path}[${index}]`, decode)
136
- );
137
- case 'record': {
138
- if (!isJsonObject(value)) schemaFailure(path, 'an object');
139
- const result: Record<string, unknown> = {};
140
- for (const [name, item] of Object.entries(value as Record<string, unknown>)) {
141
- result[name] = validateFrameworkJsonV1Value(item, schema.values, `${path}.${name}`, decode);
142
- }
143
- return decode ? result : value;
144
- }
145
- case 'object': {
146
- if (!isJsonObject(value)) schemaFailure(path, 'an object');
147
- const input = value as Record<string, unknown>;
148
- for (const name of schema.required) {
149
- if (!Object.prototype.hasOwnProperty.call(input, name)) {
150
- throw new TypeError(`framework-json-v1 required property '${path}.${name}' is missing.`);
151
- }
152
- }
153
- const result: Record<string, unknown> = {};
154
- for (const [name, item] of Object.entries(input)) {
155
- const propertySchema: unknown = schema.properties[name];
156
- if (propertySchema === undefined) {
157
- if (schema.additionalProperties === false) {
158
- throw new TypeError(`framework-json-v1 property '${path}.${name}' is not allowed.`);
159
- }
160
- continue;
161
- }
162
- result[name] = validateFrameworkJsonV1Value(
163
- item,
164
- propertySchema as ZLinkJsonSchema,
165
- `${path}.${name}`,
166
- decode
167
- );
168
- }
169
- return decode ? result : value;
170
- }
171
- }
172
- }
173
-
174
- function validateDecimalInteger(
175
- value: unknown,
176
- path: string,
177
- signed: boolean,
178
- decode: boolean
179
- ): unknown {
180
- if (typeof value !== 'string' || !/^(?:0|[1-9][0-9]*|-[1-9][0-9]*)$/u.test(value)) {
181
- schemaFailure(
182
- path,
183
- signed ? 'a canonical int64 decimal string' : 'a canonical uint64 decimal string'
184
- );
185
- }
186
- const parsed = BigInt(value as string);
187
- const minimum = signed ? SIGNED_64_MIN : 0n;
188
- const maximum = signed ? (1n << 63n) - 1n : UNSIGNED_64_MAX;
189
- if (parsed < minimum || parsed > maximum)
190
- schemaFailure(path, signed ? 'an int64 value' : 'a uint64 value');
191
- return decode ? parsed : value;
192
- }
193
-
194
- function isJsonObject(value: unknown): value is Record<string, unknown> {
195
- return typeof value === 'object' && value !== null && !Array.isArray(value);
196
- }
197
-
198
- function schemaFailure(path: string, expected: string): never {
199
- throw new TypeError(`framework-json-v1 value '${path}' must be ${expected}.`);
200
- }
201
-
202
- class JsonPropertyScanner {
203
- private index = 0;
204
-
205
- constructor(
206
- private readonly text: string,
207
- private readonly options: FrameworkJsonParseOptions
208
- ) {}
209
-
210
- scan(): void {
211
- this.skipWhitespace();
212
- this.scanValue();
213
- this.skipWhitespace();
214
- if (this.index !== this.text.length) this.fail('trailing data');
215
- }
216
-
217
- private scanValue(): void {
218
- this.skipWhitespace();
219
- const token = this.text[this.index];
220
- if (token === '{') return this.scanObject();
221
- if (token === '[') return this.scanArray();
222
- if (token === '"') {
223
- this.scanString();
224
- return;
225
- }
226
- if (token === 't') return this.scanLiteral('true');
227
- if (token === 'f') return this.scanLiteral('false');
228
- if (token === 'n') return this.scanLiteral('null');
229
- this.scanNumber();
230
- }
231
-
232
- private scanObject(): void {
233
- this.index++;
234
- this.skipWhitespace();
235
- if (this.text[this.index] === '}') {
236
- this.index++;
237
- return;
238
- }
239
- const properties = new Set<string>();
240
- for (;;) {
241
- this.skipWhitespace();
242
- if (this.text[this.index] !== '"') this.fail('object property name');
243
- const property = this.scanString();
244
- if (properties.has(property)) {
245
- throw new SyntaxError(`framework-json-v1 duplicate property '${property}'.`);
246
- }
247
- properties.add(property);
248
- if (this.options.rejectPropertyName?.(property) === true) {
249
- throw new SyntaxError(`framework-json-v1 property '${property}' is not allowed.`);
250
- }
251
- this.skipWhitespace();
252
- if (this.text[this.index] !== ':') this.fail("':' after object property");
253
- this.index++;
254
- this.scanValue();
255
- this.skipWhitespace();
256
- const delimiter = this.text[this.index++];
257
- if (delimiter === '}') return;
258
- if (delimiter !== ',') this.fail("',' or '}' after object property");
259
- }
260
- }
261
-
262
- private scanArray(): void {
263
- this.index++;
264
- this.skipWhitespace();
265
- if (this.text[this.index] === ']') {
266
- this.index++;
267
- return;
268
- }
269
- for (;;) {
270
- this.scanValue();
271
- this.skipWhitespace();
272
- const delimiter = this.text[this.index++];
273
- if (delimiter === ']') return;
274
- if (delimiter !== ',') this.fail("',' or ']' after array item");
275
- }
276
- }
277
-
278
- private scanString(): string {
279
- const start = this.index++;
280
- let sawEscape = false;
281
- for (;;) {
282
- if (this.index >= this.text.length) this.fail('unterminated string');
283
- const character = this.text[this.index++]!;
284
- if (character === '"') {
285
- // Without escapes the token content is verbatim; the outer
286
- // JSON.parse pass still rejects any raw control characters.
287
- return sawEscape
288
- ? (JSON.parse(this.text.slice(start, this.index)) as string)
289
- : this.text.slice(start + 1, this.index - 1);
290
- }
291
- if (character === '\\') {
292
- sawEscape = true;
293
- if (this.index >= this.text.length) this.fail('unterminated escape');
294
- const escaped = this.text[this.index++]!;
295
- if (escaped === 'u') this.index += 4;
296
- }
297
- }
298
- }
299
-
300
- private scanLiteral(value: 'true' | 'false' | 'null'): void {
301
- if (!this.text.startsWith(value, this.index)) this.fail(value);
302
- this.index += value.length;
303
- }
304
-
305
- private scanNumber(): void {
306
- NUMBER_TOKEN_PATTERN.lastIndex = this.index;
307
- const match = NUMBER_TOKEN_PATTERN.exec(this.text);
308
- if (match === null) this.fail('JSON value');
309
- this.index += match[0].length;
310
- }
311
-
312
- private skipWhitespace(): void {
313
- for (;;) {
314
- const code = this.text.charCodeAt(this.index);
315
- if (code === 0x20 || code === 0x09 || code === 0x0a || code === 0x0d) {
316
- this.index += 1;
317
- continue;
318
- }
319
- return;
320
- }
321
- }
322
-
323
- private fail(expected: string): never {
324
- throw new SyntaxError(`framework-json-v1 expected ${expected} at offset ${this.index}.`);
325
- }
326
- }
3
+ export const FRAMEWORK_JSON_V1_PROFILE = profile.FRAMEWORK_JSON_V1_PROFILE;
4
+ export const stringifyFrameworkJsonV1 = profile.stringifyFrameworkJsonV1;
5
+ export const parseFrameworkJsonV1 = profile.parseFrameworkJsonV1;
6
+ export type { FrameworkJsonParseOptions } from '@zlink-systems/stream-wire/internal/json';