@hypequery/protocol 0.9.0 → 0.10.1
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 +1 -1
- package/dist/bundles/index.d.ts +1 -1
- package/dist/bundles/index.d.ts.map +1 -1
- package/dist/bundles/limits.d.ts.map +1 -1
- package/dist/bundles/limits.js +3 -0
- package/dist/bundles/types.d.ts +19 -0
- package/dist/bundles/types.d.ts.map +1 -1
- package/dist/bundles/validate.d.ts.map +1 -1
- package/dist/bundles/validate.js +109 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ authentication or tenancy, or contain CLI, HTTP, UI, and Cloud operations.
|
|
|
29
29
|
|
|
30
30
|
Self-hosted Serve continues to run project source directly. Deployment bundles
|
|
31
31
|
are required only by Cloud deployment and may be generated ephemerally for
|
|
32
|
-
|
|
32
|
+
local compatibility and security diagnostics.
|
|
33
33
|
|
|
34
34
|
## Public API
|
|
35
35
|
|
package/dist/bundles/index.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export { PROTOCOL_DEPLOYMENT_BUNDLE_IDENTITY_DOMAIN, encodeProtocolDeploymentBun
|
|
|
3
3
|
export type { PreparedProtocolDeploymentBundleManifest } from './codec.js';
|
|
4
4
|
export { DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS } from './limits.js';
|
|
5
5
|
export { validateProtocolDeploymentBundleManifest } from './validate.js';
|
|
6
|
-
export type { ProtocolDeploymentBundleArtifact, ProtocolDeploymentBundleDeployment, ProtocolDeploymentBundleErrorCode, ProtocolDeploymentBundleFile, ProtocolDeploymentBundleLimits, ProtocolDeploymentBundleManifest, ProtocolDeploymentBundleOptions, } from './types.js';
|
|
6
|
+
export type { ProtocolDeploymentBundleArtifact, ProtocolDeploymentBundleDeployment, ProtocolDeploymentBundleErrorCode, ProtocolDeploymentBundleFile, ProtocolDeploymentBundleLimits, ProtocolDeploymentBundleManifest, ProtocolDeploymentBundleOptions, ProtocolDeploymentBundleSource, ProtocolDeploymentBundleSourceRevision, } from './types.js';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bundles/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,0CAA0C,EAC1C,sCAAsC,EACtC,8CAA8C,EAC9C,oCAAoC,EACpC,uCAAuC,GACxC,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,wCAAwC,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,yCAAyC,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,wCAAwC,EAAE,MAAM,eAAe,CAAC;AACzE,YAAY,EACV,gCAAgC,EAChC,kCAAkC,EAClC,iCAAiC,EACjC,4BAA4B,EAC5B,8BAA8B,EAC9B,gCAAgC,EAChC,+BAA+B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bundles/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,0CAA0C,EAC1C,sCAAsC,EACtC,8CAA8C,EAC9C,oCAAoC,EACpC,uCAAuC,GACxC,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,wCAAwC,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,yCAAyC,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,wCAAwC,EAAE,MAAM,eAAe,CAAC;AACzE,YAAY,EACV,gCAAgC,EAChC,kCAAkC,EAClC,iCAAiC,EACjC,4BAA4B,EAC5B,8BAA8B,EAC9B,gCAAgC,EAChC,+BAA+B,EAC/B,8BAA8B,EAC9B,sCAAsC,GACvC,MAAM,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/bundles/limits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,+BAA+B,EAChC,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,yCAAyC,EACtD,QAAQ,CAAC,8BAA8B,
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/bundles/limits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,+BAA+B,EAChC,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,yCAAyC,EACtD,QAAQ,CAAC,8BAA8B,CASrC,CAAC;AAEH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,+BAAoC,GAC5C,QAAQ,CAAC,8BAA8B,CAAC,CAe1C"}
|
package/dist/bundles/limits.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export const DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS = Object.freeze({
|
|
2
2
|
maxArtifacts: 100,
|
|
3
|
+
maxSourceFiles: 1_000,
|
|
3
4
|
maxPathBytes: 1_024,
|
|
4
5
|
maxDeploymentBytes: 16 * 1_024 * 1_024,
|
|
5
6
|
maxArtifactBytes: 128 * 1_024 * 1_024,
|
|
7
|
+
maxSourceFileBytes: 2 * 1_024 * 1_024,
|
|
8
|
+
maxSourceBytes: 32 * 1_024 * 1_024,
|
|
6
9
|
maxTotalBytes: 256 * 1_024 * 1_024,
|
|
7
10
|
});
|
|
8
11
|
export function resolveDeploymentBundleLimits(options = {}) {
|
package/dist/bundles/types.d.ts
CHANGED
|
@@ -9,17 +9,36 @@ export interface ProtocolDeploymentBundleDeployment extends ProtocolDeploymentBu
|
|
|
9
9
|
export interface ProtocolDeploymentBundleArtifact extends ProtocolDeploymentBundleFile {
|
|
10
10
|
readonly runtime: 'node' | 'python';
|
|
11
11
|
}
|
|
12
|
+
export interface ProtocolDeploymentBundleSourceRevision {
|
|
13
|
+
readonly kind: 'git';
|
|
14
|
+
readonly commit: string;
|
|
15
|
+
readonly dirty: boolean;
|
|
16
|
+
/** Checked-out branch at build time; absent for detached HEADs. */
|
|
17
|
+
readonly branch?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ProtocolDeploymentBundleSource {
|
|
20
|
+
/** Directory within the closed bundle that contains project-relative source files. */
|
|
21
|
+
readonly root: string;
|
|
22
|
+
/** Project-relative API module used to build the deployment. */
|
|
23
|
+
readonly entrypoint: string;
|
|
24
|
+
readonly files: readonly ProtocolDeploymentBundleFile[];
|
|
25
|
+
readonly revision?: ProtocolDeploymentBundleSourceRevision;
|
|
26
|
+
}
|
|
12
27
|
export interface ProtocolDeploymentBundleManifest {
|
|
13
28
|
readonly kind: 'hypequery-deployment-bundle';
|
|
14
29
|
readonly version: 1;
|
|
15
30
|
readonly deployment: ProtocolDeploymentBundleDeployment;
|
|
16
31
|
readonly artifacts: readonly ProtocolDeploymentBundleArtifact[];
|
|
32
|
+
readonly source?: ProtocolDeploymentBundleSource;
|
|
17
33
|
}
|
|
18
34
|
export interface ProtocolDeploymentBundleLimits {
|
|
19
35
|
readonly maxArtifacts: number;
|
|
36
|
+
readonly maxSourceFiles: number;
|
|
20
37
|
readonly maxPathBytes: number;
|
|
21
38
|
readonly maxDeploymentBytes: number;
|
|
22
39
|
readonly maxArtifactBytes: number;
|
|
40
|
+
readonly maxSourceFileBytes: number;
|
|
41
|
+
readonly maxSourceBytes: number;
|
|
23
42
|
readonly maxTotalBytes: number;
|
|
24
43
|
}
|
|
25
44
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/bundles/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,kCAAmC,SAAQ,4BAA4B;IACtF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gCAAiC,SAAQ,4BAA4B;IACpF,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAAC;CACrC;AAED,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,kCAAkC,CAAC;IACxD,QAAQ,CAAC,SAAS,EAAE,SAAS,gCAAgC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/bundles/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,kCAAmC,SAAQ,4BAA4B;IACtF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gCAAiC,SAAQ,4BAA4B;IACpF,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAAC;CACrC;AAED,MAAM,WAAW,sCAAsC;IACrD,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,mEAAmE;IACnE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,8BAA8B;IAC7C,sFAAsF;IACtF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,4BAA4B,EAAE,CAAC;IACxD,QAAQ,CAAC,QAAQ,CAAC,EAAE,sCAAsC,CAAC;CAC5D;AAED,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,kCAAkC,CAAC;IACxD,QAAQ,CAAC,SAAS,EAAE,SAAS,gCAAgC,EAAE,CAAC;IAChE,QAAQ,CAAC,MAAM,CAAC,EAAE,8BAA8B,CAAC;CAClD;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED;;;;;GAKG;AACH,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,8BAA8B,CAAC,CAAC;CAC3D;AAED,MAAM,MAAM,iCAAiC,GACzC,gBAAgB,GAChB,yBAAyB,GACzB,2BAA2B,GAC3B,yBAAyB,GACzB,wBAAwB,GACxB,6BAA6B,GAC7B,0BAA0B,GAC1B,qBAAqB,GACrB,yBAAyB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/bundles/validate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAIV,gCAAgC,EAChC,+BAA+B,
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/bundles/validate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAIV,gCAAgC,EAChC,+BAA+B,EAGhC,MAAM,YAAY,CAAC;AAmPpB,wBAAgB,wCAAwC,CACtD,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,+BAAoC,GAC5C,gCAAgC,CA+ClC"}
|
package/dist/bundles/validate.js
CHANGED
|
@@ -2,6 +2,7 @@ import { bundleError } from './errors.js';
|
|
|
2
2
|
import { resolveDeploymentBundleLimits } from './limits.js';
|
|
3
3
|
const textEncoder = new TextEncoder();
|
|
4
4
|
const SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
5
|
+
const GIT_COMMIT_PATTERN = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
|
5
6
|
const PATH_SEGMENT_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
6
7
|
const WINDOWS_RESERVED_NAME = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\.|$)/i;
|
|
7
8
|
function requireRecord(input, path) {
|
|
@@ -44,8 +45,8 @@ function requireArray(input, path, maxItems) {
|
|
|
44
45
|
}
|
|
45
46
|
return input;
|
|
46
47
|
}
|
|
47
|
-
function exactFields(value, required, path) {
|
|
48
|
-
const allowed = new Set(required);
|
|
48
|
+
function exactFields(value, required, path, optional = []) {
|
|
49
|
+
const allowed = new Set([...required, ...optional]);
|
|
49
50
|
for (const key of Object.keys(value)) {
|
|
50
51
|
if (!allowed.has(key))
|
|
51
52
|
bundleError('HQ_BUNDLE_UNKNOWN_FIELD', `${path}.${key}`);
|
|
@@ -65,8 +66,8 @@ function digest(value, path) {
|
|
|
65
66
|
bundleError('HQ_BUNDLE_INVALID_VALUE', path);
|
|
66
67
|
return value;
|
|
67
68
|
}
|
|
68
|
-
function byteLength(value, path, maximum) {
|
|
69
|
-
if (!Number.isSafeInteger(value) || value < 1) {
|
|
69
|
+
function byteLength(value, path, maximum, allowEmpty = false) {
|
|
70
|
+
if (!Number.isSafeInteger(value) || value < (allowEmpty ? 0 : 1)) {
|
|
70
71
|
bundleError('HQ_BUNDLE_INVALID_VALUE', path);
|
|
71
72
|
}
|
|
72
73
|
if (value > maximum)
|
|
@@ -112,10 +113,102 @@ function validateArtifact(input, path, limits) {
|
|
|
112
113
|
byteLength: byteLength(value.byteLength, `${path}.byteLength`, limits.maxArtifactBytes),
|
|
113
114
|
});
|
|
114
115
|
}
|
|
116
|
+
function validateSourceRevision(input, path, limits) {
|
|
117
|
+
const value = requireRecord(input, path);
|
|
118
|
+
exactFields(value, ['kind', 'commit', 'dirty'], path, ['branch']);
|
|
119
|
+
if (value.kind !== 'git') {
|
|
120
|
+
if (typeof value.kind !== 'string')
|
|
121
|
+
bundleError('HQ_BUNDLE_TYPE', `${path}.kind`);
|
|
122
|
+
bundleError('HQ_BUNDLE_INVALID_VALUE', `${path}.kind`);
|
|
123
|
+
}
|
|
124
|
+
if (typeof value.commit !== 'string')
|
|
125
|
+
bundleError('HQ_BUNDLE_TYPE', `${path}.commit`);
|
|
126
|
+
if (!GIT_COMMIT_PATTERN.test(value.commit)) {
|
|
127
|
+
bundleError('HQ_BUNDLE_INVALID_VALUE', `${path}.commit`);
|
|
128
|
+
}
|
|
129
|
+
if (typeof value.dirty !== 'boolean')
|
|
130
|
+
bundleError('HQ_BUNDLE_TYPE', `${path}.dirty`);
|
|
131
|
+
let branch;
|
|
132
|
+
if (value.branch !== undefined) {
|
|
133
|
+
if (typeof value.branch !== 'string')
|
|
134
|
+
bundleError('HQ_BUNDLE_TYPE', `${path}.branch`);
|
|
135
|
+
if (textEncoder.encode(value.branch).byteLength > limits.maxPathBytes) {
|
|
136
|
+
bundleError('HQ_BUNDLE_TOO_LARGE', `${path}.branch`);
|
|
137
|
+
}
|
|
138
|
+
const invalidCharacter = [...value.branch].some(character => {
|
|
139
|
+
const code = character.charCodeAt(0);
|
|
140
|
+
return code <= 0x20 || code === 0x7f || '~^:?*[\\'.includes(character);
|
|
141
|
+
});
|
|
142
|
+
const segments = value.branch.split('/');
|
|
143
|
+
if (!value.branch || value.branch === '@' || value.branch.startsWith('-')
|
|
144
|
+
|| value.branch.startsWith('/') || value.branch.endsWith('/')
|
|
145
|
+
|| value.branch.endsWith('.') || value.branch.includes('//')
|
|
146
|
+
|| value.branch.includes('..') || value.branch.includes('@{')
|
|
147
|
+
|| invalidCharacter
|
|
148
|
+
|| segments.some(segment => segment.startsWith('.') || segment.endsWith('.lock'))) {
|
|
149
|
+
bundleError('HQ_BUNDLE_INVALID_VALUE', `${path}.branch`);
|
|
150
|
+
}
|
|
151
|
+
branch = value.branch;
|
|
152
|
+
}
|
|
153
|
+
return freezeRecord({
|
|
154
|
+
kind: 'git',
|
|
155
|
+
commit: value.commit,
|
|
156
|
+
dirty: value.dirty,
|
|
157
|
+
...(branch ? { branch } : {}),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
function validateSource(input, path, limits) {
|
|
161
|
+
const value = requireRecord(input, path);
|
|
162
|
+
exactFields(value, ['root', 'entrypoint', 'files'], path, ['revision']);
|
|
163
|
+
const root = relativePath(value.root, `${path}.root`, limits.maxPathBytes);
|
|
164
|
+
const entrypoint = relativePath(value.entrypoint, `${path}.entrypoint`, limits.maxPathBytes);
|
|
165
|
+
const files = Object.freeze(requireArray(value.files, `${path}.files`, limits.maxSourceFiles)
|
|
166
|
+
.map((inputFile, index) => {
|
|
167
|
+
const filePath = `${path}.files[${index}]`;
|
|
168
|
+
const file = requireRecord(inputFile, filePath);
|
|
169
|
+
exactFields(file, ['path', 'sha256', 'byteLength'], filePath);
|
|
170
|
+
return freezeRecord({
|
|
171
|
+
path: relativePath(file.path, `${filePath}.path`, limits.maxPathBytes),
|
|
172
|
+
sha256: digest(file.sha256, `${filePath}.sha256`),
|
|
173
|
+
byteLength: byteLength(file.byteLength, `${filePath}.byteLength`, limits.maxSourceFileBytes, true),
|
|
174
|
+
});
|
|
175
|
+
}));
|
|
176
|
+
if (files.length < 1 || !files.some(file => file.path === entrypoint)) {
|
|
177
|
+
bundleError('HQ_BUNDLE_INVALID_REFERENCE', `${path}.entrypoint`);
|
|
178
|
+
}
|
|
179
|
+
const paths = files.map(file => file.path);
|
|
180
|
+
if (new Set(paths).size !== paths.length
|
|
181
|
+
|| new Set(paths.map(filePath => filePath.toLowerCase())).size !== paths.length) {
|
|
182
|
+
bundleError('HQ_BUNDLE_INVALID_REFERENCE', `${path}.files`);
|
|
183
|
+
}
|
|
184
|
+
const sortedPaths = [...paths].sort();
|
|
185
|
+
if (paths.some((filePath, index) => filePath !== sortedPaths[index])) {
|
|
186
|
+
bundleError('HQ_BUNDLE_INVALID_VALUE', `${path}.files`);
|
|
187
|
+
}
|
|
188
|
+
const sourceBytes = files.reduce((total, file) => total + file.byteLength, 0);
|
|
189
|
+
if (!Number.isSafeInteger(sourceBytes) || sourceBytes > limits.maxSourceBytes) {
|
|
190
|
+
bundleError('HQ_BUNDLE_TOO_LARGE', path);
|
|
191
|
+
}
|
|
192
|
+
return freezeRecord({
|
|
193
|
+
root,
|
|
194
|
+
entrypoint,
|
|
195
|
+
files,
|
|
196
|
+
...(value.revision === undefined
|
|
197
|
+
? {}
|
|
198
|
+
: { revision: validateSourceRevision(value.revision, `${path}.revision`, limits) }),
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
function hasTreeCollision(paths) {
|
|
202
|
+
const normalized = new Set(paths.map(bundlePath => bundlePath.toLowerCase()));
|
|
203
|
+
return [...normalized].some((bundlePath) => {
|
|
204
|
+
const segments = bundlePath.split('/');
|
|
205
|
+
return segments.some((_, index) => index > 0 && normalized.has(segments.slice(0, index).join('/')));
|
|
206
|
+
});
|
|
207
|
+
}
|
|
115
208
|
export function validateProtocolDeploymentBundleManifest(input, options = {}) {
|
|
116
209
|
const limits = resolveDeploymentBundleLimits(options);
|
|
117
210
|
const value = requireRecord(input, '$');
|
|
118
|
-
exactFields(value, ['kind', 'version', 'deployment', 'artifacts'], '$');
|
|
211
|
+
exactFields(value, ['kind', 'version', 'deployment', 'artifacts'], '$', ['source']);
|
|
119
212
|
if (value.kind !== 'hypequery-deployment-bundle') {
|
|
120
213
|
if (typeof value.kind !== 'string')
|
|
121
214
|
bundleError('HQ_BUNDLE_TYPE', '$.kind');
|
|
@@ -129,10 +222,15 @@ export function validateProtocolDeploymentBundleManifest(input, options = {}) {
|
|
|
129
222
|
const deployment = validateDeployment(value.deployment, '$.deployment', limits);
|
|
130
223
|
const artifacts = Object.freeze(requireArray(value.artifacts, '$.artifacts', limits.maxArtifacts)
|
|
131
224
|
.map((artifact, index) => validateArtifact(artifact, `$.artifacts[${index}]`, limits)));
|
|
132
|
-
const
|
|
225
|
+
const source = value.source === undefined
|
|
226
|
+
? undefined
|
|
227
|
+
: validateSource(value.source, '$.source', limits);
|
|
228
|
+
const sourcePaths = source?.files.map(file => `${source.root}/${file.path}`) ?? [];
|
|
229
|
+
const paths = [deployment.path, ...artifacts.map(artifact => artifact.path), ...sourcePaths];
|
|
133
230
|
if (new Set(paths).size !== paths.length
|
|
134
|
-
|| new Set(paths.map(bundlePath => bundlePath.toLowerCase())).size !== paths.length
|
|
135
|
-
|
|
231
|
+
|| new Set(paths.map(bundlePath => bundlePath.toLowerCase())).size !== paths.length
|
|
232
|
+
|| hasTreeCollision(paths)) {
|
|
233
|
+
bundleError('HQ_BUNDLE_INVALID_REFERENCE', '$');
|
|
136
234
|
}
|
|
137
235
|
if (new Set(artifacts.map(artifact => artifact.sha256)).size !== artifacts.length) {
|
|
138
236
|
bundleError('HQ_BUNDLE_INVALID_REFERENCE', '$.artifacts');
|
|
@@ -142,7 +240,8 @@ export function validateProtocolDeploymentBundleManifest(input, options = {}) {
|
|
|
142
240
|
bundleError('HQ_BUNDLE_INVALID_VALUE', '$.artifacts');
|
|
143
241
|
}
|
|
144
242
|
const totalBytes = deployment.byteLength
|
|
145
|
-
+ artifacts.reduce((total, artifact) => total + artifact.byteLength, 0)
|
|
243
|
+
+ artifacts.reduce((total, artifact) => total + artifact.byteLength, 0)
|
|
244
|
+
+ (source?.files.reduce((total, file) => total + file.byteLength, 0) ?? 0);
|
|
146
245
|
if (!Number.isSafeInteger(totalBytes) || totalBytes > limits.maxTotalBytes) {
|
|
147
246
|
bundleError('HQ_BUNDLE_TOO_LARGE', '$');
|
|
148
247
|
}
|
|
@@ -151,5 +250,6 @@ export function validateProtocolDeploymentBundleManifest(input, options = {}) {
|
|
|
151
250
|
version: 1,
|
|
152
251
|
deployment,
|
|
153
252
|
artifacts,
|
|
253
|
+
...(source ? { source } : {}),
|
|
154
254
|
});
|
|
155
255
|
}
|