@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 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.2',
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=
@@ -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';
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLGlCQUFpQixDQUFDO0FBQ2hDLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxVQUFVLENBQUM7QUFDekIsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxZQUFZLENBQUM7QUFDM0IsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLGdCQUFnQixDQUFDO0FBQy9CLGNBQWMsWUFBWSxDQUFDO0FBQzNCLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLDZCQUE2QixDQUFDO0FBQzVDLGNBQWMsV0FBVyxDQUFDO0FBQzFCLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsdUJBQXVCLENBQUM7QUFDdEMsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyxrQkFBa0IsQ0FBQztBQUNqQyxjQUFjLHdCQUF3QixDQUFDO0FBRXZDLGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsZUFBZSxDQUFDO0FBQzlCLGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsNkJBQTZCLENBQUM7QUFDNUMsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsZUFBZSxDQUFDO0FBQzlCLGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLG1CQUFtQixDQUFDO0FBQ2xDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLFdBQVcsQ0FBQztBQUMxQixjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLGNBQWMsQ0FBQyJ9
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
- /** Why the producer admits nothing for this spec revision. A refusal never retires running slots. */
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', 'readiness-target-undeclared',
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZXJ1bnRpbWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL3NlcnZpY2VydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxjQUFjLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLGFBQWEsRUFDN0csY0FBYyxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDeEQsT0FBTyxFQUFFLFlBQVksRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2hHLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxnQkFBZ0IsRUFBRSxrQkFBa0IsRUFBRSx1QkFBdUIsRUFBRSxrQkFBa0IsRUFDaEgsb0JBQW9CLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQXdENUQsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUNsRCxzQkFBc0IsRUFBRSxFQUFFO0lBQzFCLCtGQUErRjtJQUMvRixlQUFlLEVBQUUsRUFBRTtJQUNuQixvSEFBb0g7SUFDcEgsa0JBQWtCLEVBQUUsK0JBQStCLENBQUMsd0JBQXdCO0lBQzVFLHdCQUF3QixFQUFFLCtCQUErQixDQUFDLHdCQUF3QjtJQUNsRixnR0FBZ0c7SUFDaEcseUJBQXlCLEVBQUUsR0FBRztDQUN0QixDQUFDLENBQUM7QUFFWixNQUFNLDRCQUE0QixHQUFHLENBQUMsc0JBQXNCLEVBQUUsVUFBVSxFQUFFLGlCQUFpQixDQUFVLENBQUM7QUFDdEcsTUFBTSxzQkFBc0IsR0FBRztJQUM3Qix5QkFBeUIsRUFBRSxzQkFBc0IsRUFBRSxvQkFBb0IsRUFBRSxzQkFBc0I7SUFDL0YscUJBQXFCLEVBQUUscUJBQXFCLEVBQUUsMkJBQTJCLEVBQUUsNkJBQTZC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QUksQ0FBQyxLQUFLLEtBQUssV0FBVyxJQUFJLElBQUksQ0FBQyxLQUFLLEtBQUssWUFBWSxFQUFFLENBQUM7UUFDOUQsY0FBYyxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssSUFBSSxDQUFDLENBQUM7UUFDckMsT0FBTyxFQUFFLEdBQUcsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQztJQUN0RCxDQUFDO0lBQ0QsSUFBSSxJQUFJLENBQUMsS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQzdCLGNBQWMsQ0FBQyxPQUFPLENBQUMsNEJBQTRCLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDbkUsT0FBTyxFQUFFLEdBQUcsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDN0QsQ0FBQztJQUNELGNBQWMsQ0FBQyxJQUFJLENBQUMsS0FBSyxLQUFLLFNBQVMsSUFBSSxPQUFPLENBQUMsc0JBQXNCLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDekYsT0FBTyxFQUFFLEdBQUcsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7QUFDN0QsQ0FBQyxDQUFDLENBQUMifQ==
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. Adapters use it to distinguish
146
- * an idempotent reconciliation from a migration.
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
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3BsYXRmb3JtL3N0b3JhZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBUUE7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sZ0NBQWdDLEdBQUc7SUFDOUMsYUFBYSxFQUFFLGVBQWU7Q0FDdEIsQ0FBQyJ9
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