@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
|
@@ -15,7 +15,6 @@ import type {
|
|
|
15
15
|
} from './storage.js';
|
|
16
16
|
|
|
17
17
|
export const storageMigrationContractLimits = Object.freeze({
|
|
18
|
-
version: 2 as const,
|
|
19
18
|
maximumControlJsonBytes: 256 * 1024,
|
|
20
19
|
maximumConfiguredStringBytes: 2048,
|
|
21
20
|
maximumIssueMessageBytes: 4096,
|
|
@@ -49,7 +48,6 @@ export interface IStorageBindingMigrationOwner {
|
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
export interface IUnfencedObjectStorageBindingControlSnapshot {
|
|
52
|
-
schemaVersion: 2;
|
|
53
51
|
binding: TActiveObjectStorageBinding;
|
|
54
52
|
recordRevision: number;
|
|
55
53
|
snapshotDigest: string;
|
|
@@ -58,7 +56,6 @@ export interface IUnfencedObjectStorageBindingControlSnapshot {
|
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
export interface IFencedObjectStorageBindingControlSnapshot {
|
|
61
|
-
schemaVersion: 2;
|
|
62
59
|
binding: TActiveObjectStorageBinding;
|
|
63
60
|
recordRevision: number;
|
|
64
61
|
snapshotDigest: string;
|
|
@@ -84,7 +81,6 @@ export interface IObjectStorageMigrationTarget {
|
|
|
84
81
|
}
|
|
85
82
|
|
|
86
83
|
export interface IObjectStorageMigrationPrepareRequest {
|
|
87
|
-
schemaVersion: 2;
|
|
88
84
|
migrationId: string;
|
|
89
85
|
sourceControlSnapshot: IUnfencedObjectStorageBindingControlSnapshot;
|
|
90
86
|
workloadGeneration: number;
|
|
@@ -127,7 +123,6 @@ extends IStorageMigrationIssueBase {
|
|
|
127
123
|
}
|
|
128
124
|
|
|
129
125
|
export interface IStorageMigrationMutationFence {
|
|
130
|
-
schemaVersion: 2;
|
|
131
126
|
migrationId: string;
|
|
132
127
|
migrationDigest: string;
|
|
133
128
|
expectedMigrationRevision: number;
|
|
@@ -193,7 +188,6 @@ export interface IObjectStorageMigrationCleanupRequest
|
|
|
193
188
|
extends IStorageMigrationMutationFence {}
|
|
194
189
|
|
|
195
190
|
export interface IStorageMigrationStatusBase {
|
|
196
|
-
schemaVersion: 2;
|
|
197
191
|
migrationId: string;
|
|
198
192
|
migrationDigest: string;
|
|
199
193
|
migrationRevision: number;
|
|
@@ -526,7 +520,7 @@ const assertKeys = (
|
|
|
526
520
|
requiredKeysArg.some((keyArg) => !Object.hasOwn(recordArg, keyArg)) ||
|
|
527
521
|
actualKeys.some((keyArg) => !allowedKeys.has(keyArg))
|
|
528
522
|
) {
|
|
529
|
-
fail(`${fieldNameArg} does not match its exact
|
|
523
|
+
fail(`${fieldNameArg} does not match its exact schema`);
|
|
530
524
|
}
|
|
531
525
|
};
|
|
532
526
|
|
|
@@ -622,7 +616,7 @@ const readLiteral = <TLiteral extends string>(
|
|
|
622
616
|
typeof valueArg !== 'string' ||
|
|
623
617
|
!allowedArg.includes(valueArg as TLiteral)
|
|
624
618
|
) {
|
|
625
|
-
return fail(`${fieldNameArg} is outside the supported
|
|
619
|
+
return fail(`${fieldNameArg} is outside the supported values`);
|
|
626
620
|
}
|
|
627
621
|
return valueArg as TLiteral;
|
|
628
622
|
};
|
|
@@ -952,13 +946,13 @@ const normalizeDelivery = (
|
|
|
952
946
|
`${fieldNameArg}.targetPath must be a canonical path below /run/secrets`,
|
|
953
947
|
);
|
|
954
948
|
}
|
|
955
|
-
if (value.format !== 'servezone-object-storage
|
|
949
|
+
if (value.format !== 'servezone-object-storage') {
|
|
956
950
|
return fail(`${fieldNameArg}.format is unsupported`);
|
|
957
951
|
}
|
|
958
952
|
return {
|
|
959
953
|
type: 'file',
|
|
960
954
|
targetPath,
|
|
961
|
-
format: 'servezone-object-storage
|
|
955
|
+
format: 'servezone-object-storage',
|
|
962
956
|
uid: readSafeInteger(value.uid, `${fieldNameArg}.uid`, 0, 2_147_483_647),
|
|
963
957
|
gid: readSafeInteger(value.gid, `${fieldNameArg}.gid`, 0, 2_147_483_647),
|
|
964
958
|
mode: value.mode === 0o400 || value.mode === 0o440
|
|
@@ -1150,7 +1144,6 @@ const normalizeObjectStorageBinding = (
|
|
|
1150
1144
|
assertKeys(
|
|
1151
1145
|
value,
|
|
1152
1146
|
[
|
|
1153
|
-
'schemaVersion',
|
|
1154
1147
|
'id',
|
|
1155
1148
|
'serviceId',
|
|
1156
1149
|
'requestId',
|
|
@@ -1171,9 +1164,6 @@ const normalizeObjectStorageBinding = (
|
|
|
1171
1164
|
['capacity', 'createdAt', 'updatedAt', 'retentionDays'],
|
|
1172
1165
|
fieldNameArg,
|
|
1173
1166
|
);
|
|
1174
|
-
if (value.schemaVersion !== 2) {
|
|
1175
|
-
return fail(`${fieldNameArg}.schemaVersion must be 2`);
|
|
1176
|
-
}
|
|
1177
1167
|
if (value.kind !== 'objectStorage') {
|
|
1178
1168
|
return fail(`${fieldNameArg}.kind must be objectStorage`);
|
|
1179
1169
|
}
|
|
@@ -1206,7 +1196,6 @@ const normalizeObjectStorageBinding = (
|
|
|
1206
1196
|
return fail(`${fieldNameArg}.updatedAt must not precede createdAt`);
|
|
1207
1197
|
}
|
|
1208
1198
|
return {
|
|
1209
|
-
schemaVersion: 2,
|
|
1210
1199
|
id: readIdentifier(value.id, `${fieldNameArg}.id`),
|
|
1211
1200
|
serviceId: readIdentifier(value.serviceId, `${fieldNameArg}.serviceId`),
|
|
1212
1201
|
requestId: readIdentifier(value.requestId, `${fieldNameArg}.requestId`),
|
|
@@ -1327,7 +1316,6 @@ const normalizeUnfencedSnapshotShape = (
|
|
|
1327
1316
|
assertExactKeys(
|
|
1328
1317
|
value,
|
|
1329
1318
|
[
|
|
1330
|
-
'schemaVersion',
|
|
1331
1319
|
'binding',
|
|
1332
1320
|
'recordRevision',
|
|
1333
1321
|
'snapshotDigest',
|
|
@@ -1335,11 +1323,7 @@ const normalizeUnfencedSnapshotShape = (
|
|
|
1335
1323
|
],
|
|
1336
1324
|
fieldNameArg,
|
|
1337
1325
|
);
|
|
1338
|
-
if (value.schemaVersion !== 2) {
|
|
1339
|
-
return fail(`${fieldNameArg}.schemaVersion must be 2`);
|
|
1340
|
-
}
|
|
1341
1326
|
return {
|
|
1342
|
-
schemaVersion: 2,
|
|
1343
1327
|
binding: normalizeObjectStorageBinding(
|
|
1344
1328
|
value.binding,
|
|
1345
1329
|
'ready',
|
|
@@ -1370,7 +1354,6 @@ const normalizeFencedSnapshotShape = (
|
|
|
1370
1354
|
assertExactKeys(
|
|
1371
1355
|
value,
|
|
1372
1356
|
[
|
|
1373
|
-
'schemaVersion',
|
|
1374
1357
|
'binding',
|
|
1375
1358
|
'recordRevision',
|
|
1376
1359
|
'snapshotDigest',
|
|
@@ -1379,11 +1362,7 @@ const normalizeFencedSnapshotShape = (
|
|
|
1379
1362
|
],
|
|
1380
1363
|
fieldNameArg,
|
|
1381
1364
|
);
|
|
1382
|
-
if (value.schemaVersion !== 2) {
|
|
1383
|
-
return fail(`${fieldNameArg}.schemaVersion must be 2`);
|
|
1384
|
-
}
|
|
1385
1365
|
return {
|
|
1386
|
-
schemaVersion: 2,
|
|
1387
1366
|
binding: normalizeObjectStorageBinding(
|
|
1388
1367
|
value.binding,
|
|
1389
1368
|
'ready',
|
|
@@ -1413,7 +1392,6 @@ const normalizeFencedSnapshotShape = (
|
|
|
1413
1392
|
const createUnfencedSnapshotDigestPayload = (
|
|
1414
1393
|
snapshotArg: IUnfencedObjectStorageBindingControlSnapshot,
|
|
1415
1394
|
): TUnfencedObjectStorageBindingControlSnapshotDigestPayload => ({
|
|
1416
|
-
schemaVersion: 2,
|
|
1417
1395
|
binding: snapshotArg.binding,
|
|
1418
1396
|
recordRevision: snapshotArg.recordRevision,
|
|
1419
1397
|
capturedAt: snapshotArg.capturedAt,
|
|
@@ -1422,7 +1400,6 @@ const createUnfencedSnapshotDigestPayload = (
|
|
|
1422
1400
|
const createFencedSnapshotDigestPayload = (
|
|
1423
1401
|
snapshotArg: IFencedObjectStorageBindingControlSnapshot,
|
|
1424
1402
|
): TFencedObjectStorageBindingControlSnapshotDigestPayload => ({
|
|
1425
|
-
schemaVersion: 2,
|
|
1426
1403
|
binding: snapshotArg.binding,
|
|
1427
1404
|
recordRevision: snapshotArg.recordRevision,
|
|
1428
1405
|
capturedAt: snapshotArg.capturedAt,
|
|
@@ -1438,7 +1415,7 @@ export const canonicalizeUnfencedObjectStorageBindingControlSnapshotPayload = (
|
|
|
1438
1415
|
);
|
|
1439
1416
|
assertExactKeys(
|
|
1440
1417
|
value,
|
|
1441
|
-
['
|
|
1418
|
+
['binding', 'recordRevision', 'capturedAt'],
|
|
1442
1419
|
'unfenced object-storage control snapshot digest payload',
|
|
1443
1420
|
);
|
|
1444
1421
|
const normalized = normalizeUnfencedSnapshotShape({
|
|
@@ -1458,7 +1435,6 @@ export const canonicalizeFencedObjectStorageBindingControlSnapshotPayload = (
|
|
|
1458
1435
|
assertExactKeys(
|
|
1459
1436
|
value,
|
|
1460
1437
|
[
|
|
1461
|
-
'schemaVersion',
|
|
1462
1438
|
'binding',
|
|
1463
1439
|
'recordRevision',
|
|
1464
1440
|
'capturedAt',
|
|
@@ -1639,7 +1615,6 @@ const normalizePrepareRequestShape = (
|
|
|
1639
1615
|
assertExactKeys(
|
|
1640
1616
|
value,
|
|
1641
1617
|
[
|
|
1642
|
-
'schemaVersion',
|
|
1643
1618
|
'migrationId',
|
|
1644
1619
|
'sourceControlSnapshot',
|
|
1645
1620
|
'workloadGeneration',
|
|
@@ -1647,11 +1622,7 @@ const normalizePrepareRequestShape = (
|
|
|
1647
1622
|
],
|
|
1648
1623
|
'object-storage migration prepare request',
|
|
1649
1624
|
);
|
|
1650
|
-
if (value.schemaVersion !== 2) {
|
|
1651
|
-
return fail('object-storage migration prepare request.schemaVersion must be 2');
|
|
1652
|
-
}
|
|
1653
1625
|
return {
|
|
1654
|
-
schemaVersion: 2,
|
|
1655
1626
|
migrationId: readIdentifier(
|
|
1656
1627
|
value.migrationId,
|
|
1657
1628
|
'object-storage migration prepare request.migrationId',
|
|
@@ -1845,11 +1816,7 @@ const normalizeMutationFence = (
|
|
|
1845
1816
|
valueArg: Record<string, unknown>,
|
|
1846
1817
|
fieldNameArg: string,
|
|
1847
1818
|
): IStorageMigrationMutationFence => {
|
|
1848
|
-
if (valueArg.schemaVersion !== 2) {
|
|
1849
|
-
return fail(`${fieldNameArg}.schemaVersion must be 2`);
|
|
1850
|
-
}
|
|
1851
1819
|
return {
|
|
1852
|
-
schemaVersion: 2,
|
|
1853
1820
|
migrationId: readIdentifier(
|
|
1854
1821
|
valueArg.migrationId,
|
|
1855
1822
|
`${fieldNameArg}.migrationId`,
|
|
@@ -1878,7 +1845,6 @@ export const normalizeStorageMigrationMutationFence = (
|
|
|
1878
1845
|
assertExactKeys(
|
|
1879
1846
|
value,
|
|
1880
1847
|
[
|
|
1881
|
-
'schemaVersion',
|
|
1882
1848
|
'migrationId',
|
|
1883
1849
|
'migrationDigest',
|
|
1884
1850
|
'expectedMigrationRevision',
|
|
@@ -1897,7 +1863,6 @@ const normalizeQuiesceRequestShape = (
|
|
|
1897
1863
|
assertExactKeys(
|
|
1898
1864
|
value,
|
|
1899
1865
|
[
|
|
1900
|
-
'schemaVersion',
|
|
1901
1866
|
'migrationId',
|
|
1902
1867
|
'migrationDigest',
|
|
1903
1868
|
'expectedMigrationRevision',
|
|
@@ -1952,7 +1917,6 @@ const normalizeQuiesceRequestShape = (
|
|
|
1952
1917
|
const createPersistedStagingDigestPayload = (
|
|
1953
1918
|
requestArg: IObjectStorageMigrationConsumerQuiesceRequest,
|
|
1954
1919
|
): TObjectStorageMigrationPersistedStagingDigestPayload => ({
|
|
1955
|
-
schemaVersion: 2,
|
|
1956
1920
|
migrationId: requestArg.migrationId,
|
|
1957
1921
|
migrationDigest: requestArg.migrationDigest,
|
|
1958
1922
|
expectedMigrationRevision: requestArg.expectedMigrationRevision,
|
|
@@ -1972,7 +1936,6 @@ export const createObjectStorageMigrationPersistedStagingSha256 = async (
|
|
|
1972
1936
|
assertExactKeys(
|
|
1973
1937
|
value,
|
|
1974
1938
|
[
|
|
1975
|
-
'schemaVersion',
|
|
1976
1939
|
'migrationId',
|
|
1977
1940
|
'migrationDigest',
|
|
1978
1941
|
'expectedMigrationRevision',
|
|
@@ -2019,7 +1982,6 @@ const normalizeActivationRequestShape = (
|
|
|
2019
1982
|
assertExactKeys(
|
|
2020
1983
|
value,
|
|
2021
1984
|
[
|
|
2022
|
-
'schemaVersion',
|
|
2023
1985
|
'migrationId',
|
|
2024
1986
|
'migrationDigest',
|
|
2025
1987
|
'expectedMigrationRevision',
|
|
@@ -2068,7 +2030,6 @@ const normalizeActivationRequestShape = (
|
|
|
2068
2030
|
const createPersistedActivationDigestPayload = (
|
|
2069
2031
|
requestArg: IObjectStorageMigrationConsumerActivationRequest,
|
|
2070
2032
|
): TObjectStorageMigrationPersistedActivationDigestPayload => ({
|
|
2071
|
-
schemaVersion: 2,
|
|
2072
2033
|
migrationId: requestArg.migrationId,
|
|
2073
2034
|
migrationDigest: requestArg.migrationDigest,
|
|
2074
2035
|
expectedMigrationRevision: requestArg.expectedMigrationRevision,
|
|
@@ -2087,7 +2048,6 @@ export const createObjectStorageMigrationPersistedActivationSha256 = async (
|
|
|
2087
2048
|
assertExactKeys(
|
|
2088
2049
|
value,
|
|
2089
2050
|
[
|
|
2090
|
-
'schemaVersion',
|
|
2091
2051
|
'migrationId',
|
|
2092
2052
|
'migrationDigest',
|
|
2093
2053
|
'expectedMigrationRevision',
|
|
@@ -2220,7 +2180,6 @@ export const normalizeObjectStorageMigrationAbortRequest = (
|
|
|
2220
2180
|
assertExactKeys(
|
|
2221
2181
|
value,
|
|
2222
2182
|
[
|
|
2223
|
-
'schemaVersion',
|
|
2224
2183
|
'migrationId',
|
|
2225
2184
|
'migrationDigest',
|
|
2226
2185
|
'expectedMigrationRevision',
|
|
@@ -2247,7 +2206,6 @@ export const normalizeObjectStorageMigrationResumeRequest = (
|
|
|
2247
2206
|
assertExactKeys(
|
|
2248
2207
|
value,
|
|
2249
2208
|
[
|
|
2250
|
-
'schemaVersion',
|
|
2251
2209
|
'migrationId',
|
|
2252
2210
|
'migrationDigest',
|
|
2253
2211
|
'expectedMigrationRevision',
|
|
@@ -2274,7 +2232,6 @@ export const normalizeObjectStorageMigrationCleanupRequest = (
|
|
|
2274
2232
|
assertExactKeys(
|
|
2275
2233
|
value,
|
|
2276
2234
|
[
|
|
2277
|
-
'schemaVersion',
|
|
2278
2235
|
'migrationId',
|
|
2279
2236
|
'migrationDigest',
|
|
2280
2237
|
'expectedMigrationRevision',
|
|
@@ -2396,7 +2353,6 @@ const assertActiveMatchesCandidate = (
|
|
|
2396
2353
|
fieldNameArg: string,
|
|
2397
2354
|
): void => {
|
|
2398
2355
|
const immutableKeys: readonly (keyof TActiveObjectStorageBinding)[] = [
|
|
2399
|
-
'schemaVersion',
|
|
2400
2356
|
'id',
|
|
2401
2357
|
'serviceId',
|
|
2402
2358
|
'requestId',
|
|
@@ -2490,7 +2446,6 @@ const assertEvidenceFence = (
|
|
|
2490
2446
|
};
|
|
2491
2447
|
|
|
2492
2448
|
const statusBaseRequiredKeys = [
|
|
2493
|
-
'schemaVersion',
|
|
2494
2449
|
'migrationId',
|
|
2495
2450
|
'migrationDigest',
|
|
2496
2451
|
'migrationRevision',
|
|
@@ -2594,9 +2549,6 @@ export const normalizeObjectStorageMigrationStatus = async (
|
|
|
2594
2549
|
phaseOptional,
|
|
2595
2550
|
fieldName,
|
|
2596
2551
|
);
|
|
2597
|
-
if (value.schemaVersion !== 2) {
|
|
2598
|
-
return fail(`${fieldName}.schemaVersion must be 2`);
|
|
2599
|
-
}
|
|
2600
2552
|
|
|
2601
2553
|
const migrationId = readIdentifier(value.migrationId, `${fieldName}.migrationId`);
|
|
2602
2554
|
const migrationDigest = readSha256(
|
|
@@ -2633,7 +2585,6 @@ export const normalizeObjectStorageMigrationStatus = async (
|
|
|
2633
2585
|
}
|
|
2634
2586
|
await assertTargetIdentity(target, sourceBinding, `${fieldName}.target`);
|
|
2635
2587
|
const recomputedMigrationDigest = await createObjectStorageMigrationSha256({
|
|
2636
|
-
schemaVersion: 2,
|
|
2637
2588
|
migrationId,
|
|
2638
2589
|
sourceControlSnapshot: source.preparationSnapshot,
|
|
2639
2590
|
workloadGeneration,
|
|
@@ -2840,7 +2791,6 @@ export const normalizeObjectStorageMigrationStatus = async (
|
|
|
2840
2791
|
}
|
|
2841
2792
|
|
|
2842
2793
|
const normalized = {
|
|
2843
|
-
schemaVersion: 2 as const,
|
|
2844
2794
|
migrationId,
|
|
2845
2795
|
migrationDigest,
|
|
2846
2796
|
migrationRevision,
|
package/ts/platform/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TSecretManagementScope } from '../data/secret.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { IObjectStorageRetentionBinding } from './objectstorageretention.js';
|
|
3
3
|
|
|
4
4
|
export type TPlatformCapability =
|
|
5
5
|
| 'email'
|
|
@@ -68,7 +68,7 @@ export interface IPlatformBinding {
|
|
|
68
68
|
/** Durable Cloudly authority for the exact Corestore object-storage bucket. */
|
|
69
69
|
objectstorageBucketName?: string;
|
|
70
70
|
/** Capability-specific value-free immutable-retention intent and evidence. */
|
|
71
|
-
objectstorageRetention?:
|
|
71
|
+
objectstorageRetention?: IObjectStorageRetentionBinding;
|
|
72
72
|
createdAt?: number;
|
|
73
73
|
updatedAt?: number;
|
|
74
74
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export const strictCanonicalJsonRules = Object.freeze({
|
|
2
|
-
version: 1 as const,
|
|
3
2
|
encoding: 'utf-8' as const,
|
|
4
3
|
objectKeyOrdering: 'utf-16-code-unit-ascending' as const,
|
|
5
4
|
arrayOrdering: 'preserved-dense' as const,
|
|
@@ -10,6 +9,19 @@ export const strictCanonicalJsonRules = Object.freeze({
|
|
|
10
9
|
|
|
11
10
|
export type TCanonicalJsonFailure = (reasonArg: string) => never;
|
|
12
11
|
|
|
12
|
+
/**
|
|
13
|
+
* The canonical order of two wire tokens: UTF-16 code units ascending, the rule this module
|
|
14
|
+
* already orders object keys by.
|
|
15
|
+
*
|
|
16
|
+
* A list of tokens a peer sends is compared byte for byte once it is judged, so the rule that
|
|
17
|
+
* builds a sorted list and the rule that judges one have to be the same rule; a second comparison
|
|
18
|
+
* elsewhere would be a second answer to what "sorted" means.
|
|
19
|
+
*/
|
|
20
|
+
export const compareWireTokens = (leftArg: string, rightArg: string): number => {
|
|
21
|
+
if (leftArg === rightArg) return 0;
|
|
22
|
+
return leftArg < rightArg ? -1 : 1;
|
|
23
|
+
};
|
|
24
|
+
|
|
13
25
|
const assertUnicodeScalarString = (
|
|
14
26
|
valueArg: string,
|
|
15
27
|
fieldNameArg: string,
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a value a peer wrote without running the peer's code.
|
|
3
|
+
*
|
|
4
|
+
* A body arrives as decoded JSON on every honest path, but a caller can hand a contract any object
|
|
5
|
+
* it likes, and a property backed by an accessor runs code inside whatever validated it — once for
|
|
6
|
+
* the check and again for the copy, so the two can disagree. Every reader here takes own
|
|
7
|
+
* enumerable data properties only and refuses anything else instead of invoking it, which is what
|
|
8
|
+
* lets a validator promise that judging a value changed nothing and observed nothing twice.
|
|
9
|
+
*
|
|
10
|
+
* That promise covers accessors, not a `Proxy` whose descriptor trap answers differently on each
|
|
11
|
+
* call: decoded JSON from a peer never yields a Proxy, so these readers protect a validator from
|
|
12
|
+
* the accessor-bearing object an in-process caller can hand it, not from a hostile Proxy.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** One own data property that was read: `value` alone, so `undefined` stays distinguishable. */
|
|
16
|
+
export interface IDataProperty {
|
|
17
|
+
value: unknown;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A record a peer could have sent as JSON: no class, no array, nothing inherited. */
|
|
21
|
+
export const isPlainRecord = (valueArg: unknown): valueArg is Record<string, unknown> => (
|
|
22
|
+
Boolean(valueArg)
|
|
23
|
+
&& typeof valueArg === 'object'
|
|
24
|
+
&& !Array.isArray(valueArg)
|
|
25
|
+
&& (Object.getPrototypeOf(valueArg) === Object.prototype
|
|
26
|
+
|| Object.getPrototypeOf(valueArg) === null)
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* One key of a plain record, when it carries an own enumerable data property.
|
|
31
|
+
*
|
|
32
|
+
* `null` when the container is not a plain record, when the key is absent, or when it is anything
|
|
33
|
+
* but a data property — including the accessor this exists to refuse.
|
|
34
|
+
*/
|
|
35
|
+
export const readDataProperty = (valueArg: unknown, keyArg: string): IDataProperty | null => {
|
|
36
|
+
if (!isPlainRecord(valueArg)) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const descriptor = Object.getOwnPropertyDescriptor(valueArg, keyArg);
|
|
40
|
+
return descriptor?.enumerable === true && Object.hasOwn(descriptor, 'value')
|
|
41
|
+
? { value: descriptor.value }
|
|
42
|
+
: null;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A plain record's own data properties, copied one level deep into an inert record.
|
|
47
|
+
*
|
|
48
|
+
* `null` when any own key is a symbol or is not an enumerable data property, so a record that
|
|
49
|
+
* passes here has nothing left on it that could run, change or hide a value after it was judged.
|
|
50
|
+
*/
|
|
51
|
+
export const readDataProperties = (valueArg: unknown): Record<string, unknown> | null => {
|
|
52
|
+
if (!isPlainRecord(valueArg)) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const result: Record<string, unknown> = Object.create(null);
|
|
56
|
+
for (const key of Reflect.ownKeys(valueArg)) {
|
|
57
|
+
if (typeof key !== 'string') {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const property = readDataProperty(valueArg, key);
|
|
61
|
+
if (property === null) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
result[key] = property.value;
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A bounded, dense array a peer could have sent as JSON, copied into an inert list.
|
|
71
|
+
*
|
|
72
|
+
* `null` when the value is not a plain array, when it is longer than the caller's bound, when it
|
|
73
|
+
* carries any own key beyond its elements and `length` — a hole or an extra property — or when an
|
|
74
|
+
* element is not an enumerable data property. The bound is read before any element is copied, so a
|
|
75
|
+
* caller cannot be made to walk an array it would have refused anyway.
|
|
76
|
+
*/
|
|
77
|
+
export const readDataElements = (
|
|
78
|
+
valueArg: unknown,
|
|
79
|
+
maximumLengthArg: number,
|
|
80
|
+
): unknown[] | null => {
|
|
81
|
+
if (!Array.isArray(valueArg) || Object.getPrototypeOf(valueArg) !== Array.prototype) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
if (valueArg.length > maximumLengthArg
|
|
85
|
+
|| Reflect.ownKeys(valueArg).length !== valueArg.length + 1) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const elements: unknown[] = [];
|
|
89
|
+
for (let index = 0; index < valueArg.length; index++) {
|
|
90
|
+
const descriptor = Object.getOwnPropertyDescriptor(valueArg, String(index));
|
|
91
|
+
if (descriptor?.enumerable !== true || !Object.hasOwn(descriptor, 'value')) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
elements.push(descriptor.value);
|
|
95
|
+
}
|
|
96
|
+
return elements;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* True when a record carries every required key and nothing beyond the optional ones.
|
|
101
|
+
*
|
|
102
|
+
* The key-set half of an exact schema, for a validator that has already established it holds a
|
|
103
|
+
* record and wants to name every reason a body is refused rather than stop at the first. A shape
|
|
104
|
+
* with no optional members passes one list and gets "exactly these keys". Both halves judge the
|
|
105
|
+
* own enumerable keys — the ones a peer's JSON could have carried — so a required key hidden on a
|
|
106
|
+
* non-enumerable property is missing here just as it is missing from the body.
|
|
107
|
+
*
|
|
108
|
+
* Key names only: what each key holds, and whether it holds data at all, is the reader's question.
|
|
109
|
+
*/
|
|
110
|
+
export const hasExactKeys = (
|
|
111
|
+
recordArg: Record<string, unknown>,
|
|
112
|
+
requiredKeysArg: readonly string[],
|
|
113
|
+
optionalKeysArg: readonly string[] = [],
|
|
114
|
+
): boolean => {
|
|
115
|
+
const keys = Object.keys(recordArg);
|
|
116
|
+
return requiredKeysArg.every((keyArg) => keys.includes(keyArg))
|
|
117
|
+
&& keys.every((keyArg) => requiredKeysArg.includes(keyArg) || optionalKeysArg.includes(keyArg));
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Exactly these keys, carrying data and nothing that runs, copied away from the caller's object.
|
|
122
|
+
*
|
|
123
|
+
* `null` for everything else: a missing key, an extra key, or a key that is not an enumerable data
|
|
124
|
+
* property. This is the one exact-key reader every contract and carrier in this package is built
|
|
125
|
+
* on, so a shape whose schema is written down as a key list is judged the same way everywhere.
|
|
126
|
+
*/
|
|
127
|
+
export const readExactDataRecord = (
|
|
128
|
+
valueArg: unknown,
|
|
129
|
+
keysArg: readonly string[],
|
|
130
|
+
): Record<string, unknown> | null => {
|
|
131
|
+
const record = readDataProperties(valueArg);
|
|
132
|
+
if (record === null) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
const keys = Object.keys(record);
|
|
136
|
+
return keys.length === keysArg.length && keys.every((keyArg) => keysArg.includes(keyArg))
|
|
137
|
+
? record
|
|
138
|
+
: null;
|
|
139
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TSha256Digest } from '../data/immutableimage.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { IRuntimeAuthorityReference, IRuntimeController } from '../data/runtimeassignment.js';
|
|
3
3
|
import type { IRuntimeNetworkDnsLeaseRenewal } from '../data/networklease.js';
|
|
4
|
-
import type { IRuntimeNetworkDnsWindow,
|
|
4
|
+
import type { IRuntimeNetworkDnsWindow, IRuntimeNetworkNodeScope, IRuntimeNetworkProjection } from '../data/networkprojection.js';
|
|
5
5
|
import { canonicalizeStrictJson, createCanonicalJsonSha256Hex } from './canonicaljson.js';
|
|
6
6
|
|
|
7
7
|
export const failNetwork = (): never => { throw new Error('Runtime network projection contract rejected.'); };
|
|
@@ -89,15 +89,15 @@ export const networkDigest = (value: unknown): TSha256Digest => {
|
|
|
89
89
|
export const networkSignature = (value: unknown): string => {
|
|
90
90
|
requireNetwork(typeof value === 'string' && /^[a-f0-9]{128}$/.test(value)); return value;
|
|
91
91
|
};
|
|
92
|
-
export const networkController = (value: unknown):
|
|
92
|
+
export const networkController = (value: unknown): IRuntimeController => {
|
|
93
93
|
const item = networkRecord(value, ['kind', 'id', 'epoch']);
|
|
94
94
|
requireNetwork(item.kind === 'cloudly' || item.kind === 'onebox');
|
|
95
95
|
return { kind: item.kind, id: networkId(item.id), epoch: networkId(item.epoch) };
|
|
96
96
|
};
|
|
97
|
-
export const networkScope = (item: Record<string, unknown>):
|
|
97
|
+
export const networkScope = (item: Record<string, unknown>): IRuntimeNetworkNodeScope => ({
|
|
98
98
|
controller: networkController(item.controller), nodeId: networkId(item.nodeId), runtimeNamespace: networkId(item.runtimeNamespace),
|
|
99
99
|
});
|
|
100
|
-
export const networkSameScope = (left:
|
|
100
|
+
export const networkSameScope = (left: IRuntimeNetworkNodeScope, right: IRuntimeNetworkNodeScope): boolean =>
|
|
101
101
|
networkEqual(left.controller, right.controller) && left.nodeId === right.nodeId && left.runtimeNamespace === right.runtimeNamespace;
|
|
102
102
|
export const networkMaximumDnsLeaseMs = 900_000;
|
|
103
103
|
/** One rule for every signed DNS window, projection or renewal: ordered, non-empty, at most fifteen minutes. */
|
|
@@ -108,21 +108,21 @@ export const networkDnsWindow = (value: unknown): IRuntimeNetworkDnsWindow => {
|
|
|
108
108
|
&& window.expiresAt - window.issuedAt <= networkMaximumDnsLeaseMs);
|
|
109
109
|
return window;
|
|
110
110
|
};
|
|
111
|
-
export const networkReference = (value: unknown):
|
|
111
|
+
export const networkReference = (value: unknown): IRuntimeAuthorityReference => {
|
|
112
112
|
const item = networkRecord(value, ['id', 'generation', 'digest']);
|
|
113
113
|
return { id: networkId(item.id), generation: networkCounter(item.generation), digest: networkDigest(item.digest) };
|
|
114
114
|
};
|
|
115
|
-
export const networkReferenceOf = (value:
|
|
115
|
+
export const networkReferenceOf = (value: IRuntimeAuthorityReference): IRuntimeAuthorityReference =>
|
|
116
116
|
({ id: value.id, generation: value.generation, digest: value.digest });
|
|
117
117
|
/** A renewal renews exactly one projection: the same node scope and that projection's exact reference. */
|
|
118
|
-
export const networkRenewsProjection = (renewal: IRuntimeNetworkDnsLeaseRenewal, projection:
|
|
118
|
+
export const networkRenewsProjection = (renewal: IRuntimeNetworkDnsLeaseRenewal, projection: IRuntimeNetworkProjection): boolean =>
|
|
119
119
|
networkSameScope(renewal, projection) && networkEqual(renewal.projection, networkReferenceOf(projection));
|
|
120
120
|
/**
|
|
121
121
|
* The one rule for the DNS window a node may use under a projection: its admitted renewal's, else
|
|
122
122
|
* the projection's own. Both inputs are already validated caller state; this verifies no signature.
|
|
123
123
|
*/
|
|
124
124
|
export const networkEffectiveDnsWindow = (
|
|
125
|
-
projection:
|
|
125
|
+
projection: IRuntimeNetworkProjection, renewal: IRuntimeNetworkDnsLeaseRenewal | null,
|
|
126
126
|
): IRuntimeNetworkDnsWindow => {
|
|
127
127
|
if (renewal === null) return projection.dns;
|
|
128
128
|
requireNetwork(networkRenewsProjection(renewal, projection));
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The release-version grammar every serve.zone package agrees on.
|
|
3
|
+
*
|
|
4
|
+
* Exactly what a published release is named and nothing else: no prerelease, because gitzone
|
|
5
|
+
* refuses to publish one, and no build metadata, because two strings that name one release would
|
|
6
|
+
* then compare unequal. Components are read as numbers, which is the whole reason this rule
|
|
7
|
+
* exists — `32.10.0` is above `32.9.0`, and a lexical comparison of the strings says the opposite.
|
|
8
|
+
*/
|
|
9
|
+
export interface IReleaseVersion {
|
|
10
|
+
major: number;
|
|
11
|
+
minor: number;
|
|
12
|
+
patch: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Canonical decimal components: no leading zeros, no prefix, no suffix. */
|
|
16
|
+
const releaseVersionPattern = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Bounds the string before anything parses it.
|
|
20
|
+
*
|
|
21
|
+
* Every component of a real release fits many times over, so the only values this refuses are
|
|
22
|
+
* digit runs that no release could carry and that a reader would otherwise have to count.
|
|
23
|
+
*/
|
|
24
|
+
export const maximumReleaseVersionLength = 32;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The three components of one release version, or `null` for everything that is not one.
|
|
28
|
+
*
|
|
29
|
+
* A component beyond the safe-integer range is refused rather than rounded: two such versions
|
|
30
|
+
* would compare equal after rounding, and an ordering that cannot tell two releases apart is
|
|
31
|
+
* worse than no answer.
|
|
32
|
+
*/
|
|
33
|
+
export const parseReleaseVersion = (valueArg: unknown): IReleaseVersion | null => {
|
|
34
|
+
if (typeof valueArg !== 'string' || valueArg.length > maximumReleaseVersionLength) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const components = releaseVersionPattern.exec(valueArg);
|
|
38
|
+
if (components === null) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const [major, minor, patch] = components.slice(1).map(Number);
|
|
42
|
+
if (!Number.isSafeInteger(major) || !Number.isSafeInteger(minor) || !Number.isSafeInteger(patch)) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return { major, minor, patch };
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Whether a value names one published release.
|
|
50
|
+
*
|
|
51
|
+
* Every rule of the grammar goes through `parseReleaseVersion`, including the numeric one, so a
|
|
52
|
+
* validator that accepts a version cannot accept one the comparison then refuses to order.
|
|
53
|
+
*/
|
|
54
|
+
export const isReleaseVersion = (valueArg: unknown): valueArg is string => (
|
|
55
|
+
parseReleaseVersion(valueArg) !== null
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
/** Negative, zero or positive as the left version is below, equal to or above the right one. */
|
|
59
|
+
export const compareReleaseVersions = (
|
|
60
|
+
leftArg: IReleaseVersion,
|
|
61
|
+
rightArg: IReleaseVersion,
|
|
62
|
+
): number => {
|
|
63
|
+
if (leftArg.major !== rightArg.major) {
|
|
64
|
+
return leftArg.major - rightArg.major;
|
|
65
|
+
}
|
|
66
|
+
if (leftArg.minor !== rightArg.minor) {
|
|
67
|
+
return leftArg.minor - rightArg.minor;
|
|
68
|
+
}
|
|
69
|
+
return leftArg.patch - rightArg.patch;
|
|
70
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IRuntimeConfigLogPolicy } from '../data/runtimeconfig.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The execution policy a runtime config seals and a service runtime profile states ahead of it.
|
|
@@ -40,7 +40,7 @@ export const isRuntimeMemoryBytes = (valueArg: unknown): valueArg is number =>
|
|
|
40
40
|
export const isRuntimeIdentityNumber = (valueArg: unknown): valueArg is number =>
|
|
41
41
|
isBoundedInteger(valueArg, 0, runtimePolicyLimits.maximumIdentityNumber);
|
|
42
42
|
|
|
43
|
-
export const isRuntimeLogPolicy = (valueArg: unknown): valueArg is
|
|
43
|
+
export const isRuntimeLogPolicy = (valueArg: unknown): valueArg is IRuntimeConfigLogPolicy =>
|
|
44
44
|
isExactRecord(valueArg, ['maximumLineBytes', 'maximumBufferedBytes', 'retentionMs'])
|
|
45
45
|
&& isBoundedInteger(valueArg.maximumLineBytes, 1, 1_048_576)
|
|
46
46
|
&& isBoundedInteger(valueArg.maximumBufferedBytes, 1, 67_108_864)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Judging a list of tokens a peer sent against the vocabulary it may draw from.
|
|
3
|
+
*
|
|
4
|
+
* Every such list in this package is compared byte for byte by its receiver, so they all obey one
|
|
5
|
+
* rule; a second spelling of that rule elsewhere would be a second answer to what a canonical list
|
|
6
|
+
* is. A caller adds whatever else its own contract demands — a required subset, a bound — as its
|
|
7
|
+
* own clause beside this one.
|
|
8
|
+
*/
|
|
9
|
+
import { compareWireTokens } from './canonicaljson.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* True when a value is exactly a canonical token list: known names, strictly increasing.
|
|
13
|
+
*
|
|
14
|
+
* Strictly increasing states sorted and duplicate-free in one rule, which is what lets a replayed
|
|
15
|
+
* list be compared byte for byte instead of as a set. A hole is refused rather than skipped over:
|
|
16
|
+
* array iteration passes holes by, so a sparse list would satisfy every rule about its entries
|
|
17
|
+
* while carrying none of the entries a receiver then compares.
|
|
18
|
+
*/
|
|
19
|
+
export const isCanonicalTokenList = <TTokenGeneric extends string>(
|
|
20
|
+
valueArg: unknown,
|
|
21
|
+
vocabularyArg: readonly TTokenGeneric[],
|
|
22
|
+
): valueArg is TTokenGeneric[] => (
|
|
23
|
+
Array.isArray(valueArg)
|
|
24
|
+
&& Object.keys(valueArg).length === valueArg.length
|
|
25
|
+
&& valueArg.every((entryArg, indexArg) => (
|
|
26
|
+
vocabularyArg.some((tokenArg) => tokenArg === entryArg)
|
|
27
|
+
&& (indexArg === 0
|
|
28
|
+
|| compareWireTokens(valueArg[indexArg - 1] as string, entryArg as string) < 0)
|
|
29
|
+
))
|
|
30
|
+
);
|