@serve.zone/interfaces 32.24.0 → 32.25.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,49 @@
1
+ import type { IPlatformBinding } from './types.js';
2
+ import type { IPlatformObjectStorageEndpoint, TObjectStorageEndpointEnvironment, TObjectStorageEndpointEnvironmentKey } from './objectstorage.js';
3
+ import type { TObjectStorageRetentionEnvironment, TObjectStorageRetentionEnvironmentKey } from './objectstorageretention.js';
4
+ /**
5
+ * Every non-secret environment name an object-storage binding can give a workload: the nine
6
+ * endpoint names first, then the eleven retention names.
7
+ */
8
+ export declare const objectStorageBindingEnvironmentKeys: readonly ["S3_ENDPOINT", "S3_ENDPOINT_HOST", "S3_PORT", "S3_REGION", "S3_BUCKET", "S3_USE_SSL", "AWS_ENDPOINT_URL", "AWS_REGION", "AWS_S3_FORCE_PATH_STYLE", "S3_RETENTION_MODE", "S3_RETENTION_POLICY_ID", "S3_RETENTION_DURATION_SECONDS", "S3_RETENTION_INTENT_SHA256", "S3_RETENTION_SENTINEL_KEY", "S3_RETENTION_CONFIGURED_AT", "S3_RETENTION_SENTINEL_CREATED_AT", "S3_RETENTION_SENTINEL_RETAIN_UNTIL", "S3_RETENTION_SENTINEL_PAYLOAD_SHA256", "S3_RETENTION_SENTINEL_METADATA_SHA256", "S3_RETENTION_SENTINEL_ETAG"];
9
+ export type TObjectStorageBindingEnvironmentKey = TObjectStorageEndpointEnvironmentKey | TObjectStorageRetentionEnvironmentKey;
10
+ /**
11
+ * The non-secret environment of one object-storage binding: always the endpoint names, and the
12
+ * retention names exactly when the binding declares compliance retention. Never a credential.
13
+ */
14
+ export type TObjectStorageBindingEnvironment = TObjectStorageEndpointEnvironment | (TObjectStorageEndpointEnvironment & TObjectStorageRetentionEnvironment);
15
+ /**
16
+ * The environment Cloudly composes into a workload's runtime configuration for one binding.
17
+ *
18
+ * `bindingArg` is the Cloudly binding document and `endpointArg` the
19
+ * `IClusterNode.data.corestoreObjectStorage` of the node the binding is placed on. Refused by
20
+ * name, never guessed:
21
+ *
22
+ * - a binding that is not `objectstorage` or carries no canonical `objectstorageBucketName`;
23
+ * - an endpoint that `validatePlatformObjectStorageEndpoint()` refuses;
24
+ * - a binding that declares `objectstorageRetention` without `evidence`. Its bucket's retention is
25
+ * not proven yet, so the workload is not given an environment that would let it run as if its
26
+ * bucket were ordinary storage; the caller waits for the evidence.
27
+ * - evidence that does not prove the binding's own service, binding id, bucket and intent.
28
+ *
29
+ * A binding without `objectstorageRetention` gets the endpoint names alone: it promised no
30
+ * retention, so there is nothing to state.
31
+ *
32
+ * The evidence's reconciliation generation and binding-request digest are read from its own
33
+ * authority: they are what Cloudly checked when it admitted the evidence, and the binding document
34
+ * does not repeat them. Everything the binding does state is checked again here.
35
+ */
36
+ export declare const createObjectStorageBindingEnvironment: (bindingArg: IPlatformBinding, endpointArg: IPlatformObjectStorageEndpoint) => Promise<TObjectStorageBindingEnvironment>;
37
+ /**
38
+ * Validates one binding's environment: the nine endpoint names, the eleven retention names all or
39
+ * none, and nothing else — so a credential alias, or any other name, is refused.
40
+ */
41
+ export declare const validateObjectStorageBindingEnvironment: (environmentArg: unknown, pathArg?: string) => Promise<string[]>;
42
+ /**
43
+ * A workload environment with one binding's environment added.
44
+ *
45
+ * Refuses, naming every key, when the environment already holds one of the binding's names: a
46
+ * service that sets `S3_ENDPOINT` itself, or a second object-storage binding on the same service,
47
+ * would otherwise have one value silently replace the other. The inputs are not changed.
48
+ */
49
+ export declare const mergeObjectStorageBindingEnvironment: (environmentArg: Readonly<Record<string, string>>, bindingEnvironmentArg: TObjectStorageBindingEnvironment) => Record<string, string>;
@@ -0,0 +1,119 @@
1
+ import { createObjectStorageEndpointEnvironment, objectStorageEndpointEnvironmentKeys, validateObjectStorageEndpointEnvironment, validatePlatformObjectStorageBucketName, } from './objectstorage.js';
2
+ import { createObjectStorageRetentionEnvironment, objectStorageRetentionEnvironmentKeys, validateObjectStorageRetentionEnvironment, validateObjectStorageRetentionIntent, } from './objectstorageretention.js';
3
+ import { isPlainRecord, readDataProperties } from '../private/dataproperties.js';
4
+ /**
5
+ * Every non-secret environment name an object-storage binding can give a workload: the nine
6
+ * endpoint names first, then the eleven retention names.
7
+ */
8
+ export const objectStorageBindingEnvironmentKeys = Object.freeze([
9
+ ...objectStorageEndpointEnvironmentKeys,
10
+ ...objectStorageRetentionEnvironmentKeys,
11
+ ]);
12
+ /**
13
+ * The environment Cloudly composes into a workload's runtime configuration for one binding.
14
+ *
15
+ * `bindingArg` is the Cloudly binding document and `endpointArg` the
16
+ * `IClusterNode.data.corestoreObjectStorage` of the node the binding is placed on. Refused by
17
+ * name, never guessed:
18
+ *
19
+ * - a binding that is not `objectstorage` or carries no canonical `objectstorageBucketName`;
20
+ * - an endpoint that `validatePlatformObjectStorageEndpoint()` refuses;
21
+ * - a binding that declares `objectstorageRetention` without `evidence`. Its bucket's retention is
22
+ * not proven yet, so the workload is not given an environment that would let it run as if its
23
+ * bucket were ordinary storage; the caller waits for the evidence.
24
+ * - evidence that does not prove the binding's own service, binding id, bucket and intent.
25
+ *
26
+ * A binding without `objectstorageRetention` gets the endpoint names alone: it promised no
27
+ * retention, so there is nothing to state.
28
+ *
29
+ * The evidence's reconciliation generation and binding-request digest are read from its own
30
+ * authority: they are what Cloudly checked when it admitted the evidence, and the binding document
31
+ * does not repeat them. Everything the binding does state is checked again here.
32
+ */
33
+ export const createObjectStorageBindingEnvironment = async (bindingArg, endpointArg) => {
34
+ const binding = readDataProperties(bindingArg);
35
+ if (binding === null || binding.capability !== 'objectstorage') {
36
+ throw new Error('objectstorage binding environment requires an objectstorage binding');
37
+ }
38
+ const bindingName = typeof binding.id === 'string' ? binding.id : '(unnamed)';
39
+ if (validatePlatformObjectStorageBucketName(binding.objectstorageBucketName).length > 0) {
40
+ throw new Error(`objectstorage binding ${bindingName} carries no canonical bucket name; Cloudly owns it and `
41
+ + 'no environment invents one');
42
+ }
43
+ const bucketName = binding.objectstorageBucketName;
44
+ const endpointEnvironment = createObjectStorageEndpointEnvironment(endpointArg, bucketName);
45
+ const retention = binding.objectstorageRetention;
46
+ if (retention === undefined) {
47
+ return endpointEnvironment;
48
+ }
49
+ const retentionBinding = readDataProperties(retention);
50
+ if (retentionBinding === null
51
+ || validateObjectStorageRetentionIntent(retentionBinding.intent).length > 0) {
52
+ throw new Error(`objectstorage binding ${bindingName} must declare canonical compliance-retention intent`);
53
+ }
54
+ const evidence = retentionBinding.evidence;
55
+ if (evidence === undefined) {
56
+ throw new Error(`objectstorage binding ${bindingName} declares compliance retention without verified `
57
+ + 'evidence; its workload environment waits for the evidence');
58
+ }
59
+ const authority = isPlainRecord(evidence) ? readDataProperties(evidence.authority) : null;
60
+ if (authority === null) {
61
+ throw new Error('objectstorage retention evidence must use its exact schema');
62
+ }
63
+ const retentionEnvironment = await createObjectStorageRetentionEnvironment(evidence, {
64
+ serviceId: binding.serviceId,
65
+ bindingId: binding.id,
66
+ reconciliationGeneration: authority.reconciliationGeneration,
67
+ bindingRequestDigest: authority.bindingRequestDigest,
68
+ bucketName,
69
+ intent: retentionBinding.intent,
70
+ });
71
+ return { ...endpointEnvironment, ...retentionEnvironment };
72
+ };
73
+ /**
74
+ * Validates one binding's environment: the nine endpoint names, the eleven retention names all or
75
+ * none, and nothing else — so a credential alias, or any other name, is refused.
76
+ */
77
+ export const validateObjectStorageBindingEnvironment = async (environmentArg, pathArg = 'objectstorage binding environment') => {
78
+ const environment = readDataProperties(environmentArg);
79
+ if (environment === null) {
80
+ return [`${pathArg} must be a plain record of data properties`];
81
+ }
82
+ const allowedKeys = objectStorageBindingEnvironmentKeys;
83
+ const foreignKeys = Object.keys(environment).filter((keyArg) => !allowedKeys.includes(keyArg));
84
+ if (foreignKeys.length > 0) {
85
+ return [`${pathArg} must not contain ${foreignKeys.sort().join(', ')}`];
86
+ }
87
+ const endpointEnvironment = {};
88
+ for (const key of objectStorageEndpointEnvironmentKeys) {
89
+ if (Object.hasOwn(environment, key))
90
+ endpointEnvironment[key] = environment[key];
91
+ }
92
+ const errors = validateObjectStorageEndpointEnvironment(endpointEnvironment, pathArg);
93
+ const retentionKeys = objectStorageRetentionEnvironmentKeys.filter((keyArg) => (Object.hasOwn(environment, keyArg)));
94
+ if (retentionKeys.length > 0) {
95
+ const retentionEnvironment = {};
96
+ for (const key of retentionKeys)
97
+ retentionEnvironment[key] = environment[key];
98
+ errors.push(...await validateObjectStorageRetentionEnvironment(retentionEnvironment, pathArg));
99
+ }
100
+ return errors;
101
+ };
102
+ /**
103
+ * A workload environment with one binding's environment added.
104
+ *
105
+ * Refuses, naming every key, when the environment already holds one of the binding's names: a
106
+ * service that sets `S3_ENDPOINT` itself, or a second object-storage binding on the same service,
107
+ * would otherwise have one value silently replace the other. The inputs are not changed.
108
+ */
109
+ export const mergeObjectStorageBindingEnvironment = (environmentArg, bindingEnvironmentArg) => {
110
+ const collisions = Object.keys(bindingEnvironmentArg)
111
+ .filter((keyArg) => Object.hasOwn(environmentArg, keyArg))
112
+ .sort();
113
+ if (collisions.length > 0) {
114
+ throw new Error(`objectstorage binding environment collides with ${collisions.join(', ')} already set on the `
115
+ + 'workload');
116
+ }
117
+ return { ...environmentArg, ...bindingEnvironmentArg };
118
+ };
119
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2JqZWN0c3RvcmFnZWVudmlyb25tZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvcGxhdGZvcm0vb2JqZWN0c3RvcmFnZWVudmlyb25tZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQU1BLE9BQU8sRUFDTCxzQ0FBc0MsRUFDdEMsb0NBQW9DLEVBQ3BDLHdDQUF3QyxFQUN4Qyx1Q0FBdUMsR0FDeEMsTUFBTSxvQkFBb0IsQ0FBQztBQU81QixPQUFPLEVBQ0wsdUNBQXVDLEVBQ3ZDLHFDQUFxQyxFQUNyQyx5Q0FBeUMsRUFDekMsb0NBQW9DLEdBQ3JDLE1BQU0sNkJBQTZCLENBQUM7QUFDckMsT0FBTyxFQUFFLGFBQWEsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRWpGOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLG1DQUFtQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDL0QsR0FBRyxvQ0FBb0M7SUFDdkMsR0FBRyxxQ0FBcUM7Q0FDaEMsQ0FBQyxDQUFDO0FBY1o7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBQ0gsTUFBTSxDQUFDLE1BQU0scUNBQXFDLEdBQUcsS0FBSyxFQUN4RCxVQUE0QixFQUM1QixXQUEyQyxFQUNBLEVBQUU7SUFDN0MsTUFBTSxPQUFPLEdBQUcsa0JBQWtCLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDL0MsSUFBSSxPQUFPLEtBQUssSUFBSSxJQUFJLE9BQU8sQ0FBQyxVQUFVLEtBQUssZUFBZSxFQUFFLENBQUM7UUFDL0QsTUFBTSxJQUFJLEtBQUssQ0FBQyxxRUFBcUUsQ0FBQyxDQUFDO0lBQ3pGLENBQUM7SUFDRCxNQUFNLFdBQVcsR0FBRyxPQUFPLE9BQU8sQ0FBQyxFQUFFLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUM7SUFDOUUsSUFBSSx1Q0FBdUMsQ0FBQyxPQUFPLENBQUMsdUJB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
@@ -65,3 +65,43 @@ export declare const objectStorageRetentionIntentsEqual: (leftArg: unknown, righ
65
65
  export declare const validateObjectStorageRetentionEvidence: (evidenceArg: unknown, expectedArg: IObjectStorageRetentionEvidenceExpectation) => Promise<string[]>;
66
66
  export declare const validateObjectStorageRetentionBinding: (bindingArg: unknown, expectedArg: IObjectStorageRetentionEvidenceExpectation) => Promise<string[]>;
67
67
  export declare const validatePlatformBindingObjectStorageRetention: (bindingArg: unknown, expectedArg: IObjectStorageRetentionEvidenceExpectation) => Promise<string[]>;
68
+ /**
69
+ * The non-secret environment names that tell a workload which retention its bucket carries.
70
+ *
71
+ * The names are the ones the cluster relay handed workloads on the Docker path, so an application
72
+ * that read them keeps working unchanged. Every value is a projection of verified
73
+ * `IObjectStorageRetentionEvidence`; none is a credential.
74
+ *
75
+ * - `S3_RETENTION_MODE`: `intent.mode`, always `compliance`.
76
+ * - `S3_RETENTION_POLICY_ID`: `intent.policyId`.
77
+ * - `S3_RETENTION_DURATION_SECONDS`: `intent.retentionDurationSeconds` in decimal.
78
+ * - `S3_RETENTION_INTENT_SHA256`: `intentSha256`.
79
+ * - `S3_RETENTION_SENTINEL_KEY`: `receipt.sentinelKey`.
80
+ * - `S3_RETENTION_CONFIGURED_AT`: `receipt.configuredAt`, Unix milliseconds in decimal.
81
+ * - `S3_RETENTION_SENTINEL_CREATED_AT`: `receipt.sentinel.createdAt`, Unix milliseconds in decimal.
82
+ * - `S3_RETENTION_SENTINEL_RETAIN_UNTIL`: `receipt.sentinel.retainUntil`, Unix milliseconds in
83
+ * decimal.
84
+ * - `S3_RETENTION_SENTINEL_PAYLOAD_SHA256`: `receipt.sentinel.payloadSha256`.
85
+ * - `S3_RETENTION_SENTINEL_METADATA_SHA256`: `receipt.sentinel.metadataSha256`.
86
+ * - `S3_RETENTION_SENTINEL_ETAG`: `receipt.sentinel.etag`.
87
+ */
88
+ export declare const objectStorageRetentionEnvironmentKeys: readonly ["S3_RETENTION_MODE", "S3_RETENTION_POLICY_ID", "S3_RETENTION_DURATION_SECONDS", "S3_RETENTION_INTENT_SHA256", "S3_RETENTION_SENTINEL_KEY", "S3_RETENTION_CONFIGURED_AT", "S3_RETENTION_SENTINEL_CREATED_AT", "S3_RETENTION_SENTINEL_RETAIN_UNTIL", "S3_RETENTION_SENTINEL_PAYLOAD_SHA256", "S3_RETENTION_SENTINEL_METADATA_SHA256", "S3_RETENTION_SENTINEL_ETAG"];
89
+ export type TObjectStorageRetentionEnvironmentKey = typeof objectStorageRetentionEnvironmentKeys[number];
90
+ export type TObjectStorageRetentionEnvironment = {
91
+ [TKey in TObjectStorageRetentionEnvironmentKey]: string;
92
+ };
93
+ /**
94
+ * The retention environment of evidence that proves `expectedArg`.
95
+ *
96
+ * The evidence is validated against the expectation first, with the same validator every other
97
+ * consumer of retention evidence uses; the first reason it is refused is thrown. A workload is
98
+ * never told about a retention nobody proved.
99
+ */
100
+ export declare const createObjectStorageRetentionEnvironment: (evidenceArg: IObjectStorageRetentionEvidence, expectedArg: IObjectStorageRetentionEvidenceExpectation) => Promise<TObjectStorageRetentionEnvironment>;
101
+ /**
102
+ * Validates a retention environment on its own: exactly its eleven keys, canonical values, an
103
+ * intent digest that matches the stated intent, and sentinel timestamps that agree with the
104
+ * duration. It cannot prove the authority or the bucket the evidence was bound to — the
105
+ * environment does not carry them — so it judges the shape a workload reads, not the proof.
106
+ */
107
+ export declare const validateObjectStorageRetentionEnvironment: (environmentArg: unknown, pathArg?: string) => Promise<string[]>;
@@ -249,4 +249,124 @@ export const validatePlatformBindingObjectStorageRetention = async (bindingArg,
249
249
  }
250
250
  return validateObjectStorageRetentionBinding(bindingArg.objectstorageRetention, expectedArg);
251
251
  };
252
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2JqZWN0c3RvcmFnZXJldGVudGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3BsYXRmb3JtL29iamVjdHN0b3JhZ2VyZXRlbnRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDM0UsT0FBTyxFQUFFLHVDQUF1QyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDN0UsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRTVELE1BQU0sQ0FBQyxNQUFNLDRCQUE0QixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDeEQscUJBQXFCLEVBQUUsRUFBRTtJQUN6QiwrQkFBK0IsRUFBRSxHQUFHLEdBQUcsR0FBRyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRTtDQUMxRCxDQUFDLENBQUM7QUFvRUgsTUFBTSxlQUFlLEdBQUcsd0JBQXdCLENBQUM7QUFDakQsTUFBTSxpQkFBaUIsR0FBRyxxQ0FBcUMsQ0FBQztBQUNoRSxNQUFNLGFBQWEsR0FBRyxnQkFBZ0IsQ0FBQztBQUN2QyxNQUFNLFdBQVcsR0FBRyxnQkFBZ0IsQ0FBQztBQUNyQzs7OztHQUlHO0FBQ0gsTUFBTSxrQkFBa0IsR0FBRyw2REFBNkQsQ0FBQztBQUV6RixNQUFNLFFBQVEsR0FBRyxDQUFDLFFBQWlCLEVBQXVDLEVBQUUsQ0FBQyxDQUMzRSxPQUFPLENBQUMsUUFBUSxDQUFDO09BQ2QsT0FBTyxRQUFRLEtBQUssUUFBUTtPQUM1QixDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDO09BQ3hCLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsS0FBSyxNQUFNLENBQUMsU0FBUztXQUNuRCxNQUFNLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUMvQyxDQUFDO0FBRUYsTUFBTSxxQkFBcUIsR0FBRyxD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
252
+ /**
253
+ * The non-secret environment names that tell a workload which retention its bucket carries.
254
+ *
255
+ * The names are the ones the cluster relay handed workloads on the Docker path, so an application
256
+ * that read them keeps working unchanged. Every value is a projection of verified
257
+ * `IObjectStorageRetentionEvidence`; none is a credential.
258
+ *
259
+ * - `S3_RETENTION_MODE`: `intent.mode`, always `compliance`.
260
+ * - `S3_RETENTION_POLICY_ID`: `intent.policyId`.
261
+ * - `S3_RETENTION_DURATION_SECONDS`: `intent.retentionDurationSeconds` in decimal.
262
+ * - `S3_RETENTION_INTENT_SHA256`: `intentSha256`.
263
+ * - `S3_RETENTION_SENTINEL_KEY`: `receipt.sentinelKey`.
264
+ * - `S3_RETENTION_CONFIGURED_AT`: `receipt.configuredAt`, Unix milliseconds in decimal.
265
+ * - `S3_RETENTION_SENTINEL_CREATED_AT`: `receipt.sentinel.createdAt`, Unix milliseconds in decimal.
266
+ * - `S3_RETENTION_SENTINEL_RETAIN_UNTIL`: `receipt.sentinel.retainUntil`, Unix milliseconds in
267
+ * decimal.
268
+ * - `S3_RETENTION_SENTINEL_PAYLOAD_SHA256`: `receipt.sentinel.payloadSha256`.
269
+ * - `S3_RETENTION_SENTINEL_METADATA_SHA256`: `receipt.sentinel.metadataSha256`.
270
+ * - `S3_RETENTION_SENTINEL_ETAG`: `receipt.sentinel.etag`.
271
+ */
272
+ export const objectStorageRetentionEnvironmentKeys = Object.freeze([
273
+ 'S3_RETENTION_MODE',
274
+ 'S3_RETENTION_POLICY_ID',
275
+ 'S3_RETENTION_DURATION_SECONDS',
276
+ 'S3_RETENTION_INTENT_SHA256',
277
+ 'S3_RETENTION_SENTINEL_KEY',
278
+ 'S3_RETENTION_CONFIGURED_AT',
279
+ 'S3_RETENTION_SENTINEL_CREATED_AT',
280
+ 'S3_RETENTION_SENTINEL_RETAIN_UNTIL',
281
+ 'S3_RETENTION_SENTINEL_PAYLOAD_SHA256',
282
+ 'S3_RETENTION_SENTINEL_METADATA_SHA256',
283
+ 'S3_RETENTION_SENTINEL_ETAG',
284
+ ]);
285
+ /**
286
+ * The retention environment of evidence that proves `expectedArg`.
287
+ *
288
+ * The evidence is validated against the expectation first, with the same validator every other
289
+ * consumer of retention evidence uses; the first reason it is refused is thrown. A workload is
290
+ * never told about a retention nobody proved.
291
+ */
292
+ export const createObjectStorageRetentionEnvironment = async (evidenceArg, expectedArg) => {
293
+ const errors = await validateObjectStorageRetentionEvidence(evidenceArg, expectedArg);
294
+ if (errors.length > 0)
295
+ throw new Error(errors[0]);
296
+ return {
297
+ S3_RETENTION_MODE: evidenceArg.intent.mode,
298
+ S3_RETENTION_POLICY_ID: evidenceArg.intent.policyId,
299
+ S3_RETENTION_DURATION_SECONDS: String(evidenceArg.intent.retentionDurationSeconds),
300
+ S3_RETENTION_INTENT_SHA256: evidenceArg.intentSha256,
301
+ S3_RETENTION_SENTINEL_KEY: evidenceArg.receipt.sentinelKey,
302
+ S3_RETENTION_CONFIGURED_AT: String(evidenceArg.receipt.configuredAt),
303
+ S3_RETENTION_SENTINEL_CREATED_AT: String(evidenceArg.receipt.sentinel.createdAt),
304
+ S3_RETENTION_SENTINEL_RETAIN_UNTIL: String(evidenceArg.receipt.sentinel.retainUntil),
305
+ S3_RETENTION_SENTINEL_PAYLOAD_SHA256: evidenceArg.receipt.sentinel.payloadSha256,
306
+ S3_RETENTION_SENTINEL_METADATA_SHA256: evidenceArg.receipt.sentinel.metadataSha256,
307
+ S3_RETENTION_SENTINEL_ETAG: evidenceArg.receipt.sentinel.etag,
308
+ };
309
+ };
310
+ const canonicalDecimalPattern = /^[1-9][0-9]*$/;
311
+ const readCanonicalPositiveInteger = (valueArg) => (typeof valueArg === 'string'
312
+ && canonicalDecimalPattern.test(valueArg)
313
+ && Number.isSafeInteger(Number(valueArg))
314
+ ? Number(valueArg)
315
+ : undefined);
316
+ /**
317
+ * Validates a retention environment on its own: exactly its eleven keys, canonical values, an
318
+ * intent digest that matches the stated intent, and sentinel timestamps that agree with the
319
+ * duration. It cannot prove the authority or the bucket the evidence was bound to — the
320
+ * environment does not carry them — so it judges the shape a workload reads, not the proof.
321
+ */
322
+ export const validateObjectStorageRetentionEnvironment = async (environmentArg, pathArg = 'objectstorage retention environment') => {
323
+ if (!isRecord(environmentArg)
324
+ || !hasExactKeys(environmentArg, objectStorageRetentionEnvironmentKeys)
325
+ || objectStorageRetentionEnvironmentKeys.some((keyArg) => (typeof environmentArg[keyArg] !== 'string'))) {
326
+ return [`${pathArg} must contain exactly its string keys`];
327
+ }
328
+ const environment = environmentArg;
329
+ const errors = [];
330
+ const duration = readCanonicalPositiveInteger(environment.S3_RETENTION_DURATION_SECONDS);
331
+ const intent = {
332
+ mode: environment.S3_RETENTION_MODE,
333
+ policyId: environment.S3_RETENTION_POLICY_ID,
334
+ retentionDurationSeconds: duration,
335
+ };
336
+ const intentErrors = validateObjectStorageRetentionIntent(intent, `${pathArg} intent`);
337
+ errors.push(...intentErrors);
338
+ if (!sha256Pattern.test(environment.S3_RETENTION_INTENT_SHA256)
339
+ || intentErrors.length === 0
340
+ && environment.S3_RETENTION_INTENT_SHA256 !== await computeObjectStorageRetentionIntentSha256(intent)) {
341
+ errors.push(`${pathArg} S3_RETENTION_INTENT_SHA256 must be the digest of the stated intent`);
342
+ }
343
+ if (!sentinelKeyPattern.test(environment.S3_RETENTION_SENTINEL_KEY)) {
344
+ errors.push(`${pathArg} S3_RETENTION_SENTINEL_KEY must be canonical`);
345
+ }
346
+ const configuredAt = readCanonicalPositiveInteger(environment.S3_RETENTION_CONFIGURED_AT);
347
+ const createdAt = readCanonicalPositiveInteger(environment.S3_RETENTION_SENTINEL_CREATED_AT);
348
+ const retainUntil = readCanonicalPositiveInteger(environment.S3_RETENTION_SENTINEL_RETAIN_UNTIL);
349
+ if (configuredAt === undefined
350
+ || createdAt === undefined
351
+ || retainUntil === undefined
352
+ || createdAt < configuredAt) {
353
+ errors.push(`${pathArg} timestamps must be canonical positive decimals in order`);
354
+ }
355
+ else if (intentErrors.length === 0) {
356
+ try {
357
+ if (retainUntil !== createObjectStorageRetentionRetainUntil(createdAt, duration)) {
358
+ errors.push(`${pathArg} S3_RETENTION_SENTINEL_RETAIN_UNTIL must equal createdAt plus duration`);
359
+ }
360
+ }
361
+ catch {
362
+ errors.push(`${pathArg} S3_RETENTION_SENTINEL_RETAIN_UNTIL arithmetic must be safe`);
363
+ }
364
+ }
365
+ if (!sha256Pattern.test(environment.S3_RETENTION_SENTINEL_PAYLOAD_SHA256)
366
+ || !sha256Pattern.test(environment.S3_RETENTION_SENTINEL_METADATA_SHA256)
367
+ || !etagPattern.test(environment.S3_RETENTION_SENTINEL_ETAG)) {
368
+ errors.push(`${pathArg} sentinel digests and ETag must be canonical`);
369
+ }
370
+ return errors;
371
+ };
372
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2JqZWN0c3RvcmFnZXJldGVudGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3BsYXRmb3JtL29iamVjdHN0b3JhZ2VyZXRlbnRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDM0UsT0FBTyxFQUFFLHVDQUF1QyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDN0UsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRTVELE1BQU0sQ0FBQyxNQUFNLDRCQUE0QixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDeEQscUJBQXFCLEVBQUUsRUFBRTtJQUN6QiwrQkFBK0IsRUFBRSxHQUFHLEdBQUcsR0FBRyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRTtDQUMxRCxDQUFDLENBQUM7QUFvRUgsTUFBTSxlQUFlLEdBQUcsd0JBQXdCLENBQUM7QUFDakQsTUFBTSxpQkFBaUIsR0FBRyxxQ0FBcUMsQ0FBQztBQUNoRSxNQUFNLGFBQWEsR0FBRyxnQkFBZ0IsQ0FBQztBQUN2QyxNQUFNLFdBQVcsR0FBRyxnQkFBZ0IsQ0FBQztBQUNyQzs7OztHQUlHO0FBQ0gsTUFBTSxrQkFBa0IsR0FBRyw2REFBNkQsQ0FBQztBQUV6RixNQUFNLFFBQVEsR0FBRyxDQUFDLFFBQWlCLEVBQXVDLEVBQUUsQ0FBQyxDQUMzRSxPQUFPLENBQUMsUUFBUSxDQUFDO09BQ2QsT0FBTyxRQUFRLEtBQUssUUFBUTtPQUM1QixDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDO09BQ3hCLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsS0FBSyxNQUFNLENBQUMsU0FBUztXQUNuRCxNQUFNLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUMvQyxDQUFDO0FBRUYsTUFBTSxxQkFBcUIsR0FBRyxDQUFDLFFBQWlCLEVBQXNCLEVBQUUsQ0FBQyxDQUN2RSxNQUFNLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxJQUFLLFFBQW1CLEdBQUcsQ0FBQyxDQUMzRCxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sb0NBQW9DLEdBQUcsQ0FDbEQsU0FBa0IsRUFDbEIsT0FBTyxHQUFHLGdDQUFnQyxFQUNoQyxFQUFFO0lBQ1osSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUM7V0FDbkIsQ0FBQyxZQUFZLENBQUMsU0FBUyxFQUFFLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSwwQkFBMEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNoRixPQUFPLENBQUMsR0FBRyxPQUFPLDRCQUE0QixDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQztJQUM1QixJQUFJLFNBQVMsQ0FBQyxJQUFJLEtBQUssWUFBWTtXQUM5QixPQUFPLFNBQVMsQ0FBQyxRQUFRLEtBQUssUUFBUTtXQUN0QyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDL0MsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sOENBQThDLENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBQ0QsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFNBQVMsQ0FBQyx3QkFBd0IsQ0FBQztXQUN4RCxTQUFTLENBQUMsd0JBQW1DO2NBQzdDLDRCQUE0QixDQUFDLCtCQUErQixFQUFFLENBQUM7UUFDbkUsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sbURBQW1ELENBQUMsQ0FBQztJQUM3RSxDQUFDO0lBQ0QsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sdUNBQXVDLEdBQUcsQ0FDckQsWUFBb0IsRUFDcEIsMkJBQW1DLEVBQzNCLEVBQUU7SUFDVixJQUFJLENBQUMscUJBQXFCLENBQUMsWUFBWSxDQUFDO1dBQ25DLENBQUMscUJBQXFCLENBQUMsMkJBQTJCLENBQUM7V0FDbkQsMkJBQTJCLEdBQUcsNEJBQTRCLENBQUMsK0JBQStCLEVBQUUsQ0FBQztRQUNoRyxNQUFNLElBQUksS0FBSyxDQUFDLDRFQUE0RSxDQUFDLENBQUM7SUFDaEcsQ0FBQztJQUNELE1BQU0sV0FBVyxHQUFHLFlBQVksR0FBRywyQkFBMkIsR0FBRyxJQUFJLENBQUM7SUFDdEUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLElBQUksV0FBVyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ3RFLE1BQU0sSUFBSSxLQUFLLENBQUMsaUVBQWlFLENBQUMsQ0FBQztJQUNyRixDQUFDO0lBQ0QsT0FBTyxXQUFXLENBQUM7QUFDckIsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sNkNBQTZDLEdBQUcsQ0FDM0QsU0FBd0MsRUFDaEMsRUFBRTtJQUNWLE1BQU0sTUFBTSxHQUFHLG9DQUFvQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQy9ELElBQUksTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsRCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUM7UUFDcEIsVUFBVSxFQUFFLGVBQWU7UUFDM0IsU0FBUyxFQUFFO1lBQ1QsSUFBSSxFQUFFLFNBQVMsQ0FBQyxJQUFJO1lBQ3BCLFFBQVEsRUFBRSxTQUFTLENBQUMsUUFBUTtZQUM1Qix3QkFBd0IsRUFBRSxTQUFTLENBQUMsd0JBQXdCO1NBQzdEO0tBQ0YsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0seUNBQXlDLEdBQUcsS0FBSyxFQUM1RCxTQUF3QyxFQUN2QixFQUFFLENBQUMsNEJBQTRCLENBQ2hELDZDQUE2QyxDQUFDLFNBQVMsQ0FBQyxFQUN4RCxDQUFDLFNBQVMsRUFBRSxFQUFFLEdBQUcsTUFBTSxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FDL0MsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLGtDQUFrQyxHQUFHLENBQ2hELE9BQWdCLEVBQ2hCLFFBQWlCLEVBQ1IsRUFBRSxDQUFDLG9DQUFvQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDO09BQ25FLG9DQUFvQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDO09BQzFELE9BQXlDLENBQUMsSUFBSTtZQUMzQyxRQUEwQyxDQUFDLElBQUk7T0FDbEQsT0FBeUMsQ0FBQyxRQUFRO1lBQy9DLFFBQTBDLENBQUMsUUFBUTtPQUN0RCxPQUF5QyxDQUFDLHdCQUF3QjtZQUMvRCxRQUEwQyxDQUFDLHdCQUF3QixDQUFDO0FBRTdFLE1BQU0sMEJBQTBCLEdBQUcsQ0FDakMsT0FBZ0IsRUFDaEIsUUFBaUIsRUFDUixFQUFFLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztPQUMxQixRQUFRLENBQUMsUUFBUSxDQUFDO09BQ2xCLE9BQU8sQ0FBQyxJQUFJLEtBQUssWUFBWTtPQUM3QixRQUFRLENBQUMsSUFBSSxLQUFLLFlBQVk7T0FDOUIsT0FBTyxPQUFPLENBQUMsUUFBUSxLQUFLLFFBQVE7T0FDcEMsT0FBTyxDQUFDLFFBQVEsS0FBSyxRQUFRLENBQUMsUUFBUTtPQUN0QyxxQkFBcUIsQ0FBQyxPQUFPLENBQUMsd0JBQXdCLENBQUM7T0FDdkQsT0FBTyxDQUFDLHdCQUF3QixLQUFLLFFBQVEsQ0FBQyx3QkFBd0IsQ0FBQztBQUU1RSxNQUFNLENBQUMsTUFBTSxzQ0FBc0MsR0FBRyxLQUFLLEVBQ3pELFdBQW9CLEVBQ3BCLFdBQXVELEVBQ3BDLEVBQUU7SUFDckIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUM7V0FDckIsQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFO1lBQzVCLFFBQVE7WUFDUixjQUFjO1lBQ2QsV0FBVztZQUNYLFlBQVk7WUFDWixTQUFTO1lBQ1QsWUFBWTtTQUNiLENBQUMsRUFBRSxDQUFDO1FBQ0wsT0FBTyxDQUFDLDREQUE0RCxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFHLG9DQUFvQyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN4RSxNQUFNLE1BQU0sR0FBRyxXQUFXLENBQUMsTUFBdUMsQ0FBQztJQUNuRSxJQUFJLENBQUMsMEJBQTBCLENBQUMsTUFBTSxFQUFFLFdBQVcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQzVELE1BQU0sQ0FBQyxJQUFJLENBQUMsd0VBQXdFLENBQUMsQ0FBQztJQUN4RixDQUFDO0lBQ0QsSUFBSSxPQUFPLFdBQVcsQ0FBQyxZQUFZLEtBQUssUUFBUTtXQUMzQyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQztXQUM3QyxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUM7ZUFDakIsV0FBVyxDQUFDLFlBQVksS0FBSyxNQUFNLHlDQUF5QyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDNUYsTUFBTSxDQUFDLElBQUksQ0FBQyxxRUFBcUUsQ0FBQyxDQUFDO0lBQ3JGLENBQUM7SUFFRCxNQUFNLFNBQVMsR0FBRyxXQUFXLENBQUMsU0FBUyxDQUFDO0lBQ3hDLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDO1dBQ25CLENBQUMsWUFBWSxDQUFDLFNBQVMsRUFBRTtZQUMxQixXQUFXO1lBQ1gsV0FBVztZQUNYLDBCQUEwQjtZQUMxQixzQkFBc0I7U0FDdkIsQ0FBQztXQUNDLE9BQU8sU0FBUyxDQUFDLFNBQVMsS0FBSyxRQUFRO1dBQ3ZDLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUM7V0FDNUMsU0FBUyxDQUFDLFNBQVMsS0FBSyxXQUFXLENBQUMsU0FBUztXQUM3QyxPQUFPLFNBQVMsQ0FBQyxTQUFTLEtBQUssUUFBUTtXQUN2QyxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDO1dBQzVDLFNBQVMsQ0FBQyxTQUFTLEtBQUssV0FBVyxDQUFDLFNBQVM7V0FDN0MsQ0FBQyxxQkFBcUIsQ0FBQyxTQUFTLENBQUMsd0JBQXdCLENBQUM7V0FDMUQsU0FBUyxDQUFDLHdCQUF3QixLQUFLLFdBQVcsQ0FBQyx3QkFBd0I7V0FDM0UsT0FBTyxTQUFTLENBQUMsb0JBQW9CLEtBQUssUUFBUTtXQUNsRCxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLG9CQUFvQixDQUFDO1dBQ25ELFNBQVMsQ0FBQyxvQkFBb0IsS0FBSyxXQUFXLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztRQUN6RSxNQUFNLENBQUMsSUFBSSxDQUFDLGlGQUFpRixDQUFDLENBQUM7SUFDakcsQ0FBQztJQUVELE1BQU0sVUFBVSxHQUFHLFdBQVcsQ0FBQyxVQUFVLENBQUM7SUFDMUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUM7V0FDcEIsQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFO1lBQzNCLFdBQVc7WUFDWCxTQUFTO1lBQ1QsT0FBTztZQUNQLGtCQUFrQjtZQUNsQiw0QkFBNEI7U0FDN0IsQ0FBQztXQUNDLFVBQVUsQ0FBQyxTQUFTLEtBQUssSUFBSTtXQUM3QixDQUFDLFVBQVUsQ0FBQyxPQUFPLEtBQUssWUFBWSxJQUFJLFVBQVUsQ0FBQyxPQUFPLEtBQUssV0FBVyxDQUFDO1dBQzNFLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDO1dBQ2hDLFVBQVUsQ0FBQyxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUM7V0FDN0IsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxZQUFZO1dBQ3BDLFVBQVUsQ0FBQyxnQkFBZ0IsS0FBSyxJQUFJO1dBQ3BDLFVBQVUsQ0FBQywwQkFBMEIsS0FBSyxLQUFLLEVBQUUsQ0FBQztRQUNyRCxNQUFNLENBQUMsSUFBSSxDQUFDLDJEQUEyRCxDQUFDLENBQUM7SUFDM0UsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLFdBQVcsQ0FBQyxPQUFPLENBQUM7SUFDcEMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7V0FDakIsQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFO1lBQ3hCLE1BQU07WUFDTixVQUFVO1lBQ1YsMEJBQTBCO1lBQzFCLFlBQVk7WUFDWixjQUFjO1lBQ2QsYUFBYTtZQUNiLFVBQVU7U0FDWCxDQUFDLEVBQUUsQ0FBQztRQUNMLE1BQU0sQ0FBQyxJQUFJLENBQUMsMkRBQTJELENBQUMsQ0FBQztRQUN6RSxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBQ0QsSUFBSSxDQUFDLDBCQUEwQixDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQ2pELE1BQU0sQ0FBQyxJQUFJLENBQUMsdUVBQXVFLENBQUMsQ0FBQztJQUN2RixDQUFDO0lBQ0QsSUFBSSx1Q0FBdUMsQ0FDekMsT0FBTyxDQUFDLFVBQVUsRUFDbEIsd0NBQXdDLENBQ3pDLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxPQUFPLENBQUMsVUFBVSxLQUFLLFdBQVcsQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUM5RCxNQUFNLENBQUMsSUFBSSxDQUFDLDJEQUEyRCxDQUFDLENBQUM7SUFDM0UsQ0FBQztJQUNELElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDO1dBQzNDLE9BQU8sT0FBTyxDQUFDLFdBQVcsS0FBSyxRQUFRO1dBQ3ZDLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1FBQ25ELE1BQU0sQ0FBQyxJQUFJLENBQUMsMEVBQTBFLENBQUMsQ0FBQztJQUMxRixDQUFDO0lBRUQsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztJQUNsQyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQztXQUNsQixDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUU7WUFDekIsU0FBUztZQUNULE1BQU07WUFDTixVQUFVO1lBQ1YsMEJBQTBCO1lBQzFCLFdBQVc7WUFDWCxhQUFhO1lBQ2IsZUFBZTtZQUNmLGdCQUFnQjtZQUNoQixNQUFNO1NBQ1AsQ0FBQyxFQUFFLENBQUM7UUFDTCxNQUFNLENBQUMsSUFBSSxDQUFDLHFFQUFxRSxDQUFDLENBQUM7UUFDbkYsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUNELElBQUksUUFBUSxDQUFDLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLEVBQUUsQ0FBQztRQUM1RSxNQUFNLENBQUMsSUFBSSxDQUFDLHdFQUF3RSxDQUFDLENBQUM7SUFDeEYsQ0FBQztJQUNELElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDO1dBQ3pDLENBQUMscUJBQXFCLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQztXQUM1QyxDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUM7V0FDM0MsUUFBUSxDQUFDLFNBQW9CLEdBQUksT0FBTyxDQUFDLFlBQXVCLEVBQUUsQ0FBQztRQUN2RSxNQUFNLENBQUMsSUFBSSxDQUFDLGlFQUFpRSxDQUFDLENBQUM7SUFDakYsQ0FBQztTQUFNLENBQUM7UUFDTixJQUFJLENBQUM7WUFDSCxJQUFJLFFBQVEsQ0FBQyxXQUFXLEtBQUssdUNBQXVDLENBQ2xFLFFBQVEsQ0FBQyxTQUFTLEVBQ2xCLE1BQU0sQ0FBQyx3QkFBd0IsQ0FDaEMsRUFBRSxDQUFDO2dCQUNGLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0VBQXdFLENBQUMsQ0FBQztZQUN4RixDQUFDO1FBQ0gsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE1BQU0sQ0FBQyxJQUFJLENBQUMsNkRBQTZELENBQUMsQ0FBQztRQUM3RSxDQUFDO0lBQ0gsQ0FBQztJQUNELElBQUksT0FBTyxRQUFRLENBQUMsYUFBYSxLQUFLLFFBQVEsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQztXQUN4RixPQUFPLFFBQVEsQ0FBQyxjQUFjLEtBQUssUUFBUSxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDO1dBQzNGLE9BQU8sUUFBUSxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQzNFLE1BQU0sQ0FBQyxJQUFJLENBQUMscUVBQXFFLENBQUMsQ0FBQztJQUNyRixDQUFDO0lBQ0QsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUM7V0FDN0MsQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDO1dBQ3pDLFdBQVcsQ0FBQyxVQUFxQixHQUFJLFFBQVEsQ0FBQyxTQUFvQixFQUFFLENBQUM7UUFDekUsTUFBTSxDQUFDLElBQUksQ0FBQyw4RUFBOEUsQ0FBQyxDQUFDO0lBQzlGLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxxQ0FBcUMsR0FBRyxLQUFLLEVBQ3hELFVBQW1CLEVBQ25CLFdBQXVELEVBQ3BDLEVBQUU7SUFDckIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUM7V0FDcEIsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUM7V0FDcEMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUUsVUFBVSxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN4RixPQUFPLENBQUMsMkRBQTJELENBQUMsQ0FBQztJQUN2RSxDQUFDO0lBQ0QsTUFBTSxNQUFNLEdBQUcsb0NBQW9DLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3ZFLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLFdBQVcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQ3ZFLE1BQU0sQ0FBQyxJQUFJLENBQUMsK0VBQStFLENBQUMsQ0FBQztJQUMvRixDQUFDO0lBQ0QsSUFBSSxVQUFVLENBQUMsUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3RDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLHNDQUFzQyxDQUN6RCxVQUFVLENBQUMsUUFBUSxFQUNuQixXQUFXLENBQ1osQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUMsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLDZDQUE2QyxHQUFHLEtBQUssRUFDaEUsVUFBbUIsRUFDbkIsV0FBdUQsRUFDcEMsRUFBRTtJQUNyQixJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7UUFDMUIsT0FBTyxDQUFDLDREQUE0RCxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUNELElBQUksdUNBQXVDLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDO1dBQ3pFLHVDQUF1QyxDQUFDLFVBQVUsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM1RixPQUFPLENBQUMsc0VBQXNFLENBQUMsQ0FBQztJQUNsRixDQUFDO0lBQ0QsSUFBSSxVQUFVLENBQUMsVUFBVSxLQUFLLGVBQWU7V0FDeEMsVUFBVSxDQUFDLEVBQUUsS0FBSyxXQUFXLENBQUMsU0FBUztXQUN2QyxVQUFVLENBQUMsU0FBUyxLQUFLLFdBQVcsQ0FBQyxTQUFTO1dBQzlDLFVBQVUsQ0FBQyx1QkFBdUIsS0FBSyxXQUFXLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDbkUsT0FBTyxDQUFDLGdGQUFnRixDQUFDLENBQUM7SUFDNUYsQ0FBQztJQUNELElBQUksVUFBVSxDQUFDLHNCQUFzQixLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3BELE9BQU8sQ0FBQyx3RUFBd0UsQ0FBQyxDQUFDO0lBQ3BGLENBQUM7SUFDRCxPQUFPLHFDQUFxQyxDQUFDLFVBQVUsQ0FBQyxzQkFBc0IsRUFBRSxXQUFXLENBQUMsQ0FBQztBQUMvRixDQUFDLENBQUM7QUFFRjs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNILE1BQU0sQ0FBQyxNQUFNLHFDQUFxQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDakUsbUJBQW1CO0lBQ25CLHdCQUF3QjtJQUN4QiwrQkFBK0I7SUFDL0IsNEJBQTRCO0lBQzVCLDJCQUEyQjtJQUMzQiw0QkFBNEI7SUFDNUIsa0NBQWtDO0lBQ2xDLG9DQUFvQztJQUNwQyxzQ0FBc0M7SUFDdEMsdUNBQXVDO0lBQ3ZDLDRCQUE0QjtDQUNwQixDQUFDLENBQUM7QUFTWjs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsTUFBTSx1Q0FBdUMsR0FBRyxLQUFLLEVBQzFELFdBQTRDLEVBQzVDLFdBQXVELEVBQ1YsRUFBRTtJQUMvQyxNQUFNLE1BQU0sR0FBRyxNQUFNLHNDQUFzQyxDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUN0RixJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQztRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEQsT0FBTztRQUNMLGlCQUFpQixFQUFFLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSTtRQUMxQyxzQkFBc0IsRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLFFBQVE7UUFDbkQsNkJBQTZCLEVBQUUsTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsd0JBQXdCLENBQUM7UUFDbEYsMEJBQTBCLEVBQUUsV0FBVyxDQUFDLFlBQVk7UUFDcEQseUJBQXlCLEVBQUUsV0FBVyxDQUFDLE9BQU8sQ0FBQyxXQUFXO1FBQzFELDBCQUEwQixFQUFFLE1BQU0sQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQztRQUNwRSxnQ0FBZ0MsRUFBRSxNQUFNLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDO1FBQ2hGLGtDQUFrQyxFQUFFLE1BQU0sQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUM7UUFDcEYsb0NBQW9DLEVBQUUsV0FBVyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsYUFBYTtRQUNoRixxQ0FBcUMsRUFBRSxXQUFXLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxjQUFjO1FBQ2xGLDBCQUEwQixFQUFFLFdBQVcsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUk7S0FDOUQsQ0FBQztBQUNKLENBQUMsQ0FBQztBQUVGLE1BQU0sdUJBQXVCLEdBQUcsZUFBZSxDQUFDO0FBRWhELE1BQU0sNEJBQTRCLEdBQUcsQ0FBQyxRQUFpQixFQUFzQixFQUFFLENBQUMsQ0FDOUUsT0FBTyxRQUFRLEtBQUssUUFBUTtPQUN6Qix1QkFBdUIsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO09BQ3RDLE1BQU0sQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3ZDLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxTQUFTLENBQ2QsQ0FBQztBQUVGOzs7OztHQUtHO0FBQ0gsTUFBTSxDQUFDLE1BQU0seUNBQXlDLEdBQUcsS0FBSyxFQUM1RCxjQUF1QixFQUN2QixPQUFPLEdBQUcscUNBQXFDLEVBQzVCLEVBQUU7SUFDckIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUM7V0FDeEIsQ0FBQyxZQUFZLENBQUMsY0FBYyxFQUFFLHFDQUFxQyxDQUFDO1dBQ3BFLHFDQUFxQyxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FDeEQsT0FBTyxjQUFjLENBQUMsTUFBTSxDQUFDLEtBQUssUUFBUSxDQUMzQyxDQUFDLEVBQUUsQ0FBQztRQUNMLE9BQU8sQ0FBQyxHQUFHLE9BQU8sdUNBQXVDLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBQ0QsTUFBTSxXQUFXLEdBQUcsY0FBb0QsQ0FBQztJQUN6RSxNQUFNLE1BQU0sR0FBYSxFQUFFLENBQUM7SUFDNUIsTUFBTSxRQUFRLEdBQUcsNEJBQTRCLENBQUMsV0FBVyxDQUFDLDZCQUE2QixDQUFDLENBQUM7SUFDekYsTUFBTSxNQUFNLEdBQUc7UUFDYixJQUFJLEVBQUUsV0FBVyxDQUFDLGlCQUFpQjtRQUNuQyxRQUFRLEVBQUUsV0FBVyxDQUFDLHNCQUFzQjtRQUM1Qyx3QkFBd0IsRUFBRSxRQUFRO0tBQ25DLENBQUM7SUFDRixNQUFNLFlBQVksR0FBRyxvQ0FBb0MsQ0FBQyxNQUFNLEVBQUUsR0FBRyxPQUFPLFNBQVMsQ0FBQyxDQUFDO0lBQ3ZGLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxZQUFZLENBQUMsQ0FBQztJQUM3QixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsMEJBQTBCLENBQUM7V0FDMUQsWUFBWSxDQUFDLE1BQU0sS0FBSyxDQUFDO2VBQ3ZCLFdBQVcsQ0FBQywwQkFBMEIsS0FBSyxNQUFNLHlDQUF5QyxDQUMzRixNQUF1QyxDQUN4QyxFQUFFLENBQUM7UUFDTixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxxRUFBcUUsQ0FBQyxDQUFDO0lBQy9GLENBQUM7SUFDRCxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyx5QkFBeUIsQ0FBQyxFQUFFLENBQUM7UUFDcEUsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sOENBQThDLENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBQ0QsTUFBTSxZQUFZLEdBQUcsNEJBQTRCLENBQUMsV0FBVyxDQUFDLDBCQUEwQixDQUFDLENBQUM7SUFDMUYsTUFBTSxTQUFTLEdBQUcsNEJBQTRCLENBQUMsV0FBVyxDQUFDLGdDQUFnQyxDQUFDLENBQUM7SUFDN0YsTUFBTSxXQUFXLEdBQUcsNEJBQTRCLENBQUMsV0FBVyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7SUFDakcsSUFBSSxZQUFZLEtBQUssU0FBUztXQUN6QixTQUFTLEtBQUssU0FBUztXQUN2QixXQUFXLEtBQUssU0FBUztXQUN6QixTQUFTLEdBQUcsWUFBWSxFQUFFLENBQUM7UUFDOUIsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sMERBQTBELENBQUMsQ0FBQztJQUNwRixDQUFDO1NBQU0sSUFBSSxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3JDLElBQUksQ0FBQztZQUNILElBQUksV0FBVyxLQUFLLHVDQUF1QyxDQUFDLFNBQVMsRUFBRSxRQUFrQixDQUFDLEVBQUUsQ0FBQztnQkFDM0YsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sd0VBQXdFLENBQUMsQ0FBQztZQUNsRyxDQUFDO1FBQ0gsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxPQUFPLDZEQUE2RCxDQUFDLENBQUM7UUFDdkYsQ0FBQztJQUNILENBQUM7SUFDRCxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsb0NBQW9DLENBQUM7V0FDcEUsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxxQ0FBcUMsQ0FBQztXQUN0RSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLDBCQUEwQixDQUFDLEVBQUUsQ0FBQztRQUMvRCxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyw4Q0FBOEMsQ0FBQyxDQUFDO0lBQ3hFLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDLENBQUMifQ==
@@ -4,6 +4,7 @@ import type { ICluster } from '../data/cluster.js';
4
4
  import type { IClusterNode, INodeAction, INodeMetricsSample, TNodeActionName } from '../data/clusternode.js';
5
5
  import type { IDeployment } from '../data/deployment.js';
6
6
  import type { IIdentity } from '../data/user.js';
7
+ import type { IPlatformObjectStorageEndpoint } from '../platform/objectstorage.js';
7
8
  import type { INodeCredentialMetadata, INodeCredentialMutationPreconditions, INodeCredentialMutationResult, TNodeCredentialPurpose } from '../data/nodecredential.js';
8
9
  import type { INodeRuntimeRetirement } from '../data/noderetirement.js';
9
10
  import type { INodeRuntimeBindingRead, INodeRuntimeBindingRequest } from '../data/noderuntimebinding.js';
@@ -217,6 +218,34 @@ export interface IReq_Any_Cloudly_SetClusterNodeCorestoreEndpoint extends plugin
217
218
  node: IClusterNode;
218
219
  };
219
220
  }
221
+ /**
222
+ * An administrator states where a workload on one node reaches the node's Corestore object
223
+ * storage, and the region it signs for: `IClusterNode.data.corestoreObjectStorage`.
224
+ *
225
+ * A request of its own, separate from `setClusterNodeCorestoreEndpoint`, because the two are
226
+ * separate facts with separate readers — the relay dials the control endpoint, a workload dials
227
+ * this one — and setting one never touches the other. A caller that states only the control
228
+ * endpoint leaves this one as it stands.
229
+ *
230
+ * Cloudly validates it with `validatePlatformObjectStorageEndpoint` before it writes and takes the
231
+ * node's own real-write fence inside the writing transaction, as for the control endpoint.
232
+ * `objectStorage: null` clears it, which is the same fact as never having set one: no
233
+ * object-storage environment can be composed for a binding on this node. The endpoint says where,
234
+ * never with what — no credential travels in this request or in the node document.
235
+ */
236
+ export interface IReq_Any_Cloudly_SetClusterNodeCorestoreObjectStorageEndpoint extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_SetClusterNodeCorestoreObjectStorageEndpoint> {
237
+ method: 'setClusterNodeCorestoreObjectStorageEndpoint';
238
+ request: {
239
+ identity: IIdentity;
240
+ nodeId: string;
241
+ /** The node's object-storage endpoint and region, or `null` to state that it has none. */
242
+ objectStorage: IPlatformObjectStorageEndpoint | null;
243
+ };
244
+ response: {
245
+ /** The node as it now stands, so a caller needs no second read to see what it set. */
246
+ node: IClusterNode;
247
+ };
248
+ }
220
249
  export interface IReq_Any_Cloudly_CreateNodeAction extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_CreateNodeAction> {
221
250
  method: 'createNodeAction';
222
251
  request: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serve.zone/interfaces",
3
- "version": "32.24.0",
3
+ "version": "32.25.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
@@ -3486,6 +3486,78 @@ Coreflow, all exported from `data` and `platform`:
3486
3486
  While a binding of a service reports `legacy-adoption-pending`, the service's runtime status waits as
3487
3487
  `legacy-adoption-pending` instead of `bindings-pending`.
3488
3488
 
3489
+ ### Object-Storage Binding Environment
3490
+
3491
+ An object-storage binding gives its workload two things. The access key and the secret reach it
3492
+ only as Secrets: the six aliases `createCorestoreCredentialSecretValues()` expands
3493
+ (`S3_ACCESS_KEY`, `S3_ACCESS_KEY_ID`, `S3_SECRET_KEY`, `S3_SECRET_ACCESS_KEY`,
3494
+ `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`), published through the sealed Secret set. Where the
3495
+ bucket is, and which retention it carries, is non-secret and reaches it through the runtime
3496
+ configuration: Cloudly composes it into `IRuntimeConfig.environment`, the complete public
3497
+ environment, so no further runtime spec or assignment field carries it. The names are the ones
3498
+ Corestore and the cluster relay handed workloads before, so an application that read them keeps
3499
+ working unchanged.
3500
+
3501
+ | Name | Value |
3502
+ | --- | --- |
3503
+ | `S3_ENDPOINT`, `AWS_ENDPOINT_URL` | The endpoint origin, for example `http://192.0.2.15:9000`. |
3504
+ | `S3_ENDPOINT_HOST` | The origin's host; an IPv6 literal keeps its brackets. |
3505
+ | `S3_PORT` | The origin's port, `80` or `443` when the origin states none. |
3506
+ | `S3_USE_SSL` | `true` for `https:`, `false` for `http:`. |
3507
+ | `S3_REGION`, `AWS_REGION` | The signing region. |
3508
+ | `S3_BUCKET` | `IPlatformBinding.objectstorageBucketName`. |
3509
+ | `AWS_S3_FORCE_PATH_STYLE` | Always `true`: a node-local origin has no wildcard DNS. |
3510
+ | `S3_RETENTION_MODE` | `intent.mode`, always `compliance`. |
3511
+ | `S3_RETENTION_POLICY_ID` | `intent.policyId`. |
3512
+ | `S3_RETENTION_DURATION_SECONDS` | `intent.retentionDurationSeconds`. |
3513
+ | `S3_RETENTION_INTENT_SHA256` | `intentSha256`. |
3514
+ | `S3_RETENTION_SENTINEL_KEY` | `receipt.sentinelKey`. |
3515
+ | `S3_RETENTION_CONFIGURED_AT` | `receipt.configuredAt`, Unix milliseconds. |
3516
+ | `S3_RETENTION_SENTINEL_CREATED_AT` | `receipt.sentinel.createdAt`, Unix milliseconds. |
3517
+ | `S3_RETENTION_SENTINEL_RETAIN_UNTIL` | `receipt.sentinel.retainUntil`, Unix milliseconds. |
3518
+ | `S3_RETENTION_SENTINEL_PAYLOAD_SHA256` | `receipt.sentinel.payloadSha256`. |
3519
+ | `S3_RETENTION_SENTINEL_METADATA_SHA256` | `receipt.sentinel.metadataSha256`. |
3520
+ | `S3_RETENTION_SENTINEL_ETAG` | `receipt.sentinel.etag`. |
3521
+
3522
+ Every number is a canonical decimal. `objectStorageEndpointEnvironmentKeys`,
3523
+ `objectStorageRetentionEnvironmentKeys` and `objectStorageBindingEnvironmentKeys` publish the
3524
+ lists in this order, with the matching `T…EnvironmentKey` and `T…Environment` types.
3525
+
3526
+ **Where the endpoint comes from.** Corestore is node-local, so the endpoint is a fact about the
3527
+ node that holds the bucket: `IClusterNode.data.corestoreObjectStorage` is an optional
3528
+ `IPlatformObjectStorageEndpoint { endpoint, region }`, checked by
3529
+ `validatePlatformObjectStorageEndpoint()` (a canonical `http:` or `https:` origin and a lowercase
3530
+ region). It sits beside `corestore`, not inside it: the relay dials the control endpoint and a
3531
+ workload dials this one, and `IClusterNodeCorestore` keeps its exact schema, so a relay that
3532
+ validates it goes on accepting every node document. An administrator sets it with
3533
+ `setClusterNodeCorestoreObjectStorageEndpoint { identity; nodeId; objectStorage }`, answered by
3534
+ Cloudly with the node as it now stands; `objectStorage: null` clears it. The request is separate
3535
+ from `setClusterNodeCorestoreEndpoint`, so setting the control endpoint never touches it. A node
3536
+ without it cannot give a workload an object-storage environment; nothing derives a port, a scheme
3537
+ or a region.
3538
+
3539
+ **Composing.** `createObjectStorageBindingEnvironment(binding, endpoint)` returns the nine endpoint
3540
+ names for a binding that declares no retention, and all twenty when it declares retention with
3541
+ evidence. It refuses by name, and never guesses, when the binding is not `objectstorage`, carries
3542
+ no canonical bucket, or declares retention without `evidence`: a bucket whose immutability is not
3543
+ proven yet must not be handed to its workload as if it were ordinary storage, so the workload
3544
+ waits for the evidence. The evidence is validated with `validateObjectStorageRetentionEvidence()`
3545
+ against the binding's own service, binding id, bucket and intent, and the reconciliation
3546
+ generation and request digest it states. The split helpers are
3547
+ `createObjectStorageEndpointEnvironment(endpoint, bucketName)` and
3548
+ `createObjectStorageRetentionEnvironment(evidence, expectation)`.
3549
+ `mergeObjectStorageBindingEnvironment(environment, bindingEnvironment)` adds one binding's names
3550
+ to a workload environment and refuses, naming every key, a name that is already set — by the
3551
+ service itself or by a second object-storage binding — instead of letting one value replace
3552
+ another.
3553
+
3554
+ **Validating.** `validateObjectStorageBindingEnvironment()` accepts exactly the endpoint names and
3555
+ all or none of the retention names, each value the one its endpoint and evidence derive, and
3556
+ refuses any other name — so a credential alias in the public environment is refused by name.
3557
+ `validateObjectStorageEndpointEnvironment()` and `validateObjectStorageRetentionEnvironment()`
3558
+ judge each half on its own. The environment does not carry the evidence's authority, so
3559
+ validating it checks what a workload reads, not the proof behind it.
3560
+
3489
3561
  ### Launcher Environment Delivery
3490
3562
 
3491
3563
  Launcher environment delivery uses stable `szsv-<base32-sha256>` Docker
@@ -3527,6 +3599,8 @@ Available platform modules:
3527
3599
  - `platform.objectstorageretention` for value-free immutable-retention intent,
3528
3600
  capability and sentinel evidence, authority binding, digest helpers, and
3529
3601
  strict validators.
3602
+ - `platform.objectstorageenvironment` for the non-secret workload environment of an
3603
+ object-storage binding; see Object-Storage Binding Environment.
3530
3604
  - `platform.storagemigration` for fenced object-storage migration intent, status, consumer acknowledgements, canonical digests, and strict normalizers.
3531
3605
  - `platform.types` provider and binding metadata is value-free. Provider-specific
3532
3606
  operational config stays adapter-internal, while public DTOs expose typed
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/interfaces',
6
- version: '32.24.0',
6
+ version: '32.25.0',
7
7
  description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
8
8
  }
@@ -1,6 +1,7 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  import { isSha256Digest, type TSha256Digest, type TImmutableContainerPlatform } from './immutableimage.js';
3
3
  import type { ISparkNodeReportRecord } from './sparknodereport.js';
4
+ import type { IPlatformObjectStorageEndpoint } from '../platform/objectstorage.js';
4
5
  import {
5
6
  fleetCutoverContract,
6
7
  snapshotFleetCutoverPreparedVolumeHandoffAggregate,
@@ -1773,6 +1774,21 @@ export interface IClusterNode {
1773
1774
  * while Docker Swarm resolved it is exactly what stops resolving.
1774
1775
  */
1775
1776
  corestore?: IClusterNodeCorestore;
1777
+
1778
+ /**
1779
+ * Where a workload on this node reaches the node's Corestore object storage, and the region
1780
+ * it signs for.
1781
+ *
1782
+ * Cloudly owns it, sets it with `setClusterNodeCorestoreObjectStorageEndpoint`, and composes
1783
+ * it into the environment of every object-storage binding placed on this node with
1784
+ * `createObjectStorageBindingEnvironment()`. It is a sibling of `corestore`, not a member:
1785
+ * the control API and the S3 API listen on different ports and have different readers — the
1786
+ * relay dials `corestore`, a workload dials this — and `corestore` keeps its exact schema.
1787
+ * Absent means no object-storage environment can be composed for this node, and a binding's
1788
+ * workload waits rather than being handed a guessed port, scheme or region. Value-free like
1789
+ * `corestore`: it says where, never with what.
1790
+ */
1791
+ corestoreObjectStorage?: IPlatformObjectStorageEndpoint;
1776
1792
  };
1777
1793
  }
1778
1794
 
@@ -1789,7 +1805,7 @@ export interface IClusterNode {
1789
1805
  export interface IClusterNodeCorestore {
1790
1806
  /**
1791
1807
  * The canonical origin of the control API, for example
1792
- * `http://10.20.0.15:3000`.
1808
+ * `http://192.0.2.15:3000`.
1793
1809
  *
1794
1810
  * `http:` is admitted because Corestore terminates no TLS today — it binds a
1795
1811
  * plain control port and advertises no transport-encryption guarantee — and
@@ -5,6 +5,7 @@ import * as email from './email.js';
5
5
  import * as letter from './letter.js';
6
6
  import * as logging from './logging.js';
7
7
  import * as objectstorage from './objectstorage.js';
8
+ import * as objectstorageenvironment from './objectstorageenvironment.js';
8
9
  import * as objectstorageretention from './objectstorageretention.js';
9
10
  import * as pushnotification from './pushnotification.js';
10
11
  import * as sip from './sip.js';
@@ -21,6 +22,7 @@ export {
21
22
  letter,
22
23
  logging,
23
24
  objectstorage,
25
+ objectstorageenvironment,
24
26
  objectstorageretention,
25
27
  pushnotification,
26
28
  sip,
@@ -32,6 +34,7 @@ export {
32
34
 
33
35
  export * from './storage.js';
34
36
  export * from './objectstorage.js';
37
+ export * from './objectstorageenvironment.js';
35
38
  export * from './objectstorageretention.js';
36
39
  export * from './storagemigration.js';
37
40
  export * from './types.js';