@hypequery/deployment 0.7.5 → 0.9.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/README.md +5 -31
- package/dist/activation.d.ts.map +1 -1
- package/dist/activation.js +2 -1
- package/dist/authorized-contract.d.ts +72 -0
- package/dist/authorized-contract.d.ts.map +1 -0
- package/dist/authorized-contract.js +132 -0
- package/dist/bundle.d.ts.map +1 -1
- package/dist/bundle.js +10 -36
- package/dist/control-plane-limits.js +1 -1
- package/dist/filesystem-store.d.ts.map +1 -1
- package/dist/filesystem-store.js +7 -22
- package/dist/index.d.ts +6 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -9
- package/dist/intake.d.ts.map +1 -1
- package/dist/intake.js +8 -5
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +5 -2
- package/dist/principal.d.ts +11 -0
- package/dist/principal.d.ts.map +1 -0
- package/dist/principal.js +1 -0
- package/dist/semantic-data-plane.d.ts +70 -0
- package/dist/semantic-data-plane.d.ts.map +1 -0
- package/dist/semantic-data-plane.js +234 -0
- package/dist/semantic-invocation-errors.d.ts +30 -0
- package/dist/semantic-invocation-errors.d.ts.map +1 -0
- package/dist/semantic-invocation-errors.js +45 -0
- package/dist/semantic-operation-validation.d.ts +29 -0
- package/dist/semantic-operation-validation.d.ts.map +1 -0
- package/dist/semantic-operation-validation.js +157 -0
- package/dist/utils/read-bounded-file.d.ts +4 -0
- package/dist/utils/read-bounded-file.d.ts.map +1 -0
- package/dist/utils/read-bounded-file.js +18 -0
- package/dist/utils/required-access.d.ts +2 -0
- package/dist/utils/required-access.d.ts.map +1 -0
- package/dist/utils/required-access.js +4 -0
- package/dist/utils/semantic-budget-limits.d.ts +7 -0
- package/dist/utils/semantic-budget-limits.d.ts.map +1 -0
- package/dist/utils/semantic-budget-limits.js +15 -0
- package/dist/utils/semantic-executor-failure.d.ts +21 -0
- package/dist/utils/semantic-executor-failure.d.ts.map +1 -0
- package/dist/utils/semantic-executor-failure.js +52 -0
- package/package.json +5 -4
- package/dist/data-plane-adapters.d.ts +0 -18
- package/dist/data-plane-adapters.d.ts.map +0 -1
- package/dist/data-plane-adapters.js +0 -304
- package/dist/data-plane-limits.d.ts +0 -5
- package/dist/data-plane-limits.d.ts.map +0 -1
- package/dist/data-plane-limits.js +0 -5
- package/dist/data-plane-runtime.d.ts +0 -13
- package/dist/data-plane-runtime.d.ts.map +0 -1
- package/dist/data-plane-runtime.js +0 -12
- package/dist/data-plane.d.ts +0 -84
- package/dist/data-plane.d.ts.map +0 -1
- package/dist/data-plane.js +0 -209
- package/dist/filesystem-host.d.ts +0 -51
- package/dist/filesystem-host.d.ts.map +0 -1
- package/dist/filesystem-host.js +0 -73
- package/dist/host.d.ts +0 -40
- package/dist/host.d.ts.map +0 -1
- package/dist/host.js +0 -183
- package/dist/node-runtime-factory.d.ts +0 -27
- package/dist/node-runtime-factory.d.ts.map +0 -1
- package/dist/node-runtime-factory.js +0 -336
- package/dist/runtime-materialization.d.ts +0 -58
- package/dist/runtime-materialization.d.ts.map +0 -1
- package/dist/runtime-materialization.js +0 -187
- package/dist/runtime-supervisor.d.ts +0 -77
- package/dist/runtime-supervisor.d.ts.map +0 -1
- package/dist/runtime-supervisor.js +0 -265
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @hypequery/deployment
|
|
2
2
|
|
|
3
|
-
Provider-neutral building blocks for receiving, verifying, activating, and
|
|
3
|
+
Provider-neutral building blocks for receiving, verifying, activating, and invoking Hypequery deployment bundles.
|
|
4
4
|
|
|
5
5
|
This package is for Cloud providers and self-hosted control planes. Application teams normally use `hypequery deploy` through `@hypequery/cli` instead.
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ Every deployment is treated as immutable content. Before storage or execution, t
|
|
|
11
11
|
- the target-bound release envelope;
|
|
12
12
|
- the closed bundle manifest;
|
|
13
13
|
- declared paths and byte limits;
|
|
14
|
-
- every file hash and
|
|
14
|
+
- every declared file hash and the canonical deployment JSON;
|
|
15
15
|
- deployment, bundle, and release identities;
|
|
16
16
|
- activation revision consistency.
|
|
17
17
|
|
|
@@ -24,10 +24,8 @@ Symbolic links, undeclared files, path traversal, missing content, and identity
|
|
|
24
24
|
- a durable reference filesystem store;
|
|
25
25
|
- compare-and-swap activation and rollback;
|
|
26
26
|
- Node and Fetch control-plane adapters;
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
- named-query data-plane execution;
|
|
30
|
-
- a reference single-host composition.
|
|
27
|
+
- contract-driven semantic invocation with an injected dataset executor;
|
|
28
|
+
- authorization-aware contract projection for discovery.
|
|
31
29
|
|
|
32
30
|
## Minimal intake
|
|
33
31
|
|
|
@@ -50,33 +48,9 @@ const intake = createDeploymentIntake({
|
|
|
50
48
|
|
|
51
49
|
Authentication happens before upload bytes are consumed. The store receives a fully verified temporary bundle and must persist required bytes before returning.
|
|
52
50
|
|
|
53
|
-
## Single-host reference
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
import { createFileSystemDeploymentHost } from '@hypequery/deployment';
|
|
57
|
-
|
|
58
|
-
const service = createFileSystemDeploymentHost({
|
|
59
|
-
directory: '/var/lib/hypequery/deployments',
|
|
60
|
-
targets: [{ project: 'analytics', environment: 'production' }],
|
|
61
|
-
intake: {
|
|
62
|
-
authenticator: deploymentAuthenticator,
|
|
63
|
-
authorizer: deploymentAuthorizer,
|
|
64
|
-
},
|
|
65
|
-
controlPlane: {
|
|
66
|
-
authenticator: operatorAuthenticator,
|
|
67
|
-
authorizer: operatorAuthorizer,
|
|
68
|
-
},
|
|
69
|
-
configureDataPlane,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
await service.start();
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Distributed providers can keep the same interfaces while replacing persistence, runtime isolation, secret resolution, routing, and observability.
|
|
76
|
-
|
|
77
51
|
## Trust boundary
|
|
78
52
|
|
|
79
|
-
|
|
53
|
+
This package validates the deployment contract and gates semantic calls, but does not execute datasets or supervise application code. Providers supply the executor, credentials, tenant resolution, routing, and runtime isolation. The filesystem store assumes its configured directory is controlled by the operator.
|
|
80
54
|
|
|
81
55
|
## Specifications
|
|
82
56
|
|
package/dist/activation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activation.d.ts","sourceRoot":"","sources":["../src/activation.ts"],"names":[],"mappings":"AAYA,OAAO,EAGL,KAAK,iCAAiC,EACtC,KAAK,+BAA+B,EACrC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"activation.d.ts","sourceRoot":"","sources":["../src/activation.ts"],"names":[],"mappings":"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"}
|
package/dist/activation.js
CHANGED
|
@@ -3,6 +3,7 @@ import { constants } from 'node:fs';
|
|
|
3
3
|
import { lstat, mkdir, mkdtemp, open, readdir, rename, rm, } from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { prepareProtocolDeploymentReleaseEnvelope, validateProtocolDeploymentReleaseTarget, } from '@hypequery/protocol';
|
|
6
|
+
import { readBoundedFile } from './utils/read-bounded-file.js';
|
|
6
7
|
const ACTIVATION_FILE = 'activation.json';
|
|
7
8
|
const CLAIMS_DIRECTORY = 'claims';
|
|
8
9
|
// Each predecessor has one filesystem slot for its successor. Renaming a
|
|
@@ -242,7 +243,7 @@ async function readRegularFile(filePath, maximumBytes) {
|
|
|
242
243
|
if (!stat.isFile() || stat.size < 1 || stat.size > maximumBytes) {
|
|
243
244
|
throw new Error(`Stored entry is not a bounded regular file: ${filePath}`);
|
|
244
245
|
}
|
|
245
|
-
return await handle
|
|
246
|
+
return await readBoundedFile(handle, maximumBytes, 1, `Stored entry is not a bounded regular file: ${filePath}`);
|
|
246
247
|
}
|
|
247
248
|
finally {
|
|
248
249
|
await handle.close();
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What one principal is allowed to see of a deployment contract.
|
|
3
|
+
*
|
|
4
|
+
* Discovery and execution must agree about who may reach what. The data plane
|
|
5
|
+
* already decides that per call, from the endpoint policy on the target; a
|
|
6
|
+
* gateway listing tools has to make the same decision over the whole contract,
|
|
7
|
+
* before any call exists. Restating the rule there would put an authorization
|
|
8
|
+
* predicate in two packages, and the copy that drifts is the one that leaks.
|
|
9
|
+
*
|
|
10
|
+
* The projection narrows, never widens: it can remove a target a principal may
|
|
11
|
+
* not reach, and can never add one or loosen a policy. Feeding the result to
|
|
12
|
+
* catalog projection or schema compilation therefore cannot advertise something
|
|
13
|
+
* execution would refuse.
|
|
14
|
+
*/
|
|
15
|
+
import type { ProtocolAccessPolicy, ProtocolDeploymentContract, ProtocolEndpointPolicy } from '@hypequery/protocol';
|
|
16
|
+
import type { DeploymentDataPlanePrincipal } from './principal.js';
|
|
17
|
+
/**
|
|
18
|
+
* Whether a principal satisfies an access policy.
|
|
19
|
+
*
|
|
20
|
+
* Shares `missing` with the semantic data plane rather than restating it, which
|
|
21
|
+
* is the whole point of this module existing in Core: one predicate, so
|
|
22
|
+
* discovery cannot come to answer differently than execution.
|
|
23
|
+
*/
|
|
24
|
+
export declare function satisfiesDeploymentAccess(access: ProtocolAccessPolicy, principal: DeploymentDataPlanePrincipal | null): boolean;
|
|
25
|
+
/** Whether a principal may reach a target published under this endpoint policy. */
|
|
26
|
+
export declare function isDeploymentEndpointAuthorized(endpoint: ProtocolEndpointPolicy | undefined, principal: DeploymentDataPlanePrincipal | null): boolean;
|
|
27
|
+
export interface AuthorizedDeploymentProjection {
|
|
28
|
+
/**
|
|
29
|
+
* A valid contract narrowed to what the principal may see, including any
|
|
30
|
+
* dataset retained only to support a join.
|
|
31
|
+
*/
|
|
32
|
+
readonly contract: ProtocolDeploymentContract;
|
|
33
|
+
/**
|
|
34
|
+
* Datasets addressable as a `query_dataset` target, in contract order.
|
|
35
|
+
*
|
|
36
|
+
* Narrower than `contract.datasets`, which also holds datasets retained only
|
|
37
|
+
* to support a join. Always read this before advertising anything: catalog
|
|
38
|
+
* projection and rehydration enumerate every dataset they are given and
|
|
39
|
+
* neither consults an endpoint, so handing them the whole contract would
|
|
40
|
+
* advertise a supporting dataset and disclose its shape to a principal with
|
|
41
|
+
* no access to it.
|
|
42
|
+
*/
|
|
43
|
+
readonly queryable: readonly string[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Projects the contract down to what `principal` may see.
|
|
47
|
+
*
|
|
48
|
+
* A dataset is *published* when the principal may address it directly, and
|
|
49
|
+
* *supporting* when something published still needs it to stay coherent — the
|
|
50
|
+
* target of a relationship. A supporting dataset loses its endpoint and keeps
|
|
51
|
+
* only what a join reaches, so a relationship can still be traversed exactly as
|
|
52
|
+
* execution would traverse it while the dataset itself is not offered as a
|
|
53
|
+
* target.
|
|
54
|
+
*
|
|
55
|
+
* Dropping a relationship target instead would be the tempting alternative and
|
|
56
|
+
* is wrong twice: it would invalidate the relationship that names it, and it
|
|
57
|
+
* would advertise less than the data plane permits, since a one-hop join is
|
|
58
|
+
* governed by the endpoint of the dataset being queried, not by the target's.
|
|
59
|
+
*
|
|
60
|
+
* The contract and the target list are returned separately rather than as one
|
|
61
|
+
* contract because nothing downstream reads an endpoint.
|
|
62
|
+
* `projectAgentSafeCatalog` and `rehydrateProtocolDatasets` enumerate whatever
|
|
63
|
+
* they are handed, so an unpublished dataset left in the contract they see is
|
|
64
|
+
* an advertised one.
|
|
65
|
+
*
|
|
66
|
+
* The contract is revalidated. Callers hand it to catalog projection, schema
|
|
67
|
+
* compilation, and rehydration, all of which assume a valid contract; a
|
|
68
|
+
* projection that could emit an invalid one would move that failure to whatever
|
|
69
|
+
* read it next.
|
|
70
|
+
*/
|
|
71
|
+
export declare function projectAuthorizedDeploymentContract(contract: ProtocolDeploymentContract, principal: DeploymentDataPlanePrincipal | null): AuthorizedDeploymentProjection;
|
|
72
|
+
//# sourceMappingURL=authorized-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorized-contract.d.ts","sourceRoot":"","sources":["../src/authorized-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,oBAAoB,EACpB,0BAA0B,EAE1B,sBAAsB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AAGnE;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,oBAAoB,EAC5B,SAAS,EAAE,4BAA4B,GAAG,IAAI,GAC7C,OAAO,CAIT;AAED,mFAAmF;AACnF,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,sBAAsB,GAAG,SAAS,EAC5C,SAAS,EAAE,4BAA4B,GAAG,IAAI,GAC7C,OAAO,CAKT;AAkCD,MAAM,WAAW,8BAA8B;IAC7C;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,0BAA0B,CAAC;IAC9C;;;;;;;;;OASG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,mCAAmC,CACjD,QAAQ,EAAE,0BAA0B,EACpC,SAAS,EAAE,4BAA4B,GAAG,IAAI,GAC7C,8BAA8B,CA2ChC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What one principal is allowed to see of a deployment contract.
|
|
3
|
+
*
|
|
4
|
+
* Discovery and execution must agree about who may reach what. The data plane
|
|
5
|
+
* already decides that per call, from the endpoint policy on the target; a
|
|
6
|
+
* gateway listing tools has to make the same decision over the whole contract,
|
|
7
|
+
* before any call exists. Restating the rule there would put an authorization
|
|
8
|
+
* predicate in two packages, and the copy that drifts is the one that leaks.
|
|
9
|
+
*
|
|
10
|
+
* The projection narrows, never widens: it can remove a target a principal may
|
|
11
|
+
* not reach, and can never add one or loosen a policy. Feeding the result to
|
|
12
|
+
* catalog projection or schema compilation therefore cannot advertise something
|
|
13
|
+
* execution would refuse.
|
|
14
|
+
*/
|
|
15
|
+
import { validateProtocolDeploymentContract } from '@hypequery/protocol';
|
|
16
|
+
import { missing } from './utils/required-access.js';
|
|
17
|
+
/**
|
|
18
|
+
* Whether a principal satisfies an access policy.
|
|
19
|
+
*
|
|
20
|
+
* Shares `missing` with the semantic data plane rather than restating it, which
|
|
21
|
+
* is the whole point of this module existing in Core: one predicate, so
|
|
22
|
+
* discovery cannot come to answer differently than execution.
|
|
23
|
+
*/
|
|
24
|
+
export function satisfiesDeploymentAccess(access, principal) {
|
|
25
|
+
if (access.kind === 'public')
|
|
26
|
+
return true;
|
|
27
|
+
if (!principal)
|
|
28
|
+
return false;
|
|
29
|
+
return !missing(access.roles, principal.roles) && !missing(access.scopes, principal.scopes);
|
|
30
|
+
}
|
|
31
|
+
/** Whether a principal may reach a target published under this endpoint policy. */
|
|
32
|
+
export function isDeploymentEndpointAuthorized(endpoint, principal) {
|
|
33
|
+
// An absent endpoint is not a permissive one. A contract may describe a
|
|
34
|
+
// dataset it never published, and an unpublished target is unreachable for
|
|
35
|
+
// everyone — which is how the data plane's own target resolution reads it.
|
|
36
|
+
return endpoint !== undefined && satisfiesDeploymentAccess(endpoint.access, principal);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Narrows a dataset retained only to support a join.
|
|
40
|
+
*
|
|
41
|
+
* The principal cannot address this dataset, so advertising it whole would
|
|
42
|
+
* publish the name and type of every dimension, filter, and measure on it.
|
|
43
|
+
* What a join actually reaches is the target's dimensions — `resolveDataset`
|
|
44
|
+
* offers each groupable one as `<relationship>.<name>` and each filterable one
|
|
45
|
+
* under the full operator set — so those stay and everything else goes.
|
|
46
|
+
*
|
|
47
|
+
* A dataset no queryable relationship reaches keeps nothing but its time field,
|
|
48
|
+
* which the planner reads for every grained query. It is retained at all only
|
|
49
|
+
* because a relationship names it and the contract would not validate without
|
|
50
|
+
* it.
|
|
51
|
+
*/
|
|
52
|
+
function narrowToJoin(dataset, reachable) {
|
|
53
|
+
// `defaults` describes how to query the dataset directly, which is exactly
|
|
54
|
+
// what this principal may not do.
|
|
55
|
+
const { defaults: _defaults, endpoint: _endpoint, ...rest } = dataset;
|
|
56
|
+
const timeField = dataset.timeField === undefined ? undefined : String(dataset.timeField);
|
|
57
|
+
return {
|
|
58
|
+
...rest,
|
|
59
|
+
dimensions: reachable
|
|
60
|
+
? dataset.dimensions
|
|
61
|
+
: dataset.dimensions.filter(dimension => String(dimension.name) === timeField),
|
|
62
|
+
measures: [],
|
|
63
|
+
filters: [],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Projects the contract down to what `principal` may see.
|
|
68
|
+
*
|
|
69
|
+
* A dataset is *published* when the principal may address it directly, and
|
|
70
|
+
* *supporting* when something published still needs it to stay coherent — the
|
|
71
|
+
* target of a relationship. A supporting dataset loses its endpoint and keeps
|
|
72
|
+
* only what a join reaches, so a relationship can still be traversed exactly as
|
|
73
|
+
* execution would traverse it while the dataset itself is not offered as a
|
|
74
|
+
* target.
|
|
75
|
+
*
|
|
76
|
+
* Dropping a relationship target instead would be the tempting alternative and
|
|
77
|
+
* is wrong twice: it would invalidate the relationship that names it, and it
|
|
78
|
+
* would advertise less than the data plane permits, since a one-hop join is
|
|
79
|
+
* governed by the endpoint of the dataset being queried, not by the target's.
|
|
80
|
+
*
|
|
81
|
+
* The contract and the target list are returned separately rather than as one
|
|
82
|
+
* contract because nothing downstream reads an endpoint.
|
|
83
|
+
* `projectAgentSafeCatalog` and `rehydrateProtocolDatasets` enumerate whatever
|
|
84
|
+
* they are handed, so an unpublished dataset left in the contract they see is
|
|
85
|
+
* an advertised one.
|
|
86
|
+
*
|
|
87
|
+
* The contract is revalidated. Callers hand it to catalog projection, schema
|
|
88
|
+
* compilation, and rehydration, all of which assume a valid contract; a
|
|
89
|
+
* projection that could emit an invalid one would move that failure to whatever
|
|
90
|
+
* read it next.
|
|
91
|
+
*/
|
|
92
|
+
export function projectAuthorizedDeploymentContract(contract, principal) {
|
|
93
|
+
const byName = new Map(contract.datasets.map(dataset => [String(dataset.name), dataset]));
|
|
94
|
+
const published = new Set(contract.datasets
|
|
95
|
+
.filter(dataset => isDeploymentEndpointAuthorized(dataset.endpoint, principal))
|
|
96
|
+
.map(dataset => String(dataset.name)));
|
|
97
|
+
const required = new Set();
|
|
98
|
+
const require = (name) => {
|
|
99
|
+
if (required.has(name) || !byName.has(name))
|
|
100
|
+
return;
|
|
101
|
+
required.add(name);
|
|
102
|
+
// Transitive: a retained target has relationships of its own, and every
|
|
103
|
+
// target named in the contract has to still be there for it to validate.
|
|
104
|
+
for (const relationship of byName.get(name).relationships) {
|
|
105
|
+
require(String(relationship.target));
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
for (const name of published)
|
|
109
|
+
require(name);
|
|
110
|
+
// What each dataset is reachable *as a join target* for. Reach extends one
|
|
111
|
+
// queryable hop — `resolveDataset` does not recurse — and only from a dataset
|
|
112
|
+
// the principal can address, so a dataset retained purely so the contract
|
|
113
|
+
// validates passes none of it on.
|
|
114
|
+
const reachable = new Set();
|
|
115
|
+
for (const name of published) {
|
|
116
|
+
for (const relationship of byName.get(name).relationships) {
|
|
117
|
+
if (relationship.queryable)
|
|
118
|
+
reachable.add(String(relationship.target));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const datasets = contract.datasets
|
|
122
|
+
.filter(dataset => required.has(String(dataset.name)))
|
|
123
|
+
.map(dataset => (published.has(String(dataset.name))
|
|
124
|
+
? dataset
|
|
125
|
+
: narrowToJoin(dataset, reachable.has(String(dataset.name)))));
|
|
126
|
+
return Object.freeze({
|
|
127
|
+
contract: validateProtocolDeploymentContract({ ...contract, datasets }),
|
|
128
|
+
queryable: Object.freeze(datasets
|
|
129
|
+
.filter(dataset => published.has(String(dataset.name)))
|
|
130
|
+
.map(dataset => String(dataset.name))),
|
|
131
|
+
});
|
|
132
|
+
}
|
package/dist/bundle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"AAQA,OAAO,
|
|
1
|
+
{"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,KAAK,gCAAgC,EACrC,KAAK,0BAA0B,EAChC,MAAM,qBAAqB,CAAC;AAG7B,eAAO,MAAM,0BAA0B,gBAAgB,CAAC;AACxD,eAAO,MAAM,0BAA0B,oBAAoB,CAAC;AAE5D,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,gCAAgC,CAAC;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,0BAA0B,CAAC;CAC/C;AAkID,wBAAsB,sBAAsB,CAC1C,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,wBAAwB,CAAC,CAqEnC"}
|
package/dist/bundle.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import { constants, lstat, open, readdir, } from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS, prepareProtocolDeploymentBundleManifest, prepareProtocolDeploymentContract, } from '@hypequery/protocol';
|
|
5
|
+
import { readBoundedFile } from './utils/read-bounded-file.js';
|
|
5
6
|
export const DEPLOYMENT_BUNDLE_MANIFEST = 'bundle.json';
|
|
6
7
|
export const DEPLOYMENT_BUNDLE_CONTRACT = 'deployment.json';
|
|
7
8
|
const utf8Decoder = new TextDecoder('utf-8', { fatal: true });
|
|
@@ -35,7 +36,7 @@ async function readBoundedRegularFile(root, relativePath, maximum, allowEmpty =
|
|
|
35
36
|
if (stat.size < (allowEmpty ? 0 : 1) || stat.size > maximum) {
|
|
36
37
|
throw new Error(`Bundle entry exceeds its byte limit: ${relativePath}`);
|
|
37
38
|
}
|
|
38
|
-
return await handle
|
|
39
|
+
return await readBoundedFile(handle, maximum, allowEmpty ? 0 : 1, `Bundle entry exceeds its byte limit: ${relativePath}`);
|
|
39
40
|
}
|
|
40
41
|
catch (error) {
|
|
41
42
|
if (errorCode(error) === 'ELOOP') {
|
|
@@ -58,11 +59,11 @@ function expectedDirectories(files) {
|
|
|
58
59
|
return result;
|
|
59
60
|
}
|
|
60
61
|
async function verifyExactEntries(root, manifest) {
|
|
62
|
+
const source = manifest.source;
|
|
61
63
|
const expectedFiles = new Set([
|
|
62
64
|
DEPLOYMENT_BUNDLE_MANIFEST,
|
|
63
65
|
manifest.deployment.path,
|
|
64
|
-
...
|
|
65
|
-
...(manifest.source?.files.map(file => `${manifest.source.root}/${file.path}`) ?? []),
|
|
66
|
+
...(source?.files.map(file => `${source.root}/${file.path}`) ?? []),
|
|
66
67
|
]);
|
|
67
68
|
const expectedDirectoryPaths = expectedDirectories([...expectedFiles]);
|
|
68
69
|
const seenFiles = new Set();
|
|
@@ -116,34 +117,6 @@ function verifyFile(bytes, file) {
|
|
|
116
117
|
throw new Error(`Bundle entry SHA-256 does not match the manifest: ${file.path}`);
|
|
117
118
|
}
|
|
118
119
|
}
|
|
119
|
-
function requireClosedContractArtifactSet(contract) {
|
|
120
|
-
const referenced = new Map();
|
|
121
|
-
for (const query of contract.queries) {
|
|
122
|
-
if (query.implementation.kind === 'runtime-reference') {
|
|
123
|
-
referenced.set(query.implementation.artifactSha256, query.implementation.runtime);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (referenced.size !== contract.artifacts.length) {
|
|
127
|
-
throw new Error('Deployment contract contains missing or unreferenced runtime artifacts.');
|
|
128
|
-
}
|
|
129
|
-
for (const artifact of contract.artifacts) {
|
|
130
|
-
if (referenced.get(artifact.artifactSha256) !== artifact.runtime) {
|
|
131
|
-
throw new Error(`Deployment runtime artifact ${artifact.artifactSha256} is not referenced by a named query.`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
function verifyRuntimeReferences(contract, artifacts) {
|
|
136
|
-
requireClosedContractArtifactSet(contract);
|
|
137
|
-
const declared = new Map(contract.artifacts.map(artifact => [artifact.artifactSha256, artifact.runtime]));
|
|
138
|
-
if (declared.size !== artifacts.length) {
|
|
139
|
-
throw new Error('Bundle runtime artifacts do not match the deployment contract.');
|
|
140
|
-
}
|
|
141
|
-
for (const artifact of artifacts) {
|
|
142
|
-
if (declared.get(artifact.sha256) !== artifact.runtime) {
|
|
143
|
-
throw new Error(`Bundle artifact ${artifact.sha256} does not match a deployment runtime reference.`);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
120
|
export async function verifyDeploymentBundle(bundleDirectory) {
|
|
148
121
|
const root = path.resolve(bundleDirectory);
|
|
149
122
|
const rootStat = await lstat(root);
|
|
@@ -160,6 +133,9 @@ export async function verifyDeploymentBundle(bundleDirectory) {
|
|
|
160
133
|
+ (error instanceof Error ? error.message : String(error)));
|
|
161
134
|
}
|
|
162
135
|
const preparedManifest = prepareProtocolDeploymentBundleManifest(input);
|
|
136
|
+
if (preparedManifest.manifest.artifacts.length > 0) {
|
|
137
|
+
throw new Error('A deployment bundle cannot contain runtime artifacts.');
|
|
138
|
+
}
|
|
163
139
|
const expectedManifestBytes = utf8Encoder.encode(`${preparedManifest.canonical}\n`);
|
|
164
140
|
if (!Buffer.from(manifestBytes).equals(Buffer.from(expectedManifestBytes))) {
|
|
165
141
|
throw new Error('Deployment bundle manifest must contain canonical JSON followed by one newline.');
|
|
@@ -177,13 +153,12 @@ export async function verifyDeploymentBundle(bundleDirectory) {
|
|
|
177
153
|
+ (error instanceof Error ? error.message : String(error)));
|
|
178
154
|
}
|
|
179
155
|
const preparedContract = prepareProtocolDeploymentContract(contractInput);
|
|
156
|
+
if (!Buffer.from(deploymentBytes).equals(Buffer.from(`${preparedContract.canonical}\n`))) {
|
|
157
|
+
throw new Error('Deployment JSON must contain canonical JSON followed by one newline.');
|
|
158
|
+
}
|
|
180
159
|
if (preparedContract.identity !== deployment.identity) {
|
|
181
160
|
throw new Error('Deployment identity does not match the bundle manifest.');
|
|
182
161
|
}
|
|
183
|
-
for (const artifact of preparedManifest.manifest.artifacts) {
|
|
184
|
-
const bytes = await readBoundedRegularFile(root, artifact.path, DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS.maxArtifactBytes);
|
|
185
|
-
verifyFile(bytes, artifact);
|
|
186
|
-
}
|
|
187
162
|
const source = preparedManifest.manifest.source;
|
|
188
163
|
if (source) {
|
|
189
164
|
for (const file of source.files) {
|
|
@@ -192,7 +167,6 @@ export async function verifyDeploymentBundle(bundleDirectory) {
|
|
|
192
167
|
verifyFile(bytes, { ...file, path: bundlePath });
|
|
193
168
|
}
|
|
194
169
|
}
|
|
195
|
-
verifyRuntimeReferences(preparedContract.contract, preparedManifest.manifest.artifacts);
|
|
196
170
|
return Object.freeze({
|
|
197
171
|
directory: root,
|
|
198
172
|
manifest: preparedManifest.manifest,
|
|
@@ -10,7 +10,7 @@ export function resolveDeploymentControlPlaneLimits(input = {}) {
|
|
|
10
10
|
continue;
|
|
11
11
|
if (!Number.isSafeInteger(value) || value < 1
|
|
12
12
|
|| value > DEFAULT_DEPLOYMENT_CONTROL_PLANE_LIMITS[key]) {
|
|
13
|
-
throw new RangeError(`${key} must be a positive safe integer no greater than the control-plane
|
|
13
|
+
throw new RangeError(`${key} must be a positive safe integer no greater than the control-plane safety ceiling`);
|
|
14
14
|
}
|
|
15
15
|
limits[key] = value;
|
|
16
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem-store.d.ts","sourceRoot":"","sources":["../src/filesystem-store.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,iCAAiC,EACvC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"filesystem-store.d.ts","sourceRoot":"","sources":["../src/filesystem-store.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,iCAAiC,EACvC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,YAAY,CAAC;AAUpB,MAAM,MAAM,kCAAkC,GAC1C,mCAAmC,GACnC,wCAAwC,GACxC,mCAAmC,GACnC,wBAAwB,CAAC;AAE7B,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,QAAQ,CAAC,IAAI,EAAE,kCAAkC,CAAC;gBAGhD,IAAI,EAAE,kCAAkC,EACxC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAM7C;AAED,MAAM,WAAW,0CAA0C;IACzD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,iCAAiC,CAAC;IACpD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;CAC3C;AAED,MAAM,WAAW,mCAAmC,CAAC,SAAS,CAC5D,SAAQ,yBAAyB,CAAC,SAAS,CAAC;IAC5C,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC,CAAC;CAChF;AAkaD,wBAAgB,yCAAyC,CAAC,SAAS,GAAG,OAAO,EAC3E,OAAO,EAAE,0CAA0C,GAClD,mCAAmC,CAAC,SAAS,CAAC,CAkHhD"}
|
package/dist/filesystem-store.js
CHANGED
|
@@ -3,6 +3,7 @@ import { lstat, mkdir, mkdtemp, open, readdir, rename, rm, } from 'node:fs/promi
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { prepareProtocolDeploymentReleaseEnvelope, } from '@hypequery/protocol';
|
|
5
5
|
import { DEPLOYMENT_BUNDLE_MANIFEST, verifyDeploymentBundle, } from './bundle.js';
|
|
6
|
+
import { readBoundedFile } from './utils/read-bounded-file.js';
|
|
6
7
|
const RELEASE_FILE = 'release.json';
|
|
7
8
|
const MAX_MANIFEST_BYTES = 1024 * 1024;
|
|
8
9
|
const MAX_RELEASE_BYTES = 16 * 1024;
|
|
@@ -148,16 +149,17 @@ async function copyRegularFile(sourcePath, destinationPath, maximumBytes, expect
|
|
|
148
149
|
}
|
|
149
150
|
}
|
|
150
151
|
function bundleFilePaths(bundle) {
|
|
152
|
+
const source = bundle.manifest.source;
|
|
151
153
|
return Object.freeze([
|
|
152
154
|
{ path: DEPLOYMENT_BUNDLE_MANIFEST },
|
|
153
155
|
{
|
|
154
156
|
path: bundle.manifest.deployment.path,
|
|
155
157
|
byteLength: bundle.manifest.deployment.byteLength,
|
|
156
158
|
},
|
|
157
|
-
...
|
|
158
|
-
path:
|
|
159
|
-
byteLength:
|
|
160
|
-
})),
|
|
159
|
+
...(source?.files.map(file => ({
|
|
160
|
+
path: `${source.root}/${file.path}`,
|
|
161
|
+
byteLength: file.byteLength,
|
|
162
|
+
})) ?? []),
|
|
161
163
|
]);
|
|
162
164
|
}
|
|
163
165
|
async function syncBundleDirectories(bundleRoot, files) {
|
|
@@ -205,24 +207,7 @@ async function readRegularFile(filePath, maximumBytes) {
|
|
|
205
207
|
if (!stat.isFile() || stat.size < 1 || stat.size > maximumBytes) {
|
|
206
208
|
throw new Error(`Stored entry is not a bounded regular file: ${filePath}`);
|
|
207
209
|
}
|
|
208
|
-
|
|
209
|
-
const chunks = [];
|
|
210
|
-
let total = 0;
|
|
211
|
-
while (total <= maximumBytes) {
|
|
212
|
-
const remaining = maximumBytes + 1 - total;
|
|
213
|
-
const { bytesRead } = await handle.read(buffer, 0, Math.min(buffer.byteLength, remaining), null);
|
|
214
|
-
if (bytesRead === 0)
|
|
215
|
-
break;
|
|
216
|
-
total += bytesRead;
|
|
217
|
-
if (total > maximumBytes) {
|
|
218
|
-
throw new Error(`Stored entry is not a bounded regular file: ${filePath}`);
|
|
219
|
-
}
|
|
220
|
-
chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
|
|
221
|
-
}
|
|
222
|
-
if (total < 1) {
|
|
223
|
-
throw new Error(`Stored entry is not a bounded regular file: ${filePath}`);
|
|
224
|
-
}
|
|
225
|
-
return Buffer.concat(chunks, total);
|
|
210
|
+
return await readBoundedFile(handle, maximumBytes, 1, `Stored entry is not a bounded regular file: ${filePath}`);
|
|
226
211
|
}
|
|
227
212
|
finally {
|
|
228
213
|
await handle.close();
|
package/dist/index.d.ts
CHANGED
|
@@ -15,23 +15,11 @@ export { DEFAULT_DEPLOYMENT_CONTROL_PLANE_LIMITS, resolveDeploymentControlPlaneL
|
|
|
15
15
|
export type { DeploymentControlPlaneLimits } from './control-plane-limits.js';
|
|
16
16
|
export { DEFAULT_DEPLOYMENT_INTAKE_LIMITS, resolveDeploymentIntakeLimits, } from './limits.js';
|
|
17
17
|
export type { DeploymentIntakeLimits } from './limits.js';
|
|
18
|
-
export { createNodeWorkerDeploymentRuntimeFactory, NodeDeploymentRuntimeError, } from './node-runtime-factory.js';
|
|
19
|
-
export type { NodeDeploymentRuntimeEnvironment, NodeDeploymentRuntimeEnvironmentResolver, NodeDeploymentRuntimeErrorCode, NodeDeploymentRuntimeFactoryOptions, } from './node-runtime-factory.js';
|
|
20
|
-
export { createDeploymentRuntimeMaterializer, DeploymentRuntimeMaterializationError, } from './runtime-materialization.js';
|
|
21
|
-
export type { DeploymentRuntimeArtifactSnapshot, DeploymentRuntimeMaterializationErrorCode, DeploymentRuntimeMaterializer, DeploymentRuntimeMaterializerOptions, DeploymentRuntimeQueryBinding, DeploymentRuntimeRelease, DeploymentRuntimeReleaseReader, DeploymentRuntimeSnapshot, } from './runtime-materialization.js';
|
|
22
|
-
export { createDeploymentRuntimeSupervisor, DeploymentRuntimeSupervisorError, } from './runtime-supervisor.js';
|
|
23
|
-
export type { DeploymentRuntimeFactory, DeploymentRuntimeGeneration, DeploymentRuntimeInstance, DeploymentRuntimeInstanceInvocation, DeploymentRuntimeInvocation, DeploymentRuntimeReconcileResult, DeploymentRuntimeStatus, DeploymentRuntimeSupervisor, DeploymentRuntimeSupervisorErrorCode, DeploymentRuntimeSupervisorOptions, } from './runtime-supervisor.js';
|
|
24
18
|
export type { DeploymentAuthenticationInput, DeploymentAuthenticator, DeploymentAuthorizationInput, DeploymentAuthorizer, DeploymentIntake, DeploymentIntakeOptions, DeploymentIntakeRequest, DeploymentIntakeResponse, DeploymentSubmissionResponse, DeploymentSubmissionStore, VerifiedDeploymentSubmission, } from './types.js';
|
|
25
|
-
export {
|
|
26
|
-
export
|
|
27
|
-
export {
|
|
28
|
-
export
|
|
29
|
-
export {
|
|
30
|
-
export
|
|
31
|
-
export { createDeploymentDataPlaneFetchHandler, createDeploymentDataPlaneNodeHandler, } from './data-plane-adapters.js';
|
|
32
|
-
export type { DeploymentDataPlaneAdapterOptions, DeploymentDataPlaneAdapterRequest, DeploymentDataPlaneFetchHandler, DeploymentDataPlaneNodeHandler, } from './data-plane-adapters.js';
|
|
33
|
-
export { createDeploymentHost, DeploymentHostError, } from './host.js';
|
|
34
|
-
export { createFileSystemDeploymentHost } from './filesystem-host.js';
|
|
35
|
-
export type { FileSystemDeploymentHost, FileSystemDeploymentHostOptions, } from './filesystem-host.js';
|
|
36
|
-
export type { DeploymentHost, DeploymentHostDataPlaneConfiguration, DeploymentHostDataPlaneInput, DeploymentHostErrorCode, DeploymentHostOptions, } from './host.js';
|
|
19
|
+
export type { DeploymentDataPlanePrincipal } from './principal.js';
|
|
20
|
+
export { createDeploymentSemanticDataPlane, DeploymentSemanticInvocationError, toProtocolSemanticInvocationFailure, } from './semantic-data-plane.js';
|
|
21
|
+
export type { DeploymentSemanticAuthenticationInput, DeploymentSemanticBudget, DeploymentSemanticDataPlane, DeploymentSemanticDataPlaneOptions, DeploymentSemanticExecutionInput, DeploymentSemanticInvocationRequest, DeploymentSemanticTenantInput, } from './semantic-data-plane.js';
|
|
22
|
+
export { validateSemanticOperation } from './semantic-operation-validation.js';
|
|
23
|
+
export type { SemanticOperationLimits, SemanticOperationViolation, } from './semantic-operation-validation.js';
|
|
24
|
+
export { isDeploymentEndpointAuthorized, projectAuthorizedDeploymentContract, satisfiesDeploymentAccess, } from './authorized-contract.js';
|
|
37
25
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4CAA4C,EAC5C,yBAAyB,EACzB,kCAAkC,GACnC,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,6BAA6B,EAC7B,+BAA+B,EAC/B,gCAAgC,EAChC,4BAA4B,EAC5B,2BAA2B,EAC3B,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,EAC1B,uBAAuB,EACvB,6CAA6C,GAC9C,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,yCAAyC,EACzC,8BAA8B,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,kCAAkC,EAClC,mCAAmC,EACnC,0CAA0C,EAC1C,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,wCAAwC,EACxC,uCAAuC,GACxC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,kCAAkC,EAClC,iCAAiC,GAClC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,4BAA4B,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,sBAAsB,EACtB,4BAA4B,EAC5B,wCAAwC,EACxC,gCAAgC,EAChC,+BAA+B,EAC/B,6BAA6B,EAC7B,6BAA6B,EAC7B,8BAA8B,GAC/B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,uCAAuC,EACvC,mCAAmC,GACpC,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EACL,gCAAgC,EAChC,6BAA6B,GAC9B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4CAA4C,EAC5C,yBAAyB,EACzB,kCAAkC,GACnC,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,6BAA6B,EAC7B,+BAA+B,EAC/B,gCAAgC,EAChC,4BAA4B,EAC5B,2BAA2B,EAC3B,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,EAC1B,uBAAuB,EACvB,6CAA6C,GAC9C,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,yCAAyC,EACzC,8BAA8B,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,kCAAkC,EAClC,mCAAmC,EACnC,0CAA0C,EAC1C,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,wCAAwC,EACxC,uCAAuC,GACxC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,kCAAkC,EAClC,iCAAiC,GAClC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,4BAA4B,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,sBAAsB,EACtB,4BAA4B,EAC5B,wCAAwC,EACxC,gCAAgC,EAChC,+BAA+B,EAC/B,6BAA6B,EAC7B,6BAA6B,EAC7B,8BAA8B,GAC/B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,uCAAuC,EACvC,mCAAmC,GACpC,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EACL,gCAAgC,EAChC,6BAA6B,GAC9B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,YAAY,EACV,6BAA6B,EAC7B,uBAAuB,EACvB,4BAA4B,EAC5B,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,4BAA4B,EAC5B,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,EACL,iCAAiC,EACjC,iCAAiC,EACjC,mCAAmC,GACpC,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,qCAAqC,EACrC,wBAAwB,EACxB,2BAA2B,EAC3B,kCAAkC,EAClC,gCAAgC,EAChC,mCAAmC,EACnC,6BAA6B,GAC9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,YAAY,EACV,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,oCAAoC,CAAC;AAI5C,OAAO,EACL,8BAA8B,EAC9B,mCAAmC,EACnC,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,12 +7,8 @@ export { createDeploymentControlPlaneFetchHandler, createDeploymentControlPlaneN
|
|
|
7
7
|
export { createDeploymentControlPlane, } from './control-plane.js';
|
|
8
8
|
export { DEFAULT_DEPLOYMENT_CONTROL_PLANE_LIMITS, resolveDeploymentControlPlaneLimits, } from './control-plane-limits.js';
|
|
9
9
|
export { DEFAULT_DEPLOYMENT_INTAKE_LIMITS, resolveDeploymentIntakeLimits, } from './limits.js';
|
|
10
|
-
export {
|
|
11
|
-
export {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
export { createDeploymentRuntimeSupervisorExecutor } from './data-plane-runtime.js';
|
|
16
|
-
export { createDeploymentDataPlaneFetchHandler, createDeploymentDataPlaneNodeHandler, } from './data-plane-adapters.js';
|
|
17
|
-
export { createDeploymentHost, DeploymentHostError, } from './host.js';
|
|
18
|
-
export { createFileSystemDeploymentHost } from './filesystem-host.js';
|
|
10
|
+
export { createDeploymentSemanticDataPlane, DeploymentSemanticInvocationError, toProtocolSemanticInvocationFailure, } from './semantic-data-plane.js';
|
|
11
|
+
export { validateSemanticOperation } from './semantic-operation-validation.js';
|
|
12
|
+
// What one principal may see of a contract, for a gateway listing targets
|
|
13
|
+
// before any call exists (decision 0002, CLOUD-03).
|
|
14
|
+
export { isDeploymentEndpointAuthorized, projectAuthorizedDeploymentContract, satisfiesDeploymentAccess, } from './authorized-contract.js';
|
package/dist/intake.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intake.d.ts","sourceRoot":"","sources":["../src/intake.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EAIxB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"intake.d.ts","sourceRoot":"","sources":["../src/intake.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EAIxB,MAAM,YAAY,CAAC;AAwSpB,wBAAgB,sBAAsB,CAAC,SAAS,EAC9C,OAAO,EAAE,uBAAuB,CAAC,SAAS,CAAC,GAC1C,gBAAgB,CAiIlB"}
|
package/dist/intake.js
CHANGED
|
@@ -85,10 +85,10 @@ function decodeJson(bytes, description) {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
function requireReconstructablePaths(manifest) {
|
|
88
|
+
const source = manifest.manifest.source;
|
|
88
89
|
const files = [
|
|
89
90
|
manifest.manifest.deployment.path,
|
|
90
|
-
...
|
|
91
|
-
...(manifest.manifest.source?.files.map(file => `${manifest.manifest.source.root}/${file.path}`) ?? []),
|
|
91
|
+
...(source?.files.map(file => `${source.root}/${file.path}`) ?? []),
|
|
92
92
|
];
|
|
93
93
|
const fileSet = new Set(files);
|
|
94
94
|
if (fileSet.has(DEPLOYMENT_BUNDLE_MANIFEST)) {
|
|
@@ -149,6 +149,9 @@ async function readManifest(reader, maximum) {
|
|
|
149
149
|
throw error;
|
|
150
150
|
throw badRequest('The deployment bundle manifest is invalid.', error);
|
|
151
151
|
}
|
|
152
|
+
if (prepared.manifest.artifacts.length > 0) {
|
|
153
|
+
throw badRequest('A deployment bundle cannot contain runtime artifacts.');
|
|
154
|
+
}
|
|
152
155
|
const canonical = Buffer.from(`${prepared.canonical}\n`);
|
|
153
156
|
if (!part.bytes.equals(canonical)) {
|
|
154
157
|
throw badRequest('The deployment bundle manifest must use canonical JSON followed by one newline.');
|
|
@@ -282,12 +285,12 @@ export function createDeploymentIntake(options) {
|
|
|
282
285
|
const bundleRoot = path.join(temporaryRoot, 'bundle');
|
|
283
286
|
await mkdir(bundleRoot);
|
|
284
287
|
await writeFile(path.join(bundleRoot, DEPLOYMENT_BUNDLE_MANIFEST), manifest.bytes, { flag: 'wx' });
|
|
288
|
+
const source = manifest.prepared.manifest.source;
|
|
285
289
|
const files = [
|
|
286
290
|
manifest.prepared.manifest.deployment,
|
|
287
|
-
...
|
|
288
|
-
...(manifest.prepared.manifest.source?.files.map(file => ({
|
|
291
|
+
...(source?.files.map(file => ({
|
|
289
292
|
...file,
|
|
290
|
-
path: `${
|
|
293
|
+
path: `${source.root}/${file.path}`,
|
|
291
294
|
})) ?? []),
|
|
292
295
|
];
|
|
293
296
|
for (let index = 0; index < files.length; index += 1) {
|
package/dist/limits.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AAED,eAAO,MAAM,gCAAgC,EAAE,QAAQ,CAAC,sBAAsB,
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AAED,eAAO,MAAM,gCAAgC,EAAE,QAAQ,CAAC,sBAAsB,CAQ5E,CAAC;AAEH,wBAAgB,6BAA6B,CAC3C,KAAK,GAAE,OAAO,CAAC,sBAAsB,CAAM,GAC1C,QAAQ,CAAC,sBAAsB,CAAC,CAelC"}
|
package/dist/limits.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS } from '@hypequery/protocol';
|
|
2
2
|
export const DEFAULT_DEPLOYMENT_INTAKE_LIMITS = Object.freeze({
|
|
3
|
-
|
|
3
|
+
// Source and deployment bytes, plus the manifest and headers for up to 1,000 files.
|
|
4
|
+
maxRequestBytes: DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS.maxDeploymentBytes
|
|
5
|
+
+ DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS.maxSourceBytes
|
|
6
|
+
+ (10 * 1024 * 1024),
|
|
4
7
|
maxReleaseBytes: 16 * 1024,
|
|
5
8
|
maxManifestBytes: 1024 * 1024,
|
|
6
9
|
maxPartHeaderBytes: 8 * 1024,
|
|
@@ -14,7 +17,7 @@ export function resolveDeploymentIntakeLimits(input = {}) {
|
|
|
14
17
|
if (!Number.isSafeInteger(value) || value < 1
|
|
15
18
|
|| value > DEFAULT_DEPLOYMENT_INTAKE_LIMITS[key]) {
|
|
16
19
|
throw new RangeError(`${key} must be a positive safe integer no greater than `
|
|
17
|
-
+ `${DEFAULT_DEPLOYMENT_INTAKE_LIMITS[key]} (the deployment intake
|
|
20
|
+
+ `${DEFAULT_DEPLOYMENT_INTAKE_LIMITS[key]} (the deployment intake safety ceiling)`);
|
|
18
21
|
}
|
|
19
22
|
result[key] = value;
|
|
20
23
|
}
|