@serve.zone/interfaces 32.1.0 → 32.3.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.
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The readers a storage control body is judged by, and the one normalizer that turns a storage
3
+ * request into the exact value its digest is taken over.
4
+ *
5
+ * Two modules judge the same bytes in their own error vocabulary — `platform/storage.ts` for a
6
+ * storage request on its own and `platform/storagemigration.ts` for the migration control plane
7
+ * that carries one — so the rules take the failure they report through. A second copy of them
8
+ * would be a second answer to what a request is, and a request digest that a control plane issues
9
+ * and a consumer re-derives would stop being one value.
10
+ */
11
+ import type { IAppStoreFilesystemStorageRequest, IAppStoreObjectStorageRequest, TAppStoreStorageRequest } from '../appstore/types.js';
12
+ import type { TObjectStorageDelivery } from '../platform/storage.js';
13
+ import type { TCanonicalJsonFailure } from './canonicaljson.js';
14
+ /** Byte bounds every reader of a storage control string applies. */
15
+ export declare const storageContractStringLimits: Readonly<{
16
+ maximumConfiguredStringBytes: 2048;
17
+ maximumEnvironmentKeyBytes: 256;
18
+ maximumSecretPathBytes: 2048;
19
+ }>;
20
+ export declare const createStorageContractReaders: (failArg: TCanonicalJsonFailure) => {
21
+ utf8ByteLength: (valueArg: string) => number;
22
+ readRecord: (valueArg: unknown, fieldNameArg: string) => Record<string, unknown>;
23
+ readDenseArray: (valueArg: unknown, fieldNameArg: string, minimumLengthArg: number, maximumLengthArg: number) => unknown[];
24
+ assertKeys: (recordArg: Record<string, unknown>, requiredKeysArg: readonly string[], optionalKeysArg: readonly string[], fieldNameArg: string) => void;
25
+ assertExactKeys: (recordArg: Record<string, unknown>, expectedKeysArg: readonly string[], fieldNameArg: string) => void;
26
+ readString: (valueArg: unknown, fieldNameArg: string, maximumBytesArg?: number) => string;
27
+ readIdentifier: (valueArg: unknown, fieldNameArg: string) => string;
28
+ readSha256: (valueArg: unknown, fieldNameArg: string) => string;
29
+ readSafeInteger: (valueArg: unknown, fieldNameArg: string, minimumArg: number, maximumArg?: number) => number;
30
+ readBoolean: (valueArg: unknown, fieldNameArg: string) => boolean;
31
+ readLiteral: <TLiteral extends string>(valueArg: unknown, allowedArg: readonly TLiteral[], fieldNameArg: string) => TLiteral;
32
+ readCapacityQuantity: (valueArg: unknown, fieldNameArg: string) => string;
33
+ capacityQuantityBytes: (valueArg: string) => bigint;
34
+ readEnvironmentKey: (valueArg: unknown, fieldNameArg: string) => string;
35
+ normalizeCapacityRequest: (valueArg: unknown, fieldNameArg: string) => NonNullable<TAppStoreStorageRequest["capacity"]>;
36
+ normalizeDelivery: (valueArg: unknown, fieldNameArg: string) => TObjectStorageDelivery;
37
+ normalizeObjectStorageRequest: (valueArg: unknown, fieldNameArg: string) => IAppStoreObjectStorageRequest;
38
+ normalizeFilesystemStorageRequest: (valueArg: unknown, fieldNameArg: string) => IAppStoreFilesystemStorageRequest;
39
+ normalizeStorageRequest: (valueArg: unknown, fieldNameArg: string) => TAppStoreStorageRequest;
40
+ };
@@ -0,0 +1,399 @@
1
+ import { normalizeServiceAbsolutePath } from '../data/service.js';
2
+ /** Byte bounds every reader of a storage control string applies. */
3
+ export const storageContractStringLimits = Object.freeze({
4
+ maximumConfiguredStringBytes: 2048,
5
+ maximumEnvironmentKeyBytes: 256,
6
+ maximumSecretPathBytes: 2048,
7
+ });
8
+ const canonicalIdPattern = /^[A-Za-z0-9][A-Za-z0-9._:@-]{0,191}$/;
9
+ const environmentKeyPattern = /^[A-Z_][A-Z0-9_]{0,255}$/;
10
+ const sha256Pattern = /^[a-f0-9]{64}$/;
11
+ const capacityPattern = /^[1-9][0-9]*(?:KiB|MiB|GiB|TiB)$/;
12
+ /**
13
+ * The mount a Secret file is delivered under. A filesystem request that mounts it, or anything
14
+ * containing it, would shadow every credential the platform writes for the same service.
15
+ */
16
+ const secretDeliveryRoot = '/run/secrets';
17
+ export const createStorageContractReaders = (failArg) => {
18
+ const utf8ByteLength = (valueArg) => {
19
+ return new TextEncoder().encode(valueArg).byteLength;
20
+ };
21
+ const readRecord = (valueArg, fieldNameArg) => {
22
+ if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg)) {
23
+ return failArg(`${fieldNameArg} must be a plain object`);
24
+ }
25
+ const prototype = Object.getPrototypeOf(valueArg);
26
+ if (prototype !== Object.prototype && prototype !== null) {
27
+ return failArg(`${fieldNameArg} must be a plain object`);
28
+ }
29
+ const record = valueArg;
30
+ const ownKeys = Reflect.ownKeys(record);
31
+ if (ownKeys.some((keyArg) => typeof keyArg !== 'string')) {
32
+ return failArg(`${fieldNameArg} must not contain symbol keys`);
33
+ }
34
+ for (const key of ownKeys) {
35
+ const descriptor = Object.getOwnPropertyDescriptor(record, key);
36
+ if (!descriptor ||
37
+ !descriptor.enumerable ||
38
+ !Object.hasOwn(descriptor, 'value') ||
39
+ descriptor.value === undefined) {
40
+ return failArg(`${fieldNameArg} must contain enumerable JSON data properties only`);
41
+ }
42
+ }
43
+ return record;
44
+ };
45
+ const readDenseArray = (valueArg, fieldNameArg, minimumLengthArg, maximumLengthArg) => {
46
+ if (!Array.isArray(valueArg) ||
47
+ Object.getPrototypeOf(valueArg) !== Array.prototype) {
48
+ return failArg(`${fieldNameArg} must be a dense plain array`);
49
+ }
50
+ if (valueArg.length < minimumLengthArg ||
51
+ valueArg.length > maximumLengthArg) {
52
+ return failArg(`${fieldNameArg} must contain between ${minimumLengthArg} and ${maximumLengthArg} entries`);
53
+ }
54
+ for (let index = 0; index < valueArg.length; index++) {
55
+ if (!Object.hasOwn(valueArg, index)) {
56
+ return failArg(`${fieldNameArg} must not contain sparse entries`);
57
+ }
58
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, String(index));
59
+ if (!descriptor ||
60
+ !descriptor.enumerable ||
61
+ !Object.hasOwn(descriptor, 'value') ||
62
+ descriptor.value === undefined) {
63
+ return failArg(`${fieldNameArg} must contain enumerable JSON data entries only`);
64
+ }
65
+ }
66
+ for (const key of Reflect.ownKeys(valueArg)) {
67
+ if (key === 'length')
68
+ continue;
69
+ if (typeof key !== 'string' ||
70
+ !/^(?:0|[1-9][0-9]*)$/.test(key) ||
71
+ Number(key) >= valueArg.length) {
72
+ return failArg(`${fieldNameArg} must not contain extra properties`);
73
+ }
74
+ }
75
+ return valueArg;
76
+ };
77
+ const assertKeys = (recordArg, requiredKeysArg, optionalKeysArg, fieldNameArg) => {
78
+ const actualKeys = Object.keys(recordArg).sort();
79
+ const allowedKeys = new Set([...requiredKeysArg, ...optionalKeysArg]);
80
+ if (requiredKeysArg.some((keyArg) => !Object.hasOwn(recordArg, keyArg)) ||
81
+ actualKeys.some((keyArg) => !allowedKeys.has(keyArg))) {
82
+ failArg(`${fieldNameArg} does not match its exact schema`);
83
+ }
84
+ };
85
+ const assertExactKeys = (recordArg, expectedKeysArg, fieldNameArg) => {
86
+ assertKeys(recordArg, expectedKeysArg, [], fieldNameArg);
87
+ };
88
+ const readString = (valueArg, fieldNameArg, maximumBytesArg = storageContractStringLimits.maximumConfiguredStringBytes) => {
89
+ if (typeof valueArg !== 'string' ||
90
+ valueArg.length === 0 ||
91
+ utf8ByteLength(valueArg) > maximumBytesArg ||
92
+ /[\u0000-\u001f\u007f]/u.test(valueArg)) {
93
+ return failArg(`${fieldNameArg} must be a bounded non-empty JSON string`);
94
+ }
95
+ for (let index = 0; index < valueArg.length; index++) {
96
+ const codeUnit = valueArg.charCodeAt(index);
97
+ if (codeUnit >= 0xd800 && codeUnit <= 0xdbff) {
98
+ const following = valueArg.charCodeAt(index + 1);
99
+ if (following < 0xdc00 || following > 0xdfff) {
100
+ return failArg(`${fieldNameArg} contains an unpaired UTF-16 surrogate`);
101
+ }
102
+ index++;
103
+ }
104
+ else if (codeUnit >= 0xdc00 && codeUnit <= 0xdfff) {
105
+ return failArg(`${fieldNameArg} contains an unpaired UTF-16 surrogate`);
106
+ }
107
+ }
108
+ return valueArg;
109
+ };
110
+ const readIdentifier = (valueArg, fieldNameArg) => {
111
+ if (typeof valueArg !== 'string' || !canonicalIdPattern.test(valueArg)) {
112
+ return failArg(`${fieldNameArg} must be a canonical identifier`);
113
+ }
114
+ return valueArg;
115
+ };
116
+ const readSha256 = (valueArg, fieldNameArg) => {
117
+ if (typeof valueArg !== 'string' || !sha256Pattern.test(valueArg)) {
118
+ return failArg(`${fieldNameArg} must be a bare lowercase 64-hex SHA-256 digest`);
119
+ }
120
+ return valueArg;
121
+ };
122
+ const readSafeInteger = (valueArg, fieldNameArg, minimumArg, maximumArg = Number.MAX_SAFE_INTEGER) => {
123
+ if (typeof valueArg !== 'number' ||
124
+ !Number.isSafeInteger(valueArg) ||
125
+ Object.is(valueArg, -0) ||
126
+ valueArg < minimumArg ||
127
+ valueArg > maximumArg) {
128
+ return failArg(`${fieldNameArg} must be a safe integer between ${minimumArg} and ${maximumArg}`);
129
+ }
130
+ return valueArg;
131
+ };
132
+ const readBoolean = (valueArg, fieldNameArg) => {
133
+ if (typeof valueArg !== 'boolean') {
134
+ return failArg(`${fieldNameArg} must be a boolean`);
135
+ }
136
+ return valueArg;
137
+ };
138
+ const readLiteral = (valueArg, allowedArg, fieldNameArg) => {
139
+ if (typeof valueArg !== 'string' ||
140
+ !allowedArg.includes(valueArg)) {
141
+ return failArg(`${fieldNameArg} is outside the supported values`);
142
+ }
143
+ return valueArg;
144
+ };
145
+ const readCapacityQuantity = (valueArg, fieldNameArg) => {
146
+ if (typeof valueArg !== 'string' || !capacityPattern.test(valueArg)) {
147
+ return failArg(`${fieldNameArg} must be a canonical base-2 capacity quantity`);
148
+ }
149
+ const numericPart = valueArg.replace(/(?:KiB|MiB|GiB|TiB)$/, '');
150
+ if (!Number.isSafeInteger(Number(numericPart))) {
151
+ return failArg(`${fieldNameArg} exceeds the safe integer quantity range`);
152
+ }
153
+ return valueArg;
154
+ };
155
+ const capacityQuantityBytes = (valueArg) => {
156
+ const units = {
157
+ KiB: 1024n,
158
+ MiB: 1024n ** 2n,
159
+ GiB: 1024n ** 3n,
160
+ TiB: 1024n ** 4n,
161
+ };
162
+ const unit = valueArg.slice(-3);
163
+ return BigInt(valueArg.slice(0, -3)) * units[unit];
164
+ };
165
+ const normalizeCapacityRequest = (valueArg, fieldNameArg) => {
166
+ const value = readRecord(valueArg, fieldNameArg);
167
+ assertKeys(value, ['request'], ['limit'], fieldNameArg);
168
+ const request = readCapacityQuantity(value.request, `${fieldNameArg}.request`);
169
+ const limit = Object.hasOwn(value, 'limit')
170
+ ? readCapacityQuantity(value.limit, `${fieldNameArg}.limit`)
171
+ : undefined;
172
+ if (limit && capacityQuantityBytes(limit) < capacityQuantityBytes(request)) {
173
+ return failArg(`${fieldNameArg}.limit must be at least request`);
174
+ }
175
+ return {
176
+ request,
177
+ ...(limit ? { limit } : {}),
178
+ };
179
+ };
180
+ const readEnvironmentKey = (valueArg, fieldNameArg) => {
181
+ if (typeof valueArg !== 'string' ||
182
+ utf8ByteLength(valueArg) >
183
+ storageContractStringLimits.maximumEnvironmentKeyBytes ||
184
+ !environmentKeyPattern.test(valueArg)) {
185
+ return failArg(`${fieldNameArg} must be a canonical environment key`);
186
+ }
187
+ return valueArg;
188
+ };
189
+ const normalizeDelivery = (valueArg, fieldNameArg) => {
190
+ const value = readRecord(valueArg, fieldNameArg);
191
+ if (value.type === 'launcher-environment') {
192
+ assertExactKeys(value, ['type', 'keys'], fieldNameArg);
193
+ const keys = readRecord(value.keys, `${fieldNameArg}.keys`);
194
+ assertKeys(keys, ['endpoint', 'bucket', 'region', 'accessKeyId', 'secretAccessKey'], ['sessionToken'], `${fieldNameArg}.keys`);
195
+ const normalizedKeys = {
196
+ endpoint: readEnvironmentKey(keys.endpoint, `${fieldNameArg}.keys.endpoint`),
197
+ bucket: readEnvironmentKey(keys.bucket, `${fieldNameArg}.keys.bucket`),
198
+ region: readEnvironmentKey(keys.region, `${fieldNameArg}.keys.region`),
199
+ accessKeyId: readEnvironmentKey(keys.accessKeyId, `${fieldNameArg}.keys.accessKeyId`),
200
+ secretAccessKey: readEnvironmentKey(keys.secretAccessKey, `${fieldNameArg}.keys.secretAccessKey`),
201
+ ...(Object.hasOwn(keys, 'sessionToken')
202
+ ? {
203
+ sessionToken: readEnvironmentKey(keys.sessionToken, `${fieldNameArg}.keys.sessionToken`),
204
+ }
205
+ : {}),
206
+ };
207
+ if (new Set(Object.values(normalizedKeys)).size !==
208
+ Object.keys(normalizedKeys).length) {
209
+ return failArg(`${fieldNameArg}.keys values must be distinct`);
210
+ }
211
+ return { type: 'launcher-environment', keys: normalizedKeys };
212
+ }
213
+ if (value.type === 'file') {
214
+ assertExactKeys(value, ['type', 'targetPath', 'format', 'uid', 'gid', 'mode'], fieldNameArg);
215
+ const targetPath = readString(value.targetPath, `${fieldNameArg}.targetPath`, storageContractStringLimits.maximumSecretPathBytes);
216
+ if (!targetPath.startsWith(`${secretDeliveryRoot}/`) ||
217
+ targetPath.includes('\\') ||
218
+ targetPath.split('/').some((segmentArg) => segmentArg === '.' || segmentArg === '..')) {
219
+ return failArg(`${fieldNameArg}.targetPath must be a canonical path below ${secretDeliveryRoot}`);
220
+ }
221
+ if (value.format !== 'servezone-object-storage') {
222
+ return failArg(`${fieldNameArg}.format is unsupported`);
223
+ }
224
+ return {
225
+ type: 'file',
226
+ targetPath,
227
+ format: 'servezone-object-storage',
228
+ uid: readSafeInteger(value.uid, `${fieldNameArg}.uid`, 0, 2_147_483_647),
229
+ gid: readSafeInteger(value.gid, `${fieldNameArg}.gid`, 0, 2_147_483_647),
230
+ mode: value.mode === 0o400 || value.mode === 0o440
231
+ ? value.mode
232
+ : failArg(`${fieldNameArg}.mode must be 0400 or 0440`),
233
+ };
234
+ }
235
+ return failArg(`${fieldNameArg}.type is unsupported`);
236
+ };
237
+ const normalizeObjectStorageProtection = (valueArg, fieldNameArg) => {
238
+ const value = readRecord(valueArg, fieldNameArg);
239
+ assertKeys(value, [], ['backup', 'versioning', 'retentionDays'], fieldNameArg);
240
+ if (Object.keys(value).length === 0) {
241
+ return failArg(`${fieldNameArg} must not be empty`);
242
+ }
243
+ return {
244
+ ...(Object.hasOwn(value, 'backup')
245
+ ? {
246
+ backup: value.backup === 'required'
247
+ ? 'required'
248
+ : failArg(`${fieldNameArg}.backup must be required`),
249
+ }
250
+ : {}),
251
+ ...(Object.hasOwn(value, 'versioning')
252
+ ? {
253
+ versioning: value.versioning === 'required'
254
+ ? 'required'
255
+ : failArg(`${fieldNameArg}.versioning must be required`),
256
+ }
257
+ : {}),
258
+ ...(Object.hasOwn(value, 'retentionDays')
259
+ ? {
260
+ retentionDays: readSafeInteger(value.retentionDays, `${fieldNameArg}.retentionDays`, 1, 365_000),
261
+ }
262
+ : {}),
263
+ };
264
+ };
265
+ const normalizeFilesystemProtection = (valueArg, fieldNameArg) => {
266
+ const value = readRecord(valueArg, fieldNameArg);
267
+ assertKeys(value, [], ['backup', 'snapshots', 'consistency'], fieldNameArg);
268
+ if (Object.keys(value).length === 0) {
269
+ return failArg(`${fieldNameArg} must not be empty`);
270
+ }
271
+ return {
272
+ ...(Object.hasOwn(value, 'backup')
273
+ ? {
274
+ backup: value.backup === 'required'
275
+ ? 'required'
276
+ : failArg(`${fieldNameArg}.backup must be required`),
277
+ }
278
+ : {}),
279
+ ...(Object.hasOwn(value, 'snapshots')
280
+ ? {
281
+ snapshots: readLiteral(value.snapshots, ['portable', 'native'], `${fieldNameArg}.snapshots`),
282
+ }
283
+ : {}),
284
+ ...(Object.hasOwn(value, 'consistency')
285
+ ? {
286
+ consistency: readLiteral(value.consistency, ['crashConsistent', 'applicationConsistent'], `${fieldNameArg}.consistency`),
287
+ }
288
+ : {}),
289
+ };
290
+ };
291
+ const readMountPath = (valueArg, fieldNameArg) => {
292
+ const value = readString(valueArg, fieldNameArg, storageContractStringLimits.maximumSecretPathBytes);
293
+ if (normalizeServiceAbsolutePath(value) !== value || value === '/') {
294
+ return failArg(`${fieldNameArg} must be a canonical non-root absolute path`);
295
+ }
296
+ if (value === secretDeliveryRoot ||
297
+ value.startsWith(`${secretDeliveryRoot}/`) ||
298
+ secretDeliveryRoot.startsWith(`${value}/`)) {
299
+ return failArg(`${fieldNameArg} must not overlap ${secretDeliveryRoot}`);
300
+ }
301
+ return value;
302
+ };
303
+ const normalizeObjectStorageRequest = (valueArg, fieldNameArg) => {
304
+ const value = readRecord(valueArg, fieldNameArg);
305
+ assertKeys(value, [
306
+ 'id',
307
+ 'kind',
308
+ 'storageClass',
309
+ 'accessMode',
310
+ 'reclaimPolicy',
311
+ 'delivery',
312
+ ], ['capacity', 'protection'], fieldNameArg);
313
+ if (value.kind !== 'objectStorage') {
314
+ return failArg(`${fieldNameArg}.kind must be objectStorage`);
315
+ }
316
+ return {
317
+ id: readIdentifier(value.id, `${fieldNameArg}.id`),
318
+ kind: 'objectStorage',
319
+ storageClass: readIdentifier(value.storageClass, `${fieldNameArg}.storageClass`),
320
+ accessMode: readLiteral(value.accessMode, ['readOnly', 'readWrite'], `${fieldNameArg}.accessMode`),
321
+ reclaimPolicy: readLiteral(value.reclaimPolicy, ['retain', 'delete'], `${fieldNameArg}.reclaimPolicy`),
322
+ delivery: normalizeDelivery(value.delivery, `${fieldNameArg}.delivery`),
323
+ ...(Object.hasOwn(value, 'capacity')
324
+ ? {
325
+ capacity: normalizeCapacityRequest(value.capacity, `${fieldNameArg}.capacity`),
326
+ }
327
+ : {}),
328
+ ...(Object.hasOwn(value, 'protection')
329
+ ? {
330
+ protection: normalizeObjectStorageProtection(value.protection, `${fieldNameArg}.protection`),
331
+ }
332
+ : {}),
333
+ };
334
+ };
335
+ const normalizeFilesystemStorageRequest = (valueArg, fieldNameArg) => {
336
+ const value = readRecord(valueArg, fieldNameArg);
337
+ assertKeys(value, [
338
+ 'id',
339
+ 'kind',
340
+ 'storageClass',
341
+ 'accessMode',
342
+ 'reclaimPolicy',
343
+ 'mountPath',
344
+ ], ['capacity', 'protection'], fieldNameArg);
345
+ if (value.kind !== 'filesystem') {
346
+ return failArg(`${fieldNameArg}.kind must be filesystem`);
347
+ }
348
+ return {
349
+ id: readIdentifier(value.id, `${fieldNameArg}.id`),
350
+ kind: 'filesystem',
351
+ storageClass: readIdentifier(value.storageClass, `${fieldNameArg}.storageClass`),
352
+ accessMode: readLiteral(value.accessMode, ['ReadWriteOnce', 'ReadOnlyMany', 'ReadWriteMany'], `${fieldNameArg}.accessMode`),
353
+ reclaimPolicy: readLiteral(value.reclaimPolicy, ['retain', 'delete'], `${fieldNameArg}.reclaimPolicy`),
354
+ mountPath: readMountPath(value.mountPath, `${fieldNameArg}.mountPath`),
355
+ ...(Object.hasOwn(value, 'capacity')
356
+ ? {
357
+ capacity: normalizeCapacityRequest(value.capacity, `${fieldNameArg}.capacity`),
358
+ }
359
+ : {}),
360
+ ...(Object.hasOwn(value, 'protection')
361
+ ? {
362
+ protection: normalizeFilesystemProtection(value.protection, `${fieldNameArg}.protection`),
363
+ }
364
+ : {}),
365
+ };
366
+ };
367
+ const normalizeStorageRequest = (valueArg, fieldNameArg) => {
368
+ const value = readRecord(valueArg, fieldNameArg);
369
+ if (value.kind === 'filesystem') {
370
+ return normalizeFilesystemStorageRequest(value, fieldNameArg);
371
+ }
372
+ if (value.kind === 'objectStorage') {
373
+ return normalizeObjectStorageRequest(value, fieldNameArg);
374
+ }
375
+ return failArg(`${fieldNameArg}.kind must be filesystem or objectStorage`);
376
+ };
377
+ return {
378
+ utf8ByteLength,
379
+ readRecord,
380
+ readDenseArray,
381
+ assertKeys,
382
+ assertExactKeys,
383
+ readString,
384
+ readIdentifier,
385
+ readSha256,
386
+ readSafeInteger,
387
+ readBoolean,
388
+ readLiteral,
389
+ readCapacityQuantity,
390
+ capacityQuantityBytes,
391
+ readEnvironmentKey,
392
+ normalizeCapacityRequest,
393
+ normalizeDelivery,
394
+ normalizeObjectStorageRequest,
395
+ normalizeFilesystemStorageRequest,
396
+ normalizeStorageRequest,
397
+ };
398
+ };
399
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZWNvbnRyYWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvcHJpdmF0ZS9zdG9yYWdlY29udHJhY3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBZUEsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFJbEUsb0VBQW9FO0FBQ3BFLE1BQU0sQ0FBQyxNQUFNLDJCQUEyQixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDdkQsNEJBQTRCLEVBQUUsSUFBSTtJQUNsQywwQkFBMEIsRUFBRSxHQUFHO0lBQy9CLHNCQUFzQixFQUFFLElBQUk7Q0FDN0IsQ0FBQyxDQUFDO0FBRUgsTUFBTSxrQkFBa0IsR0FBRyxzQ0FBc0MsQ0FBQztBQUNsRSxNQUFNLHFCQUFxQixHQUFHLDBCQUEwQixDQUFDO0FBQ3pELE1BQU0sYUFBYSxHQUFHLGdCQUFnQixDQUFDO0FBQ3ZDLE1BQU0sZUFBZSxHQUFHLGtDQUFrQyxDQUFDO0FBQzNEOzs7R0FHRztBQUNILE1BQU0sa0JBQWtCLEdBQUcsY0FBYyxDQUFDO0FBRTFDLE1BQU0sQ0FBQyxNQUFNLDRCQUE0QixHQUFHLENBQUMsT0FBOEIsRUFBRSxFQUFFO0lBQzdFLE1BQU0sY0FBYyxHQUFHLENBQUMsUUFBZ0IsRUFBVSxFQUFFO1FBQ2xELE9BQU8sSUFBSSxXQUFXLEVBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsVUFBVSxDQUFDO0lBQ3ZELENBQUMsQ0FBQztJQUVGLE1BQU0sVUFBVSxHQUFHLENBQ2pCLFFBQWlCLEVBQ2pCLFlBQW9CLEVBQ0ssRUFBRTtRQUMzQixJQUFJLENBQUMsUUFBUSxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDekUsT0FBTyxPQUFPLENBQUMsR0FBRyxZQUFZLHlCQUF5QixDQUFDLENBQUM7UUFDM0QsQ0FBQztRQUNELE1BQU0sU0FB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serve.zone/interfaces",
3
- "version": "32.1.0",
3
+ "version": "32.3.0",
4
4
  "private": false,
5
5
  "description": "Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.",
6
6
  "exports": {
package/readme.md CHANGED
@@ -146,6 +146,22 @@ rather than with this release. `ISparkSwarmNodeHeartbeatRequest` is now owned he
146
146
  so Cloudly and Spark no longer carry private copies of it, and every Swarm-era body
147
147
  — request and answer alike — carries `protocol` and is judged in the same order.
148
148
 
149
+ Each of the four routes has its validator here, so a server never writes its own
150
+ member checks: `data.validateSparkSwarmNodeHeartbeatRequest`,
151
+ `data.validateSparkMetricsSampleRequest`, `data.validateSparkActionResultRequest`
152
+ and `data.validateSparkSwarmObservationRequest`. All four answer the same way —
153
+ one string per refused member, naming the member, and an empty list for an
154
+ admissible body — so a route table can hold them side by side. They read the
155
+ envelope first (exact key set, the sender's offer, then the reporter's identity),
156
+ then the payload: a heartbeat's metrics and full runtime description including
157
+ each described serve.zone service, a sample's four observations and optional
158
+ network rates, and an action result whose status is one a node can actually
159
+ report, never `pending`. Bodies are judged member by member rather than as
160
+ canonical bytes, because only the observation is digested and the others carry
161
+ fractional CPU, memory and rate observations; every level is copied away from the
162
+ caller's object first, so an accessor is refused instead of run. None of them
163
+ authenticates a node or acts on the body.
164
+
149
165
  Cloudly must authenticate the bearer against current Spark authority and fence
150
166
  credential generation and session epoch transactionally before recording host
151
167
  liveness. `ISparkNodeHeartbeatReceipt` contains only server-derived acceptance
@@ -1293,6 +1309,40 @@ metadata plus a service-owned credential management scope and delivery policy,
1293
1309
  never credential references or values. Filesystem
1294
1310
  bindings expose the container mount and access mode, never a host path.
1295
1311
 
1312
+ A binding's `requestDigest` is stated by one function, so the control plane that
1313
+ issues it and the consumer that re-derives it compute the same value:
1314
+
1315
+ ```typescript
1316
+ const requestDigest = await platform.createStorageRequestSha256(storageRequest);
1317
+ ```
1318
+
1319
+ It normalizes the request to its contract shape, canonicalizes it and returns
1320
+ bare lowercase hex over the request alone — no prefix, and nothing wrapped
1321
+ around the request. A body that is not a storage request is refused with
1322
+ `platform.StorageContractError` instead of hashed, and
1323
+ `platform.canonicalizeStorageRequest` returns the exact bytes the digest is
1324
+ taken over. `platform.storageRequestCanonicalDigestGoldenVectors` states both
1325
+ for a filesystem request and for both object-storage deliveries.
1326
+
1327
+ Which requests exist at all is stated by the same contract:
1328
+
1329
+ ```typescript
1330
+ const storageRequest = platform.normalizeStorageRequest(declaredRequest);
1331
+ ```
1332
+
1333
+ `platform.normalizeStorageRequest` reads a body against the exact request schema
1334
+ and returns the request in its contract shape — required members present,
1335
+ optional members carried only when declared, canonical environment keys, no
1336
+ empty `protection` block, no explicitly undefined member, no `-0` or unsafe
1337
+ integer, and plain JSON data members only. It is the value the other two
1338
+ functions are derived from: canonicalizing and digesting a request normalize it
1339
+ first, so a consumer that admits a request through this function and a control
1340
+ plane that digests it cannot accept different sets of requests. The input is
1341
+ never mutated and the returned request is a fresh object. A body that is not a
1342
+ storage request is refused with `platform.StorageContractError`, whose message
1343
+ names the failing member so a consumer can map the refusal to its own status
1344
+ vocabulary instead of restating the rules.
1345
+
1296
1346
  Portable manifests and resolved bindings intentionally have no fields for
1297
1347
  Synology, NFS, Kerberos, Corestore, Kubernetes, Docker drivers, servers,
1298
1348
  exports, mount options, provider credential values, or local fallback paths. Runtimes
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/interfaces',
6
- version: '32.1.0',
6
+ version: '32.3.0',
7
7
  description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
8
8
  }