@zlink-systems/framework 0.19.0 → 0.21.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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Configuration/Builders.d.ts +0 -2
- package/dist/contracts/Configuration/Configs.d.ts +1 -0
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -2
- package/dist/contracts/Locations/Authority.d.ts +1 -7
- package/dist/runtime/actors/actor-authority-publication.js +25 -22
- package/dist/runtime/actors/actor-creation.js +30 -9
- package/dist/runtime/actors/actor-runtime-state.d.ts +3 -0
- package/dist/runtime/actors/index.d.ts +3 -0
- package/dist/runtime/actors/index.js +14 -3
- package/dist/runtime/admission.d.ts +2 -0
- package/dist/runtime/admission.js +11 -5
- package/dist/runtime/backend/contracts/index.d.ts +4 -1
- package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +1 -0
- package/dist/runtime/backend/node/node-mesh-backend-adapter.js +1 -1
- package/dist/runtime/backend/node/node-raw-binding-port.d.ts +2 -1
- package/dist/runtime/backend/node/node-raw-binding-port.js +12 -5
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +1 -1
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +6 -0
- package/dist/runtime/channels/channel-socket-options.js +7 -0
- package/dist/runtime/channels/channel-socket-registry.js +3 -0
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +1 -1
- package/dist/runtime/foundation/service-stateful-runtime.js +1 -5
- package/dist/runtime/host/actor-placement-coordinator.d.ts +14 -5
- package/dist/runtime/host/actor-placement-coordinator.js +159 -47
- package/dist/runtime/host/index.d.ts +2 -1
- package/dist/runtime/host/index.js +77 -120
- package/dist/runtime/host/location-runtime-owner.js +4 -2
- package/dist/runtime/host/remote-actor-join-receiver.js +12 -3
- package/dist/runtime/locations/creation-operation-id.d.ts +4 -0
- package/dist/runtime/locations/creation-operation-id.js +12 -0
- package/dist/runtime/locations/in-memory-authority-store.js +8 -22
- package/dist/runtime/locations/location-store-repository.js +36 -59
- package/dist/runtime/locations/opaque-record-key.d.ts +5 -0
- package/dist/runtime/locations/opaque-record-key.js +16 -0
- package/dist/runtime/locations/runtime.d.ts +7 -0
- package/dist/runtime/locations/runtime.js +130 -42
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +1672 -0
- package/dist/runtime/protocol/service_wire_codec.generated.js +9169 -0
- package/dist/runtime/spots/spot-node-runtime-manager.js +2 -2
- package/package.json +2 -2
- package/src/contracts/Configuration/Builders.ts +0 -2
- package/src/contracts/Configuration/Configs.ts +1 -0
- package/src/contracts/Configuration/RegistrationTypes.ts +1 -2
- package/src/contracts/Locations/Authority.ts +1 -8
- package/src/runtime/actors/actor-authority-publication.ts +25 -22
- package/src/runtime/actors/actor-creation.ts +45 -11
- package/src/runtime/actors/actor-runtime-state.ts +4 -0
- package/src/runtime/actors/index.ts +32 -4
- package/src/runtime/admission.ts +8 -5
- package/src/runtime/backend/contracts/index.ts +4 -1
- package/src/runtime/backend/node/node-mesh-backend-adapter.ts +2 -1
- package/src/runtime/backend/node/node-raw-binding-port.ts +16 -5
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +1 -1
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +7 -0
- package/src/runtime/channels/channel-socket-options.ts +9 -0
- package/src/runtime/channels/channel-socket-registry.ts +4 -0
- package/src/runtime/foundation/service-stateful-runtime.ts +2 -6
- package/src/runtime/host/actor-placement-coordinator.ts +216 -77
- package/src/runtime/host/index.ts +95 -135
- package/src/runtime/host/location-runtime-owner.ts +4 -2
- package/src/runtime/host/remote-actor-join-receiver.ts +15 -3
- package/src/runtime/locations/creation-operation-id.ts +11 -0
- package/src/runtime/locations/in-memory-authority-store.ts +7 -29
- package/src/runtime/locations/location-store-repository.ts +71 -69
- package/src/runtime/locations/opaque-record-key.ts +26 -0
- package/src/runtime/locations/runtime.ts +154 -60
- package/src/runtime/protocol/service_wire_codec.generated.ts +8302 -0
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +1 -1
- 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,
|
|
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',
|
|
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 >
|
|
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,
|
|
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
|
-
|
|
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.
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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/
|
|
2290
|
-
//
|
|
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)(
|
|
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
|
|
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)(
|
|
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
|
|
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)(
|
|
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
|
|
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)(
|
|
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
|
|
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)(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
2796
|
-
|
|
2797
|
-
operationId: { ...
|
|
2773
|
+
sourceNodeRid: operation.sourceNodeRid,
|
|
2774
|
+
sourceNodeGeneration: operation.sourceNodeGeneration,
|
|
2775
|
+
operationId: { ...operation.operationId }
|
|
2798
2776
|
},
|
|
2799
|
-
terminalEnvelope: Buffer.from(
|
|
2800
|
-
|
|
2801
|
-
|
|
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 >
|
|
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>;
|