@serve.zone/interfaces 32.0.2 → 32.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +37 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/index.d.ts +1 -0
- package/dist_ts/data/index.js +2 -1
- package/dist_ts/data/noderetirement.d.ts +39 -0
- package/dist_ts/data/noderetirement.js +31 -0
- package/dist_ts/data/serviceruntime.d.ts +10 -2
- package/dist_ts/data/serviceruntime.js +4 -3
- package/dist_ts/platform/storage.d.ts +29 -2
- package/dist_ts/platform/storage.golden.d.ts +31 -0
- package/dist_ts/platform/storage.golden.js +84 -0
- package/dist_ts/platform/storage.js +37 -1
- package/dist_ts/platform/storagemigration.js +11 -287
- package/dist_ts/private/storagecontract.d.ts +40 -0
- package/dist_ts/private/storagecontract.js +399 -0
- package/dist_ts/requests/node.d.ts +25 -0
- package/package.json +1 -1
- package/readme.md +40 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/index.ts +1 -0
- package/ts/data/noderetirement.ts +63 -0
- package/ts/data/serviceruntime.ts +12 -3
- package/ts/platform/storage.golden.ts +97 -0
- package/ts/platform/storage.ts +59 -2
- package/ts/platform/storagemigration.ts +31 -440
- package/ts/private/storagecontract.ts +623 -0
- package/ts/requests/node.ts +29 -0
package/changelog.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-09-18 - 32.2.0
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Add `platform.createStorageRequestSha256(value)` and `platform.canonicalizeStorageRequest(value)`,
|
|
8
|
+
the contract's own statement of `IResolvedStorageBindingBase.requestDigest`: the request alone,
|
|
9
|
+
normalized to its contract shape, written as strict canonical JSON and hashed to bare lowercase
|
|
10
|
+
hex. A control plane issues that value on a binding and its consumer re-derives it, so both now
|
|
11
|
+
call one function instead of each deriving a value the other cannot reproduce — a prefix or a
|
|
12
|
+
wrapper object around the request is a different value for the same binding. Anything that is not
|
|
13
|
+
a storage request is refused with the new `platform.StorageContractError` rather than hashed.
|
|
14
|
+
`platform.storageRequestCanonicalDigestGoldenVectors` writes the digest down for a filesystem
|
|
15
|
+
request and for both object-storage deliveries.
|
|
16
|
+
- The storage request normalizer is now one implementation for both kinds, shared by
|
|
17
|
+
`platform.storage` and `platform.storagemigration`, so
|
|
18
|
+
`createObjectStorageMigrationTargetRequestSha256` and `createStorageRequestSha256` cannot drift.
|
|
19
|
+
Migration contract errors keep their own class and messages.
|
|
20
|
+
|
|
21
|
+
## 2026-09-18 - 32.1.0
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
- Add `data.INodeRuntimeRetirement { id, clusterId, state: 'retiring' | 'retired', actorId, since }`
|
|
26
|
+
with `snapshotNodeRuntimeRetirement`, the record the producer chain reads to take a node out of
|
|
27
|
+
its cluster's runtime. The producers read its presence, not its state: a node that has a
|
|
28
|
+
retirement row is no longer an egress member and desires no slots.
|
|
29
|
+
- Add `requests.node.retireClusterNode { identity, nodeId, expectedGeneration }` → `{ retirement }`,
|
|
30
|
+
the admin write that starts a node's retirement and so makes it deletable. It fences on the
|
|
31
|
+
cluster runtime generation read with `getClusterRuntime`, and refuses with one of
|
|
32
|
+
`data.nodeRuntimeRetirementRefusals`: `node-missing`, `cluster-runtime-not-pallet`,
|
|
33
|
+
`node-already-retired` or `conflict`.
|
|
34
|
+
- Add `ports-too-many` and `node-authority-unsupported` to `data.TServiceRuntimeRefusal`. The first
|
|
35
|
+
names a service declaring more target ports than `runtimeConfigContract.maximumTargetPorts`
|
|
36
|
+
carries, which until now had no name and left Cloudly throwing an unattributable contract
|
|
37
|
+
assertion; the second names a node whose session resolved fewer workload authorities than the spec
|
|
38
|
+
needs, which the admit step refuses instead of parking the work on the node.
|
|
39
|
+
|
|
3
40
|
## 2026-09-18 - 32.0.2
|
|
4
41
|
|
|
5
42
|
### Fixes
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@serve.zone/interfaces',
|
|
6
|
-
version: '32.0
|
|
6
|
+
version: '32.2.0',
|
|
7
7
|
description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLHVGQUF1RjtDQUNyRyxDQUFBIn0=
|
package/dist_ts/data/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export * from './isolatedrestore.golden.js';
|
|
|
25
25
|
export * from './mail.js';
|
|
26
26
|
export * from './nodecredential.js';
|
|
27
27
|
export * from './nodeenrollment.js';
|
|
28
|
+
export * from './noderetirement.js';
|
|
28
29
|
export * from './networkaddressplan.js';
|
|
29
30
|
export * from './networkauthority.js';
|
|
30
31
|
export * from './networkcredential.js';
|
package/dist_ts/data/index.js
CHANGED
|
@@ -25,6 +25,7 @@ export * from './isolatedrestore.golden.js';
|
|
|
25
25
|
export * from './mail.js';
|
|
26
26
|
export * from './nodecredential.js';
|
|
27
27
|
export * from './nodeenrollment.js';
|
|
28
|
+
export * from './noderetirement.js';
|
|
28
29
|
export * from './networkaddressplan.js';
|
|
29
30
|
export * from './networkauthority.js';
|
|
30
31
|
export * from './networkcredential.js';
|
|
@@ -57,4 +58,4 @@ export * from './traffic.js';
|
|
|
57
58
|
export * from './user.js';
|
|
58
59
|
export * from './version.js';
|
|
59
60
|
export * from './webpush.js';
|
|
60
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
61
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLGlCQUFpQixDQUFDO0FBQ2hDLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxVQUFVLENBQUM7QUFDekIsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxZQUFZLENBQUM7QUFDM0IsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLGdCQUFnQixDQUFDO0FBQy9CLGNBQWMsWUFBWSxDQUFDO0FBQzNCLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLDZCQUE2QixDQUFDO0FBQzVDLGNBQWMsV0FBVyxDQUFDO0FBQzFCLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsd0JBQXdCLENBQUM7QUFFdkMsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyw2QkFBNkIsQ0FBQztBQUM1QyxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGdCQUFnQixDQUFDO0FBQy9CLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsV0FBVyxDQUFDO0FBQzFCLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsY0FBYyxDQUFDIn0=
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
declare const nodeRuntimeRetirementStates: readonly ["retiring", "retired"];
|
|
2
|
+
/**
|
|
3
|
+
* How far a node's retirement has come: `retiring` while the producer still stops and removes the
|
|
4
|
+
* node's slots, the compiler quarantines its handoff and both node credentials are revoked;
|
|
5
|
+
* `retired` once all of that has settled and nothing but the node document is left to delete.
|
|
6
|
+
*/
|
|
7
|
+
export type TNodeRuntimeRetirementState = typeof nodeRuntimeRetirementStates[number];
|
|
8
|
+
/**
|
|
9
|
+
* That one node leaves its cluster's runtime, stored beside the node document rather than inside
|
|
10
|
+
* it, because a node update merges caller data and no caller may retire a node with it.
|
|
11
|
+
*
|
|
12
|
+
* The producers read the row's presence rather than its state: a node that has one is no longer an
|
|
13
|
+
* egress member and desires no slots. The row is therefore written before anything is taken away,
|
|
14
|
+
* and it stays for as long as the node document does.
|
|
15
|
+
*/
|
|
16
|
+
export interface INodeRuntimeRetirement {
|
|
17
|
+
/** The node id. */
|
|
18
|
+
id: string;
|
|
19
|
+
/** The cluster the node is retiring from, copied by Cloudly; never caller-chosen. */
|
|
20
|
+
clusterId: string;
|
|
21
|
+
state: TNodeRuntimeRetirementState;
|
|
22
|
+
/** The administrator who asked for the retirement. */
|
|
23
|
+
actorId: string;
|
|
24
|
+
/** Unix milliseconds on Cloudly's clock, when the row entered its current state. */
|
|
25
|
+
since: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Every reason Cloudly answers instead of retiring a node. Each travels as a `TypedResponseError`,
|
|
29
|
+
* and none of them takes anything away: a refused retirement leaves the node exactly as it was.
|
|
30
|
+
*/
|
|
31
|
+
export declare const nodeRuntimeRetirementRefusals: readonly ["node-missing", "cluster-runtime-not-pallet", "node-already-retired", "conflict"];
|
|
32
|
+
/** One of the reasons Cloudly answers instead of a retirement row. */
|
|
33
|
+
export type TNodeRuntimeRetirementRefusal = typeof nodeRuntimeRetirementRefusals[number];
|
|
34
|
+
/**
|
|
35
|
+
* Structural snapshot for exact persistence; whether the node exists and whether its cluster admits
|
|
36
|
+
* the retirement is Cloudly's.
|
|
37
|
+
*/
|
|
38
|
+
export declare const snapshotNodeRuntimeRetirement: (value: unknown) => INodeRuntimeRetirement;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { captureNetwork, networkCounter, networkId, networkRecord, requireNetwork } from '../private/networkcontract.js';
|
|
2
|
+
import { isOneOf, producerSafe } from '../private/producercontract.js';
|
|
3
|
+
const nodeRuntimeRetirementStates = ['retiring', 'retired'];
|
|
4
|
+
/**
|
|
5
|
+
* Every reason Cloudly answers instead of retiring a node. Each travels as a `TypedResponseError`,
|
|
6
|
+
* and none of them takes anything away: a refused retirement leaves the node exactly as it was.
|
|
7
|
+
*/
|
|
8
|
+
export const nodeRuntimeRetirementRefusals = Object.freeze([
|
|
9
|
+
/** No node of that id exists, so there is nothing to retire. */
|
|
10
|
+
'node-missing',
|
|
11
|
+
/**
|
|
12
|
+
* The node's cluster runs no Pallet runtime — it has no phase record, or a phase other than
|
|
13
|
+
* `pallet`. Which of the two it is, `getClusterRuntime` says.
|
|
14
|
+
*/
|
|
15
|
+
'cluster-runtime-not-pallet',
|
|
16
|
+
/** The node already carries a retirement row; neither of its states is left by retiring again. */
|
|
17
|
+
'node-already-retired',
|
|
18
|
+
/** `expectedGeneration` is not the cluster runtime's current generation, so a cutover moved underneath the caller. */
|
|
19
|
+
'conflict',
|
|
20
|
+
]);
|
|
21
|
+
/**
|
|
22
|
+
* Structural snapshot for exact persistence; whether the node exists and whether its cluster admits
|
|
23
|
+
* the retirement is Cloudly's.
|
|
24
|
+
*/
|
|
25
|
+
export const snapshotNodeRuntimeRetirement = (value) => producerSafe(() => {
|
|
26
|
+
const item = networkRecord(captureNetwork(value), ['id', 'clusterId', 'state', 'actorId', 'since']);
|
|
27
|
+
requireNetwork(isOneOf(nodeRuntimeRetirementStates, item.state));
|
|
28
|
+
return { id: networkId(item.id), clusterId: networkId(item.clusterId), state: item.state,
|
|
29
|
+
actorId: networkId(item.actorId), since: networkCounter(item.since) };
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZXJldGlyZW1lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL25vZGVyZXRpcmVtZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxjQUFjLEVBQUUsY0FBYyxFQUFFLFNBQVMsRUFBRSxhQUFhLEVBQUUsY0FBYyxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDekgsT0FBTyxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUV2RSxNQUFNLDJCQUEyQixHQUFHLENBQUMsVUFBVSxFQUFFLFNBQVMsQ0FBVSxDQUFDO0FBNkJyRTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSw2QkFBNkIsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ3pELGdFQUFnRTtJQUNoRSxjQUFjO0lBQ2Q7OztPQUdHO0lBQ0gsNEJBQTRCO0lBQzVCLGtHQUFrRztJQUNsRyxzQkFBc0I7SUFDdEIsc0hBQXNIO0lBQ3RILFVBQVU7Q0FDRixDQUFDLENBQUM7QUFLWjs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSw2QkFBNkIsR0FBRyxDQUFDLEtBQWMsRUFBMEIsRUFBRSxDQUFDLFlBQVksQ0FBQyxHQUFHLEVBQUU7SUFDekcsTUFBTSxJQUFJLEdBQUcsYUFBYSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ3BHLGNBQWMsQ0FBQyxPQUFPLENBQUMsMkJBQTJCLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDakUsT0FBTyxFQUFFLEVBQUUsRUFBRSxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLFNBQVMsRUFBRSxTQUFTLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSztRQUN0RixPQUFPLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsY0FBYyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO0FBQzFFLENBQUMsQ0FBQyxDQUFDIn0=
|
|
@@ -70,14 +70,22 @@ export declare const serviceRuntimeContract: Readonly<{
|
|
|
70
70
|
readonly maximumAssignmentPageSize: 256;
|
|
71
71
|
}>;
|
|
72
72
|
declare const serviceRuntimeWaitingReasons: readonly ["node-network-pending", "conflict", "failure-backoff"];
|
|
73
|
-
declare const serviceRuntimeRefusals: readonly ["cluster-runtime-missing", "organization-missing", "image-plan-missing", "platform-unsupported", "secrets-unsupported", "volumes-unsupported", "port-protocol-unsupported", "readiness-target-undeclared", "environment-too-large", "no-eligible-node", "replica-limit"];
|
|
73
|
+
declare const serviceRuntimeRefusals: readonly ["cluster-runtime-missing", "organization-missing", "image-plan-missing", "platform-unsupported", "secrets-unsupported", "volumes-unsupported", "port-protocol-unsupported", "ports-too-many", "readiness-target-undeclared", "environment-too-large", "no-eligible-node", "replica-limit", "node-authority-unsupported"];
|
|
74
74
|
/**
|
|
75
75
|
* Why the producer is not converging yet, though nothing needs an administrator:
|
|
76
76
|
* `node-network-pending` waits for a node's network readiness, `conflict` for a sweep over inputs
|
|
77
77
|
* that changed while it ran, `failure-backoff` for a failed replica's backoff to elapse.
|
|
78
78
|
*/
|
|
79
79
|
export type TServiceRuntimeWaitingReason = typeof serviceRuntimeWaitingReasons[number];
|
|
80
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* Why the producer admits nothing for this spec revision. A refusal never retires running slots.
|
|
82
|
+
*
|
|
83
|
+
* The two a reader cannot derive from the name alone: `ports-too-many` is a service declaring more
|
|
84
|
+
* target ports than `runtimeConfigContract.maximumTargetPorts` a config carries — a count, where
|
|
85
|
+
* `port-protocol-unsupported` is about one port's protocol — and `node-authority-unsupported` is a
|
|
86
|
+
* node whose session resolved fewer workload authorities than this spec needs, which the admit step
|
|
87
|
+
* refuses rather than handing the node work it would silently park.
|
|
88
|
+
*/
|
|
81
89
|
export type TServiceRuntimeRefusal = typeof serviceRuntimeRefusals[number];
|
|
82
90
|
interface IServiceRuntimeStatusBase {
|
|
83
91
|
/** The service id. */
|
|
@@ -15,8 +15,9 @@ export const serviceRuntimeContract = Object.freeze({
|
|
|
15
15
|
const serviceRuntimeWaitingReasons = ['node-network-pending', 'conflict', 'failure-backoff'];
|
|
16
16
|
const serviceRuntimeRefusals = [
|
|
17
17
|
'cluster-runtime-missing', 'organization-missing', 'image-plan-missing', 'platform-unsupported',
|
|
18
|
-
'secrets-unsupported', 'volumes-unsupported', 'port-protocol-unsupported', '
|
|
19
|
-
'environment-too-large', 'no-eligible-node', 'replica-limit',
|
|
18
|
+
'secrets-unsupported', 'volumes-unsupported', 'port-protocol-unsupported', 'ports-too-many',
|
|
19
|
+
'readiness-target-undeclared', 'environment-too-large', 'no-eligible-node', 'replica-limit',
|
|
20
|
+
'node-authority-unsupported',
|
|
20
21
|
];
|
|
21
22
|
const sortedIds = (value, maximum) => networkSorted(networkList(value, maximum, networkId), id => id);
|
|
22
23
|
const placementOf = (value) => {
|
|
@@ -89,4 +90,4 @@ export const snapshotServiceRuntimeStatus = (value) => producerSafe(() => {
|
|
|
89
90
|
requireNetwork(item.state === 'refused' && isOneOf(serviceRuntimeRefusals, item.reason));
|
|
90
91
|
return { ...base, state: item.state, reason: item.reason };
|
|
91
92
|
});
|
|
92
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
93
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZXJ1bnRpbWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL3NlcnZpY2VydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxjQUFjLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLGFBQWEsRUFDN0csY0FBYyxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDeEQsT0FBTyxFQUFFLFlBQVksRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2hHLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxnQkFBZ0IsRUFBRSxrQkFBa0IsRUFBRSx1QkFBdUIsRUFBRSxrQkFBa0IsRUFDaEgsb0JBQW9CLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQXdENUQsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUNsRCxzQkFBc0IsRUFBRSxFQUFFO0lBQzFCLCtGQUErRjtJQUMvRixlQUFlLEVBQUUsRUFBRTtJQUNuQixvSEFBb0g7SUFDcEgsa0JBQWtCLEVBQUUsK0JBQStCLENBQUMsd0JBQXdCO0lBQzVFLHdCQUF3QixFQUFFLCtCQUErQixDQUFDLHdCQUF3QjtJQUNsRixnR0FBZ0c7SUFDaEcseUJBQXlCLEVBQUUsR0FBRztDQUN0QixDQUFDLENBQUM7QUFFWixNQUFNLDRCQUE0QixHQUFHLENBQUMsc0JBQXNCLEVBQUUsVUFBVSxFQUFFLGlCQUFpQixDQUFVLENBQUM7QUFDdEcsTUFBTSxzQkFBc0IsR0FBRztJQUM3Qix5QkFBeUIsRUFBRSxzQkFBc0IsRUFBRSxvQkFBb0IsRUFBRSxzQkFBc0I7SUFDL0YscUJBQXFCLEVBQUUscUJBQXFCLEVBQUUsMkJBQTJCLEVBQUUsZ0JBQWdC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
|
|
@@ -142,8 +142,12 @@ export interface IResolvedStorageBindingBase {
|
|
|
142
142
|
/** Stable App Store storageRequests[].id. */
|
|
143
143
|
requestId: string;
|
|
144
144
|
/**
|
|
145
|
-
* Canonical digest of the normalized request
|
|
146
|
-
*
|
|
145
|
+
* Canonical digest of the normalized request, exactly as
|
|
146
|
+
* `createStorageRequestSha256` states it: bare lowercase hex over the request
|
|
147
|
+
* alone. Adapters use it to distinguish an idempotent reconciliation from a
|
|
148
|
+
* migration, and a consumer re-derives it to recognise the request it asked
|
|
149
|
+
* for, so the control plane and the consumer call that one function rather
|
|
150
|
+
* than each deriving a value the other cannot reproduce.
|
|
147
151
|
*/
|
|
148
152
|
requestDigest: string;
|
|
149
153
|
kind: TStorageResourceKind;
|
|
@@ -180,3 +184,26 @@ export interface IResolvedObjectStorageBinding extends IResolvedStorageBindingBa
|
|
|
180
184
|
retentionDays?: number;
|
|
181
185
|
}
|
|
182
186
|
export type TResolvedStorageBinding = IResolvedFilesystemStorageBinding | IResolvedObjectStorageBinding;
|
|
187
|
+
export declare class StorageContractError extends Error {
|
|
188
|
+
constructor(reasonArg: string);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* The exact bytes a storage request's digest is taken over: the request normalized to its contract
|
|
192
|
+
* shape, written as strict canonical JSON — keys in UTF-16 code-unit order, no whitespace, no
|
|
193
|
+
* absent member carried as `null`.
|
|
194
|
+
*
|
|
195
|
+
* Anything that is not a storage request is refused rather than hashed, because a digest of an
|
|
196
|
+
* unjudged body would name a request no adapter could fulfil.
|
|
197
|
+
*/
|
|
198
|
+
export declare const canonicalizeStorageRequest: (valueArg: unknown) => string;
|
|
199
|
+
/**
|
|
200
|
+
* The storage request digest: bare lowercase hex SHA-256 over the canonical request, with no
|
|
201
|
+
* prefix and nothing but the request in the hashed value.
|
|
202
|
+
*
|
|
203
|
+
* A control plane issues this value on a binding and a consumer re-derives it from the request it
|
|
204
|
+
* declared; the two only agree because they call this one function. A second derivation elsewhere
|
|
205
|
+
* — a prefix, or a wrapper object around the request — is a different value for the same binding,
|
|
206
|
+
* and the consumer would keep rejecting a binding that is in fact its own.
|
|
207
|
+
*/
|
|
208
|
+
export declare const createStorageRequestSha256: (valueArg: unknown) => Promise<string>;
|
|
209
|
+
export { storageRequestCanonicalDigestGoldenVectors, type IStorageRequestCanonicalDigestGoldenVector, } from './storage.golden.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { IAppStoreFilesystemStorageRequest, IAppStoreObjectStorageRequest } from '../appstore/types.js';
|
|
2
|
+
export interface IStorageRequestCanonicalDigestGoldenVector<TInput> {
|
|
3
|
+
input: TInput;
|
|
4
|
+
canonicalJson: string;
|
|
5
|
+
sha256: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The storage request digest, written down for both kinds and both deliveries.
|
|
9
|
+
*
|
|
10
|
+
* A control plane and its consumer compare this value, so it is stated here as bytes rather than
|
|
11
|
+
* as whatever the current normalizer happens to produce: a member that starts or stops
|
|
12
|
+
* participating, an optional member that starts being carried when it is absent, or a delivery
|
|
13
|
+
* mode written as anything but its number would move these digests and be caught here.
|
|
14
|
+
*/
|
|
15
|
+
export declare const storageRequestCanonicalDigestGoldenVectors: {
|
|
16
|
+
filesystem: {
|
|
17
|
+
input: IAppStoreFilesystemStorageRequest;
|
|
18
|
+
canonicalJson: string;
|
|
19
|
+
sha256: string;
|
|
20
|
+
};
|
|
21
|
+
objectStorageLauncherEnvironment: {
|
|
22
|
+
input: IAppStoreObjectStorageRequest;
|
|
23
|
+
canonicalJson: string;
|
|
24
|
+
sha256: string;
|
|
25
|
+
};
|
|
26
|
+
objectStorageFile: {
|
|
27
|
+
input: IAppStoreObjectStorageRequest;
|
|
28
|
+
canonicalJson: string;
|
|
29
|
+
sha256: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { deepFreezeValue } from '../private/canonicaljson.js';
|
|
2
|
+
const filesystemRequest = {
|
|
3
|
+
id: 'app-state',
|
|
4
|
+
kind: 'filesystem',
|
|
5
|
+
storageClass: 'databaseFast',
|
|
6
|
+
accessMode: 'ReadWriteOnce',
|
|
7
|
+
reclaimPolicy: 'delete',
|
|
8
|
+
mountPath: '/var/lib/app',
|
|
9
|
+
capacity: {
|
|
10
|
+
request: '20GiB',
|
|
11
|
+
limit: '40GiB',
|
|
12
|
+
},
|
|
13
|
+
protection: {
|
|
14
|
+
backup: 'required',
|
|
15
|
+
snapshots: 'portable',
|
|
16
|
+
consistency: 'applicationConsistent',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
const objectStorageLauncherEnvironmentRequest = {
|
|
20
|
+
id: 'object-data',
|
|
21
|
+
kind: 'objectStorage',
|
|
22
|
+
storageClass: 'backupCapacity',
|
|
23
|
+
accessMode: 'readWrite',
|
|
24
|
+
reclaimPolicy: 'retain',
|
|
25
|
+
delivery: {
|
|
26
|
+
type: 'launcher-environment',
|
|
27
|
+
keys: {
|
|
28
|
+
endpoint: 'APP_S3_ENDPOINT',
|
|
29
|
+
bucket: 'APP_S3_BUCKET',
|
|
30
|
+
region: 'APP_S3_REGION',
|
|
31
|
+
accessKeyId: 'APP_S3_ACCESS_KEY',
|
|
32
|
+
secretAccessKey: 'APP_S3_SECRET_KEY',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
capacity: {
|
|
36
|
+
request: '500GiB',
|
|
37
|
+
},
|
|
38
|
+
protection: {
|
|
39
|
+
backup: 'required',
|
|
40
|
+
versioning: 'required',
|
|
41
|
+
retentionDays: 30,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
const objectStorageFileRequest = {
|
|
45
|
+
id: 'object-archive',
|
|
46
|
+
kind: 'objectStorage',
|
|
47
|
+
storageClass: 'archiveCapacity',
|
|
48
|
+
accessMode: 'readOnly',
|
|
49
|
+
reclaimPolicy: 'delete',
|
|
50
|
+
delivery: {
|
|
51
|
+
type: 'file',
|
|
52
|
+
targetPath: '/run/secrets/object-archive.json',
|
|
53
|
+
format: 'servezone-object-storage',
|
|
54
|
+
uid: 10_000,
|
|
55
|
+
gid: 10_000,
|
|
56
|
+
mode: 0o400,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* The storage request digest, written down for both kinds and both deliveries.
|
|
61
|
+
*
|
|
62
|
+
* A control plane and its consumer compare this value, so it is stated here as bytes rather than
|
|
63
|
+
* as whatever the current normalizer happens to produce: a member that starts or stops
|
|
64
|
+
* participating, an optional member that starts being carried when it is absent, or a delivery
|
|
65
|
+
* mode written as anything but its number would move these digests and be caught here.
|
|
66
|
+
*/
|
|
67
|
+
export const storageRequestCanonicalDigestGoldenVectors = deepFreezeValue({
|
|
68
|
+
filesystem: {
|
|
69
|
+
input: filesystemRequest,
|
|
70
|
+
canonicalJson: '{"accessMode":"ReadWriteOnce","capacity":{"limit":"40GiB","request":"20GiB"},"id":"app-state","kind":"filesystem","mountPath":"/var/lib/app","protection":{"backup":"required","consistency":"applicationConsistent","snapshots":"portable"},"reclaimPolicy":"delete","storageClass":"databaseFast"}',
|
|
71
|
+
sha256: '0f8dc2e480ade7110be1f1d95f666cc56d5b90110d1c4a1b8b8383e2eeda6fae',
|
|
72
|
+
},
|
|
73
|
+
objectStorageLauncherEnvironment: {
|
|
74
|
+
input: objectStorageLauncherEnvironmentRequest,
|
|
75
|
+
canonicalJson: '{"accessMode":"readWrite","capacity":{"request":"500GiB"},"delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"id":"object-data","kind":"objectStorage","protection":{"backup":"required","retentionDays":30,"versioning":"required"},"reclaimPolicy":"retain","storageClass":"backupCapacity"}',
|
|
76
|
+
sha256: '88bd943800bea75b576612b966484e66ddbf7ec9529a7f29dd1eadc9a36e2b79',
|
|
77
|
+
},
|
|
78
|
+
objectStorageFile: {
|
|
79
|
+
input: objectStorageFileRequest,
|
|
80
|
+
canonicalJson: '{"accessMode":"readOnly","delivery":{"format":"servezone-object-storage","gid":10000,"mode":256,"targetPath":"/run/secrets/object-archive.json","type":"file","uid":10000},"id":"object-archive","kind":"objectStorage","reclaimPolicy":"delete","storageClass":"archiveCapacity"}',
|
|
81
|
+
sha256: '13186abbfe733b3917363e0694d367f2d6aa87a4064445532d7c857ee274f795',
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZS5nb2xkZW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9wbGF0Zm9ybS9zdG9yYWdlLmdvbGRlbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFJQSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFROUQsTUFBTSxpQkFBaUIsR0FBc0M7SUFDM0QsRUFBRSxFQUFFLFdBQVc7SUFDZixJQUFJLEVBQUUsWUFBWTtJQUNsQixZQUFZLEVBQUUsY0FBYztJQUM1QixVQUFVLEVBQUUsZUFBZTtJQUMzQixhQUFhLEVBQUUsUUFBUTtJQUN2QixTQUFTLEVBQUUsY0FBYztJQUN6QixRQUFRLEVBQUU7UUFDUixPQUFPLEVBQUUsT0FBTztRQUNoQixLQUFLLEVBQUUsT0FBTztLQUNmO0lBQ0QsVUFBVSxFQUFFO1FBQ1YsTUFBTSxFQUFFLFVBQVU7UUFDbEIsU0FBUyxFQUFFLFVBQVU7UUFDckIsV0FBVyxFQUFFLHVCQUF1QjtLQUNyQztDQUNGLENBQUM7QUFFRixNQUFNLHVDQUF1QyxHQUFrQztJQUM3RSxFQUFFLEVBQUUsYUFBYTtJQUNqQixJQUFJLEVBQUUsZUFBZTtJQUNyQixZQUFZLEVBQUUsZ0JBQWdCO0lBQzlCLFVBQVUsRUFBRSxXQUFXO0lBQ3ZCLGFBQWEsRUFBRSxRQUFRO0lBQ3ZCLFFBQVEsRUFBRTtRQUNSLElBQUksRUFBRSxzQkFBc0I7UUFDNUIsSUFBSSxFQUFFO1lBQ0osUUFBUSxFQUFFLGlCQUFpQjtZQUMzQixNQUFNLEVBQUUsZUFBZTtZQUN2QixNQUFNLEVBQUUsZUFBZTtZQUN2QixXQUFXLEVBQUUsbUJBQW1CO1lBQ2hDLGVBQWUsRUFBRSxtQkFBbUI7U0FDckM7S0FDRjtJQUNELFFBQVEsRUFBRTtRQUNSLE9BQU8sRUFBRSxRQUFRO0tBQ2xCO0lBQ0QsVUFBVSxFQUFFO1FBQ1YsTUFBTSxFQUFFLFVBQVU7UUFDbEIsVUFBVSxFQUFFLFVBQVU7UUFDdEIsYUFBYSxFQUFFLEVBQUU7S0FDbEI7Q0FDRixDQUFDO0FBRUYsTUFBTSx3QkFBd0IsR0FBa0M7SUFDOUQsRUFBRSxFQUFFLGdCQUFnQjtJQUNwQixJQUFJLEVBQUUsZUFBZTtJQUNyQixZQUFZLEVBQUUsaUJBQWlCO0lBQy9CLFVBQVUsRUFBRSxVQUFVO0lBQ3RCLGFBQWEsRUFBRSxRQUFRO0lBQ3ZCLFFBQVEsRUFBRTtRQUNSLElBQUksRUFBRSxNQUFNO1FBQ1osVUFBVSxFQUFFLGtDQUFrQztRQUM5QyxNQUFNLEVBQUUsMEJBQTBCO1FBQ2xDLEdBQUcsRUFBRSxNQUFNO1FBQ1gsR0FBRyxFQUFFLE1BQU07UUFDWCxJQUFJLEVBQUUsS0FBSztLQUNaO0NBQ0YsQ0FBQztBQUVGOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLENBQUMsTUFBTSwwQ0FBMEMsR0FBRyxlQUFlLENBQUM7SUFDeEUsVUFBVSxFQUFFO1FBQ1YsS0FBSyxFQUFFLGlCQUFpQjtRQUN4QixhQUFhLEVBQUUsc1NBQXNTO1FBQ3JULE1BQU0sRUFBRSxrRUFBa0U7S0FDM0U7SUFDRCxnQ0FBZ0MsRUFBRTtRQUNoQyxLQUFLLEVBQUUsdUNBQXVDO1FBQzlDLGFBQWEsRUFBRSx3YkFBd2I7UUFDdmMsTUFBTSxFQUFFLGtFQUFrRTtLQUMzRTtJQUNELGlCQUFpQixFQUFFO1FBQ2pCLEtBQUssRUFBRSx3QkFBd0I7UUFDL0IsYUFBYSxFQUFFLG9SQUFvUjtRQUNuUyxNQUFNLEVBQUUsa0VBQWtFO0tBQzNFO0NBQ0YsQ0FBQyxDQUFDIn0=
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { canonicalizeStrictJson, createCanonicalJsonSha256Hex, } from '../private/canonicaljson.js';
|
|
2
|
+
import { createStorageContractReaders } from '../private/storagecontract.js';
|
|
1
3
|
/**
|
|
2
4
|
* Compatibility bridge for the existing generic platform capability. New
|
|
3
5
|
* filesystem requests intentionally have no generic IPlatformBinding mapping.
|
|
@@ -5,4 +7,38 @@
|
|
|
5
7
|
export const storageKindPlatformCapabilityIds = {
|
|
6
8
|
objectStorage: 'objectstorage',
|
|
7
9
|
};
|
|
8
|
-
|
|
10
|
+
export class StorageContractError extends Error {
|
|
11
|
+
constructor(reasonArg) {
|
|
12
|
+
super(`storage contract error: ${reasonArg}`);
|
|
13
|
+
this.name = 'StorageContractError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const fail = (reasonArg) => {
|
|
17
|
+
throw new StorageContractError(reasonArg);
|
|
18
|
+
};
|
|
19
|
+
const { normalizeStorageRequest } = createStorageContractReaders(fail);
|
|
20
|
+
/**
|
|
21
|
+
* The exact bytes a storage request's digest is taken over: the request normalized to its contract
|
|
22
|
+
* shape, written as strict canonical JSON — keys in UTF-16 code-unit order, no whitespace, no
|
|
23
|
+
* absent member carried as `null`.
|
|
24
|
+
*
|
|
25
|
+
* Anything that is not a storage request is refused rather than hashed, because a digest of an
|
|
26
|
+
* unjudged body would name a request no adapter could fulfil.
|
|
27
|
+
*/
|
|
28
|
+
export const canonicalizeStorageRequest = (valueArg) => {
|
|
29
|
+
return canonicalizeStrictJson(normalizeStorageRequest(valueArg, 'storage request'), fail);
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The storage request digest: bare lowercase hex SHA-256 over the canonical request, with no
|
|
33
|
+
* prefix and nothing but the request in the hashed value.
|
|
34
|
+
*
|
|
35
|
+
* A control plane issues this value on a binding and a consumer re-derives it from the request it
|
|
36
|
+
* declared; the two only agree because they call this one function. A second derivation elsewhere
|
|
37
|
+
* — a prefix, or a wrapper object around the request — is a different value for the same binding,
|
|
38
|
+
* and the consumer would keep rejecting a binding that is in fact its own.
|
|
39
|
+
*/
|
|
40
|
+
export const createStorageRequestSha256 = async (valueArg) => {
|
|
41
|
+
return createCanonicalJsonSha256Hex(canonicalizeStorageRequest(valueArg), fail);
|
|
42
|
+
};
|
|
43
|
+
export { storageRequestCanonicalDigestGoldenVectors, } from './storage.golden.js';
|
|
44
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3BsYXRmb3JtL3N0b3JhZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUNMLHNCQUFzQixFQUN0Qiw0QkFBNEIsR0FDN0IsTUFBTSw2QkFBNkIsQ0FBQztBQUNyQyxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQVE3RTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxnQ0FBZ0MsR0FBRztJQUM5QyxhQUFhLEVBQUUsZUFBZTtDQUN0QixDQUFDO0FBaU9YLE1BQU0sT0FBTyxvQkFBcUIsU0FBUSxLQUFLO0lBQzdDLFlBQW1CLFNBQWlCO1FBQ2xDLEtBQUssQ0FBQywyQkFBMkIsU0FBUyxFQUFFLENBQUMsQ0FBQztRQUM5QyxJQUFJLENBQUMsSUFBSSxHQUFHLHNCQUFzQixDQUFDO0lBQ3JDLENBQUM7Q0FDRjtBQUVELE1BQU0sSUFBSSxHQUFHLENBQUMsU0FBaUIsRUFBUyxFQUFFO0lBQ3hDLE1BQU0sSUFBSSxvQkFBb0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUM1QyxDQUFDLENBQUM7QUFFRixNQUFNLEVBQUUsdUJBQXVCLEVBQUUsR0FBRyw0QkFBNEIsQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUV2RTs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sMEJBQTBCLEdBQUcsQ0FBQyxRQUFpQixFQUFVLEVBQUU7SUFDdEUsT0FBTyxzQkFBc0IsQ0FDM0IsdUJBQXVCLENBQUMsUUFBUSxFQUFFLGlCQUFpQixDQUFDLEVBQ3BELElBQUksQ0FDTCxDQUFDO0FBQ0osQ0FBQyxDQUFDO0FBRUY7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxLQUFLLEVBQzdDLFFBQWlCLEVBQ0EsRUFBRTtJQUNuQixPQUFPLDRCQUE0QixDQUFDLDBCQUEwQixDQUFDLFFBQVEsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQ2xGLENBQUMsQ0FBQztBQUVGLE9BQU8sRUFDTCwwQ0FBMEMsR0FFM0MsTUFBTSxxQkFBcUIsQ0FBQyJ9
|