@serve.zone/interfaces 31.9.0 → 32.0.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/.smartconfig.json +1 -0
- package/changelog.md +467 -0
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/appstore/types.d.ts +4 -6
- package/dist_ts/appstore/types.js +5 -5
- package/dist_ts/data/backup.d.ts +3 -26
- package/dist_ts/data/cluster.d.ts +36 -11
- package/dist_ts/data/cluster.js +33 -22
- package/dist_ts/data/clusteringress.d.ts +8 -0
- package/dist_ts/data/clusteringress.js +13 -8
- package/dist_ts/data/clusternode.d.ts +121 -74
- package/dist_ts/data/clusternode.js +109 -132
- package/dist_ts/data/coremail.d.ts +3 -7
- package/dist_ts/data/coremail.js +2 -2
- package/dist_ts/data/coremail.runtime.d.ts +0 -1
- package/dist_ts/data/coremail.runtime.js +5 -22
- package/dist_ts/data/deploymentadoption.d.ts +0 -2
- package/dist_ts/data/deploymentadoption.js +40 -6
- package/dist_ts/data/deploymentoperation.js +16 -3
- package/dist_ts/data/deploymentpreflight.d.ts +0 -2
- package/dist_ts/data/deploymentpreflight.js +1 -1
- package/dist_ts/data/immutableimage.d.ts +38 -21
- package/dist_ts/data/immutableimage.js +45 -5
- package/dist_ts/data/index.d.ts +1 -1
- package/dist_ts/data/isolatedrestore.d.ts +139 -21
- package/dist_ts/data/isolatedrestore.golden.d.ts +0 -1
- package/dist_ts/data/isolatedrestore.golden.js +6 -9
- package/dist_ts/data/isolatedrestore.js +176 -40
- package/dist_ts/data/mail.d.ts +1 -1
- package/dist_ts/data/networkaddressplan.d.ts +8 -8
- package/dist_ts/data/networkaddressplan.js +4 -4
- package/dist_ts/data/networkauthority.d.ts +20 -22
- package/dist_ts/data/networkauthority.js +26 -28
- package/dist_ts/data/networkcredential.d.ts +10 -10
- package/dist_ts/data/networkcredential.js +16 -16
- package/dist_ts/data/networkdelivery.d.ts +18 -18
- package/dist_ts/data/networkdelivery.js +16 -16
- package/dist_ts/data/networklease.d.ts +18 -7
- package/dist_ts/data/networklease.js +29 -7
- package/dist_ts/data/networknode.d.ts +2 -2
- package/dist_ts/data/networkprojection.d.ts +59 -60
- package/dist_ts/data/networkprojection.js +53 -57
- package/dist_ts/data/networkprotection.d.ts +27 -28
- package/dist_ts/data/networkprotection.js +36 -36
- package/dist_ts/data/networkrouter.d.ts +11 -11
- package/dist_ts/data/networkrouter.js +1 -1
- package/dist_ts/data/networksigning.d.ts +16 -18
- package/dist_ts/data/networksigning.js +20 -21
- package/dist_ts/data/nodecredential.d.ts +4 -6
- package/dist_ts/data/nodeenrollment.d.ts +35 -40
- package/dist_ts/data/nodeenrollment.js +57 -72
- package/dist_ts/data/privatenetwork.d.ts +21 -24
- package/dist_ts/data/privatenetwork.js +39 -54
- package/dist_ts/data/runtimeassignment.d.ts +50 -34
- package/dist_ts/data/runtimeassignment.js +79 -45
- package/dist_ts/data/runtimeconfig.d.ts +21 -22
- package/dist_ts/data/runtimeconfig.js +24 -24
- package/dist_ts/data/runtimesession.d.ts +100 -62
- package/dist_ts/data/runtimesession.js +98 -79
- package/dist_ts/data/runtimeterminalreceipt.d.ts +28 -29
- package/dist_ts/data/runtimeterminalreceipt.js +42 -42
- package/dist_ts/data/secret.d.ts +18 -25
- package/dist_ts/data/secret.js +12 -52
- package/dist_ts/data/servicecredential.d.ts +14 -16
- package/dist_ts/data/servicecredential.js +17 -28
- package/dist_ts/data/serviceruntime.d.ts +7 -7
- package/dist_ts/data/serviceruntime.js +4 -4
- package/dist_ts/data/sparknodereport.d.ts +27 -14
- package/dist_ts/data/sparknodereport.js +35 -28
- package/dist_ts/data/webpush.d.ts +0 -1
- package/dist_ts/index.d.ts +2 -1
- package/dist_ts/index.js +3 -2
- package/dist_ts/platform/objectstorageretention.d.ts +21 -24
- package/dist_ts/platform/objectstorageretention.js +6 -18
- package/dist_ts/platform/storage.d.ts +1 -3
- package/dist_ts/platform/storagemigration.d.ts +0 -7
- package/dist_ts/platform/storagemigration.golden.d.ts +0 -1
- package/dist_ts/platform/storagemigration.golden.js +8 -12
- package/dist_ts/platform/storagemigration.js +6 -51
- package/dist_ts/platform/types.d.ts +2 -2
- package/dist_ts/private/canonicaljson.d.ts +9 -1
- package/dist_ts/private/canonicaljson.js +14 -2
- package/dist_ts/private/dataproperties.d.ts +62 -0
- package/dist_ts/private/dataproperties.js +117 -0
- package/dist_ts/private/networkcontract.d.ts +10 -10
- package/dist_ts/private/networkcontract.js +1 -1
- package/dist_ts/private/releaseversion.d.ts +37 -0
- package/dist_ts/private/releaseversion.js +48 -0
- package/dist_ts/private/runtimepolicy.d.ts +2 -2
- package/dist_ts/private/runtimepolicy.js +1 -1
- package/dist_ts/private/tokenlist.d.ts +9 -0
- package/dist_ts/private/tokenlist.js +23 -0
- package/dist_ts/protocol.d.ts +137 -0
- package/dist_ts/protocol.js +255 -0
- package/dist_ts/requests/admin.d.ts +8 -8
- package/dist_ts/requests/backup.d.ts +102 -112
- package/dist_ts/requests/cluster.d.ts +10 -10
- package/dist_ts/requests/clusteringress.d.ts +9 -0
- package/dist_ts/requests/clusteringress.js +1 -1
- package/dist_ts/requests/config.d.ts +3 -3
- package/dist_ts/requests/corestore.d.ts +0 -3
- package/dist_ts/requests/corestore.js +5 -9
- package/dist_ts/requests/network.d.ts +30 -30
- package/dist_ts/requests/node.d.ts +15 -28
- package/dist_ts/requests/pallet.d.ts +13 -13
- package/dist_ts/requests/runtimesession.d.ts +53 -41
- package/dist_ts/requests/secret.d.ts +4 -5
- package/dist_ts/requests/secret.js +1 -5
- package/dist_ts/runtime.corestore.d.ts +56 -74
- package/dist_ts/runtime.corestore.databaseexportpackage.d.ts +30 -36
- package/dist_ts/runtime.corestore.databaseexportpackage.golden.d.ts +11 -12
- package/dist_ts/runtime.corestore.databaseexportpackage.golden.js +54 -71
- package/dist_ts/runtime.corestore.databaseexportpackage.js +9 -25
- package/dist_ts/runtime.corestore.js +35 -135
- package/dist_ts/runtime.corestore.relay.js +2 -7
- package/dist_ts/runtime.d.ts +38 -48
- package/dist_ts/runtime.js +20 -77
- package/dist_ts/runtime.networkprojection.d.ts +4 -4
- package/dist_ts/runtime.networkprojection.js +18 -18
- package/dist_ts/runtime.workloadinit.d.ts +23 -24
- package/dist_ts/runtime.workloadinit.js +6 -13
- package/package.json +2 -2
- package/readme.md +421 -270
- package/ts/00_commitinfo_data.ts +3 -3
- package/ts/appstore/types.ts +4 -6
- package/ts/data/backup.ts +3 -38
- package/ts/data/cluster.ts +51 -34
- package/ts/data/clusteringress.ts +12 -12
- package/ts/data/clusternode.ts +204 -232
- package/ts/data/coremail.runtime.ts +4 -21
- package/ts/data/coremail.ts +3 -7
- package/ts/data/deploymentadoption.ts +46 -4
- package/ts/data/deploymentoperation.ts +16 -1
- package/ts/data/deploymentpreflight.ts +0 -2
- package/ts/data/immutableimage.ts +71 -24
- package/ts/data/index.ts +1 -1
- package/ts/data/isolatedrestore.golden.ts +5 -9
- package/ts/data/isolatedrestore.ts +339 -54
- package/ts/data/mail.ts +1 -1
- package/ts/data/networkaddressplan.ts +13 -13
- package/ts/data/networkauthority.ts +42 -46
- package/ts/data/networkcredential.ts +24 -24
- package/ts/data/networkdelivery.ts +27 -27
- package/ts/data/networklease.ts +40 -13
- package/ts/data/networknode.ts +2 -2
- package/ts/data/networkprojection.ts +119 -124
- package/ts/data/networkprotection.ts +54 -55
- package/ts/data/networkrouter.ts +14 -14
- package/ts/data/networksigning.ts +29 -32
- package/ts/data/nodecredential.ts +4 -6
- package/ts/data/nodeenrollment.ts +96 -114
- package/ts/data/privatenetwork.ts +58 -74
- package/ts/data/runtimeassignment.ts +143 -94
- package/ts/data/runtimeconfig.ts +45 -46
- package/ts/data/runtimesession.ts +185 -138
- package/ts/data/runtimeterminalreceipt.ts +72 -73
- package/ts/data/secret.ts +28 -76
- package/ts/data/servicecredential.ts +33 -43
- package/ts/data/serviceruntime.ts +11 -11
- package/ts/data/sparknodereport.ts +48 -36
- package/ts/data/webpush.ts +0 -1
- package/ts/index.ts +2 -0
- package/ts/platform/objectstorageretention.ts +36 -55
- package/ts/platform/storage.ts +1 -3
- package/ts/platform/storagemigration.golden.ts +7 -11
- package/ts/platform/storagemigration.ts +5 -55
- package/ts/platform/types.ts +2 -2
- package/ts/private/canonicaljson.ts +13 -1
- package/ts/private/dataproperties.ts +139 -0
- package/ts/private/networkcontract.ts +9 -9
- package/ts/private/releaseversion.ts +70 -0
- package/ts/private/runtimepolicy.ts +2 -2
- package/ts/private/tokenlist.ts +30 -0
- package/ts/protocol.ts +364 -0
- package/ts/requests/admin.ts +11 -11
- package/ts/requests/backup.ts +112 -117
- package/ts/requests/cluster.ts +13 -13
- package/ts/requests/clusteringress.ts +9 -0
- package/ts/requests/config.ts +3 -3
- package/ts/requests/corestore.ts +4 -16
- package/ts/requests/network.ts +40 -40
- package/ts/requests/node.ts +21 -38
- package/ts/requests/pallet.ts +17 -17
- package/ts/requests/runtimesession.ts +63 -51
- package/ts/requests/secret.ts +5 -10
- package/ts/runtime.corestore.databaseexportpackage.golden.ts +77 -95
- package/ts/runtime.corestore.databaseexportpackage.ts +51 -73
- package/ts/runtime.corestore.relay.ts +1 -10
- package/ts/runtime.corestore.ts +118 -268
- package/ts/runtime.networkprojection.ts +30 -30
- package/ts/runtime.ts +83 -158
- package/ts/runtime.workloadinit.ts +36 -48
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.d.ts +0 -902
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.golden.d.ts +0 -35
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.golden.js +0 -315
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.js +0 -3315
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.d.ts +0 -291
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.d.ts +0 -30
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.js +0 -408
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.js +0 -1126
- package/ts/runtime.cloudlylegacydeploymentsettlement.golden.ts +0 -421
- package/ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.ts +0 -510
- package/ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.ts +0 -2470
- package/ts/runtime.cloudlylegacydeploymentsettlement.ts +0 -6630
|
@@ -5,8 +5,11 @@ import {
|
|
|
5
5
|
createSha256Hex,
|
|
6
6
|
deepFreezeValue,
|
|
7
7
|
} from '../private/canonicaljson.js';
|
|
8
|
+
import {
|
|
9
|
+
readDataElements, readDataProperty, readExactDataRecord,
|
|
10
|
+
} from '../private/dataproperties.js';
|
|
8
11
|
|
|
9
|
-
export interface
|
|
12
|
+
export interface INodeEnrollmentCredentialProposal {
|
|
10
13
|
purpose: TNodeCredentialPurpose;
|
|
11
14
|
installationId: string;
|
|
12
15
|
mutationId: string;
|
|
@@ -17,8 +20,7 @@ export interface INodeEnrollmentCredentialProposalV1 {
|
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
/** Value-free, immutable proposal. Hashes are still sensitive transport fields. */
|
|
20
|
-
export interface
|
|
21
|
-
schemaVersion: 1;
|
|
23
|
+
export interface INodeEnrollment {
|
|
22
24
|
/** 32 CSPRNG bytes encoded as lowercase hexadecimal; retain across every retry. */
|
|
23
25
|
enrollmentId: string;
|
|
24
26
|
cloudlyOrigin: string;
|
|
@@ -27,18 +29,18 @@ export interface INodeEnrollmentV1 {
|
|
|
27
29
|
| { kind: 'jump'; proofHash: string }
|
|
28
30
|
| { kind: 'adopt-existing'; nodeId: string; proofHash: string };
|
|
29
31
|
credentials: [
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
INodeEnrollmentCredentialProposal & { purpose: 'spark' },
|
|
33
|
+
INodeEnrollmentCredentialProposal & { purpose: 'pallet' },
|
|
32
34
|
];
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
export interface
|
|
36
|
-
enrollment:
|
|
37
|
+
export interface INodeEnrollmentRequest {
|
|
38
|
+
enrollment: INodeEnrollment;
|
|
37
39
|
/** Never persist on the server, log, put in URLs, or expose in transport hooks. */
|
|
38
40
|
proof: { kind: 'bootstrap' | 'pending-spark'; bearer: string };
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
export interface
|
|
43
|
+
export interface INodeEnrollmentCredentialAcknowledgement {
|
|
42
44
|
purpose: TNodeCredentialPurpose;
|
|
43
45
|
installationId: string;
|
|
44
46
|
mutationId: string;
|
|
@@ -47,29 +49,26 @@ export interface INodeEnrollmentCredentialAcknowledgementV1 {
|
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
/** Immutable commit evidence, not authorization or workload readiness. */
|
|
50
|
-
export interface
|
|
51
|
-
schemaVersion: 1;
|
|
52
|
+
export interface INodeEnrollmentAcknowledgement {
|
|
52
53
|
enrollmentId: string;
|
|
53
54
|
cloudlyOrigin: string;
|
|
54
55
|
nodeId: string;
|
|
55
56
|
requestDigest: string;
|
|
56
57
|
credentials: [
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
INodeEnrollmentCredentialAcknowledgement & { purpose: 'spark' },
|
|
59
|
+
INodeEnrollmentCredentialAcknowledgement & { purpose: 'pallet' },
|
|
59
60
|
];
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
/** Returned only after current Spark authentication and proof that Pallet is absent. */
|
|
63
|
-
export interface
|
|
64
|
-
schemaVersion: 1;
|
|
64
|
+
export interface INodeEnrollmentState {
|
|
65
65
|
nodeId: string;
|
|
66
66
|
spark: { generation: number; sessionEpoch: number };
|
|
67
67
|
pallet: 'absent';
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/** Root-authenticated, node-local IPC only. Initial Pallet authority is always absent. */
|
|
71
|
-
export interface
|
|
72
|
-
schemaVersion: 1;
|
|
71
|
+
export interface IPalletNodeEnrollmentPreparation {
|
|
73
72
|
purpose: 'pallet';
|
|
74
73
|
installationId: string;
|
|
75
74
|
mutationId: string;
|
|
@@ -78,13 +77,12 @@ export interface IPalletNodeEnrollmentPreparationV1 {
|
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
/** Full exact activation wire body; Cloudly authentication remains the coordinator's responsibility. */
|
|
81
|
-
export interface
|
|
82
|
-
enrollment:
|
|
83
|
-
acknowledgement:
|
|
80
|
+
export interface IPalletNodeEnrollmentActivation {
|
|
81
|
+
enrollment: INodeEnrollment;
|
|
82
|
+
acknowledgement: INodeEnrollmentAcknowledgement;
|
|
84
83
|
}
|
|
85
84
|
|
|
86
|
-
interface
|
|
87
|
-
schemaVersion: 1;
|
|
85
|
+
interface IPalletNodeEnrollmentConfirmationBase {
|
|
88
86
|
purpose: 'pallet';
|
|
89
87
|
enrollmentId: string;
|
|
90
88
|
cloudlyOrigin: string;
|
|
@@ -92,23 +90,23 @@ interface IPalletNodeEnrollmentConfirmationBaseV1 {
|
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
/** The exact pending binding is durable now, not merely a historical receipt. */
|
|
95
|
-
export interface
|
|
93
|
+
export interface IPalletNodeEnrollmentBound extends IPalletNodeEnrollmentConfirmationBase {
|
|
96
94
|
phase: 'bound';
|
|
97
95
|
/** Null before Cloudly assigns a fresh Jump node; exact existing node for adoption. */
|
|
98
96
|
nodeId: string | null;
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
/** Exact CURRENT local Pallet identity, not Spark activation or remote authorization. */
|
|
102
|
-
export interface
|
|
100
|
+
export interface IPalletNodeEnrollmentActive extends IPalletNodeEnrollmentConfirmationBase {
|
|
103
101
|
phase: 'active';
|
|
104
102
|
nodeId: string;
|
|
105
103
|
}
|
|
106
104
|
|
|
107
|
-
export type
|
|
108
|
-
|
|
|
105
|
+
export type TPalletNodeEnrollmentConfirmation =
|
|
106
|
+
| IPalletNodeEnrollmentBound | IPalletNodeEnrollmentActive;
|
|
109
107
|
|
|
110
108
|
/** Wire bounds, not a listener, permission check, timeout implementation or storage API. */
|
|
111
|
-
export const
|
|
109
|
+
export const palletNodeEnrollmentContract = Object.freeze({
|
|
112
110
|
socketPath: '/run/serve.zone/pallet/control.sock',
|
|
113
111
|
frame: 'u32be-length-prefixed-utf8-json-then-write-half-close',
|
|
114
112
|
requestsPerConnection: 1,
|
|
@@ -116,8 +114,8 @@ export const palletNodeEnrollmentV1Contract = Object.freeze({
|
|
|
116
114
|
maxResponseBytes: 16384,
|
|
117
115
|
} as const);
|
|
118
116
|
|
|
119
|
-
export const
|
|
120
|
-
digestDomain: 'serve.zone/node-enrollment
|
|
117
|
+
export const nodeEnrollmentContract = Object.freeze({
|
|
118
|
+
digestDomain: 'serve.zone/node-enrollment',
|
|
121
119
|
localActivation: 'independently-durable-convergence',
|
|
122
120
|
bootstrapProof: 'first-commit-only',
|
|
123
121
|
pendingSparkProof: 'committed-exact-receipt-only',
|
|
@@ -128,31 +126,18 @@ function requireValue(valueArg: unknown): asserts valueArg {
|
|
|
128
126
|
if (!valueArg) fail();
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
/**
|
|
129
|
+
/** Exactly this shape's keys, read once as data; an accessor is refused, never invoked. */
|
|
132
130
|
const record = (valueArg: unknown, keysArg: readonly string[]): Record<string, unknown> => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
requireValue(prototype === Object.prototype || prototype === null);
|
|
136
|
-
const keys = Reflect.ownKeys(valueArg);
|
|
137
|
-
requireValue(keys.length === keysArg.length);
|
|
138
|
-
const snapshot: Record<string, unknown> = Object.create(null);
|
|
139
|
-
for (const key of keys) {
|
|
140
|
-
requireValue(typeof key === 'string' && keysArg.includes(key));
|
|
141
|
-
const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
|
|
142
|
-
requireValue(descriptor?.enumerable && Object.hasOwn(descriptor, 'value'));
|
|
143
|
-
snapshot[key] = descriptor.value;
|
|
144
|
-
}
|
|
131
|
+
const snapshot = readExactDataRecord(valueArg, keysArg);
|
|
132
|
+
requireValue(snapshot !== null);
|
|
145
133
|
return snapshot;
|
|
146
134
|
};
|
|
147
135
|
|
|
136
|
+
/** The dense two-element credential tuple, read the same way as a record. */
|
|
148
137
|
const pair = (valueArg: unknown): [unknown, unknown] => {
|
|
149
|
-
|
|
150
|
-
requireValue(
|
|
151
|
-
|
|
152
|
-
const second = Object.getOwnPropertyDescriptor(valueArg, '1');
|
|
153
|
-
requireValue(first?.enumerable && Object.hasOwn(first, 'value'));
|
|
154
|
-
requireValue(second?.enumerable && Object.hasOwn(second, 'value'));
|
|
155
|
-
return [first.value, second.value];
|
|
138
|
+
const elements = readDataElements(valueArg, 2);
|
|
139
|
+
requireValue(elements !== null && elements.length === 2);
|
|
140
|
+
return [elements[0], elements[1]];
|
|
156
141
|
};
|
|
157
142
|
const id = (valueArg: unknown): string => {
|
|
158
143
|
requireValue(typeof valueArg === 'string' && /^[A-Za-z0-9_-]{1,128}$/.test(valueArg));
|
|
@@ -184,7 +169,7 @@ const hostname = (valueArg: unknown): string => {
|
|
|
184
169
|
|
|
185
170
|
const proposal = <TPurpose extends TNodeCredentialPurpose>(
|
|
186
171
|
valueArg: unknown, purposeArg: TPurpose,
|
|
187
|
-
):
|
|
172
|
+
): INodeEnrollmentCredentialProposal & { purpose: TPurpose } => {
|
|
188
173
|
const value = record(valueArg, ['purpose', 'installationId', 'mutationId', 'tokenHash',
|
|
189
174
|
'expectedGeneration', 'expectedSessionEpoch']);
|
|
190
175
|
requireValue(value.purpose === purposeArg);
|
|
@@ -194,22 +179,20 @@ const proposal = <TPurpose extends TNodeCredentialPurpose>(
|
|
|
194
179
|
};
|
|
195
180
|
|
|
196
181
|
const distinctOwners = (
|
|
197
|
-
sparkArg:
|
|
198
|
-
palletArg:
|
|
182
|
+
sparkArg: INodeEnrollmentCredentialAcknowledgement | INodeEnrollmentCredentialProposal,
|
|
183
|
+
palletArg: INodeEnrollmentCredentialAcknowledgement | INodeEnrollmentCredentialProposal,
|
|
199
184
|
): void => {
|
|
200
185
|
requireValue(sparkArg.installationId !== palletArg.installationId
|
|
201
186
|
&& sparkArg.mutationId !== palletArg.mutationId && sparkArg.tokenHash !== palletArg.tokenHash);
|
|
202
187
|
};
|
|
203
188
|
|
|
204
189
|
/** Detached frozen snapshot, captured synchronously before hashing or other awaits. */
|
|
205
|
-
export const
|
|
206
|
-
const value = record(valueArg, ['
|
|
190
|
+
export const snapshotNodeEnrollment = (valueArg: unknown): INodeEnrollment => {
|
|
191
|
+
const value = record(valueArg, ['enrollmentId', 'cloudlyOrigin', 'hostname',
|
|
207
192
|
'bootstrap', 'credentials']);
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
requireValue(
|
|
211
|
-
const kind = Object.getOwnPropertyDescriptor(value.bootstrap, 'kind');
|
|
212
|
-
requireValue(kind && Object.hasOwn(kind, 'value'));
|
|
193
|
+
// Read the discriminant as data, never through an input getter.
|
|
194
|
+
const kind = readDataProperty(value.bootstrap, 'kind');
|
|
195
|
+
requireValue(kind !== null);
|
|
213
196
|
const bootstrap = record(value.bootstrap, kind.value === 'jump'
|
|
214
197
|
? ['kind', 'proofHash'] : ['kind', 'nodeId', 'proofHash']);
|
|
215
198
|
requireValue(bootstrap.kind === 'jump' || bootstrap.kind === 'adopt-existing');
|
|
@@ -221,7 +204,7 @@ export const snapshotNodeEnrollmentV1 = (valueArg: unknown): INodeEnrollmentV1 =
|
|
|
221
204
|
requireValue(bootstrap.kind === 'jump'
|
|
222
205
|
? spark.expectedGeneration === 0 && spark.expectedSessionEpoch === 0
|
|
223
206
|
: spark.expectedGeneration > 0);
|
|
224
|
-
return deepFreezeValue({
|
|
207
|
+
return deepFreezeValue({ enrollmentId: hash(value.enrollmentId),
|
|
225
208
|
cloudlyOrigin: origin(value.cloudlyOrigin), hostname: hostname(value.hostname),
|
|
226
209
|
bootstrap: bootstrap.kind === 'jump'
|
|
227
210
|
? { kind: 'jump', proofHash: hash(bootstrap.proofHash) }
|
|
@@ -229,16 +212,16 @@ export const snapshotNodeEnrollmentV1 = (valueArg: unknown): INodeEnrollmentV1 =
|
|
|
229
212
|
credentials: [spark, pallet] });
|
|
230
213
|
};
|
|
231
214
|
|
|
232
|
-
export const
|
|
233
|
-
const payload =
|
|
215
|
+
export const computeNodeEnrollmentDigest = async (valueArg: INodeEnrollment): Promise<string> => {
|
|
216
|
+
const payload = snapshotNodeEnrollment(valueArg);
|
|
234
217
|
return createCanonicalJsonSha256Hex(canonicalizeStrictJson({
|
|
235
|
-
domain:
|
|
218
|
+
domain: nodeEnrollmentContract.digestDomain, payload,
|
|
236
219
|
}, fail), fail);
|
|
237
220
|
};
|
|
238
221
|
|
|
239
|
-
export const
|
|
222
|
+
export const snapshotNodeEnrollmentRequest = (valueArg: unknown): INodeEnrollmentRequest => {
|
|
240
223
|
const value = record(valueArg, ['enrollment', 'proof']);
|
|
241
|
-
const enrollment =
|
|
224
|
+
const enrollment = snapshotNodeEnrollment(value.enrollment);
|
|
242
225
|
const proof = record(value.proof, ['kind', 'bearer']);
|
|
243
226
|
requireValue(proof.kind === 'bootstrap' || proof.kind === 'pending-spark');
|
|
244
227
|
requireValue(typeof proof.bearer === 'string');
|
|
@@ -252,11 +235,11 @@ export const snapshotNodeEnrollmentRequestV1 = (valueArg: unknown): INodeEnrollm
|
|
|
252
235
|
* receiptState from its owned transaction, compare the complete stored proposal,
|
|
253
236
|
* and fence current Jump/Spark/Pallet authority before any commit or replay.
|
|
254
237
|
*/
|
|
255
|
-
export const
|
|
256
|
-
valueArg:
|
|
238
|
+
export const verifyNodeEnrollmentProof = async (
|
|
239
|
+
valueArg: INodeEnrollmentRequest, receiptStateArg: 'absent' | 'committed',
|
|
257
240
|
): Promise<boolean> => {
|
|
258
241
|
try {
|
|
259
|
-
const { enrollment, proof } =
|
|
242
|
+
const { enrollment, proof } = snapshotNodeEnrollmentRequest(valueArg);
|
|
260
243
|
if (!(proof.kind === 'bootstrap' && receiptStateArg === 'absent')
|
|
261
244
|
&& !(proof.kind === 'pending-spark' && receiptStateArg === 'committed')) return false;
|
|
262
245
|
// This helper hashes exact UTF-8 text; no JSON quoting or normalization.
|
|
@@ -268,35 +251,34 @@ export const verifyNodeEnrollmentProofV1 = async (
|
|
|
268
251
|
|
|
269
252
|
const credentialAcknowledgement = <TPurpose extends TNodeCredentialPurpose>(
|
|
270
253
|
valueArg: unknown, purposeArg: TPurpose,
|
|
271
|
-
):
|
|
254
|
+
): INodeEnrollmentCredentialAcknowledgement & { purpose: TPurpose } => {
|
|
272
255
|
const value = record(valueArg, ['purpose', 'installationId', 'mutationId', 'tokenHash', 'generation']);
|
|
273
256
|
requireValue(value.purpose === purposeArg);
|
|
274
257
|
return { purpose: purposeArg, installationId: id(value.installationId), mutationId: id(value.mutationId),
|
|
275
258
|
tokenHash: hash(value.tokenHash), generation: counter(value.generation, 1) };
|
|
276
259
|
};
|
|
277
260
|
|
|
278
|
-
export const
|
|
261
|
+
export const snapshotNodeEnrollmentAcknowledgement = (
|
|
279
262
|
valueArg: unknown,
|
|
280
|
-
):
|
|
281
|
-
const value = record(valueArg, ['
|
|
263
|
+
): INodeEnrollmentAcknowledgement => {
|
|
264
|
+
const value = record(valueArg, ['enrollmentId', 'cloudlyOrigin', 'nodeId',
|
|
282
265
|
'requestDigest', 'credentials']);
|
|
283
|
-
requireValue(value.schemaVersion === 1);
|
|
284
266
|
const [sparkInput, palletInput] = pair(value.credentials);
|
|
285
267
|
const spark = credentialAcknowledgement(sparkInput, 'spark');
|
|
286
268
|
const pallet = credentialAcknowledgement(palletInput, 'pallet');
|
|
287
269
|
distinctOwners(spark, pallet);
|
|
288
270
|
requireValue(pallet.generation === 1);
|
|
289
|
-
return deepFreezeValue({
|
|
271
|
+
return deepFreezeValue({ enrollmentId: hash(value.enrollmentId),
|
|
290
272
|
cloudlyOrigin: origin(value.cloudlyOrigin), nodeId: id(value.nodeId),
|
|
291
273
|
requestDigest: hash(value.requestDigest), credentials: [spark, pallet] });
|
|
292
274
|
};
|
|
293
275
|
|
|
294
276
|
/** Content binding only. Authenticate Cloudly first; persist only the returned snapshot. */
|
|
295
|
-
export const
|
|
296
|
-
enrollmentArg:
|
|
297
|
-
): Promise<
|
|
298
|
-
const enrollment =
|
|
299
|
-
const ack =
|
|
277
|
+
export const bindNodeEnrollmentAcknowledgement = async (
|
|
278
|
+
enrollmentArg: INodeEnrollment, acknowledgementArg: INodeEnrollmentAcknowledgement,
|
|
279
|
+
): Promise<INodeEnrollmentAcknowledgement> => {
|
|
280
|
+
const enrollment = snapshotNodeEnrollment(enrollmentArg);
|
|
281
|
+
const ack = snapshotNodeEnrollmentAcknowledgement(acknowledgementArg);
|
|
300
282
|
requireValue(ack.enrollmentId === enrollment.enrollmentId && ack.cloudlyOrigin === enrollment.cloudlyOrigin
|
|
301
283
|
&& (enrollment.bootstrap.kind === 'jump' || ack.nodeId === enrollment.bootstrap.nodeId));
|
|
302
284
|
for (const index of [0, 1] as const) {
|
|
@@ -306,35 +288,35 @@ export const bindNodeEnrollmentAcknowledgementV1 = async (
|
|
|
306
288
|
&& actual.mutationId === expected.mutationId && actual.tokenHash === expected.tokenHash
|
|
307
289
|
&& actual.generation === expected.expectedGeneration + 1);
|
|
308
290
|
}
|
|
309
|
-
requireValue(ack.requestDigest === await
|
|
291
|
+
requireValue(ack.requestDigest === await computeNodeEnrollmentDigest(enrollment));
|
|
310
292
|
return ack;
|
|
311
293
|
};
|
|
312
294
|
|
|
313
|
-
export const
|
|
314
|
-
const value = record(valueArg, ['
|
|
315
|
-
requireValue(value.
|
|
295
|
+
export const snapshotNodeEnrollmentState = (valueArg: unknown): INodeEnrollmentState => {
|
|
296
|
+
const value = record(valueArg, ['nodeId', 'spark', 'pallet']);
|
|
297
|
+
requireValue(value.pallet === 'absent');
|
|
316
298
|
const spark = record(value.spark, ['generation', 'sessionEpoch']);
|
|
317
|
-
return deepFreezeValue({
|
|
299
|
+
return deepFreezeValue({ nodeId: id(value.nodeId), pallet: 'absent',
|
|
318
300
|
spark: { generation: counter(spark.generation, 1, true), sessionEpoch: counter(spark.sessionEpoch, 0, true) } });
|
|
319
301
|
};
|
|
320
302
|
|
|
321
303
|
/** Decoded JSON/data records only, captured synchronously; never invokes getters. */
|
|
322
|
-
export const
|
|
304
|
+
export const snapshotPalletNodeEnrollmentPreparation = (
|
|
323
305
|
valueArg: unknown,
|
|
324
|
-
):
|
|
325
|
-
const value = record(valueArg, ['
|
|
306
|
+
): IPalletNodeEnrollmentPreparation => {
|
|
307
|
+
const value = record(valueArg, ['purpose', 'installationId', 'mutationId',
|
|
326
308
|
'cloudlyOrigin', 'nodeId']);
|
|
327
|
-
requireValue(value.
|
|
328
|
-
return deepFreezeValue({
|
|
309
|
+
requireValue(value.purpose === 'pallet');
|
|
310
|
+
return deepFreezeValue({ purpose: 'pallet',
|
|
329
311
|
installationId: id(value.installationId), mutationId: id(value.mutationId),
|
|
330
312
|
cloudlyOrigin: origin(value.cloudlyOrigin), nodeId: value.nodeId === null ? null : id(value.nodeId) });
|
|
331
313
|
};
|
|
332
314
|
|
|
333
315
|
/** Content binding only. Authenticate the local Pallet transport before trusting this proposal. */
|
|
334
|
-
export const
|
|
335
|
-
preparationArg:
|
|
336
|
-
):
|
|
337
|
-
const preparation =
|
|
316
|
+
export const bindPalletNodeEnrollmentPreparation = (
|
|
317
|
+
preparationArg: IPalletNodeEnrollmentPreparation, proposalArg: unknown,
|
|
318
|
+
): INodeEnrollment['credentials'][1] => {
|
|
319
|
+
const preparation = snapshotPalletNodeEnrollmentPreparation(preparationArg);
|
|
338
320
|
const result = proposal(proposalArg, 'pallet');
|
|
339
321
|
requireValue(result.installationId === preparation.installationId
|
|
340
322
|
&& result.mutationId === preparation.mutationId
|
|
@@ -343,22 +325,22 @@ export const bindPalletNodeEnrollmentPreparationV1 = (
|
|
|
343
325
|
};
|
|
344
326
|
|
|
345
327
|
/** Capture the exact wrapper and both nested values before any asynchronous content binding. */
|
|
346
|
-
export const
|
|
328
|
+
export const snapshotPalletNodeEnrollmentActivation = (
|
|
347
329
|
valueArg: unknown,
|
|
348
|
-
):
|
|
330
|
+
): IPalletNodeEnrollmentActivation => {
|
|
349
331
|
const value = record(valueArg, ['enrollment', 'acknowledgement']);
|
|
350
|
-
return deepFreezeValue({ enrollment:
|
|
351
|
-
acknowledgement:
|
|
332
|
+
return deepFreezeValue({ enrollment: snapshotNodeEnrollment(value.enrollment),
|
|
333
|
+
acknowledgement: snapshotNodeEnrollmentAcknowledgement(value.acknowledgement) });
|
|
352
334
|
};
|
|
353
335
|
|
|
354
|
-
export const
|
|
336
|
+
export const snapshotPalletNodeEnrollmentConfirmation = (
|
|
355
337
|
valueArg: unknown,
|
|
356
|
-
):
|
|
357
|
-
const value = record(valueArg, ['
|
|
338
|
+
): TPalletNodeEnrollmentConfirmation => {
|
|
339
|
+
const value = record(valueArg, ['purpose', 'enrollmentId', 'cloudlyOrigin',
|
|
358
340
|
'requestDigest', 'phase', 'nodeId']);
|
|
359
|
-
requireValue(value.
|
|
341
|
+
requireValue(value.purpose === 'pallet'
|
|
360
342
|
&& (value.phase === 'bound' || value.phase === 'active'));
|
|
361
|
-
const common = {
|
|
343
|
+
const common = { purpose: 'pallet' as const,
|
|
362
344
|
enrollmentId: hash(value.enrollmentId), cloudlyOrigin: origin(value.cloudlyOrigin),
|
|
363
345
|
requestDigest: hash(value.requestDigest) };
|
|
364
346
|
return deepFreezeValue(value.phase === 'bound'
|
|
@@ -367,15 +349,15 @@ export const snapshotPalletNodeEnrollmentConfirmationV1 = (
|
|
|
367
349
|
};
|
|
368
350
|
|
|
369
351
|
/** Pure binding only. Pallet must prove its durable pending binding before issuing this response. */
|
|
370
|
-
export const
|
|
371
|
-
enrollmentArg:
|
|
372
|
-
): Promise<
|
|
373
|
-
const enrollment =
|
|
374
|
-
const confirmation =
|
|
352
|
+
export const bindPalletNodeEnrollmentBound = async (
|
|
353
|
+
enrollmentArg: INodeEnrollment, confirmationArg: IPalletNodeEnrollmentBound,
|
|
354
|
+
): Promise<IPalletNodeEnrollmentBound> => {
|
|
355
|
+
const enrollment = snapshotNodeEnrollment(enrollmentArg);
|
|
356
|
+
const confirmation = snapshotPalletNodeEnrollmentConfirmation(confirmationArg);
|
|
375
357
|
requireValue(confirmation.phase === 'bound' && confirmation.enrollmentId === enrollment.enrollmentId
|
|
376
358
|
&& confirmation.cloudlyOrigin === enrollment.cloudlyOrigin
|
|
377
359
|
&& confirmation.nodeId === (enrollment.bootstrap.kind === 'jump' ? null : enrollment.bootstrap.nodeId));
|
|
378
|
-
requireValue(confirmation.requestDigest === await
|
|
360
|
+
requireValue(confirmation.requestDigest === await computeNodeEnrollmentDigest(enrollment));
|
|
379
361
|
return confirmation;
|
|
380
362
|
};
|
|
381
363
|
|
|
@@ -384,15 +366,15 @@ export const bindPalletNodeEnrollmentBoundV1 = async (
|
|
|
384
366
|
* Pallet owner must first prove its exact CURRENT local identity, not just a receipt.
|
|
385
367
|
* This does not assert Spark activation, current Cloudly authority or workload readiness.
|
|
386
368
|
*/
|
|
387
|
-
export const
|
|
388
|
-
activationArg:
|
|
389
|
-
confirmationArg:
|
|
390
|
-
): Promise<
|
|
369
|
+
export const bindPalletNodeEnrollmentActive = async (
|
|
370
|
+
activationArg: IPalletNodeEnrollmentActivation,
|
|
371
|
+
confirmationArg: IPalletNodeEnrollmentActive,
|
|
372
|
+
): Promise<IPalletNodeEnrollmentActive> => {
|
|
391
373
|
// Capture every caller-owned value before the asynchronous shared acknowledgement binder.
|
|
392
|
-
const { enrollment, acknowledgement } =
|
|
393
|
-
const confirmation =
|
|
374
|
+
const { enrollment, acknowledgement } = snapshotPalletNodeEnrollmentActivation(activationArg);
|
|
375
|
+
const confirmation = snapshotPalletNodeEnrollmentConfirmation(confirmationArg);
|
|
394
376
|
requireValue(confirmation.phase === 'active');
|
|
395
|
-
const ack = await
|
|
377
|
+
const ack = await bindNodeEnrollmentAcknowledgement(enrollment, acknowledgement);
|
|
396
378
|
requireValue(confirmation.enrollmentId === ack.enrollmentId && confirmation.cloudlyOrigin === ack.cloudlyOrigin
|
|
397
379
|
&& confirmation.nodeId === ack.nodeId && confirmation.requestDigest === ack.requestDigest);
|
|
398
380
|
return confirmation;
|