@zlink-systems/framework 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Channels/IZLinkFanoutClient.d.ts +0 -6
- package/dist/contracts/RouteMesh/RuntimeTopology.d.ts +8 -0
- package/dist/internal.d.ts +1 -0
- package/dist/internal.js +1 -0
- package/dist/runtime/activation-admission.d.ts +29 -0
- package/dist/runtime/activation-admission.js +61 -0
- package/dist/runtime/actors/actor-context.js +6 -6
- package/dist/runtime/actors/actor-handoff.d.ts +9 -3
- package/dist/runtime/actors/actor-handoff.js +28 -17
- package/dist/runtime/actors/actor-local-native-join.js +2 -18
- package/dist/runtime/actors/actor-remote-joiner.d.ts +2 -2
- package/dist/runtime/actors/actor-remote-joiner.js +6 -8
- package/dist/runtime/actors/actor-runtime-contracts.d.ts +4 -2
- package/dist/runtime/actors/actor-source-transfer.d.ts +5 -5
- package/dist/runtime/actors/deferred-join-completion.d.ts +14 -0
- package/dist/runtime/actors/deferred-join-completion.js +20 -0
- package/dist/runtime/actors/index.d.ts +1 -1
- package/dist/runtime/actors/index.js +15 -5
- package/dist/runtime/admission.d.ts +5 -1
- package/dist/runtime/admission.js +4 -0
- package/dist/runtime/backend/contracts/index.d.ts +2 -10
- package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -9
- package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +1 -2
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +4 -18
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +6 -3
- package/dist/runtime/backend/node/node-backend-adapter-support.js +12 -28
- package/dist/runtime/backend/node/node-event-loop-poller.d.ts +1 -1
- package/dist/runtime/backend/node/node-event-loop-poller.js +8 -2
- package/dist/runtime/backend/node/node-raw-binding-port.d.ts +1 -1
- package/dist/runtime/backend/node/node-raw-binding-port.js +11 -3
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +12 -9
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +61 -29
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +1 -1
- package/dist/runtime/backend/raw-binding-port.d.ts +12 -0
- package/dist/runtime/channels/channel-clients.d.ts +0 -1
- package/dist/runtime/channels/channel-clients.js +0 -8
- package/dist/runtime/channels/channel-outbound-operations.js +2 -10
- package/dist/runtime/channels/channel-runtime-manager.d.ts +2 -5
- package/dist/runtime/channels/channel-runtime-manager.js +1 -12
- package/dist/runtime/channels/channel-socket-registry.d.ts +17 -4
- package/dist/runtime/channels/channel-socket-registry.js +49 -62
- package/dist/runtime/channels/channel-transports.d.ts +0 -3
- package/dist/runtime/channels/fanout-location-runtime.js +3 -9
- package/dist/runtime/execution/index.d.ts +18 -8
- package/dist/runtime/execution/index.js +55 -29
- package/dist/runtime/execution/serial-execution-queue.d.ts +5 -6
- package/dist/runtime/execution/serial-execution-queue.js +49 -15
- package/dist/runtime/foundation/listener-records.d.ts +11 -0
- package/dist/runtime/foundation/listener-records.js +20 -0
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +10 -21
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +66 -392
- package/dist/runtime/foundation/service-authority-payload-codec.d.ts +1 -0
- package/dist/runtime/foundation/service-authority-payload-codec.js +8 -0
- package/dist/runtime/foundation/service-maintenance-runtime.js +23 -2
- package/dist/runtime/foundation/service-relocation-coordinator.d.ts +9 -0
- package/dist/runtime/foundation/service-relocation-coordinator.js +14 -1
- package/dist/runtime/foundation/service-relocation-object-owner.d.ts +8 -0
- package/dist/runtime/foundation/service-relocation-object-owner.js +16 -4
- package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +6 -13
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +10 -7
- package/dist/runtime/foundation/service-stateful-runtime.js +100 -60
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +9 -4
- package/dist/runtime/foundation/service-stateful-wire-codec.js +153 -90
- package/dist/runtime/foundation/service-topology-registry.d.ts +1 -2
- package/dist/runtime/foundation/service-topology-registry.js +6 -30
- package/dist/runtime/host/actor-transfer-runtime.d.ts +17 -15
- package/dist/runtime/host/actor-transfer-runtime.js +73 -86
- package/dist/runtime/host/index.d.ts +6 -2
- package/dist/runtime/host/index.js +63 -37
- package/dist/runtime/host/remote-bound-session-relay.js +4 -3
- package/dist/runtime/host/route-mesh-runtime.d.ts +2 -0
- package/dist/runtime/host/route-mesh-runtime.js +7 -5
- package/dist/runtime/host/service-relocation-host-runtime.d.ts +50 -8
- package/dist/runtime/host/service-relocation-host-runtime.js +343 -270
- package/dist/runtime/host/spot-runtime-options-factory.d.ts +7 -4
- package/dist/runtime/host/spot-runtime-options-factory.js +4 -8
- package/dist/runtime/host/stateful-authority-route-runtime.js +6 -2
- package/dist/runtime/host/user-spot-creation-coordinator.d.ts +11 -3
- package/dist/runtime/host/user-spot-creation-coordinator.js +85 -87
- package/dist/runtime/locations/in-memory-provider-location-store.js +8 -6
- package/dist/runtime/locations/lifecycle.d.ts +1 -1
- package/dist/runtime/locations/lifecycle.js +2 -2
- package/dist/runtime/locations/resolvers.js +7 -2
- package/dist/runtime/locations/spot-location-claims.d.ts +2 -2
- package/dist/runtime/locations/spot-location-claims.js +3 -27
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +1 -0
- package/dist/runtime/protocol/service_wire_codec.generated.js +5 -1
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +1 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +3 -2
- package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +3 -3
- package/dist/runtime/spots/formal-remote-actor-admission-registry.js +4 -4
- package/dist/runtime/spots/formal-remote-actor-transfer-registry.d.ts +3 -3
- package/dist/runtime/spots/index.d.ts +25 -19
- package/dist/runtime/spots/index.js +207 -205
- package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
- package/dist/runtime/spots/spot-activation-registry.js +34 -31
- package/dist/runtime/spots/spot-activation-state.d.ts +2 -11
- package/dist/runtime/spots/spot-activation-state.js +4 -17
- package/dist/runtime/spots/spot-activation.d.ts +8 -6
- package/dist/runtime/spots/spot-activation.js +54 -49
- package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -1
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +1 -1
- package/dist/runtime/spots/spot-actor-join-dispatch.d.ts +2 -2
- package/dist/runtime/spots/spot-actor-join-dispatch.js +3 -5
- package/dist/runtime/spots/spot-actor-lifecycle-drain.js +2 -2
- package/dist/runtime/spots/spot-actor-membership.d.ts +4 -0
- package/dist/runtime/spots/spot-actor-membership.js +26 -12
- package/dist/runtime/spots/spot-entry-activation.d.ts +1 -2
- package/dist/runtime/spots/spot-entry-activation.js +0 -1
- package/dist/runtime/spots/spot-manager-public.js +1 -1
- package/dist/runtime/spots/spot-native-actor-join-admission.d.ts +1 -1
- package/dist/runtime/spots/spot-native-actor-join-admission.js +2 -2
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +5 -5
- package/dist/runtime/spots/spot-node-runtime-manager.js +7 -11
- package/dist/runtime/spots/spot-outbound.js +1 -29
- package/dist/runtime/spots/spot-routed-actor-admission.d.ts +1 -0
- package/dist/runtime/spots/spot-routed-actor-admission.js +10 -0
- package/dist/runtime/spots/spot-routed-frame-dispatch.d.ts +2 -6
- package/dist/runtime/spots/spot-routed-frame-dispatch.js +2 -70
- package/dist/runtime/spots/spot-runtime-ports.d.ts +3 -5
- package/dist/runtime/spots/spot-serial-executor.d.ts +5 -0
- package/dist/runtime/spots/spot-serial-executor.js +8 -1
- package/dist/runtime/spots/spot-serial-turn-executor.d.ts +3 -0
- package/dist/runtime/spots/spot-serial-turn-executor.js +8 -4
- package/dist/runtime/streams/actor-session-binding-registry.d.ts +13 -15
- package/dist/runtime/streams/actor-session-binding-registry.js +19 -171
- package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +3 -4
- package/dist/runtime/streams/bound-session-service.js +1 -18
- package/dist/runtime/streams/index.d.ts +2 -0
- package/dist/runtime/streams/index.js +19 -19
- package/dist/runtime/streams/session-serial-executor.js +2 -2
- package/package.json +3 -3
- package/src/contracts/Channels/IZLinkFanoutClient.ts +0 -7
- package/src/contracts/RouteMesh/RuntimeTopology.ts +10 -0
- package/src/internal.ts +1 -0
- package/src/runtime/activation-admission.ts +78 -0
- package/src/runtime/actors/actor-context.ts +6 -6
- package/src/runtime/actors/actor-handoff.ts +31 -23
- package/src/runtime/actors/actor-local-native-join.ts +3 -42
- package/src/runtime/actors/actor-remote-joiner.ts +6 -25
- package/src/runtime/actors/actor-runtime-contracts.ts +4 -10
- package/src/runtime/actors/actor-source-transfer.ts +5 -18
- package/src/runtime/actors/deferred-join-completion.ts +40 -0
- package/src/runtime/actors/index.ts +22 -9
- package/src/runtime/admission.ts +5 -1
- package/src/runtime/backend/contracts/index.ts +2 -13
- package/src/runtime/backend/mesh-actor-session-node-adapter.ts +2 -10
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +5 -25
- package/src/runtime/backend/node/node-backend-adapter-support.ts +9 -29
- package/src/runtime/backend/node/node-event-loop-poller.ts +14 -2
- package/src/runtime/backend/node/node-raw-binding-port.ts +17 -3
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +65 -32
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +2 -2
- package/src/runtime/backend/raw-binding-port.ts +13 -0
- package/src/runtime/channels/channel-clients.ts +0 -11
- package/src/runtime/channels/channel-outbound-operations.ts +3 -11
- package/src/runtime/channels/channel-runtime-manager.ts +4 -15
- package/src/runtime/channels/channel-socket-registry.ts +69 -71
- package/src/runtime/channels/channel-transports.ts +0 -3
- package/src/runtime/channels/fanout-location-runtime.ts +4 -16
- package/src/runtime/execution/index.ts +68 -30
- package/src/runtime/execution/serial-execution-queue.ts +52 -20
- package/src/runtime/foundation/listener-records.ts +21 -0
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +66 -466
- package/src/runtime/foundation/service-authority-payload-codec.ts +10 -0
- package/src/runtime/foundation/service-maintenance-runtime.ts +30 -9
- package/src/runtime/foundation/service-relocation-coordinator.ts +13 -0
- package/src/runtime/foundation/service-relocation-object-owner.ts +18 -5
- package/src/runtime/foundation/service-session-binding-ingress-port.ts +6 -14
- package/src/runtime/foundation/service-stateful-runtime.ts +151 -89
- package/src/runtime/foundation/service-stateful-wire-codec.ts +203 -121
- package/src/runtime/foundation/service-topology-registry.ts +8 -48
- package/src/runtime/host/actor-transfer-runtime.ts +94 -166
- package/src/runtime/host/index.ts +119 -54
- package/src/runtime/host/remote-bound-session-relay.ts +4 -3
- package/src/runtime/host/route-mesh-runtime.ts +9 -5
- package/src/runtime/host/service-relocation-host-runtime.ts +495 -376
- package/src/runtime/host/spot-runtime-options-factory.ts +24 -13
- package/src/runtime/host/stateful-authority-route-runtime.ts +8 -4
- package/src/runtime/host/user-spot-creation-coordinator.ts +147 -142
- package/src/runtime/locations/in-memory-provider-location-store.ts +11 -7
- package/src/runtime/locations/lifecycle.ts +3 -2
- package/src/runtime/locations/resolvers.ts +19 -13
- package/src/runtime/locations/spot-location-claims.ts +5 -34
- package/src/runtime/protocol/service_wire_codec.generated.ts +9 -2
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +6 -6
- package/src/runtime/spots/formal-remote-actor-transfer-registry.ts +3 -3
- package/src/runtime/spots/index.ts +341 -295
- package/src/runtime/spots/spot-activation-registry.ts +41 -31
- package/src/runtime/spots/spot-activation-state.ts +4 -16
- package/src/runtime/spots/spot-activation.ts +102 -80
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +2 -2
- package/src/runtime/spots/spot-actor-join-dispatch.ts +6 -7
- package/src/runtime/spots/spot-actor-lifecycle-drain.ts +20 -18
- package/src/runtime/spots/spot-actor-membership.ts +81 -17
- package/src/runtime/spots/spot-entry-activation.ts +0 -3
- package/src/runtime/spots/spot-manager-public.ts +8 -4
- package/src/runtime/spots/spot-native-actor-join-admission.ts +2 -2
- package/src/runtime/spots/spot-node-runtime-manager.ts +12 -18
- package/src/runtime/spots/spot-outbound.ts +4 -47
- package/src/runtime/spots/spot-routed-actor-admission.ts +20 -0
- package/src/runtime/spots/spot-routed-frame-dispatch.ts +6 -76
- package/src/runtime/spots/spot-runtime-ports.ts +6 -17
- package/src/runtime/spots/spot-serial-executor.ts +9 -1
- package/src/runtime/spots/spot-serial-turn-executor.ts +10 -4
- package/src/runtime/streams/actor-session-binding-registry.ts +20 -308
- package/src/runtime/streams/actor-session-binding-runtime-owner.ts +2 -12
- package/src/runtime/streams/bound-session-service.ts +2 -36
- package/src/runtime/streams/index.ts +29 -27
- package/src/runtime/streams/session-serial-executor.ts +2 -2
- package/dist/runtime/actors/deferred-join-accepted-journal.d.ts +0 -47
- package/dist/runtime/actors/deferred-join-accepted-journal.js +0 -992
- package/src/runtime/actors/deferred-join-accepted-journal.ts +0 -1346
|
@@ -1,992 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ZLinkDeferredJoinAcceptedJournal = void 0;
|
|
4
|
-
exports.isDeferredJoinAcceptedRootPublication = isDeferredJoinAcceptedRootPublication;
|
|
5
|
-
const node_crypto_1 = require("node:crypto");
|
|
6
|
-
const contracts_1 = require("../../contracts");
|
|
7
|
-
const authority_key_codec_1 = require("../locations/authority-key-codec");
|
|
8
|
-
const service_relocation_runtime_1 = require("../foundation/service-relocation-runtime");
|
|
9
|
-
const relocation_blob_1 = require("../locations/relocation-blob");
|
|
10
|
-
const routing_id_1 = require("../routing-id");
|
|
11
|
-
const actor_authority_publication_1 = require("./actor-authority-publication");
|
|
12
|
-
const actor_authority_payload_codec_1 = require("./actor-authority-payload-codec");
|
|
13
|
-
const runtime_message_1 = require("../backend/runtime-message");
|
|
14
|
-
const payload_codec_1 = require("../messaging/payload-codec");
|
|
15
|
-
const service_wire_pilot_codec_generated_1 = require("../protocol/service_wire_pilot_codec.generated");
|
|
16
|
-
const RETENTION_MS = 24 * 60 * 60 * 1_000;
|
|
17
|
-
const ROOT_VERSION = 2;
|
|
18
|
-
const ROOT_MAGIC = Buffer.from('ZLJR');
|
|
19
|
-
const JOURNAL_INVENTORY_DOMAIN = Buffer.from('zlink-node-deferred-join-authority-v1\0', 'utf8');
|
|
20
|
-
/** Identifies whether an authority slot points at a deferred Join journal root. */
|
|
21
|
-
async function isDeferredJoinAcceptedRootPublication(relocation, reference, checksumCrc32c, expected, signal) {
|
|
22
|
-
if (expected.objectKind !== 'actor' || expected.aggregateGeneration === 0n)
|
|
23
|
-
return false;
|
|
24
|
-
const read = await relocation.read({ value: reference }, signal);
|
|
25
|
-
if (read.kind !== 'found' || (0, service_relocation_runtime_1.crc32c)(read.bytes) !== checksumCrc32c)
|
|
26
|
-
return false;
|
|
27
|
-
if (hasJournalRootMagic(read.bytes)) {
|
|
28
|
-
try {
|
|
29
|
-
const root = decodeRoot(read.bytes);
|
|
30
|
-
return (expected.aggregateId === operationAggregateId(root.operationId) &&
|
|
31
|
-
expected.aggregateGeneration === root.actor.objectGeneration &&
|
|
32
|
-
expected.authorityKey === (0, authority_key_codec_1.encodeAuthorityKey)('actor', root.actor.actorId).value &&
|
|
33
|
-
expected.objectGeneration === root.actor.objectGeneration);
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
const root = await readCanonicalDeferredJoinRoot(relocation, read.bytes, signal);
|
|
40
|
-
return (root !== undefined &&
|
|
41
|
-
root.identity.aggregateId === expected.aggregateId &&
|
|
42
|
-
root.identity.aggregateGeneration === expected.aggregateGeneration &&
|
|
43
|
-
root.identity.authorityKey === expected.authorityKey &&
|
|
44
|
-
root.identity.objectKind === expected.objectKind &&
|
|
45
|
-
root.identity.objectGeneration === expected.objectGeneration);
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Keeps a cross-node Accepted Join completion under the Actor authority.
|
|
49
|
-
* Every cursor transition writes and verifies a new immutable root before the
|
|
50
|
-
* authority CAS. A failed callback leaves the committed root available for the
|
|
51
|
-
* next target Actor mailbox retry.
|
|
52
|
-
*/
|
|
53
|
-
class ZLinkDeferredJoinAcceptedJournal {
|
|
54
|
-
authority;
|
|
55
|
-
relocation;
|
|
56
|
-
messageSerializers;
|
|
57
|
-
constructor(authority, relocation, messageSerializers) {
|
|
58
|
-
this.authority = authority;
|
|
59
|
-
this.relocation = relocation;
|
|
60
|
-
this.messageSerializers = messageSerializers;
|
|
61
|
-
}
|
|
62
|
-
async prepare(actorId, operationId, actor, rawReply, replyContentType, signal, canonicalInventoryDigest) {
|
|
63
|
-
validateIdentity(actorId, operationId, actor);
|
|
64
|
-
if (replyContentType !== undefined && replyContentType.length === 0) {
|
|
65
|
-
throw new TypeError('Deferred Join reply content type must be non-empty.');
|
|
66
|
-
}
|
|
67
|
-
signal?.throwIfAborted();
|
|
68
|
-
const key = (0, authority_key_codec_1.encodeAuthorityKey)('actor', actorId);
|
|
69
|
-
const read = await this.authority.readAuthority(key, signal);
|
|
70
|
-
if (read.kind !== 'snapshot') {
|
|
71
|
-
throw new Error(`Actor '${actorId}' has no authority for durable Join completion.`);
|
|
72
|
-
}
|
|
73
|
-
requireAuthorityActor(read.payload, actor);
|
|
74
|
-
const existing = await this.readPublished(read, signal);
|
|
75
|
-
if (existing !== undefined) {
|
|
76
|
-
if (isSameOperation(existing, operationId, actor)) {
|
|
77
|
-
return existing;
|
|
78
|
-
}
|
|
79
|
-
if (existing.cursor !== 'delivered') {
|
|
80
|
-
requireSameOperation(existing, operationId, actor);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
const rootValue = {
|
|
84
|
-
operationId,
|
|
85
|
-
actor,
|
|
86
|
-
rawReply: Buffer.from(rawReply),
|
|
87
|
-
...(replyContentType === undefined ? {} : { replyContentType }),
|
|
88
|
-
cursor: 'prepared'
|
|
89
|
-
};
|
|
90
|
-
const initialPublication = decodeAuthorityPublication(read.payload);
|
|
91
|
-
const initialCanonicalIdentity = (0, service_relocation_runtime_1.serviceRelocationAuthoritySlotIdentity)(read.payload);
|
|
92
|
-
const canonicalPublication = initialPublication?.canonical === true ? initialPublication : undefined;
|
|
93
|
-
const root = canonicalPublication !== undefined &&
|
|
94
|
-
(canonicalInventoryDigest !== undefined ||
|
|
95
|
-
!canonicalPublication.reference.value.startsWith('zlink-direct:'))
|
|
96
|
-
? await this.storeCanonicalRoot(rootValue, read, canonicalPublication, signal, canonicalInventoryDigest)
|
|
97
|
-
: await this.storeRoot(rootValue, signal);
|
|
98
|
-
if (initialCanonicalIdentity !== undefined && canonicalInventoryDigest !== undefined) {
|
|
99
|
-
return {
|
|
100
|
-
...root,
|
|
101
|
-
authority: read
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
let expected = read;
|
|
105
|
-
for (let attempt = 0; attempt < 3; attempt++) {
|
|
106
|
-
const currentPublication = decodeAuthorityPublication(expected.payload);
|
|
107
|
-
const canonicalIdentity = (0, service_relocation_runtime_1.serviceRelocationAuthoritySlotIdentity)(expected.payload);
|
|
108
|
-
const publication = {
|
|
109
|
-
applicationPayload: Buffer.from(currentPublication?.applicationPayload ??
|
|
110
|
-
(0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(expected.payload)),
|
|
111
|
-
reference: root.reference,
|
|
112
|
-
checksumCrc32c: root.checksumCrc32c,
|
|
113
|
-
aggregateId: canonicalIdentity !== undefined
|
|
114
|
-
? canonicalIdentity.aggregateId
|
|
115
|
-
: operationAggregateId(operationId),
|
|
116
|
-
aggregateGeneration: canonicalIdentity === undefined
|
|
117
|
-
? actor.objectGeneration
|
|
118
|
-
: requireCanonicalAggregateGeneration(canonicalIdentity.aggregateGeneration),
|
|
119
|
-
targetOwnerId: expected.ownerId,
|
|
120
|
-
targetOwnerLeaseGeneration: expected.ownerLeaseGeneration,
|
|
121
|
-
...(currentPublication?.canonicalPublication === undefined
|
|
122
|
-
? {}
|
|
123
|
-
: { canonicalPublication: currentPublication.canonicalPublication })
|
|
124
|
-
};
|
|
125
|
-
const result = await this.authority.compareExchangeAuthority(key, expected.storeVersion, {
|
|
126
|
-
kind: 'put',
|
|
127
|
-
generationTransition: 'preserve',
|
|
128
|
-
payload: currentPublication === undefined && canonicalIdentity !== undefined
|
|
129
|
-
? new service_relocation_runtime_1.ServiceRelocationAuthorityPayloadCodec().publish(expected.payload, toServiceRelocationPublication(publication))
|
|
130
|
-
: replaceDeferredJoinAuthorityPublication(expected.payload, encodeAuthorityPublication(publication))
|
|
131
|
-
}, signal);
|
|
132
|
-
if (result.kind === 'stored') {
|
|
133
|
-
if (existing !== undefined) {
|
|
134
|
-
await this.deleteBestEffort(existing.reference);
|
|
135
|
-
}
|
|
136
|
-
return {
|
|
137
|
-
...root,
|
|
138
|
-
authority: storedSnapshot(result)
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
if (result.kind !== 'conflict' || result.current.kind !== 'snapshot')
|
|
142
|
-
break;
|
|
143
|
-
const current = await this.readPublished(result.current, signal);
|
|
144
|
-
if (current !== undefined) {
|
|
145
|
-
await this.deleteBestEffort(root.reference);
|
|
146
|
-
requireSameOperation(current, operationId, actor);
|
|
147
|
-
return current;
|
|
148
|
-
}
|
|
149
|
-
requireAuthorityActor(result.current.payload, actor);
|
|
150
|
-
expected = result.current;
|
|
151
|
-
}
|
|
152
|
-
await this.deleteBestEffort(root.reference);
|
|
153
|
-
throw new Error(`Actor '${actorId}' authority rejected Join completion publication.`);
|
|
154
|
-
}
|
|
155
|
-
async recover(actorId, signal) {
|
|
156
|
-
const read = await this.authority.readAuthority((0, authority_key_codec_1.encodeAuthorityKey)('actor', actorId), signal);
|
|
157
|
-
return read.kind === 'snapshot' ? await this.readPublished(read, signal) : undefined;
|
|
158
|
-
}
|
|
159
|
-
markCommitted(root, actor, signal) {
|
|
160
|
-
if (actor !== undefined)
|
|
161
|
-
requireSameActor(root, actor);
|
|
162
|
-
return this.moveCursor(root, 'committed', actor, signal);
|
|
163
|
-
}
|
|
164
|
-
markDelivered(root, signal) {
|
|
165
|
-
return this.moveCursor(root, 'delivered', undefined, signal);
|
|
166
|
-
}
|
|
167
|
-
async discardPrepared(root, signal) {
|
|
168
|
-
const key = (0, authority_key_codec_1.encodeAuthorityKey)('actor', root.actor.actorId);
|
|
169
|
-
for (let attempt = 0; attempt < 3; attempt++) {
|
|
170
|
-
const read = await this.authority.readAuthority(key, signal);
|
|
171
|
-
if (read.kind !== 'snapshot')
|
|
172
|
-
return;
|
|
173
|
-
const current = await this.readPublished(read, signal);
|
|
174
|
-
if (current === undefined)
|
|
175
|
-
return;
|
|
176
|
-
requireSameOperation(current, root.operationId, root.actor);
|
|
177
|
-
if (current.cursor !== 'prepared')
|
|
178
|
-
return;
|
|
179
|
-
const publication = decodeAuthorityPublication(read.payload);
|
|
180
|
-
if (publication === undefined)
|
|
181
|
-
return;
|
|
182
|
-
const result = await this.authority.compareExchangeAuthority(key, read.storeVersion, {
|
|
183
|
-
kind: 'put',
|
|
184
|
-
generationTransition: 'preserve',
|
|
185
|
-
payload: replaceDeferredJoinAuthorityPublication(read.payload, publication.applicationPayload)
|
|
186
|
-
}, signal);
|
|
187
|
-
if (result.kind === 'stored') {
|
|
188
|
-
await this.deleteBestEffort(current.reference);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
throw new Error(`Actor '${root.actor.actorId}' deferred Join preparation could not be discarded.`);
|
|
193
|
-
}
|
|
194
|
-
async deliver(root, actor, actorRef, submitMailbox, signal) {
|
|
195
|
-
requireSameActor(root, actorRef);
|
|
196
|
-
return await submitMailbox(async () => {
|
|
197
|
-
const current = await this.recover(actorRef.actorId, signal);
|
|
198
|
-
if (current === undefined) {
|
|
199
|
-
if (root.cursor === 'delivered')
|
|
200
|
-
return root;
|
|
201
|
-
throw new Error(`Actor '${actorRef.actorId}' lost its deferred Join completion root.`);
|
|
202
|
-
}
|
|
203
|
-
requireSameOperation(current, root.operationId, actorRef);
|
|
204
|
-
if (current.cursor === 'delivered') {
|
|
205
|
-
await this.releaseDelivered(current, signal);
|
|
206
|
-
return current;
|
|
207
|
-
}
|
|
208
|
-
if (current.cursor !== 'committed') {
|
|
209
|
-
throw new Error(`Actor '${actorRef.actorId}' Join completion is not committed.`);
|
|
210
|
-
}
|
|
211
|
-
const completion = {
|
|
212
|
-
status: 'accepted',
|
|
213
|
-
operationId: current.operationId,
|
|
214
|
-
actor: current.actor,
|
|
215
|
-
reply: current.rawReply.byteLength === 0
|
|
216
|
-
? undefined
|
|
217
|
-
: current.replyContentType === undefined
|
|
218
|
-
? contracts_1.ZLinkMessage.fromEncoded(contracts_1.ZLinkEncodedPayload.from(current.rawReply))
|
|
219
|
-
: (0, payload_codec_1.wrapFrameworkPayloadMessage)(runtime_message_1.ZLinkBufferMessage.from(current.rawReply), this.messageSerializers, current.replyContentType, undefined, 'reply')
|
|
220
|
-
};
|
|
221
|
-
await actor.onJoinCompleted?.(completion);
|
|
222
|
-
let delivered = current;
|
|
223
|
-
for (let attempt = 0; attempt < 3; attempt++) {
|
|
224
|
-
delivered = await this.markDelivered(delivered, signal);
|
|
225
|
-
if (delivered.cursor === 'delivered') {
|
|
226
|
-
await this.releaseDelivered(delivered, signal);
|
|
227
|
-
return delivered;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
throw new Error(`Actor '${actorRef.actorId}' Join completion callback ran but its Delivered cursor could not be stored.`);
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
async releaseDelivered(root, signal) {
|
|
234
|
-
const key = (0, authority_key_codec_1.encodeAuthorityKey)('actor', root.actor.actorId);
|
|
235
|
-
for (let attempt = 0; attempt < 3; attempt++) {
|
|
236
|
-
const read = await this.authority.readAuthority(key, signal);
|
|
237
|
-
if (read.kind !== 'snapshot')
|
|
238
|
-
return;
|
|
239
|
-
const current = await this.readPublished(read, signal);
|
|
240
|
-
if (current === undefined)
|
|
241
|
-
return;
|
|
242
|
-
requireSameOperation(current, root.operationId, root.actor);
|
|
243
|
-
if (current.cursor !== 'delivered') {
|
|
244
|
-
throw new Error(`Actor '${root.actor.actorId}' Join completion root is not Delivered.`);
|
|
245
|
-
}
|
|
246
|
-
const publication = decodeAuthorityPublication(read.payload);
|
|
247
|
-
if (publication === undefined)
|
|
248
|
-
return;
|
|
249
|
-
const result = await this.authority.compareExchangeAuthority(key, read.storeVersion, {
|
|
250
|
-
kind: 'put',
|
|
251
|
-
generationTransition: 'preserve',
|
|
252
|
-
payload: replaceDeferredJoinAuthorityPublication(read.payload, publication.applicationPayload)
|
|
253
|
-
}, signal);
|
|
254
|
-
if (result.kind === 'stored') {
|
|
255
|
-
await this.deleteBestEffort(current.reference);
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
throw new Error(`Actor '${root.actor.actorId}' Delivered Join completion could not be released.`);
|
|
260
|
-
}
|
|
261
|
-
async moveCursor(root, next, actor, signal) {
|
|
262
|
-
const currentIndex = cursorIndex(root.cursor);
|
|
263
|
-
const nextIndex = cursorIndex(next);
|
|
264
|
-
if (nextIndex < currentIndex || nextIndex > currentIndex + 1) {
|
|
265
|
-
throw new Error('Deferred Join completion cursor transition is invalid.');
|
|
266
|
-
}
|
|
267
|
-
if (next === root.cursor)
|
|
268
|
-
return root;
|
|
269
|
-
const key = (0, authority_key_codec_1.encodeAuthorityKey)('actor', root.actor.actorId);
|
|
270
|
-
const read = await this.authority.readAuthority(key, signal);
|
|
271
|
-
if (read.kind !== 'snapshot') {
|
|
272
|
-
throw new Error(`Actor '${root.actor.actorId}' authority disappeared during Join completion.`);
|
|
273
|
-
}
|
|
274
|
-
let current = await this.readPublished(read, signal);
|
|
275
|
-
if (current === undefined) {
|
|
276
|
-
const retainedRoot = await this.relocation.read(root.reference, signal);
|
|
277
|
-
if (retainedRoot.kind === 'found' && (0, service_relocation_runtime_1.crc32c)(retainedRoot.bytes) === root.checksumCrc32c) {
|
|
278
|
-
const retained = hasJournalRootMagic(retainedRoot.bytes)
|
|
279
|
-
? decodeRoot(retainedRoot.bytes)
|
|
280
|
-
: (await readCanonicalDeferredJoinRoot(this.relocation, retainedRoot.bytes, signal))
|
|
281
|
-
?.completion;
|
|
282
|
-
if (retained?.cursor === 'delivered' &&
|
|
283
|
-
isSameOperation({ ...root, ...retained }, root.operationId, root.actor)) {
|
|
284
|
-
current = {
|
|
285
|
-
authority: read,
|
|
286
|
-
reference: root.reference,
|
|
287
|
-
checksumCrc32c: root.checksumCrc32c,
|
|
288
|
-
...retained
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
if (current === undefined &&
|
|
293
|
-
next === 'committed' &&
|
|
294
|
-
actor !== undefined &&
|
|
295
|
-
authorityMatchesActor(read.payload, actor)) {
|
|
296
|
-
throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, `Actor '${root.actor.actorId}' Join completion delivery is indeterminate: ` +
|
|
297
|
-
'the authority no longer references the operation and no matching retained root exists.');
|
|
298
|
-
}
|
|
299
|
-
if (current === undefined) {
|
|
300
|
-
throw new Error(`Actor '${root.actor.actorId}' no longer references its Join completion root.`);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
requireSameOperation(current, root.operationId, root.actor);
|
|
304
|
-
if (cursorIndex(current.cursor) >= nextIndex)
|
|
305
|
-
return current;
|
|
306
|
-
const replacement = await this.storeRoot({
|
|
307
|
-
operationId: current.operationId,
|
|
308
|
-
actor: actor ?? current.actor,
|
|
309
|
-
rawReply: current.rawReply,
|
|
310
|
-
...(current.replyContentType === undefined
|
|
311
|
-
? {}
|
|
312
|
-
: { replyContentType: current.replyContentType }),
|
|
313
|
-
cursor: next
|
|
314
|
-
}, signal);
|
|
315
|
-
const publication = decodeAuthorityPublication(read.payload);
|
|
316
|
-
if (publication === undefined) {
|
|
317
|
-
await this.deleteBestEffort(replacement.reference);
|
|
318
|
-
throw new Error('Actor authority lost its deferred Join publication.');
|
|
319
|
-
}
|
|
320
|
-
const identity = (0, actor_authority_publication_1.decodeRelocatingActorAuthorityIdentity)(publication.applicationPayload, read.objectGeneration);
|
|
321
|
-
if (identity === undefined) {
|
|
322
|
-
await this.deleteBestEffort(replacement.reference);
|
|
323
|
-
throw new Error('Actor authority identity is invalid.');
|
|
324
|
-
}
|
|
325
|
-
const result = await this.authority.compareExchangeAuthority(key, read.storeVersion, {
|
|
326
|
-
kind: 'put',
|
|
327
|
-
generationTransition: 'preserve',
|
|
328
|
-
payload: replaceDeferredJoinAuthorityPublication(read.payload, encodeAuthorityPublication({
|
|
329
|
-
...publication,
|
|
330
|
-
applicationPayload: actor === undefined
|
|
331
|
-
? publication.applicationPayload
|
|
332
|
-
: (0, actor_authority_payload_codec_1.replaceActorRelocationAuthorityApplicationPayload)(publication.applicationPayload, (0, actor_authority_publication_1.encodeActorAuthorityIdentity)({ ...identity, actor })),
|
|
333
|
-
reference: replacement.reference,
|
|
334
|
-
checksumCrc32c: replacement.checksumCrc32c
|
|
335
|
-
}))
|
|
336
|
-
}, signal);
|
|
337
|
-
if (result.kind !== 'stored') {
|
|
338
|
-
await this.deleteBestEffort(replacement.reference);
|
|
339
|
-
const recovered = await this.recover(root.actor.actorId, signal);
|
|
340
|
-
if (recovered === undefined) {
|
|
341
|
-
throw new Error('Deferred Join cursor CAS conflicted without a recoverable root.');
|
|
342
|
-
}
|
|
343
|
-
requireSameOperation(recovered, root.operationId, root.actor);
|
|
344
|
-
return recovered;
|
|
345
|
-
}
|
|
346
|
-
await this.deleteBestEffort(current.reference);
|
|
347
|
-
return {
|
|
348
|
-
...replacement,
|
|
349
|
-
authority: storedSnapshot(result)
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
async readPublished(authority, signal) {
|
|
353
|
-
const publication = decodeAuthorityPublication(authority.payload);
|
|
354
|
-
if (publication === undefined)
|
|
355
|
-
return undefined;
|
|
356
|
-
// Preparing has no relocation root, while Captured still names the
|
|
357
|
-
// source-memory direct-transfer payload. Neither pre-target-publication
|
|
358
|
-
// phase can contain a Relocation Store backed deferred Join root.
|
|
359
|
-
const canonicalPhase = publication.canonicalPublication?.canonicalPhase;
|
|
360
|
-
if (canonicalPhase === 1 || canonicalPhase === 2)
|
|
361
|
-
return undefined;
|
|
362
|
-
const read = await this.relocation.read(publication.reference, signal);
|
|
363
|
-
if (read.kind !== 'found' &&
|
|
364
|
-
publication.canonical === true &&
|
|
365
|
-
publication.reference.value.startsWith('zlink-direct:')) {
|
|
366
|
-
return undefined;
|
|
367
|
-
}
|
|
368
|
-
if (read.kind !== 'found' || (0, service_relocation_runtime_1.crc32c)(read.bytes) !== publication.checksumCrc32c) {
|
|
369
|
-
throw new Error('Published deferred Join completion root is missing or corrupt.');
|
|
370
|
-
}
|
|
371
|
-
if (publication.canonical === true && !hasJournalRootMagic(read.bytes)) {
|
|
372
|
-
const root = await readCanonicalDeferredJoinRoot(this.relocation, read.bytes, signal);
|
|
373
|
-
if (root === undefined) {
|
|
374
|
-
// A canonical relocation root and the post-commit Join journal share
|
|
375
|
-
// the embedded slot. A root without a completion remains Host-owned.
|
|
376
|
-
return undefined;
|
|
377
|
-
}
|
|
378
|
-
if (root.identity.aggregateId !== publication.aggregateId ||
|
|
379
|
-
root.identity.aggregateGeneration !== publication.aggregateGeneration ||
|
|
380
|
-
root.identity.objectGeneration !== authority.objectGeneration) {
|
|
381
|
-
throw new Error('Published deferred Join completion root identity does not match its authority slot.');
|
|
382
|
-
}
|
|
383
|
-
return {
|
|
384
|
-
authority,
|
|
385
|
-
reference: publication.reference,
|
|
386
|
-
checksumCrc32c: publication.checksumCrc32c,
|
|
387
|
-
...root.completion
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
return {
|
|
391
|
-
authority,
|
|
392
|
-
reference: publication.reference,
|
|
393
|
-
checksumCrc32c: publication.checksumCrc32c,
|
|
394
|
-
...decodeRoot(read.bytes)
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
async storeRoot(value, signal) {
|
|
398
|
-
const payload = encodeRoot(value);
|
|
399
|
-
const checksumCrc32c = (0, service_relocation_runtime_1.crc32c)(payload);
|
|
400
|
-
const stored = await (0, relocation_blob_1.putNewRelocationBlob)(this.relocation, payload, RETENTION_MS, signal);
|
|
401
|
-
if (stored.expiresAt.getTime() <= stored.storeNow.getTime()) {
|
|
402
|
-
await this.deleteBestEffort(stored.reference);
|
|
403
|
-
throw new Error('Relocation Store returned an invalid deferred Join root receipt.');
|
|
404
|
-
}
|
|
405
|
-
const read = await this.relocation.read(stored.reference, signal);
|
|
406
|
-
if (read.kind !== 'found' || !Buffer.from(read.bytes).equals(payload)) {
|
|
407
|
-
await this.deleteBestEffort(stored.reference);
|
|
408
|
-
throw new Error('Relocation Store failed deferred Join root verification.');
|
|
409
|
-
}
|
|
410
|
-
return {
|
|
411
|
-
...value,
|
|
412
|
-
rawReply: Buffer.from(value.rawReply),
|
|
413
|
-
reference: stored.reference,
|
|
414
|
-
checksumCrc32c
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
async storeCanonicalRoot(value, authority, publication, signal, canonicalInventoryDigest) {
|
|
418
|
-
let inventory;
|
|
419
|
-
if (canonicalInventoryDigest !== undefined) {
|
|
420
|
-
if (!/^[0-9a-f]{64}$/u.test(canonicalInventoryDigest)) {
|
|
421
|
-
throw new Error('Canonical relocation inventory digest is invalid.');
|
|
422
|
-
}
|
|
423
|
-
inventory = Buffer.from(canonicalInventoryDigest, 'hex');
|
|
424
|
-
}
|
|
425
|
-
else {
|
|
426
|
-
const current = await this.relocation.read(publication.reference, signal);
|
|
427
|
-
if (current.kind !== 'found' || (0, service_relocation_runtime_1.crc32c)(current.bytes) !== publication.checksumCrc32c) {
|
|
428
|
-
throw new Error('Canonical relocation manifest is missing or corrupt.');
|
|
429
|
-
}
|
|
430
|
-
inventory = decodeCanonicalTreeManifest(current.bytes).inventoryDigest;
|
|
431
|
-
}
|
|
432
|
-
const logicalRoot = encodeCanonicalDeferredJoinRoot(value, authority, publication, inventory);
|
|
433
|
-
const stored = await storeCanonicalTree(this.relocation, logicalRoot, inventory, signal);
|
|
434
|
-
return {
|
|
435
|
-
...value,
|
|
436
|
-
rawReply: Buffer.from(value.rawReply),
|
|
437
|
-
reference: stored.reference,
|
|
438
|
-
checksumCrc32c: stored.checksumCrc32c
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
async deleteBestEffort(reference) {
|
|
442
|
-
try {
|
|
443
|
-
await this.relocation.delete(reference);
|
|
444
|
-
}
|
|
445
|
-
catch {
|
|
446
|
-
// Fixed retention remains the orphan cleanup boundary.
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
exports.ZLinkDeferredJoinAcceptedJournal = ZLinkDeferredJoinAcceptedJournal;
|
|
451
|
-
function requireAuthorityActor(payload, actor) {
|
|
452
|
-
if (!authorityMatchesActor(payload, actor)) {
|
|
453
|
-
throw new Error(`Actor '${actor.actorId}' authority fence does not match its ActorRef.`);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
function authorityMatchesActor(payload, actor) {
|
|
457
|
-
const publication = decodeAuthorityPublication(payload);
|
|
458
|
-
const applications = publication === undefined
|
|
459
|
-
? [(0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(payload)]
|
|
460
|
-
: [publication.applicationPayload, (0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(payload)];
|
|
461
|
-
return applications.some((application) => {
|
|
462
|
-
const identity = (0, actor_authority_publication_1.decodeRelocatingActorAuthorityIdentity)(application, actor.objectGeneration);
|
|
463
|
-
return (identity !== undefined &&
|
|
464
|
-
identity.actor.actorId === actor.actorId &&
|
|
465
|
-
identity.actor.objectGeneration === actor.objectGeneration &&
|
|
466
|
-
(0, routing_id_1.routingIdWireHex)(identity.actor.nodeRid) === (0, routing_id_1.routingIdWireHex)(actor.nodeRid));
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
function encodeRoot(value) {
|
|
470
|
-
const nodeRidHex = (0, routing_id_1.routingIdWireHex)(value.actor.nodeRid);
|
|
471
|
-
const encoded = Buffer.concat([
|
|
472
|
-
ROOT_MAGIC,
|
|
473
|
-
Buffer.from(JSON.stringify({
|
|
474
|
-
version: ROOT_VERSION,
|
|
475
|
-
operationHigh: value.operationId.high.toString(),
|
|
476
|
-
operationLow: value.operationId.low.toString(),
|
|
477
|
-
actorId: value.actor.actorId,
|
|
478
|
-
actorGeneration: value.actor.objectGeneration.toString(),
|
|
479
|
-
actorMeshName: value.actor.meshName,
|
|
480
|
-
actorNodeRid: String(value.actor.nodeRid),
|
|
481
|
-
actorNodeRidHex: nodeRidHex,
|
|
482
|
-
rawReply: Buffer.from(value.rawReply).toString('base64'),
|
|
483
|
-
...(value.replyContentType === undefined
|
|
484
|
-
? {}
|
|
485
|
-
: { replyContentType: value.replyContentType }),
|
|
486
|
-
cursor: value.cursor
|
|
487
|
-
}), 'utf8')
|
|
488
|
-
]);
|
|
489
|
-
return encoded;
|
|
490
|
-
}
|
|
491
|
-
function decodeRoot(payload) {
|
|
492
|
-
if (payload.byteLength === 0) {
|
|
493
|
-
throw new Error('Deferred Join completion root is empty.');
|
|
494
|
-
}
|
|
495
|
-
const bytes = Buffer.from(payload);
|
|
496
|
-
const encoded = hasJournalRootMagic(bytes) ? bytes.subarray(ROOT_MAGIC.byteLength) : bytes;
|
|
497
|
-
const value = JSON.parse(encoded.toString('utf8'));
|
|
498
|
-
if (value.version !== ROOT_VERSION ||
|
|
499
|
-
typeof value.operationHigh !== 'string' ||
|
|
500
|
-
typeof value.operationLow !== 'string' ||
|
|
501
|
-
typeof value.actorId !== 'string' ||
|
|
502
|
-
typeof value.actorGeneration !== 'string' ||
|
|
503
|
-
typeof value.actorMeshName !== 'string' ||
|
|
504
|
-
typeof value.actorNodeRid !== 'string' ||
|
|
505
|
-
typeof value.rawReply !== 'string' ||
|
|
506
|
-
(value.replyContentType !== undefined &&
|
|
507
|
-
(typeof value.replyContentType !== 'string' || value.replyContentType.length === 0)) ||
|
|
508
|
-
!isCursor(value.cursor)) {
|
|
509
|
-
throw new Error('Deferred Join completion root is invalid.');
|
|
510
|
-
}
|
|
511
|
-
const rawReply = Buffer.from(value.rawReply, 'base64');
|
|
512
|
-
if (rawReply.toString('base64') !== value.rawReply) {
|
|
513
|
-
throw new Error('Deferred Join completion reply is not canonical base64.');
|
|
514
|
-
}
|
|
515
|
-
const actorGeneration = BigInt(value.actorGeneration);
|
|
516
|
-
const operationId = {
|
|
517
|
-
high: BigInt(value.operationHigh),
|
|
518
|
-
low: BigInt(value.operationLow)
|
|
519
|
-
};
|
|
520
|
-
const actor = {
|
|
521
|
-
actorId: value.actorId,
|
|
522
|
-
objectGeneration: actorGeneration,
|
|
523
|
-
meshName: value.actorMeshName,
|
|
524
|
-
nodeRid: (0, routing_id_1.decodeRoutingId)(value.actorNodeRid, typeof value.actorNodeRidHex === 'string' ? value.actorNodeRidHex : undefined)
|
|
525
|
-
};
|
|
526
|
-
validateIdentity(value.actorId, operationId, actor);
|
|
527
|
-
return {
|
|
528
|
-
operationId,
|
|
529
|
-
actor,
|
|
530
|
-
rawReply,
|
|
531
|
-
...(typeof value.replyContentType === 'string'
|
|
532
|
-
? { replyContentType: value.replyContentType }
|
|
533
|
-
: {}),
|
|
534
|
-
cursor: value.cursor
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
function encodeAuthorityPublication(value) {
|
|
538
|
-
return Buffer.from(new service_relocation_runtime_1.ServiceRelocationAuthorityPayloadCodec().publish(value.applicationPayload, toServiceRelocationPublication(value)));
|
|
539
|
-
}
|
|
540
|
-
function toServiceRelocationPublication(value) {
|
|
541
|
-
return {
|
|
542
|
-
...value.canonicalPublication,
|
|
543
|
-
reference: value.reference.value,
|
|
544
|
-
checksumCrc32c: value.checksumCrc32c,
|
|
545
|
-
aggregateId: value.aggregateId,
|
|
546
|
-
aggregateGeneration: value.aggregateGeneration,
|
|
547
|
-
inventoryDigest: journalInventoryDigest(value.applicationPayload),
|
|
548
|
-
targetOwnerId: value.targetOwnerId,
|
|
549
|
-
targetOwnerLeaseGeneration: value.targetOwnerLeaseGeneration
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
|
-
function decodeAuthorityPublication(payload) {
|
|
553
|
-
const outerApplication = (0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(payload);
|
|
554
|
-
const candidates = Buffer.from(outerApplication).equals(Buffer.from(payload))
|
|
555
|
-
? [Buffer.from(payload)]
|
|
556
|
-
: [Buffer.from(outerApplication), Buffer.from(payload)];
|
|
557
|
-
for (const candidate of candidates) {
|
|
558
|
-
const publication = decodeDirectAuthorityPublication(candidate);
|
|
559
|
-
if (publication !== undefined)
|
|
560
|
-
return publication;
|
|
561
|
-
}
|
|
562
|
-
return undefined;
|
|
563
|
-
}
|
|
564
|
-
function replaceDeferredJoinAuthorityPublication(payload, replacement) {
|
|
565
|
-
const codec = new service_relocation_runtime_1.ServiceRelocationAuthorityPayloadCodec();
|
|
566
|
-
const currentPublication = codec.read(payload);
|
|
567
|
-
const replacementPublication = codec.read(replacement);
|
|
568
|
-
if (currentPublication?.canonical === true || replacementPublication?.canonical === true) {
|
|
569
|
-
// Canonical authority has exactly one embedded relocation slot. A journal
|
|
570
|
-
// cursor replaces that slot atomically; it must never be wrapped or nested
|
|
571
|
-
// under an older ZLAR/application layer.
|
|
572
|
-
return Buffer.from(replacement);
|
|
573
|
-
}
|
|
574
|
-
const outerApplication = (0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(payload);
|
|
575
|
-
if (!Buffer.from(outerApplication).equals(Buffer.from(payload)) &&
|
|
576
|
-
decodeDirectAuthorityPublication(outerApplication) !== undefined) {
|
|
577
|
-
return (0, service_relocation_runtime_1.replaceServiceRelocationAuthorityApplicationPayload)(payload, replacement);
|
|
578
|
-
}
|
|
579
|
-
return decodeDirectAuthorityPublication(payload) === undefined
|
|
580
|
-
? (0, service_relocation_runtime_1.replaceServiceRelocationAuthorityApplicationPayload)(payload, replacement)
|
|
581
|
-
: Buffer.from(replacement);
|
|
582
|
-
}
|
|
583
|
-
function decodeDirectAuthorityPublication(payload) {
|
|
584
|
-
const publication = new service_relocation_runtime_1.ServiceRelocationAuthorityPayloadCodec().read(payload);
|
|
585
|
-
if (publication === undefined)
|
|
586
|
-
return undefined;
|
|
587
|
-
const applicationPayload = (0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(payload);
|
|
588
|
-
return publication.canonical === true ||
|
|
589
|
-
publication.inventoryDigest === journalInventoryDigest(applicationPayload)
|
|
590
|
-
? deferredJoinPublication(applicationPayload, publication)
|
|
591
|
-
: undefined;
|
|
592
|
-
}
|
|
593
|
-
function deferredJoinPublication(applicationPayload, publication) {
|
|
594
|
-
return {
|
|
595
|
-
applicationPayload,
|
|
596
|
-
reference: { value: publication.reference },
|
|
597
|
-
checksumCrc32c: publication.checksumCrc32c,
|
|
598
|
-
aggregateId: publication.aggregateId,
|
|
599
|
-
aggregateGeneration: publication.aggregateGeneration,
|
|
600
|
-
targetOwnerId: publication.targetOwnerId,
|
|
601
|
-
targetOwnerLeaseGeneration: publication.targetOwnerLeaseGeneration,
|
|
602
|
-
canonical: publication.canonical,
|
|
603
|
-
...(publication.canonical === true ? { canonicalPublication: publication } : {})
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
function hasJournalRootMagic(payload) {
|
|
607
|
-
const bytes = Buffer.from(payload);
|
|
608
|
-
return (bytes.byteLength >= ROOT_MAGIC.byteLength &&
|
|
609
|
-
bytes.subarray(0, ROOT_MAGIC.byteLength).equals(ROOT_MAGIC));
|
|
610
|
-
}
|
|
611
|
-
function journalInventoryDigest(applicationPayload) {
|
|
612
|
-
return (0, node_crypto_1.createHash)('sha256')
|
|
613
|
-
.update(JOURNAL_INVENTORY_DOMAIN)
|
|
614
|
-
.update(applicationPayload)
|
|
615
|
-
.digest('hex');
|
|
616
|
-
}
|
|
617
|
-
function operationAggregateId(operationId) {
|
|
618
|
-
const encoded = [operationId.high, operationId.low]
|
|
619
|
-
.map((value) => BigInt.asUintN(64, value).toString(16).padStart(16, '0'))
|
|
620
|
-
.join('');
|
|
621
|
-
return (`${encoded.slice(0, 8)}-${encoded.slice(8, 12)}-${encoded.slice(12, 16)}` +
|
|
622
|
-
`-${encoded.slice(16, 20)}-${encoded.slice(20)}`);
|
|
623
|
-
}
|
|
624
|
-
function requireCanonicalAggregateGeneration(value) {
|
|
625
|
-
if (value === 0n) {
|
|
626
|
-
throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.DataLost, 'Canonical relocation slot has no aggregate generation.');
|
|
627
|
-
}
|
|
628
|
-
return value;
|
|
629
|
-
}
|
|
630
|
-
function decodeCanonicalTreeManifest(payload) {
|
|
631
|
-
const generated = (0, service_wire_pilot_codec_generated_1.decodeRelocationManifestV1)(payload);
|
|
632
|
-
const chunks = generated.chunks.map((chunk, index) => {
|
|
633
|
-
if (chunk.order !== index) {
|
|
634
|
-
throw new Error('Canonical relocation chunk identity is invalid.');
|
|
635
|
-
}
|
|
636
|
-
return {
|
|
637
|
-
order: chunk.order,
|
|
638
|
-
reference: { value: chunk.reference },
|
|
639
|
-
length: chunk.length,
|
|
640
|
-
checksumCrc32c: chunk.checksumCrc32c
|
|
641
|
-
};
|
|
642
|
-
});
|
|
643
|
-
if (chunks.length === 0) {
|
|
644
|
-
throw new Error('Canonical relocation chunk count is invalid.');
|
|
645
|
-
}
|
|
646
|
-
if (chunks.reduce((total, value) => total + value.length, 0n) !== generated.totalLength) {
|
|
647
|
-
throw new Error('Canonical relocation manifest length is invalid.');
|
|
648
|
-
}
|
|
649
|
-
return {
|
|
650
|
-
inventoryDigest: Buffer.from(generated.inventoryDigestSha256),
|
|
651
|
-
logicalLength: generated.totalLength,
|
|
652
|
-
logicalChecksumCrc32c: generated.totalChecksumCrc32c,
|
|
653
|
-
chunks
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
async function storeCanonicalTree(store, logicalRoot, inventoryDigest, signal) {
|
|
657
|
-
const logical = Buffer.from(logicalRoot);
|
|
658
|
-
const logicalChecksumCrc32c = (0, service_relocation_runtime_1.crc32c)(logical);
|
|
659
|
-
const chunk = Buffer.from((0, service_wire_pilot_codec_generated_1.encodeRelocationDataChunkV1)({
|
|
660
|
-
order: 0,
|
|
661
|
-
data: logical
|
|
662
|
-
}));
|
|
663
|
-
const storedChunk = await putAndVerifyCanonicalBlob(store, chunk, signal);
|
|
664
|
-
const manifest = Buffer.from((0, service_wire_pilot_codec_generated_1.encodeRelocationManifestV1)({
|
|
665
|
-
logicalFormatVersion: 1,
|
|
666
|
-
totalLength: BigInt(logical.byteLength),
|
|
667
|
-
totalChecksumCrc32c: logicalChecksumCrc32c,
|
|
668
|
-
inventoryDigestSha256: Buffer.from(inventoryDigest),
|
|
669
|
-
chunks: [
|
|
670
|
-
{
|
|
671
|
-
order: 0,
|
|
672
|
-
reference: storedChunk.reference.value,
|
|
673
|
-
length: BigInt(logical.byteLength),
|
|
674
|
-
checksumCrc32c: logicalChecksumCrc32c
|
|
675
|
-
}
|
|
676
|
-
]
|
|
677
|
-
}));
|
|
678
|
-
const storedManifest = await putAndVerifyCanonicalBlob(store, manifest, signal);
|
|
679
|
-
return {
|
|
680
|
-
reference: storedManifest.reference,
|
|
681
|
-
checksumCrc32c: (0, service_relocation_runtime_1.crc32c)(manifest)
|
|
682
|
-
};
|
|
683
|
-
}
|
|
684
|
-
async function putAndVerifyCanonicalBlob(store, payload, signal) {
|
|
685
|
-
const stored = await (0, relocation_blob_1.putNewRelocationBlob)(store, payload, RETENTION_MS, signal);
|
|
686
|
-
const read = await store.read(stored.reference, signal);
|
|
687
|
-
if (read.kind !== 'found' || !Buffer.from(read.bytes).equals(Buffer.from(payload))) {
|
|
688
|
-
await store.delete(stored.reference).catch(() => undefined);
|
|
689
|
-
throw new Error('Relocation Store failed canonical tree verification.');
|
|
690
|
-
}
|
|
691
|
-
return { reference: stored.reference };
|
|
692
|
-
}
|
|
693
|
-
async function readCanonicalDeferredJoinRoot(store, manifestPayload, signal) {
|
|
694
|
-
let manifest;
|
|
695
|
-
try {
|
|
696
|
-
manifest = decodeCanonicalTreeManifest(manifestPayload);
|
|
697
|
-
}
|
|
698
|
-
catch {
|
|
699
|
-
return undefined;
|
|
700
|
-
}
|
|
701
|
-
const parts = [];
|
|
702
|
-
for (const expected of manifest.chunks) {
|
|
703
|
-
const read = await store.read(expected.reference, signal);
|
|
704
|
-
if (read.kind !== 'found')
|
|
705
|
-
throw new Error('Canonical relocation chunk is missing.');
|
|
706
|
-
const chunk = (0, service_wire_pilot_codec_generated_1.decodeRelocationDataChunkV1)(read.bytes);
|
|
707
|
-
if (chunk.order !== expected.order || BigInt(chunk.data.byteLength) !== expected.length) {
|
|
708
|
-
throw new Error('Canonical relocation chunk identity is invalid.');
|
|
709
|
-
}
|
|
710
|
-
const data = Buffer.from(chunk.data);
|
|
711
|
-
if ((0, service_relocation_runtime_1.crc32c)(data) !== expected.checksumCrc32c) {
|
|
712
|
-
throw new Error('Canonical relocation chunk data checksum is invalid.');
|
|
713
|
-
}
|
|
714
|
-
parts.push(data);
|
|
715
|
-
}
|
|
716
|
-
const logical = Buffer.concat(parts);
|
|
717
|
-
if (BigInt(logical.byteLength) !== manifest.logicalLength ||
|
|
718
|
-
(0, service_relocation_runtime_1.crc32c)(logical) !== manifest.logicalChecksumCrc32c) {
|
|
719
|
-
throw new Error('Canonical relocation logical root checksum is invalid.');
|
|
720
|
-
}
|
|
721
|
-
return decodeCanonicalDeferredJoinRoot(logical);
|
|
722
|
-
}
|
|
723
|
-
function encodeCanonicalDeferredJoinRoot(value, authority, publication, inventoryDigest) {
|
|
724
|
-
const key = (0, authority_key_codec_1.encodeAuthorityKey)('actor', value.actor.actorId).value;
|
|
725
|
-
const completion = encodeDotNetDeferredJoinCompletion(value);
|
|
726
|
-
return Buffer.concat([
|
|
727
|
-
u32le(0x5a4c5231),
|
|
728
|
-
u16le(2),
|
|
729
|
-
dotNetGuidBytes(publication.aggregateId),
|
|
730
|
-
u64le(publication.aggregateGeneration),
|
|
731
|
-
bytes32le(inventoryDigest),
|
|
732
|
-
u32le(1),
|
|
733
|
-
text16le(key),
|
|
734
|
-
Buffer.of(1),
|
|
735
|
-
u64le(authority.objectGeneration),
|
|
736
|
-
u64le(authority.authorityOwnerGeneration),
|
|
737
|
-
bytes32le(Buffer.alloc(0)),
|
|
738
|
-
u32le(0),
|
|
739
|
-
u32le(0),
|
|
740
|
-
bytes32le(Buffer.alloc(0)),
|
|
741
|
-
bytes32le(completion)
|
|
742
|
-
]);
|
|
743
|
-
}
|
|
744
|
-
function decodeCanonicalDeferredJoinRoot(payload) {
|
|
745
|
-
const reader = new LittleEndianReader(payload);
|
|
746
|
-
if (reader.u32() !== 0x5a4c5231 || reader.u16() !== 2)
|
|
747
|
-
return undefined;
|
|
748
|
-
const aggregateId = canonicalUuidFromDotNetBytes(reader.take(16));
|
|
749
|
-
const aggregateGeneration = reader.u64();
|
|
750
|
-
reader.bytes32();
|
|
751
|
-
const count = reader.u32();
|
|
752
|
-
let completion;
|
|
753
|
-
let completionIdentity;
|
|
754
|
-
for (let index = 0; index < count; index++) {
|
|
755
|
-
const authorityKey = reader.text16();
|
|
756
|
-
const objectKind = reader.u8();
|
|
757
|
-
const objectGeneration = reader.u64();
|
|
758
|
-
reader.u64();
|
|
759
|
-
reader.bytes32();
|
|
760
|
-
const jobs = reader.u32();
|
|
761
|
-
for (let job = 0; job < jobs; job++) {
|
|
762
|
-
reader.u64();
|
|
763
|
-
reader.bytes32();
|
|
764
|
-
}
|
|
765
|
-
const timers = reader.u32();
|
|
766
|
-
for (let timer = 0; timer < timers; timer++) {
|
|
767
|
-
reader.text16();
|
|
768
|
-
reader.i64();
|
|
769
|
-
reader.i64();
|
|
770
|
-
reader.bytes32();
|
|
771
|
-
}
|
|
772
|
-
reader.bytes32();
|
|
773
|
-
const encodedCompletion = reader.bytes32();
|
|
774
|
-
if (encodedCompletion.byteLength !== 0) {
|
|
775
|
-
if (completion !== undefined)
|
|
776
|
-
throw new Error('Canonical relocation root has duplicate completions.');
|
|
777
|
-
completion = decodeDotNetDeferredJoinCompletion(encodedCompletion);
|
|
778
|
-
if (objectKind !== 1)
|
|
779
|
-
return undefined;
|
|
780
|
-
completionIdentity = {
|
|
781
|
-
authorityKey,
|
|
782
|
-
objectKind: 'actor',
|
|
783
|
-
objectGeneration
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
if (!reader.done)
|
|
788
|
-
throw new Error('Canonical relocation root has trailing bytes.');
|
|
789
|
-
if (completion === undefined || completionIdentity === undefined)
|
|
790
|
-
return undefined;
|
|
791
|
-
if (completion.actor.objectGeneration !== completionIdentity.objectGeneration ||
|
|
792
|
-
(0, authority_key_codec_1.encodeAuthorityKey)('actor', completion.actor.actorId).value !== completionIdentity.authorityKey) {
|
|
793
|
-
return undefined;
|
|
794
|
-
}
|
|
795
|
-
return {
|
|
796
|
-
identity: {
|
|
797
|
-
...completionIdentity,
|
|
798
|
-
aggregateId,
|
|
799
|
-
aggregateGeneration
|
|
800
|
-
},
|
|
801
|
-
completion
|
|
802
|
-
};
|
|
803
|
-
}
|
|
804
|
-
function encodeDotNetDeferredJoinCompletion(value) {
|
|
805
|
-
const routingId = Buffer.from((0, routing_id_1.encodeRoutingIdStorageHex)(value.actor.nodeRid), 'hex');
|
|
806
|
-
return Buffer.concat([
|
|
807
|
-
u32le(0x5a4c4a43),
|
|
808
|
-
Buffer.of(2),
|
|
809
|
-
text16le(value.actor.actorId),
|
|
810
|
-
u64le(value.actor.objectGeneration),
|
|
811
|
-
u64le(value.operationId.high),
|
|
812
|
-
u64le(value.operationId.low),
|
|
813
|
-
text16le(value.actor.meshName),
|
|
814
|
-
Buffer.of(routingId.byteLength),
|
|
815
|
-
routingId,
|
|
816
|
-
u64le(value.actor.objectGeneration),
|
|
817
|
-
Buffer.of(value.replyContentType === undefined ? 0 : 1),
|
|
818
|
-
...(value.replyContentType === undefined ? [] : [text16le(value.replyContentType)]),
|
|
819
|
-
bytes32le(value.rawReply),
|
|
820
|
-
Buffer.of(cursorIndex(value.cursor) + 1)
|
|
821
|
-
]);
|
|
822
|
-
}
|
|
823
|
-
function decodeDotNetDeferredJoinCompletion(payload) {
|
|
824
|
-
const reader = new LittleEndianReader(payload);
|
|
825
|
-
if (reader.u32() !== 0x5a4c4a43 || reader.u8() !== 2) {
|
|
826
|
-
throw new Error('Canonical deferred Join completion header is invalid.');
|
|
827
|
-
}
|
|
828
|
-
const actorId = reader.text16();
|
|
829
|
-
const objectGeneration = reader.u64();
|
|
830
|
-
const operationId = { high: reader.u64(), low: reader.u64() };
|
|
831
|
-
const meshName = reader.text16();
|
|
832
|
-
const nodeBytes = reader.take(reader.u8());
|
|
833
|
-
const actorGeneration = reader.u64();
|
|
834
|
-
const contentTypePresence = reader.u8();
|
|
835
|
-
if (contentTypePresence > 1) {
|
|
836
|
-
throw new Error('Canonical deferred Join completion content type is invalid.');
|
|
837
|
-
}
|
|
838
|
-
const replyContentType = contentTypePresence === 1 ? reader.text16() : undefined;
|
|
839
|
-
const rawReply = reader.bytes32();
|
|
840
|
-
const cursorValue = reader.u8();
|
|
841
|
-
if (!reader.done || actorGeneration !== objectGeneration || cursorValue < 1 || cursorValue > 3) {
|
|
842
|
-
throw new Error('Canonical deferred Join completion is invalid.');
|
|
843
|
-
}
|
|
844
|
-
const actor = {
|
|
845
|
-
actorId,
|
|
846
|
-
objectGeneration,
|
|
847
|
-
meshName,
|
|
848
|
-
nodeRid: (0, routing_id_1.decodeRoutingId)('', nodeBytes.toString('hex'))
|
|
849
|
-
};
|
|
850
|
-
validateIdentity(actorId, operationId, actor);
|
|
851
|
-
return {
|
|
852
|
-
operationId,
|
|
853
|
-
actor,
|
|
854
|
-
rawReply,
|
|
855
|
-
...(replyContentType === undefined ? {} : { replyContentType }),
|
|
856
|
-
cursor: ['prepared', 'committed', 'delivered'][cursorValue - 1]
|
|
857
|
-
};
|
|
858
|
-
}
|
|
859
|
-
class LittleEndianReader {
|
|
860
|
-
offset = 0;
|
|
861
|
-
bytes;
|
|
862
|
-
constructor(payload) {
|
|
863
|
-
this.bytes = Buffer.from(payload);
|
|
864
|
-
}
|
|
865
|
-
get done() {
|
|
866
|
-
return this.offset === this.bytes.byteLength;
|
|
867
|
-
}
|
|
868
|
-
take(length) {
|
|
869
|
-
if (length < 0 || this.offset + length > this.bytes.byteLength) {
|
|
870
|
-
throw new Error('Canonical relocation root is truncated.');
|
|
871
|
-
}
|
|
872
|
-
const result = this.bytes.subarray(this.offset, this.offset + length);
|
|
873
|
-
this.offset += length;
|
|
874
|
-
return result;
|
|
875
|
-
}
|
|
876
|
-
u8() {
|
|
877
|
-
return this.take(1)[0];
|
|
878
|
-
}
|
|
879
|
-
u16() {
|
|
880
|
-
return this.take(2).readUInt16LE();
|
|
881
|
-
}
|
|
882
|
-
u32() {
|
|
883
|
-
return this.take(4).readUInt32LE();
|
|
884
|
-
}
|
|
885
|
-
u64() {
|
|
886
|
-
return this.take(8).readBigUInt64LE();
|
|
887
|
-
}
|
|
888
|
-
i64() {
|
|
889
|
-
return this.take(8).readBigInt64LE();
|
|
890
|
-
}
|
|
891
|
-
text16() {
|
|
892
|
-
const bytes = this.take(this.u16());
|
|
893
|
-
return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
|
|
894
|
-
}
|
|
895
|
-
bytes32() {
|
|
896
|
-
return this.take(this.u32());
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
function dotNetGuidBytes(value) {
|
|
900
|
-
const bytes = Buffer.from(value.replaceAll('-', ''), 'hex');
|
|
901
|
-
return Buffer.from([
|
|
902
|
-
bytes[3],
|
|
903
|
-
bytes[2],
|
|
904
|
-
bytes[1],
|
|
905
|
-
bytes[0],
|
|
906
|
-
bytes[5],
|
|
907
|
-
bytes[4],
|
|
908
|
-
bytes[7],
|
|
909
|
-
bytes[6],
|
|
910
|
-
...bytes.subarray(8)
|
|
911
|
-
]);
|
|
912
|
-
}
|
|
913
|
-
function canonicalUuidFromDotNetBytes(value) {
|
|
914
|
-
const bytes = Buffer.from(value);
|
|
915
|
-
if (bytes.byteLength !== 16) {
|
|
916
|
-
throw new TypeError('Canonical relocation aggregate id is invalid.');
|
|
917
|
-
}
|
|
918
|
-
const canonical = Buffer.from([
|
|
919
|
-
bytes[3],
|
|
920
|
-
bytes[2],
|
|
921
|
-
bytes[1],
|
|
922
|
-
bytes[0],
|
|
923
|
-
bytes[5],
|
|
924
|
-
bytes[4],
|
|
925
|
-
bytes[7],
|
|
926
|
-
bytes[6],
|
|
927
|
-
...bytes.subarray(8)
|
|
928
|
-
]).toString('hex');
|
|
929
|
-
return (`${canonical.slice(0, 8)}-${canonical.slice(8, 12)}-${canonical.slice(12, 16)}` +
|
|
930
|
-
`-${canonical.slice(16, 20)}-${canonical.slice(20)}`);
|
|
931
|
-
}
|
|
932
|
-
function text16le(value) {
|
|
933
|
-
const bytes = Buffer.from(value, 'utf8');
|
|
934
|
-
if (bytes.byteLength === 0 || bytes.byteLength > 0xffff)
|
|
935
|
-
throw new Error('Text16 is invalid.');
|
|
936
|
-
return Buffer.concat([u16le(bytes.byteLength), bytes]);
|
|
937
|
-
}
|
|
938
|
-
function bytes32le(value) {
|
|
939
|
-
return Buffer.concat([u32le(value.byteLength), Buffer.from(value)]);
|
|
940
|
-
}
|
|
941
|
-
function u16le(value) {
|
|
942
|
-
const result = Buffer.alloc(2);
|
|
943
|
-
result.writeUInt16LE(value);
|
|
944
|
-
return result;
|
|
945
|
-
}
|
|
946
|
-
function u32le(value) {
|
|
947
|
-
const result = Buffer.alloc(4);
|
|
948
|
-
result.writeUInt32LE(value);
|
|
949
|
-
return result;
|
|
950
|
-
}
|
|
951
|
-
function u64le(value) {
|
|
952
|
-
const result = Buffer.alloc(8);
|
|
953
|
-
result.writeBigUInt64LE(value);
|
|
954
|
-
return result;
|
|
955
|
-
}
|
|
956
|
-
function validateIdentity(actorId, operationId, actor) {
|
|
957
|
-
if (actorId.length === 0 ||
|
|
958
|
-
actor.actorId !== actorId ||
|
|
959
|
-
actor.objectGeneration <= 0n ||
|
|
960
|
-
(operationId.high === 0n && operationId.low === 0n)) {
|
|
961
|
-
throw new Error('Deferred Join completion identity is invalid.');
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
function requireSameOperation(root, operationId, actor) {
|
|
965
|
-
if (!isSameOperation(root, operationId, actor)) {
|
|
966
|
-
throw new Error(`Actor '${actor.actorId}' already has a different durable Join completion.`);
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
function isSameOperation(root, operationId, actor) {
|
|
970
|
-
return (root.operationId.high === operationId.high &&
|
|
971
|
-
root.operationId.low === operationId.low &&
|
|
972
|
-
root.actor.actorId === actor.actorId &&
|
|
973
|
-
root.actor.objectGeneration === actor.objectGeneration);
|
|
974
|
-
}
|
|
975
|
-
function requireSameActor(root, actor) {
|
|
976
|
-
if (root.actor.actorId !== actor.actorId ||
|
|
977
|
-
root.actor.objectGeneration !== actor.objectGeneration) {
|
|
978
|
-
throw new Error('Deferred Join completion generation fence is stale ' +
|
|
979
|
-
`(root ${root.actor.actorId}/${root.actor.objectGeneration}, ` +
|
|
980
|
-
`actor ${actor.actorId}/${actor.objectGeneration}).`);
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
function cursorIndex(cursor) {
|
|
984
|
-
return cursor === 'prepared' ? 1 : cursor === 'committed' ? 2 : 3;
|
|
985
|
-
}
|
|
986
|
-
function isCursor(value) {
|
|
987
|
-
return value === 'prepared' || value === 'committed' || value === 'delivered';
|
|
988
|
-
}
|
|
989
|
-
function storedSnapshot(result) {
|
|
990
|
-
const { kind: _kind, ...snapshot } = result;
|
|
991
|
-
return { kind: 'snapshot', ...snapshot };
|
|
992
|
-
}
|