@zlink-systems/framework 0.19.0 → 0.20.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 (70) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Configuration/Builders.d.ts +0 -2
  3. package/dist/contracts/Configuration/Configs.d.ts +1 -0
  4. package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -2
  5. package/dist/contracts/Locations/Authority.d.ts +1 -7
  6. package/dist/runtime/actors/actor-authority-publication.js +25 -22
  7. package/dist/runtime/actors/actor-creation.js +30 -9
  8. package/dist/runtime/actors/actor-runtime-state.d.ts +3 -0
  9. package/dist/runtime/actors/index.d.ts +3 -0
  10. package/dist/runtime/actors/index.js +14 -3
  11. package/dist/runtime/admission.d.ts +2 -0
  12. package/dist/runtime/admission.js +11 -5
  13. package/dist/runtime/backend/contracts/index.d.ts +4 -1
  14. package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +1 -0
  15. package/dist/runtime/backend/node/node-mesh-backend-adapter.js +1 -1
  16. package/dist/runtime/backend/node/node-raw-binding-port.d.ts +2 -1
  17. package/dist/runtime/backend/node/node-raw-binding-port.js +12 -5
  18. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +1 -1
  19. package/dist/runtime/backend/node/node-socket-backend-adapter.js +6 -0
  20. package/dist/runtime/channels/channel-socket-options.js +7 -0
  21. package/dist/runtime/channels/channel-socket-registry.js +3 -0
  22. package/dist/runtime/foundation/service-stateful-runtime.d.ts +1 -1
  23. package/dist/runtime/foundation/service-stateful-runtime.js +1 -5
  24. package/dist/runtime/host/actor-placement-coordinator.d.ts +14 -5
  25. package/dist/runtime/host/actor-placement-coordinator.js +159 -47
  26. package/dist/runtime/host/index.d.ts +2 -1
  27. package/dist/runtime/host/index.js +77 -120
  28. package/dist/runtime/host/location-runtime-owner.js +4 -2
  29. package/dist/runtime/host/remote-actor-join-receiver.js +12 -3
  30. package/dist/runtime/locations/creation-operation-id.d.ts +4 -0
  31. package/dist/runtime/locations/creation-operation-id.js +12 -0
  32. package/dist/runtime/locations/in-memory-authority-store.js +8 -22
  33. package/dist/runtime/locations/location-store-repository.js +36 -59
  34. package/dist/runtime/locations/opaque-record-key.d.ts +5 -0
  35. package/dist/runtime/locations/opaque-record-key.js +16 -0
  36. package/dist/runtime/locations/runtime.d.ts +7 -0
  37. package/dist/runtime/locations/runtime.js +130 -42
  38. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +1672 -0
  39. package/dist/runtime/protocol/service_wire_codec.generated.js +9169 -0
  40. package/dist/runtime/spots/spot-node-runtime-manager.js +2 -2
  41. package/package.json +2 -2
  42. package/src/contracts/Configuration/Builders.ts +0 -2
  43. package/src/contracts/Configuration/Configs.ts +1 -0
  44. package/src/contracts/Configuration/RegistrationTypes.ts +1 -2
  45. package/src/contracts/Locations/Authority.ts +1 -8
  46. package/src/runtime/actors/actor-authority-publication.ts +25 -22
  47. package/src/runtime/actors/actor-creation.ts +45 -11
  48. package/src/runtime/actors/actor-runtime-state.ts +4 -0
  49. package/src/runtime/actors/index.ts +32 -4
  50. package/src/runtime/admission.ts +8 -5
  51. package/src/runtime/backend/contracts/index.ts +4 -1
  52. package/src/runtime/backend/node/node-mesh-backend-adapter.ts +2 -1
  53. package/src/runtime/backend/node/node-raw-binding-port.ts +16 -5
  54. package/src/runtime/backend/node/node-raw-mesh-backend.ts +1 -1
  55. package/src/runtime/backend/node/node-socket-backend-adapter.ts +7 -0
  56. package/src/runtime/channels/channel-socket-options.ts +9 -0
  57. package/src/runtime/channels/channel-socket-registry.ts +4 -0
  58. package/src/runtime/foundation/service-stateful-runtime.ts +2 -6
  59. package/src/runtime/host/actor-placement-coordinator.ts +216 -77
  60. package/src/runtime/host/index.ts +95 -135
  61. package/src/runtime/host/location-runtime-owner.ts +4 -2
  62. package/src/runtime/host/remote-actor-join-receiver.ts +15 -3
  63. package/src/runtime/locations/creation-operation-id.ts +11 -0
  64. package/src/runtime/locations/in-memory-authority-store.ts +7 -29
  65. package/src/runtime/locations/location-store-repository.ts +71 -69
  66. package/src/runtime/locations/opaque-record-key.ts +26 -0
  67. package/src/runtime/locations/runtime.ts +154 -60
  68. package/src/runtime/protocol/service_wire_codec.generated.ts +8302 -0
  69. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +1 -1
  70. package/src/runtime/spots/spot-node-runtime-manager.ts +2 -2
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZLinkInMemoryAuthorityStore = void 0;
4
4
  const node_crypto_1 = require("node:crypto");
5
5
  const authority_key_codec_1 = require("./authority-key-codec");
6
+ const opaque_record_key_1 = require("./opaque-record-key");
6
7
  const MAX_GENERATION = 0x7fffffffffffffffn;
7
8
  const MAX_PAYLOAD_BYTES = 1024 * 1024;
8
9
  const CREATION_TERMINAL_RETENTION_MS = 5 * 60 * 1000;
@@ -278,7 +279,7 @@ class ZLinkInMemoryAuthorityStore {
278
279
  if (request.completion.kind === 'created') {
279
280
  validatePayload(request.completion.readyPayload);
280
281
  }
281
- const terminalRecord = validateTerminalForMutation(request.completion.terminal, request.completion.kind, request.reservationId, request.key.kind, this.now());
282
+ const terminalRecord = validateTerminalForMutation(request.completion.terminal, this.now());
282
283
  const existingTerminal = this.operationTerminals.get(creationOperationKey(terminalRecord.operation));
283
284
  if (existingTerminal !== undefined
284
285
  && existingTerminal.expiresAt.getTime() > this.now().getTime()) {
@@ -352,7 +353,7 @@ class ZLinkInMemoryAuthorityStore {
352
353
  this.operationTerminals.delete(key);
353
354
  return { kind: 'missing', storeNow: this.now() };
354
355
  }
355
- return { kind: 'found', record: copyTerminalRecord(record) };
356
+ return { kind: 'found', terminalEnvelope: Buffer.from(record.terminalEnvelope) };
356
357
  }
357
358
  creationTerminalAvailable(record) {
358
359
  const key = creationOperationKey(record.operation);
@@ -634,7 +635,7 @@ function validateCreationOperation(operation) {
634
635
  throw new TypeError('Creation terminal source node RID must contain 1..255 UTF-8 bytes without NUL.');
635
636
  }
636
637
  if (operation.sourceNodeGeneration < 1n
637
- || operation.sourceNodeGeneration > MAX_GENERATION
638
+ || operation.sourceNodeGeneration > MAX_U64
638
639
  || operation.operationId.high < 0n
639
640
  || operation.operationId.high > MAX_U64
640
641
  || operation.operationId.low < 0n
@@ -643,17 +644,12 @@ function validateCreationOperation(operation) {
643
644
  throw new RangeError('Creation terminal source generation and operation ID are invalid.');
644
645
  }
645
646
  }
646
- function validateTerminalForMutation(publication, state, reservationId, objectKind, storeNow) {
647
+ function validateTerminalForMutation(publication, storeNow) {
647
648
  if (publication === undefined)
648
649
  return undefined;
649
650
  validateCreationOperation(publication.operation);
650
- if (publication.terminalEnvelope.byteLength > MAX_PAYLOAD_BYTES
651
- || publication.terminalEnvelopeSha256.byteLength !== 32) {
652
- throw new RangeError('Creation terminal envelope must not exceed 1 MiB and requires a SHA-256 digest.');
653
- }
654
- const actualSha = (0, node_crypto_1.createHash)('sha256').update(publication.terminalEnvelope).digest();
655
- if (!(0, node_crypto_1.timingSafeEqual)(actualSha, Buffer.from(publication.terminalEnvelopeSha256))) {
656
- throw new TypeError('Creation terminal envelope SHA-256 does not match its bytes.');
651
+ if (publication.terminalEnvelope.byteLength > MAX_PAYLOAD_BYTES) {
652
+ throw new RangeError('Creation terminal envelope must not exceed 1 MiB.');
657
653
  }
658
654
  const deadlineMs = publication.operationDeadline.getTime();
659
655
  const expiresAtMs = deadlineMs + CREATION_TERMINAL_RETENTION_MS;
@@ -663,23 +659,14 @@ function validateTerminalForMutation(publication, state, reservationId, objectKi
663
659
  throw new RangeError('Creation terminal expiry must be the live operation deadline plus five minutes.');
664
660
  }
665
661
  return {
666
- state,
667
662
  operation: copyCreationOperation(publication.operation),
668
- reservationId: requireText(reservationId, 'creation reservation ID'),
669
- objectKind,
670
663
  terminalEnvelope: Buffer.from(publication.terminalEnvelope),
671
- terminalEnvelopeSha256: Buffer.from(publication.terminalEnvelopeSha256),
672
664
  expiresAt: new Date(expiresAtMs),
673
665
  storeNow: new Date(storeNow.getTime())
674
666
  };
675
667
  }
676
668
  function creationOperationKey(operation) {
677
- return [
678
- String(operation.sourceNodeRid),
679
- operation.sourceNodeGeneration.toString(),
680
- operation.operationId.high.toString(16).padStart(16, '0'),
681
- operation.operationId.low.toString(16).padStart(16, '0')
682
- ].join('\0');
669
+ return (0, opaque_record_key_1.creationTerminalPreimage)(operation);
683
670
  }
684
671
  function copyCreationOperation(operation) {
685
672
  return {
@@ -696,7 +683,6 @@ function copyTerminalRecord(record) {
696
683
  ...record,
697
684
  operation: copyCreationOperation(record.operation),
698
685
  terminalEnvelope: Buffer.from(record.terminalEnvelope),
699
- terminalEnvelopeSha256: Buffer.from(record.terminalEnvelopeSha256),
700
686
  expiresAt: new Date(record.expiresAt),
701
687
  storeNow: new Date(record.storeNow)
702
688
  };
@@ -7,6 +7,7 @@ const contracts_1 = require("../../contracts");
7
7
  const Locations_1 = require("../../contracts/Locations");
8
8
  const in_memory_location_store_1 = require("./in-memory-location-store");
9
9
  const in_memory_provider_location_store_1 = require("./in-memory-provider-location-store");
10
+ const opaque_record_key_1 = require("./opaque-record-key");
10
11
  const authority_key_codec_1 = require("./authority-key-codec");
11
12
  const aggregate_inventory_store_1 = require("./aggregate-inventory-store");
12
13
  const routing_id_1 = require("../routing-id");
@@ -840,7 +841,6 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
840
841
  capacity: cloneCapacity(request.capacity)
841
842
  };
842
843
  const record = {
843
- reservationId,
844
844
  snapshot: {
845
845
  payload: Buffer.from(request.creatingPayload),
846
846
  objectGeneration: generation,
@@ -909,14 +909,14 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
909
909
  return { kind: 'stale' };
910
910
  const record = decodeAuthorityRecord(current.value.bytes);
911
911
  if (record.terminal === 'committed'
912
- && record.reservationId === request.reservationId
912
+ && record.snapshot.pendingCreation === undefined
913
913
  && record.snapshot.allocation.state === 'active') {
914
914
  return {
915
915
  kind: 'alreadyCommitted',
916
916
  ready: authoritySnapshot(record.snapshot, current.value.version, current.value.storeNow)
917
917
  };
918
918
  }
919
- if (record.reservationId !== request.reservationId
919
+ if (record.snapshot.pendingCreation?.reservationId !== request.reservationId
920
920
  || current.value.version.value !== request.expectedStoreVersion
921
921
  || record.snapshot.allocation.state !== 'reserved'
922
922
  || !sameCreationTarget(record.snapshot, request.target)) {
@@ -937,7 +937,6 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
937
937
  ? emptyCapacityRecord()
938
938
  : decodeJson(capacityRead.value.bytes);
939
939
  const ready = {
940
- reservationId: request.reservationId,
941
940
  terminal: 'committed',
942
941
  snapshot: {
943
942
  ...record.snapshot,
@@ -985,7 +984,7 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
985
984
  if (current.kind === 'missing')
986
985
  return { kind: 'stale' };
987
986
  const record = decodeAuthorityRecord(current.value.bytes);
988
- if (record.reservationId !== request.reservationId
987
+ if (record.snapshot.pendingCreation?.reservationId !== request.reservationId
989
988
  || current.value.version.value !== request.expectedStoreVersion
990
989
  || record.snapshot.allocation.state !== 'reserved'
991
990
  || !sameCreationTarget(record.snapshot, request.target)) {
@@ -1047,13 +1046,13 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1047
1046
  if (existingTerminal.kind === 'found') {
1048
1047
  return {
1049
1048
  kind: 'alreadyCompleted',
1050
- terminal: reviveCreationTerminal(decodeJson(existingTerminal.value.bytes))
1049
+ terminal: retainedCreationTerminal(terminal.operation, existingTerminal.value.bytes, existingTerminal.value.expiresAt, existingTerminal.value.storeNow)
1051
1050
  };
1052
1051
  }
1053
1052
  if (current.kind === 'missing')
1054
1053
  return { kind: 'stale' };
1055
1054
  const record = decodeAuthorityRecord(current.value.bytes);
1056
- if (record.reservationId !== request.reservationId
1055
+ if (record.snapshot.pendingCreation?.reservationId !== request.reservationId
1057
1056
  || current.value.version.value !== request.expectedStoreVersion
1058
1057
  || record.snapshot.allocation.state !== 'reserved'
1059
1058
  || !sameCreationTarget(record.snapshot, request.target)) {
@@ -1088,7 +1087,6 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1088
1087
  kind: 'put',
1089
1088
  key: rowKey,
1090
1089
  bytes: encodeAuthorityRecord({
1091
- reservationId: request.reservationId,
1092
1090
  terminal: 'committed',
1093
1091
  snapshot: {
1094
1092
  ...record.snapshot,
@@ -1131,7 +1129,7 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1131
1129
  {
1132
1130
  kind: 'put',
1133
1131
  key: terminalRowKey,
1134
- bytes: encodeJson(terminalAtStore),
1132
+ bytes: terminalAtStore.terminalEnvelope,
1135
1133
  retentionMs
1136
1134
  }
1137
1135
  ]
@@ -1150,7 +1148,6 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1150
1148
  throw new Error('Actor creation completion did not return an authority row version.');
1151
1149
  }
1152
1150
  const readyRecord = decodeAuthorityRecord(encodeAuthorityRecord({
1153
- reservationId: request.reservationId,
1154
1151
  terminal: 'committed',
1155
1152
  snapshot: {
1156
1153
  ...record.snapshot,
@@ -1173,7 +1170,7 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1173
1170
  ? { kind: 'missing', storeNow: result.storeNow }
1174
1171
  : {
1175
1172
  kind: 'found',
1176
- record: reviveCreationTerminal(decodeJson(result.value.bytes))
1173
+ terminalEnvelope: Buffer.from(result.value.bytes)
1177
1174
  };
1178
1175
  }
1179
1176
  async claimOwnerLease(ownerId, leaseTtlMs, signal) {
@@ -1569,11 +1566,12 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1569
1566
  removed += 1n;
1570
1567
  continue;
1571
1568
  }
1572
- if (record.reservationId === undefined)
1569
+ const reservationId = record.snapshot.pendingCreation?.reservationId;
1570
+ if (reservationId === undefined)
1573
1571
  continue;
1574
1572
  const aborted = await this.abort({
1575
1573
  key: identity,
1576
- reservationId: record.reservationId,
1574
+ reservationId,
1577
1575
  expectedStoreVersion: current.value.version.value,
1578
1576
  target: {
1579
1577
  meshName: record.snapshot.allocation.descriptor.meshName,
@@ -2286,12 +2284,12 @@ function sha256Hex(bytes) {
2286
2284
  // literal NUL bytes -- the same scheme the opaque record store hashes with
2287
2285
  // SHA-256 to derive the Redis key -- so a runtime in one language can read a
2288
2286
  // record another language wrote. Not used for framework-internal-only rows
2289
- // (aggregate/capacity/creation-terminal/spot/actor/route), which stay on the
2290
- // legacy PREFIX scheme since they aren't part of the public opaque contract.
2287
+ // (aggregate/capacity/spot/actor/route), which stay on the legacy PREFIX
2288
+ // scheme since they aren't part of the public opaque contract.
2291
2289
  function ownerKey(ownerId) {
2292
- return (0, in_memory_provider_location_store_1.storeKey)(`owner-lease\0${requireNoNul(ownerId, 'OwnerId')}`);
2290
+ return (0, in_memory_provider_location_store_1.storeKey)((0, opaque_record_key_1.opaqueRecordPreimage)('owner-lease', requireNoNul(ownerId, 'OwnerId')));
2293
2291
  }
2294
- const AUTHORITY_PREIMAGE_PREFIX = 'authority\0';
2292
+ const AUTHORITY_PREIMAGE_PREFIX = `${(0, opaque_record_key_1.opaqueRecordPreimage)('authority')}\0`;
2295
2293
  function authorityKey(value) {
2296
2294
  return (0, in_memory_provider_location_store_1.storeKey)(authorityPreimage(value));
2297
2295
  }
@@ -2300,7 +2298,7 @@ function authorityPreimage(value) {
2300
2298
  // §2.3: Entry|User|Instance Spot kinds share one segment ("spot") -- one
2301
2299
  // Id has exactly one authority row regardless of spot kind.
2302
2300
  const segment = decoded.kind === 'actor' ? 'actor' : 'spot';
2303
- return `${AUTHORITY_PREIMAGE_PREFIX}${segment}\0${requireNoNul(decoded.globalId, 'Authority Id')}`;
2301
+ return (0, opaque_record_key_1.opaqueRecordPreimage)('authority', segment, requireNoNul(decoded.globalId, 'Authority Id'));
2304
2302
  }
2305
2303
  // Reverses authorityPreimage(): recovers the framework-internal zla1-encoded
2306
2304
  // ZLinkAuthorityKey contract value from a scanned opaque record's logical
@@ -2351,35 +2349,25 @@ function capacityKey(meshName, nodeRid) {
2351
2349
  }
2352
2350
  function creationTerminalKey(operation) {
2353
2351
  validateCreationOperation(operation);
2354
- return (0, in_memory_provider_location_store_1.storeKey)(`${PREFIX}creation-terminal:${[
2355
- String(operation.sourceNodeRid),
2356
- operation.sourceNodeGeneration.toString(),
2357
- operation.operationId.high.toString(16).padStart(16, '0'),
2358
- operation.operationId.low.toString(16).padStart(16, '0')
2359
- ].map(encodeURIComponent).join(':')}`);
2352
+ return (0, in_memory_provider_location_store_1.storeKey)((0, opaque_record_key_1.creationTerminalPreimage)(operation));
2360
2353
  }
2361
2354
  function meshPrefix(meshName) {
2362
- return `mesh-node\0${requireNoNul(meshName, 'MeshName')}\0`;
2355
+ return `${(0, opaque_record_key_1.opaqueRecordPreimage)('mesh-node', requireNoNul(meshName, 'MeshName'))}\0`;
2363
2356
  }
2364
2357
  function meshKey(meshName, nodeRid) {
2365
- return (0, in_memory_provider_location_store_1.storeKey)(`${meshPrefix(meshName)}${routingIdHexSegment(nodeRid)}`);
2358
+ return (0, in_memory_provider_location_store_1.storeKey)((0, opaque_record_key_1.opaqueRecordPreimage)('mesh-node', requireNoNul(meshName, 'MeshName'), (0, opaque_record_key_1.routingIdHexSegment)(nodeRid)));
2366
2359
  }
2367
2360
  function clientServerPrefix(channelName) {
2368
- return `client-server\0${requireNoNul(channelName, 'ChannelName')}\0`;
2361
+ return `${(0, opaque_record_key_1.opaqueRecordPreimage)('client-server', requireNoNul(channelName, 'ChannelName'))}\0`;
2369
2362
  }
2370
2363
  function clientServerKey(channelName, serverRid) {
2371
- return (0, in_memory_provider_location_store_1.storeKey)(`${clientServerPrefix(channelName)}${routingIdHexSegment(serverRid)}`);
2372
- }
2373
- // {hex(RoutingId)}: lowercase hex of the RoutingId's raw bytes
2374
- // (21-location-runtime.md#2.4).
2375
- function routingIdHexSegment(rid) {
2376
- return (0, routing_id_1.encodeRoutingIdStorageHex)(rid).toLowerCase();
2364
+ return (0, in_memory_provider_location_store_1.storeKey)((0, opaque_record_key_1.opaqueRecordPreimage)('client-server', requireNoNul(channelName, 'ChannelName'), (0, opaque_record_key_1.routingIdHexSegment)(serverRid)));
2377
2365
  }
2378
2366
  function fanoutPrefix(channelName) {
2379
- return `fanout-publisher\0${requireNoNul(channelName, 'ChannelName')}\0`;
2367
+ return `${(0, opaque_record_key_1.opaqueRecordPreimage)('fanout-publisher', requireNoNul(channelName, 'ChannelName'))}\0`;
2380
2368
  }
2381
2369
  function fanoutKey(channelName, publisherRid) {
2382
- return (0, in_memory_provider_location_store_1.storeKey)(`${fanoutPrefix(channelName)}${routingIdHexSegment(publisherRid)}`);
2370
+ return (0, in_memory_provider_location_store_1.storeKey)((0, opaque_record_key_1.opaqueRecordPreimage)('fanout-publisher', requireNoNul(channelName, 'ChannelName'), (0, opaque_record_key_1.routingIdHexSegment)(publisherRid)));
2383
2371
  }
2384
2372
  function spotKey(meshName, spotId) {
2385
2373
  return (0, in_memory_provider_location_store_1.storeKey)(`${PREFIX}spot:${encodeURIComponent(meshName)}:${encodeURIComponent(spotId)}`);
@@ -2651,8 +2639,6 @@ function encodeAuthorityRecord(record) {
2651
2639
  // These fields gate Node-only creation/aggregate recovery. They are absent
2652
2640
  // from normal authority values (including the golden vector), while the
2653
2641
  // interoperable envelope above remains byte-canonical.
2654
- if (record.reservationId !== undefined)
2655
- envelope.reservationId = record.reservationId;
2656
2642
  if (record.terminal !== undefined)
2657
2643
  envelope.terminal = record.terminal;
2658
2644
  if (record.aggregate !== undefined)
@@ -2670,7 +2656,6 @@ function decodeAuthorityRecord(bytes) {
2670
2656
  const pending = value.pendingCreation;
2671
2657
  const objectKind = runtimePlacementObjectKind(String(allocation.objectKind));
2672
2658
  return {
2673
- reservationId: typeof value.reservationId === 'string' ? value.reservationId : undefined,
2674
2659
  terminal: value.terminal,
2675
2660
  aggregate: value.aggregate === undefined
2676
2661
  ? undefined
@@ -2755,13 +2740,8 @@ function runtimeSpotPlacementObjectKind(kind) {
2755
2740
  function createTerminalRecord(request, now) {
2756
2741
  const publication = request.completion.terminal;
2757
2742
  validateCreationOperation(publication.operation);
2758
- if (publication.terminalEnvelope.byteLength > MAX_CREATION_TERMINAL_BYTES
2759
- || publication.terminalEnvelopeSha256.byteLength !== 32) {
2760
- throw new RangeError('Creation terminal envelope must not exceed 1 MiB and requires a SHA-256 digest.');
2761
- }
2762
- const actualSha = (0, node_crypto_1.createHash)('sha256').update(publication.terminalEnvelope).digest();
2763
- if (!(0, node_crypto_1.timingSafeEqual)(actualSha, Buffer.from(publication.terminalEnvelopeSha256))) {
2764
- throw new TypeError('Creation terminal envelope SHA-256 does not match its bytes.');
2743
+ if (publication.terminalEnvelope.byteLength > MAX_CREATION_TERMINAL_BYTES) {
2744
+ throw new RangeError('Creation terminal envelope must not exceed 1 MiB.');
2765
2745
  }
2766
2746
  const deadlineMs = publication.operationDeadline.getTime();
2767
2747
  const expiresAtMs = deadlineMs + CREATION_TERMINAL_RETENTION_MS;
@@ -2774,32 +2754,29 @@ function createTerminalRecord(request, now) {
2774
2754
  validatePayloadSize(request.completion.readyPayload, 'Actor ready payload');
2775
2755
  }
2776
2756
  return {
2777
- state: request.completion.kind,
2778
2757
  operation: {
2779
2758
  sourceNodeRid: publication.operation.sourceNodeRid,
2780
2759
  sourceNodeGeneration: publication.operation.sourceNodeGeneration,
2781
2760
  operationId: { ...publication.operation.operationId }
2782
2761
  },
2783
- reservationId: requireText(request.reservationId, 'creation reservation ID'),
2784
- objectKind: request.key.kind,
2785
2762
  terminalEnvelope: Buffer.from(publication.terminalEnvelope),
2786
- terminalEnvelopeSha256: Buffer.from(publication.terminalEnvelopeSha256),
2787
2763
  expiresAt: new Date(expiresAtMs),
2788
2764
  storeNow: new Date(now)
2789
2765
  };
2790
2766
  }
2791
- function reviveCreationTerminal(record) {
2767
+ function retainedCreationTerminal(operation, terminalEnvelope, expiresAt, storeNow) {
2768
+ if (expiresAt === undefined) {
2769
+ throw new Error('Retained creation terminal is missing its expiration.');
2770
+ }
2792
2771
  return {
2793
- ...record,
2794
2772
  operation: {
2795
- ...record.operation,
2796
- sourceNodeRid: String(record.operation.sourceNodeRid),
2797
- operationId: { ...record.operation.operationId }
2773
+ sourceNodeRid: operation.sourceNodeRid,
2774
+ sourceNodeGeneration: operation.sourceNodeGeneration,
2775
+ operationId: { ...operation.operationId }
2798
2776
  },
2799
- terminalEnvelope: Buffer.from(record.terminalEnvelope),
2800
- terminalEnvelopeSha256: Buffer.from(record.terminalEnvelopeSha256),
2801
- expiresAt: reviveDate(record.expiresAt),
2802
- storeNow: reviveDate(record.storeNow)
2777
+ terminalEnvelope: Buffer.from(terminalEnvelope),
2778
+ expiresAt: new Date(expiresAt),
2779
+ storeNow: new Date(storeNow)
2803
2780
  };
2804
2781
  }
2805
2782
  function validateCreationOperation(operation) {
@@ -2809,7 +2786,7 @@ function validateCreationOperation(operation) {
2809
2786
  throw new TypeError('Creation terminal source node RID must contain 1..255 UTF-8 bytes without NUL.');
2810
2787
  }
2811
2788
  if (operation.sourceNodeGeneration < 1n
2812
- || operation.sourceNodeGeneration > MAX_GENERATION
2789
+ || operation.sourceNodeGeneration > MAX_U64
2813
2790
  || operation.operationId.high < 0n
2814
2791
  || operation.operationId.high > MAX_U64
2815
2792
  || operation.operationId.low < 0n
@@ -0,0 +1,5 @@
1
+ import type { RoutingId } from '../../contracts/Common/CoreTypes';
2
+ import type { ZLinkCreationOperationIdentity } from './internal-location-contracts';
3
+ export declare function opaqueRecordPreimage(record: string, ...segments: readonly string[]): string;
4
+ export declare function creationTerminalPreimage(operation: ZLinkCreationOperationIdentity): string;
5
+ export declare function routingIdHexSegment(routingId: RoutingId): string;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.opaqueRecordPreimage = opaqueRecordPreimage;
4
+ exports.creationTerminalPreimage = creationTerminalPreimage;
5
+ exports.routingIdHexSegment = routingIdHexSegment;
6
+ const routing_id_1 = require("../routing-id");
7
+ function opaqueRecordPreimage(record, ...segments) {
8
+ return [record, ...segments].join('\0');
9
+ }
10
+ function creationTerminalPreimage(operation) {
11
+ return opaqueRecordPreimage('creation-terminal', routingIdHexSegment(operation.sourceNodeRid), operation.sourceNodeGeneration.toString(), operation.operationId.high.toString(16).padStart(16, '0')
12
+ + operation.operationId.low.toString(16).padStart(16, '0'));
13
+ }
14
+ function routingIdHexSegment(routingId) {
15
+ return (0, routing_id_1.encodeRoutingIdStorageHex)(routingId).toLowerCase();
16
+ }
@@ -57,6 +57,10 @@ export interface ZLinkLocationEventSink {
57
57
  export declare class ZLinkOwnerCleanupError extends Error {
58
58
  constructor(cause: unknown);
59
59
  }
60
+ export declare class ZLinkOwnerLeaseClaimError extends Error {
61
+ readonly kind: 'conflict' | 'generationExhausted';
62
+ constructor(kind: 'conflict' | 'generationExhausted');
63
+ }
60
64
  export declare class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
61
65
  readonly ownerId: string;
62
66
  private readonly options;
@@ -90,6 +94,7 @@ export declare class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
90
94
  get isStarted(): boolean;
91
95
  get nodeRid(): RoutingId | undefined;
92
96
  get currentOwnerToken(): ZLinkLocationOwnerToken | undefined;
97
+ closeOwnerLeaseAdmission(error: unknown): void;
93
98
  reclaimOwnerAuthorities(signal?: AbortSignal): Promise<void>;
94
99
  private readAllAuthorityEntries;
95
100
  addOwnershipLostHandler(handler: (event: ZLinkOwnershipLostEvent) => void): void;
@@ -103,6 +108,8 @@ export declare class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
103
108
  cleanupOwner(signal?: AbortSignal): Promise<void>;
104
109
  renewOwnerLeaseOnce(signal?: AbortSignal): Promise<boolean>;
105
110
  private claimFreshOwnerLease;
111
+ private claimOwnerLeaseWithConfirmation;
112
+ private confirmOwnerLease;
106
113
  private setOwnerLeaseDeadline;
107
114
  publishDraining(signal?: AbortSignal): Promise<boolean>;
108
115
  writeMeshNode(descriptor: Omit<ZLinkMeshNodeDescriptor, 'ownerId' | 'leaseGeneration' | 'updatedAt'>, intent: ZLinkLocationWriteIntent, signal?: AbortSignal): Promise<ZLinkLocationWriteResult>;