@serve.zone/interfaces 31.8.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.
Files changed (215) hide show
  1. package/.smartconfig.json +1 -0
  2. package/changelog.md +512 -0
  3. package/dist_ts/00_commitinfo_data.js +3 -3
  4. package/dist_ts/appstore/types.d.ts +4 -6
  5. package/dist_ts/appstore/types.js +5 -5
  6. package/dist_ts/data/backup.d.ts +3 -26
  7. package/dist_ts/data/cluster.d.ts +36 -11
  8. package/dist_ts/data/cluster.js +33 -22
  9. package/dist_ts/data/clusteringress.d.ts +8 -0
  10. package/dist_ts/data/clusteringress.js +13 -8
  11. package/dist_ts/data/clusternode.d.ts +121 -74
  12. package/dist_ts/data/clusternode.js +109 -132
  13. package/dist_ts/data/clusterruntime.d.ts +39 -0
  14. package/dist_ts/data/clusterruntime.js +11 -0
  15. package/dist_ts/data/coremail.d.ts +3 -7
  16. package/dist_ts/data/coremail.js +2 -2
  17. package/dist_ts/data/coremail.runtime.d.ts +0 -1
  18. package/dist_ts/data/coremail.runtime.js +5 -22
  19. package/dist_ts/data/deploymentadoption.d.ts +0 -2
  20. package/dist_ts/data/deploymentadoption.js +40 -6
  21. package/dist_ts/data/deploymentoperation.js +16 -3
  22. package/dist_ts/data/deploymentpreflight.d.ts +0 -2
  23. package/dist_ts/data/deploymentpreflight.js +1 -1
  24. package/dist_ts/data/immutableimage.d.ts +38 -21
  25. package/dist_ts/data/immutableimage.js +45 -5
  26. package/dist_ts/data/index.d.ts +5 -1
  27. package/dist_ts/data/index.js +5 -1
  28. package/dist_ts/data/isolatedrestore.d.ts +139 -21
  29. package/dist_ts/data/isolatedrestore.golden.d.ts +0 -1
  30. package/dist_ts/data/isolatedrestore.golden.js +6 -9
  31. package/dist_ts/data/isolatedrestore.js +176 -40
  32. package/dist_ts/data/mail.d.ts +1 -1
  33. package/dist_ts/data/networkaddressplan.d.ts +78 -0
  34. package/dist_ts/data/networkaddressplan.js +114 -0
  35. package/dist_ts/data/networkauthority.d.ts +20 -22
  36. package/dist_ts/data/networkauthority.js +29 -43
  37. package/dist_ts/data/networkcredential.d.ts +10 -10
  38. package/dist_ts/data/networkcredential.js +16 -16
  39. package/dist_ts/data/networkdelivery.d.ts +18 -18
  40. package/dist_ts/data/networkdelivery.js +16 -16
  41. package/dist_ts/data/networklease.d.ts +18 -7
  42. package/dist_ts/data/networklease.js +29 -7
  43. package/dist_ts/data/networknode.d.ts +37 -0
  44. package/dist_ts/data/networknode.js +6 -0
  45. package/dist_ts/data/networkprojection.d.ts +59 -60
  46. package/dist_ts/data/networkprojection.js +53 -57
  47. package/dist_ts/data/networkprotection.d.ts +27 -28
  48. package/dist_ts/data/networkprotection.js +36 -36
  49. package/dist_ts/data/networkrouter.d.ts +11 -11
  50. package/dist_ts/data/networkrouter.js +1 -1
  51. package/dist_ts/data/networksigning.d.ts +16 -18
  52. package/dist_ts/data/networksigning.js +20 -21
  53. package/dist_ts/data/nodecredential.d.ts +4 -6
  54. package/dist_ts/data/nodeenrollment.d.ts +35 -40
  55. package/dist_ts/data/nodeenrollment.js +57 -72
  56. package/dist_ts/data/privatenetwork.d.ts +21 -24
  57. package/dist_ts/data/privatenetwork.js +39 -54
  58. package/dist_ts/data/runtimeassignment.d.ts +50 -34
  59. package/dist_ts/data/runtimeassignment.js +79 -45
  60. package/dist_ts/data/runtimeconfig.d.ts +21 -22
  61. package/dist_ts/data/runtimeconfig.js +37 -100
  62. package/dist_ts/data/runtimesession.d.ts +100 -62
  63. package/dist_ts/data/runtimesession.js +98 -79
  64. package/dist_ts/data/runtimeterminalreceipt.d.ts +28 -29
  65. package/dist_ts/data/runtimeterminalreceipt.js +42 -42
  66. package/dist_ts/data/secret.d.ts +18 -25
  67. package/dist_ts/data/secret.js +12 -52
  68. package/dist_ts/data/servicecredential.d.ts +14 -16
  69. package/dist_ts/data/servicecredential.js +17 -28
  70. package/dist_ts/data/serviceruntime.d.ts +128 -0
  71. package/dist_ts/data/serviceruntime.js +92 -0
  72. package/dist_ts/data/sparknodereport.d.ts +27 -14
  73. package/dist_ts/data/sparknodereport.js +35 -28
  74. package/dist_ts/data/webpush.d.ts +0 -1
  75. package/dist_ts/index.d.ts +2 -1
  76. package/dist_ts/index.js +3 -2
  77. package/dist_ts/platform/objectstorageretention.d.ts +21 -24
  78. package/dist_ts/platform/objectstorageretention.js +6 -18
  79. package/dist_ts/platform/storage.d.ts +1 -3
  80. package/dist_ts/platform/storagemigration.d.ts +0 -7
  81. package/dist_ts/platform/storagemigration.golden.d.ts +0 -1
  82. package/dist_ts/platform/storagemigration.golden.js +8 -12
  83. package/dist_ts/platform/storagemigration.js +6 -51
  84. package/dist_ts/platform/types.d.ts +2 -2
  85. package/dist_ts/private/canonicaljson.d.ts +9 -1
  86. package/dist_ts/private/canonicaljson.js +14 -2
  87. package/dist_ts/private/dataproperties.d.ts +62 -0
  88. package/dist_ts/private/dataproperties.js +117 -0
  89. package/dist_ts/private/networkcontract.d.ts +14 -10
  90. package/dist_ts/private/networkcontract.js +15 -1
  91. package/dist_ts/private/producercontract.d.ts +11 -0
  92. package/dist_ts/private/producercontract.js +21 -0
  93. package/dist_ts/private/releaseversion.d.ts +37 -0
  94. package/dist_ts/private/releaseversion.js +48 -0
  95. package/dist_ts/private/runtimepolicy.d.ts +31 -0
  96. package/dist_ts/private/runtimepolicy.js +90 -0
  97. package/dist_ts/private/tokenlist.d.ts +9 -0
  98. package/dist_ts/private/tokenlist.js +23 -0
  99. package/dist_ts/protocol.d.ts +137 -0
  100. package/dist_ts/protocol.js +255 -0
  101. package/dist_ts/requests/admin.d.ts +8 -8
  102. package/dist_ts/requests/backup.d.ts +102 -112
  103. package/dist_ts/requests/cluster.d.ts +47 -10
  104. package/dist_ts/requests/cluster.js +1 -1
  105. package/dist_ts/requests/clusteringress.d.ts +9 -0
  106. package/dist_ts/requests/clusteringress.js +1 -1
  107. package/dist_ts/requests/config.d.ts +3 -3
  108. package/dist_ts/requests/corestore.d.ts +0 -3
  109. package/dist_ts/requests/corestore.js +5 -9
  110. package/dist_ts/requests/network.d.ts +87 -31
  111. package/dist_ts/requests/node.d.ts +15 -28
  112. package/dist_ts/requests/pallet.d.ts +13 -13
  113. package/dist_ts/requests/runtimesession.d.ts +53 -41
  114. package/dist_ts/requests/secret.d.ts +4 -5
  115. package/dist_ts/requests/secret.js +1 -5
  116. package/dist_ts/requests/service.d.ts +60 -0
  117. package/dist_ts/runtime.corestore.d.ts +56 -74
  118. package/dist_ts/runtime.corestore.databaseexportpackage.d.ts +30 -36
  119. package/dist_ts/runtime.corestore.databaseexportpackage.golden.d.ts +11 -12
  120. package/dist_ts/runtime.corestore.databaseexportpackage.golden.js +54 -71
  121. package/dist_ts/runtime.corestore.databaseexportpackage.js +9 -25
  122. package/dist_ts/runtime.corestore.js +35 -135
  123. package/dist_ts/runtime.corestore.relay.js +2 -7
  124. package/dist_ts/runtime.d.ts +38 -48
  125. package/dist_ts/runtime.js +20 -77
  126. package/dist_ts/runtime.networkprojection.d.ts +4 -4
  127. package/dist_ts/runtime.networkprojection.js +18 -18
  128. package/dist_ts/runtime.workloadinit.d.ts +23 -24
  129. package/dist_ts/runtime.workloadinit.js +6 -13
  130. package/package.json +2 -2
  131. package/readme.md +540 -269
  132. package/ts/00_commitinfo_data.ts +3 -3
  133. package/ts/appstore/types.ts +4 -6
  134. package/ts/data/backup.ts +3 -38
  135. package/ts/data/cluster.ts +51 -34
  136. package/ts/data/clusteringress.ts +12 -12
  137. package/ts/data/clusternode.ts +204 -232
  138. package/ts/data/clusterruntime.ts +45 -0
  139. package/ts/data/coremail.runtime.ts +4 -21
  140. package/ts/data/coremail.ts +3 -7
  141. package/ts/data/deploymentadoption.ts +46 -4
  142. package/ts/data/deploymentoperation.ts +16 -1
  143. package/ts/data/deploymentpreflight.ts +0 -2
  144. package/ts/data/immutableimage.ts +71 -24
  145. package/ts/data/index.ts +5 -1
  146. package/ts/data/isolatedrestore.golden.ts +5 -9
  147. package/ts/data/isolatedrestore.ts +339 -54
  148. package/ts/data/mail.ts +1 -1
  149. package/ts/data/networkaddressplan.ts +175 -0
  150. package/ts/data/networkauthority.ts +45 -61
  151. package/ts/data/networkcredential.ts +24 -24
  152. package/ts/data/networkdelivery.ts +27 -27
  153. package/ts/data/networklease.ts +40 -13
  154. package/ts/data/networknode.ts +37 -0
  155. package/ts/data/networkprojection.ts +119 -124
  156. package/ts/data/networkprotection.ts +54 -55
  157. package/ts/data/networkrouter.ts +14 -14
  158. package/ts/data/networksigning.ts +29 -32
  159. package/ts/data/nodecredential.ts +4 -6
  160. package/ts/data/nodeenrollment.ts +96 -114
  161. package/ts/data/privatenetwork.ts +58 -74
  162. package/ts/data/runtimeassignment.ts +143 -94
  163. package/ts/data/runtimeconfig.ts +62 -122
  164. package/ts/data/runtimesession.ts +185 -138
  165. package/ts/data/runtimeterminalreceipt.ts +72 -73
  166. package/ts/data/secret.ts +28 -76
  167. package/ts/data/servicecredential.ts +33 -43
  168. package/ts/data/serviceruntime.ts +208 -0
  169. package/ts/data/sparknodereport.ts +48 -36
  170. package/ts/data/webpush.ts +0 -1
  171. package/ts/index.ts +2 -0
  172. package/ts/platform/objectstorageretention.ts +36 -55
  173. package/ts/platform/storage.ts +1 -3
  174. package/ts/platform/storagemigration.golden.ts +7 -11
  175. package/ts/platform/storagemigration.ts +5 -55
  176. package/ts/platform/types.ts +2 -2
  177. package/ts/private/canonicaljson.ts +13 -1
  178. package/ts/private/dataproperties.ts +139 -0
  179. package/ts/private/networkcontract.ts +23 -9
  180. package/ts/private/producercontract.ts +19 -0
  181. package/ts/private/releaseversion.ts +70 -0
  182. package/ts/private/runtimepolicy.ts +105 -0
  183. package/ts/private/tokenlist.ts +30 -0
  184. package/ts/protocol.ts +364 -0
  185. package/ts/requests/admin.ts +11 -11
  186. package/ts/requests/backup.ts +112 -117
  187. package/ts/requests/cluster.ts +58 -13
  188. package/ts/requests/clusteringress.ts +9 -0
  189. package/ts/requests/config.ts +3 -3
  190. package/ts/requests/corestore.ts +4 -16
  191. package/ts/requests/network.ts +90 -41
  192. package/ts/requests/node.ts +21 -38
  193. package/ts/requests/pallet.ts +17 -17
  194. package/ts/requests/runtimesession.ts +63 -51
  195. package/ts/requests/secret.ts +5 -10
  196. package/ts/requests/service.ts +81 -0
  197. package/ts/runtime.corestore.databaseexportpackage.golden.ts +77 -95
  198. package/ts/runtime.corestore.databaseexportpackage.ts +51 -73
  199. package/ts/runtime.corestore.relay.ts +1 -10
  200. package/ts/runtime.corestore.ts +118 -268
  201. package/ts/runtime.networkprojection.ts +30 -30
  202. package/ts/runtime.ts +83 -158
  203. package/ts/runtime.workloadinit.ts +36 -48
  204. package/dist_ts/runtime.cloudlylegacydeploymentsettlement.d.ts +0 -902
  205. package/dist_ts/runtime.cloudlylegacydeploymentsettlement.golden.d.ts +0 -35
  206. package/dist_ts/runtime.cloudlylegacydeploymentsettlement.golden.js +0 -315
  207. package/dist_ts/runtime.cloudlylegacydeploymentsettlement.js +0 -3315
  208. package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.d.ts +0 -291
  209. package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.d.ts +0 -30
  210. package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.js +0 -408
  211. package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.js +0 -1126
  212. package/ts/runtime.cloudlylegacydeploymentsettlement.golden.ts +0 -421
  213. package/ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.ts +0 -510
  214. package/ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.ts +0 -2470
  215. package/ts/runtime.cloudlylegacydeploymentsettlement.ts +0 -6630
@@ -11,6 +11,7 @@ import {
11
11
  deepFreezeValue,
12
12
  strictCanonicalJsonRules,
13
13
  } from '../private/canonicaljson.js';
14
+ import { hasExactKeys } from '../private/dataproperties.js';
14
15
 
15
16
  /** Operations carried by a short-lived, single-operation restore grant. */
16
17
  export const isolatedRestoreGrantOperations = Object.freeze([
@@ -25,16 +26,15 @@ export type TIsolatedRestoreGrantOperation =
25
26
  (typeof isolatedRestoreGrantOperations)[number];
26
27
 
27
28
  /**
28
- * Versioned limits shared by signers, relays, and Corestore.
29
+ * The limits signers, relays and Corestore all hold this family to.
29
30
  *
30
- * V1 uses an inline descriptor manifest inside a 1 MiB control request. Its
31
- * 4,096 object slots reserve 256 entries for config, snapshots, keys, and
32
- * index segments; the remaining 3,840 slots fit 1,920 default 8 MiB pack/index
31
+ * The descriptor manifest travels inside a 1 MiB control request. Its 4,096
32
+ * object slots reserve 256 entries for config, snapshots, keys, and index
33
+ * segments; the remaining 3,840 slots fit 1,920 default 8 MiB pack/index
33
34
  * pairs. The 15 GiB total envelope is therefore reachable with the default
34
35
  * ContainerArchive packing profile instead of advertising impossible capacity.
35
36
  */
36
37
  export const isolatedRestoreContractLimits = Object.freeze({
37
- version: 1 as const,
38
38
  maximumControlJsonBytes: 1024 * 1024,
39
39
  maximumRestoreGrantBytes: 64 * 1024,
40
40
  maximumConfiguredStringBytes: 2048,
@@ -50,9 +50,8 @@ export const isolatedRestoreContractLimits = Object.freeze({
50
50
  maximumObjectChunks: 4096,
51
51
  });
52
52
 
53
- /** ContainerArchive v1 paths that may be replicated into restore staging. */
53
+ /** The ContainerArchive repository paths that may be replicated into restore staging. */
54
54
  export const isolatedRestoreRepositoryPathProfile = Object.freeze({
55
- version: 1 as const,
56
55
  rootObject: 'config.json' as const,
57
56
  topLevelDirectories: Object.freeze([
58
57
  'packs',
@@ -69,7 +68,6 @@ export const isolatedRestoreRepositoryPathProfile = Object.freeze({
69
68
  * Persist this projection for audit/recovery, never the compact bearer JWT.
70
69
  */
71
70
  export interface IIsolatedRestoreGrantClaims {
72
- grantVersion: 1;
73
71
  iss: string;
74
72
  aud: string;
75
73
  sub: string;
@@ -126,9 +124,23 @@ export interface IIsolatedRestoreControlForbiddenAuthority {
126
124
  archiveManifestSha256?: never;
127
125
  }
128
126
 
129
- export interface IIsolatedRestoreControlPrepareRequest
127
+ /** What every isolated-restore control body carries, and the only authority Corestore accepts. */
128
+ export interface IIsolatedRestoreControlAuthority
130
129
  extends IIsolatedRestoreControlForbiddenAuthority {
130
+ /**
131
+ * The compact RS256 restore grant Cloudly signed for exactly this operation, carried untouched
132
+ * to Corestore.
133
+ *
134
+ * It names the operation, expires within minutes, and binds the cluster, the node name, the
135
+ * canonical resource mappings and the archive manifest, so a carrier can forward it but can
136
+ * neither widen it nor mint one. Sensitive ephemeral input: it is a bearer credential, so
137
+ * exclude the complete request from hooks, logs, diagnostics and durable journals on every hop.
138
+ */
131
139
  restoreGrant: string;
140
+ }
141
+
142
+ export interface IIsolatedRestoreControlPrepareRequest
143
+ extends IIsolatedRestoreControlAuthority {
132
144
  expectedRevision: number;
133
145
  resourceMappings: TIsolatedRestoreResourceMapping[];
134
146
  archiveManifest: IBackupArchiveManifest;
@@ -141,8 +153,7 @@ export interface IIsolatedRestoreControlPrepareRequest
141
153
  * reaches the object boundary; it does not prove object completion.
142
154
  */
143
155
  export interface IIsolatedRestoreControlWriteRequest
144
- extends IIsolatedRestoreControlForbiddenAuthority {
145
- restoreGrant: string;
156
+ extends IIsolatedRestoreControlAuthority {
146
157
  expectedRevision: number;
147
158
  path: string;
148
159
  size: number;
@@ -153,21 +164,17 @@ export interface IIsolatedRestoreControlWriteRequest
153
164
  }
154
165
 
155
166
  export interface IIsolatedRestoreControlExecuteRequest
156
- extends IIsolatedRestoreControlForbiddenAuthority {
157
- restoreGrant: string;
167
+ extends IIsolatedRestoreControlAuthority {
158
168
  expectedRevision: number;
159
169
  }
160
170
 
161
171
  export interface IIsolatedRestoreControlCleanupRequest
162
- extends IIsolatedRestoreControlForbiddenAuthority {
163
- restoreGrant: string;
172
+ extends IIsolatedRestoreControlAuthority {
164
173
  expectedRevision: number;
165
174
  }
166
175
 
167
176
  export interface IIsolatedRestoreControlStatusRequest
168
- extends IIsolatedRestoreControlForbiddenAuthority {
169
- restoreGrant: string;
170
- }
177
+ extends IIsolatedRestoreControlAuthority {}
171
178
 
172
179
  export type TIsolatedRestoreControlRequest =
173
180
  | IIsolatedRestoreControlPrepareRequest
@@ -182,7 +189,6 @@ export type TIsolatedRestoreControlRequest =
182
189
  * authorized write requests can contribute to the same object.
183
190
  */
184
191
  export interface IIsolatedRestoreAuthorityProjection {
185
- version: 1;
186
192
  iss: string;
187
193
  aud: string;
188
194
  sub: string;
@@ -284,7 +290,6 @@ export interface IIsolatedRestoreCompletedObjectBinding {
284
290
  * they do not replace grant authentication or authenticate an untrusted store.
285
291
  */
286
292
  export interface IIsolatedRestoreDurableChunkReceipt {
287
- version: 1;
288
293
  authority: Readonly<IIsolatedRestoreAuthorityProjection>;
289
294
  authoritySha256: string;
290
295
  descriptor: Readonly<IBackupArchiveObject>;
@@ -296,7 +301,6 @@ export interface IIsolatedRestoreDurableChunkReceipt {
296
301
 
297
302
  /** Durable, bearer-free proof regenerated from receipts and one file snapshot. */
298
303
  export interface IIsolatedRestoreDurableCompletedObjectProof {
299
- version: 1;
300
304
  authority: Readonly<IIsolatedRestoreAuthorityProjection>;
301
305
  authoritySha256: string;
302
306
  descriptor: Readonly<IBackupArchiveObject>;
@@ -469,14 +473,10 @@ const assertExactKeys = (
469
473
  recordArg: Record<string, unknown>,
470
474
  expectedKeysArg: readonly string[],
471
475
  fieldNameArg: string,
476
+ optionalKeysArg: readonly string[] = [],
472
477
  ): void => {
473
- const actualKeys = Object.keys(recordArg).sort();
474
- const expectedKeys = [...expectedKeysArg].sort();
475
- if (
476
- actualKeys.length !== expectedKeys.length ||
477
- actualKeys.some((keyArg, indexArg) => keyArg !== expectedKeys[indexArg])
478
- ) {
479
- fail(`${fieldNameArg} does not match its exact versioned schema`);
478
+ if (!hasExactKeys(recordArg, expectedKeysArg, optionalKeysArg)) {
479
+ fail(`${fieldNameArg} does not match its exact schema`);
480
480
  }
481
481
  };
482
482
 
@@ -1105,12 +1105,9 @@ export const normalizeIsolatedRestoreArchiveManifest = (
1105
1105
  const manifest = readRecord(valueArg, 'archiveManifest');
1106
1106
  assertExactKeys(
1107
1107
  manifest,
1108
- ['version', 'backupId', 'createdAt', 'objects', 'totalSize'],
1108
+ ['backupId', 'createdAt', 'objects', 'totalSize'],
1109
1109
  'archiveManifest',
1110
1110
  );
1111
- if (manifest.version !== 1) {
1112
- return fail('archiveManifest.version must be 1');
1113
- }
1114
1111
  const objectEntries = readDenseArray(
1115
1112
  manifest.objects,
1116
1113
  'archiveManifest.objects',
@@ -1141,7 +1138,7 @@ export const normalizeIsolatedRestoreArchiveManifest = (
1141
1138
  isolatedRestoreContractLimits.maximumArchiveTotalBytes
1142
1139
  ) {
1143
1140
  return fail(
1144
- 'archiveManifest object sizes exceed the versioned total-size limit',
1141
+ 'archiveManifest object sizes exceed the total-size limit',
1145
1142
  );
1146
1143
  }
1147
1144
  calculatedTotalSize += size;
@@ -1196,7 +1193,6 @@ export const normalizeIsolatedRestoreArchiveManifest = (
1196
1193
  }
1197
1194
 
1198
1195
  return deepFreeze({
1199
- version: 1,
1200
1196
  backupId: readScopedId(manifest.backupId, 'archiveManifest.backupId'),
1201
1197
  createdAt: readSafeInteger(
1202
1198
  manifest.createdAt,
@@ -1215,7 +1211,6 @@ export const normalizeIsolatedRestoreGrantClaims = (
1215
1211
  assertExactKeys(
1216
1212
  claims,
1217
1213
  [
1218
- 'grantVersion',
1219
1214
  'iss',
1220
1215
  'aud',
1221
1216
  'sub',
@@ -1238,9 +1233,6 @@ export const normalizeIsolatedRestoreGrantClaims = (
1238
1233
  ],
1239
1234
  'restore grant claims',
1240
1235
  );
1241
- if (claims.grantVersion !== 1) {
1242
- return fail('grantVersion must be 1');
1243
- }
1244
1236
  if (
1245
1237
  typeof claims.operation !== 'string' ||
1246
1238
  !isolatedRestoreGrantOperations.includes(
@@ -1258,7 +1250,6 @@ export const normalizeIsolatedRestoreGrantClaims = (
1258
1250
  }
1259
1251
 
1260
1252
  const normalizedClaims: IIsolatedRestoreGrantClaims = {
1261
- grantVersion: 1,
1262
1253
  iss: readConfiguredString(claims.iss, 'iss'),
1263
1254
  aud: readConfiguredString(claims.aud, 'aud'),
1264
1255
  sub: readIdentifier(claims.sub, 'sub'),
@@ -1390,7 +1381,7 @@ export const normalizeIsolatedRestoreControlWriteRequest = (
1390
1381
  if (
1391
1382
  contents.byteLength > isolatedRestoreContractLimits.maximumWriteChunkBytes
1392
1383
  ) {
1393
- return fail('write request decoded chunk exceeds the versioned chunk limit');
1384
+ return fail('write request decoded chunk exceeds the chunk limit');
1394
1385
  }
1395
1386
  if (size === 0) {
1396
1387
  if (offset !== 0 || contents.byteLength !== 0) {
@@ -1453,6 +1444,314 @@ export const normalizeIsolatedRestoreControlStatusRequest = (
1453
1444
  );
1454
1445
  };
1455
1446
 
1447
+ /**
1448
+ * A node-scoped control call: which node of the cluster, and the control body carried to it.
1449
+ *
1450
+ * One relay serves every node of its cluster over one session, so the connection that answers
1451
+ * proves the cluster and never the node — exactly as `getClusterCorestoreInventory` states it. The
1452
+ * control body is the one Corestore reads; the relay forwards it untouched and may not widen it.
1453
+ */
1454
+ export interface IIsolatedRestoreNodeControl<TControlGeneric> {
1455
+ nodeId: string;
1456
+ control: TControlGeneric;
1457
+ }
1458
+
1459
+ /**
1460
+ * Reads one node-scoped control request, judging the control with its own normalizer.
1461
+ *
1462
+ * The caller passes the normalizer of the operation it serves, so there is one reader for the
1463
+ * envelope and one judge per control body instead of five near-identical readers.
1464
+ */
1465
+ export const normalizeIsolatedRestoreNodeControl = <TControlGeneric>(
1466
+ valueArg: unknown,
1467
+ normalizeControlArg: (controlArg: unknown) => TControlGeneric,
1468
+ ): Readonly<IIsolatedRestoreNodeControl<TControlGeneric>> => {
1469
+ const request = readRecord(valueArg, 'node control request');
1470
+ assertExactKeys(request, ['nodeId', 'control'], 'node control request');
1471
+ return Object.freeze({
1472
+ nodeId: readIdentifier(request.nodeId, 'node control request.nodeId'),
1473
+ control: normalizeControlArg(request.control),
1474
+ });
1475
+ };
1476
+
1477
+ /**
1478
+ * Every reason a relay answers instead of carrying a control to the node.
1479
+ *
1480
+ * The relay writes `<name>: <reason>` and the caller matches the name. Only the first two are the
1481
+ * relay's own statement: they say the control never reached Corestore, which is the one thing
1482
+ * Corestore cannot say about itself. Everything Corestore answered — a refused grant, a refused
1483
+ * body, a revision conflict, an unsupported mapping, a restore it does not hold — arrives under
1484
+ * `restore-node-refused` with Corestore's own reason behind it, because inventing a second
1485
+ * vocabulary for those would be a second answer to what happened.
1486
+ */
1487
+ export const isolatedRestoreNodeControlRefusals = Object.freeze([
1488
+ /** This relay carries no Corestore endpoint for that node of its cluster. */
1489
+ 'restore-node-not-carried',
1490
+ /** The node's Corestore did not answer, so nothing of the control was applied. */
1491
+ 'restore-node-unreachable',
1492
+ /** Corestore answered and refused; its own reason follows the name. */
1493
+ 'restore-node-refused',
1494
+ ] as const);
1495
+
1496
+ /** One of the reasons a relay answers instead of a node's progress. */
1497
+ export type TIsolatedRestoreNodeControlRefusal =
1498
+ typeof isolatedRestoreNodeControlRefusals[number];
1499
+
1500
+ /**
1501
+ * What a node states about one isolated restore it holds, in Corestore's own words.
1502
+ *
1503
+ * These are the staging states Corestore keeps, taken verbatim: the node is the only party that
1504
+ * knows them, and the control plane composes its own record status out of what the node states
1505
+ * rather than asking the node to speak the control plane's vocabulary.
1506
+ */
1507
+ export const isolatedRestoreProgressStatuses = Object.freeze([
1508
+ /** The plan is staged: the manifest is known and its objects may be written. */
1509
+ 'prepared',
1510
+ /** The staged objects are being restored into the scratch namespace. */
1511
+ 'executing',
1512
+ /** The restore stopped on an error; the staging tree and its state stay for cleanup. */
1513
+ 'failed',
1514
+ /** Every mapping of the plan was restored. */
1515
+ 'executed',
1516
+ /** The staging tree is gone; nothing of this restore is left on the node. */
1517
+ 'cleaned',
1518
+ ] as const);
1519
+
1520
+ /** One staging state of an isolated restore on a node. */
1521
+ export type TIsolatedRestoreProgressStatus =
1522
+ typeof isolatedRestoreProgressStatuses[number];
1523
+
1524
+ /**
1525
+ * Where one staged object stands, stated only by the call that carried a chunk of it.
1526
+ *
1527
+ * `nextOffset` is the byte the next chunk continues at, so a resumed or replayed staging run
1528
+ * continues where the node already is instead of where the sender assumed it was. `completed`
1529
+ * means the node holds the whole object and proved its digest; reaching the object's size does
1530
+ * not, which is why the two are separate facts.
1531
+ */
1532
+ export interface IIsolatedRestoreObjectProgress {
1533
+ path: string;
1534
+ nextOffset: number;
1535
+ completed: boolean;
1536
+ }
1537
+
1538
+ /**
1539
+ * One node's answer to an isolated-restore control call.
1540
+ *
1541
+ * Everything here is a fact the node holds: Corestore's summary of its staging state, plus the
1542
+ * node the relay carried the control to. It is deliberately not the control plane's record — a
1543
+ * node knows nothing of the source backup, the requesting actor or the verification the control
1544
+ * plane will run — so the control plane composes its record from this and its own knowledge, as it
1545
+ * does with the Corestore inventory.
1546
+ */
1547
+ export interface IIsolatedRestoreProgress {
1548
+ /** The cluster node this progress describes, as the cluster document names it. */
1549
+ nodeId: string;
1550
+ restoreId: string;
1551
+ stagingArchiveId: string;
1552
+ status: TIsolatedRestoreProgressStatus;
1553
+ /** The node state's compare-and-swap value; the next control carries it as `expectedRevision`. */
1554
+ revision: number;
1555
+ /** The fence the node last committed under, so a stale writer is visible to the caller. */
1556
+ lastFence: number;
1557
+ expectedObjects: number;
1558
+ receivedObjects: number;
1559
+ completedMappings: number;
1560
+ totalMappings: number;
1561
+ preparedAt: number;
1562
+ updatedAt: number;
1563
+ executedAt?: number;
1564
+ /**
1565
+ * Present only on a staged chunk: where that one object stands.
1566
+ *
1567
+ * It is named apart from Corestore's own `object` member, which is the receipt for a received
1568
+ * object and a different shape; see `stageIsolatedRestoreArchive` for the projection.
1569
+ */
1570
+ stagedObject?: IIsolatedRestoreObjectProgress;
1571
+ }
1572
+
1573
+ const isolatedRestoreProgressKeys = [
1574
+ 'nodeId',
1575
+ 'restoreId',
1576
+ 'stagingArchiveId',
1577
+ 'status',
1578
+ 'revision',
1579
+ 'lastFence',
1580
+ 'expectedObjects',
1581
+ 'receivedObjects',
1582
+ 'completedMappings',
1583
+ 'totalMappings',
1584
+ 'preparedAt',
1585
+ 'updatedAt',
1586
+ ] as const;
1587
+
1588
+ const optionalIsolatedRestoreProgressKeys = ['executedAt', 'stagedObject'] as const;
1589
+
1590
+ const normalizeIsolatedRestoreObjectProgress = (
1591
+ valueArg: unknown,
1592
+ ): IIsolatedRestoreObjectProgress => {
1593
+ const progress = readRecord(valueArg, 'restore progress.stagedObject');
1594
+ assertExactKeys(
1595
+ progress,
1596
+ ['path', 'nextOffset', 'completed'],
1597
+ 'restore progress.stagedObject',
1598
+ );
1599
+ if (typeof progress.completed !== 'boolean') {
1600
+ return fail('restore progress.stagedObject.completed must be a boolean');
1601
+ }
1602
+ return {
1603
+ path: readRepositoryPath(progress.path, 'restore progress.stagedObject.path'),
1604
+ nextOffset: readSafeInteger(
1605
+ progress.nextOffset,
1606
+ 'restore progress.stagedObject.nextOffset',
1607
+ 0,
1608
+ isolatedRestoreContractLimits.maximumArchiveObjectBytes,
1609
+ ),
1610
+ completed: progress.completed,
1611
+ };
1612
+ };
1613
+
1614
+ /**
1615
+ * Reads one node's progress and refuses everything that is not exactly it.
1616
+ *
1617
+ * The counts are read against each other rather than one by one: a node cannot have received more
1618
+ * objects than its manifest lists or completed more mappings than its plan has, and a restore it
1619
+ * never prepared has no progress at all — a node that does not hold the restore refuses the call
1620
+ * (`restore-node-refused`) instead of answering a progress with revision 0. `revision` and
1621
+ * `lastFence` are read from 1 for the same reason: a committed state carries the revision it was
1622
+ * committed as and the fence of the lease that committed it, so neither is ever 0.
1623
+ *
1624
+ * The states a run passes through are read against the archive as well: `executing` and `executed`
1625
+ * hold the whole archive, and `executed` completed every mapping and says when.
1626
+ */
1627
+ export const normalizeIsolatedRestoreProgress = (
1628
+ valueArg: unknown,
1629
+ ): Readonly<IIsolatedRestoreProgress> => {
1630
+ const progress = readRecord(valueArg, 'restore progress');
1631
+ assertExactKeys(
1632
+ progress,
1633
+ isolatedRestoreProgressKeys,
1634
+ 'restore progress',
1635
+ optionalIsolatedRestoreProgressKeys,
1636
+ );
1637
+ if (
1638
+ typeof progress.status !== 'string' ||
1639
+ !isolatedRestoreProgressStatuses.includes(
1640
+ progress.status as TIsolatedRestoreProgressStatus,
1641
+ )
1642
+ ) {
1643
+ return fail('restore progress.status is unsupported');
1644
+ }
1645
+ const expectedObjects = readSafeInteger(
1646
+ progress.expectedObjects,
1647
+ 'restore progress.expectedObjects',
1648
+ 1,
1649
+ isolatedRestoreContractLimits.maximumArchiveObjects,
1650
+ );
1651
+ const totalMappings = readSafeInteger(
1652
+ progress.totalMappings,
1653
+ 'restore progress.totalMappings',
1654
+ 1,
1655
+ isolatedRestoreContractLimits.maximumResourceMappings,
1656
+ );
1657
+ const preparedAt = readSafeInteger(progress.preparedAt, 'restore progress.preparedAt', 1);
1658
+ const normalized: IIsolatedRestoreProgress = {
1659
+ nodeId: readIdentifier(progress.nodeId, 'restore progress.nodeId'),
1660
+ restoreId: readScopedId(progress.restoreId, 'restore progress.restoreId'),
1661
+ stagingArchiveId: readScopedId(
1662
+ progress.stagingArchiveId,
1663
+ 'restore progress.stagingArchiveId',
1664
+ ),
1665
+ status: progress.status as TIsolatedRestoreProgressStatus,
1666
+ revision: readSafeInteger(progress.revision, 'restore progress.revision', 1),
1667
+ lastFence: readSafeInteger(progress.lastFence, 'restore progress.lastFence', 1),
1668
+ expectedObjects,
1669
+ receivedObjects: readSafeInteger(
1670
+ progress.receivedObjects,
1671
+ 'restore progress.receivedObjects',
1672
+ 0,
1673
+ expectedObjects,
1674
+ ),
1675
+ completedMappings: readSafeInteger(
1676
+ progress.completedMappings,
1677
+ 'restore progress.completedMappings',
1678
+ 0,
1679
+ totalMappings,
1680
+ ),
1681
+ totalMappings,
1682
+ preparedAt,
1683
+ updatedAt: readSafeInteger(progress.updatedAt, 'restore progress.updatedAt', preparedAt),
1684
+ ...(Object.hasOwn(progress, 'executedAt')
1685
+ ? {
1686
+ executedAt: readSafeInteger(
1687
+ progress.executedAt,
1688
+ 'restore progress.executedAt',
1689
+ preparedAt,
1690
+ ),
1691
+ }
1692
+ : {}),
1693
+ ...(Object.hasOwn(progress, 'stagedObject')
1694
+ ? { stagedObject: normalizeIsolatedRestoreObjectProgress(progress.stagedObject) }
1695
+ : {}),
1696
+ };
1697
+ // Corestore asserts that every manifest object was received before it commits `executing`, and
1698
+ // refuses archive writes from that state on, so a run that reached either state holds the whole
1699
+ // archive; `executedAt` is written by the same commit that sets `executed`.
1700
+ if (
1701
+ (normalized.status === 'executing' || normalized.status === 'executed') &&
1702
+ normalized.receivedObjects !== expectedObjects
1703
+ ) {
1704
+ return fail(
1705
+ `restore progress.status ${normalized.status} requires every archive object to be received`,
1706
+ );
1707
+ }
1708
+ if (normalized.status === 'executed') {
1709
+ if (normalized.completedMappings !== totalMappings) {
1710
+ return fail('restore progress.status executed requires every mapping to be completed');
1711
+ }
1712
+ if (normalized.executedAt === undefined) {
1713
+ return fail('restore progress.status executed requires an executedAt');
1714
+ }
1715
+ }
1716
+ return deepFreeze(normalized);
1717
+ };
1718
+
1719
+ /** The node and restore a caller sent a control for, and expects the answer to describe. */
1720
+ export interface IIsolatedRestoreProgressExpectation {
1721
+ nodeId: string;
1722
+ restoreId: string;
1723
+ }
1724
+
1725
+ /**
1726
+ * The progress a node stated, bound to the call it answers.
1727
+ *
1728
+ * The control body carries no node and no restore id — the signed grant is the only authority for
1729
+ * the restore, and the relay routes on `nodeId` — so the caller is the one party holding both
1730
+ * facts, and this is where the answer is tied back to them. Without it a relay could answer with
1731
+ * another node's progress, or with another restore's, and the fields alone would look perfectly
1732
+ * canonical.
1733
+ */
1734
+ export const bindIsolatedRestoreProgressToNode = (
1735
+ progressArg: unknown,
1736
+ expectationArg: IIsolatedRestoreProgressExpectation,
1737
+ ): Readonly<IIsolatedRestoreProgress> => {
1738
+ const expectation = readRecord(expectationArg, 'restore progress expectation');
1739
+ assertExactKeys(expectation, ['nodeId', 'restoreId'], 'restore progress expectation');
1740
+ const nodeId = readIdentifier(expectation.nodeId, 'restore progress expectation.nodeId');
1741
+ const restoreId = readScopedId(
1742
+ expectation.restoreId,
1743
+ 'restore progress expectation.restoreId',
1744
+ );
1745
+ const progress = normalizeIsolatedRestoreProgress(progressArg);
1746
+ if (progress.nodeId !== nodeId) {
1747
+ return fail('restore progress must describe the node the control was carried to');
1748
+ }
1749
+ if (progress.restoreId !== restoreId) {
1750
+ return fail('restore progress must describe the restore its grant names');
1751
+ }
1752
+ return progress;
1753
+ };
1754
+
1456
1755
  const canonicalizeJson = (valueArg: unknown): string => {
1457
1756
  return canonicalizeStrictJson(valueArg, fail);
1458
1757
  };
@@ -1482,7 +1781,6 @@ export const normalizeIsolatedRestoreAuthorityProjection = (
1482
1781
  assertExactKeys(
1483
1782
  authority,
1484
1783
  [
1485
- 'version',
1486
1784
  'iss',
1487
1785
  'aud',
1488
1786
  'sub',
@@ -1500,11 +1798,7 @@ export const normalizeIsolatedRestoreAuthorityProjection = (
1500
1798
  ],
1501
1799
  'restore authority projection',
1502
1800
  );
1503
- if (authority.version !== 1) {
1504
- return fail('restore authority projection.version must be 1');
1505
- }
1506
1801
  const normalized: IIsolatedRestoreAuthorityProjection = {
1507
- version: 1,
1508
1802
  iss: readConfiguredString(authority.iss, 'restore authority projection.iss'),
1509
1803
  aud: readConfiguredString(authority.aud, 'restore authority projection.aud'),
1510
1804
  sub: readIdentifier(authority.sub, 'restore authority projection.sub'),
@@ -1571,7 +1865,6 @@ export const createIsolatedRestoreAuthorityProjection = (
1571
1865
  ): Readonly<IIsolatedRestoreAuthorityProjection> => {
1572
1866
  const claims = normalizeIsolatedRestoreGrantClaims(claimsArg);
1573
1867
  return normalizeIsolatedRestoreAuthorityProjection({
1574
- version: 1,
1575
1868
  iss: claims.iss,
1576
1869
  aud: claims.aud,
1577
1870
  sub: claims.sub,
@@ -2003,7 +2296,6 @@ const createDurableChunkReceiptPayload = (
2003
2296
  receiptArg: IIsolatedRestoreDurableChunkReceipt,
2004
2297
  ): TIsolatedRestoreDurableChunkReceiptPayload => {
2005
2298
  return {
2006
- version: 1,
2007
2299
  authority: receiptArg.authority,
2008
2300
  authoritySha256: receiptArg.authoritySha256,
2009
2301
  descriptor: receiptArg.descriptor,
@@ -2026,7 +2318,6 @@ export const normalizeIsolatedRestoreDurableChunkReceipt = (
2026
2318
  assertExactKeys(
2027
2319
  receipt,
2028
2320
  [
2029
- 'version',
2030
2321
  'authority',
2031
2322
  'authoritySha256',
2032
2323
  'descriptor',
@@ -2037,9 +2328,6 @@ export const normalizeIsolatedRestoreDurableChunkReceipt = (
2037
2328
  ],
2038
2329
  'durable chunk receipt',
2039
2330
  );
2040
- if (receipt.version !== 1) {
2041
- return fail('durable chunk receipt.version must be 1');
2042
- }
2043
2331
  const authority = normalizeIsolatedRestoreAuthorityProjection(
2044
2332
  receipt.authority,
2045
2333
  );
@@ -2096,7 +2384,6 @@ export const normalizeIsolatedRestoreDurableChunkReceipt = (
2096
2384
  );
2097
2385
  }
2098
2386
  return deepFreeze({
2099
- version: 1,
2100
2387
  authority,
2101
2388
  authoritySha256: readSha256(
2102
2389
  receipt.authoritySha256,
@@ -2148,7 +2435,6 @@ export const createIsolatedRestoreDurableChunkReceipt = async (
2148
2435
  ): Promise<Readonly<IIsolatedRestoreDurableChunkReceipt>> => {
2149
2436
  const binding = requireBoundWriteRequest(bindingArg);
2150
2437
  const payload: TIsolatedRestoreDurableChunkReceiptPayload = {
2151
- version: 1,
2152
2438
  authority: binding.authority,
2153
2439
  authoritySha256: binding.authoritySha256,
2154
2440
  descriptor: binding.descriptor,
@@ -2263,7 +2549,6 @@ export const verifyIsolatedRestoreDurableCompletedObject = async (
2263
2549
  canonicalizeJson(receipts),
2264
2550
  );
2265
2551
  const proofPayload = {
2266
- version: 1 as const,
2267
2552
  authority,
2268
2553
  authoritySha256,
2269
2554
  descriptor,
package/ts/data/mail.ts CHANGED
@@ -271,7 +271,7 @@ export interface IServiceMailInboundConfig {
271
271
  typedMethod?: string;
272
272
  /**
273
273
  * Published Docker/Swarm port that dcrouter may SMTP-forward inbound mail to.
274
- * It must resolve to one `IRuntimeNetworkPublishedPortV1` entry of the
274
+ * It must resolve to one `IRuntimeNetworkPublishedPort` entry of the
275
275
  * service's signed runtime network projection: the same node host port, with
276
276
  * its own Cloudly authorization. A value with no matching published port is
277
277
  * not routable.