@hypequery/deployment 0.5.1 → 0.7.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 CHANGED
@@ -223,7 +223,17 @@ import {
223
223
 
224
224
  const supervisor = createDeploymentRuntimeSupervisor({
225
225
  materializer,
226
- factory: createNodeWorkerDeploymentRuntimeFactory(),
226
+ factory: createNodeWorkerDeploymentRuntimeFactory({
227
+ async resolveEnvironment(snapshot, { signal }) {
228
+ const connection = await resolveClickHouseConnection(snapshot.target, { signal });
229
+ return {
230
+ CLICKHOUSE_URL: connection.url,
231
+ CLICKHOUSE_DATABASE: connection.database,
232
+ CLICKHOUSE_USERNAME: connection.username,
233
+ CLICKHOUSE_PASSWORD: connection.password,
234
+ };
235
+ },
236
+ }),
227
237
  });
228
238
 
229
239
  await supervisor.reconcile({ project: 'analytics', environment: 'production' });
@@ -241,6 +251,19 @@ materialized bytes in worker threads and removes their temporary files on
241
251
  shutdown. Provider factories can implement Python, process, container, or
242
252
  remote-sandbox isolation behind the same lifecycle interface.
243
253
 
254
+ `resolveEnvironment(snapshot, { signal })` lets a provider resolve secrets and
255
+ configuration for one immutable deployment target before its worker imports any
256
+ artifact. When configured, the returned string record replaces the inherited
257
+ process environment for that worker, so concurrent targets do not need to
258
+ mutate shared `process.env`. Returning an empty record creates a worker with an
259
+ empty environment. Omitting the resolver preserves Node's default environment
260
+ inheritance for existing single-host integrations.
261
+
262
+ Resolvers should return the smallest environment the deployment needs and
263
+ honour the startup abort signal during external secret-store calls. Environment
264
+ resolution failure prevents the candidate from becoming ready and removes its
265
+ temporary artifact bytes.
266
+
244
267
  The reference worker is a lifecycle boundary, not a hostile-code security
245
268
  sandbox. Only trusted deployment code should use it directly.
246
269
 
@@ -1 +1 @@
1
- {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"AAQA,OAAO,EAKL,KAAK,gCAAgC,EACrC,KAAK,0BAA0B,EAChC,MAAM,qBAAqB,CAAC;AAE7B,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;AAoKD,wBAAsB,sBAAsB,CAC1C,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,wBAAwB,CAAC,CA2DnC"}
1
+ {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"AAQA,OAAO,EAKL,KAAK,gCAAgC,EACrC,KAAK,0BAA0B,EAChC,MAAM,qBAAqB,CAAC;AAE7B,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;AAsKD,wBAAsB,sBAAsB,CAC1C,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,wBAAwB,CAAC,CAwEnC"}
package/dist/bundle.js CHANGED
@@ -14,7 +14,7 @@ function errorCode(error) {
14
14
  function sha256(bytes) {
15
15
  return createHash('sha256').update(bytes).digest('hex');
16
16
  }
17
- async function readBoundedRegularFile(root, relativePath, maximum) {
17
+ async function readBoundedRegularFile(root, relativePath, maximum, allowEmpty = false) {
18
18
  const absolutePath = path.join(root, ...relativePath.split('/'));
19
19
  let handle;
20
20
  try {
@@ -25,14 +25,14 @@ async function readBoundedRegularFile(root, relativePath, maximum) {
25
25
  if (!initialStat.isFile()) {
26
26
  throw new Error(`Bundle entry is not a regular file: ${relativePath}`);
27
27
  }
28
- if (initialStat.size < 1 || initialStat.size > maximum) {
28
+ if (initialStat.size < (allowEmpty ? 0 : 1) || initialStat.size > maximum) {
29
29
  throw new Error(`Bundle entry exceeds its byte limit: ${relativePath}`);
30
30
  }
31
31
  handle = await open(absolutePath, constants.O_RDONLY | constants.O_NOFOLLOW);
32
32
  const stat = await handle.stat();
33
33
  if (!stat.isFile())
34
34
  throw new Error(`Bundle entry is not a regular file: ${relativePath}`);
35
- if (stat.size < 1 || stat.size > maximum) {
35
+ if (stat.size < (allowEmpty ? 0 : 1) || stat.size > maximum) {
36
36
  throw new Error(`Bundle entry exceeds its byte limit: ${relativePath}`);
37
37
  }
38
38
  return await handle.readFile();
@@ -62,6 +62,7 @@ async function verifyExactEntries(root, manifest) {
62
62
  DEPLOYMENT_BUNDLE_MANIFEST,
63
63
  manifest.deployment.path,
64
64
  ...manifest.artifacts.map(artifact => artifact.path),
65
+ ...(manifest.source?.files.map(file => `${manifest.source.root}/${file.path}`) ?? []),
65
66
  ]);
66
67
  const expectedDirectoryPaths = expectedDirectories([...expectedFiles]);
67
68
  const seenFiles = new Set();
@@ -183,6 +184,14 @@ export async function verifyDeploymentBundle(bundleDirectory) {
183
184
  const bytes = await readBoundedRegularFile(root, artifact.path, DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS.maxArtifactBytes);
184
185
  verifyFile(bytes, artifact);
185
186
  }
187
+ const source = preparedManifest.manifest.source;
188
+ if (source) {
189
+ for (const file of source.files) {
190
+ const bundlePath = `${source.root}/${file.path}`;
191
+ const bytes = await readBoundedRegularFile(root, bundlePath, DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS.maxSourceFileBytes, true);
192
+ verifyFile(bytes, { ...file, path: bundlePath });
193
+ }
194
+ }
186
195
  verifyRuntimeReferences(preparedContract.contract, preparedManifest.manifest.artifacts);
187
196
  return Object.freeze({
188
197
  directory: root,
package/dist/index.d.ts CHANGED
@@ -16,7 +16,7 @@ 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
18
  export { createNodeWorkerDeploymentRuntimeFactory, NodeDeploymentRuntimeError, } from './node-runtime-factory.js';
19
- export type { NodeDeploymentRuntimeErrorCode, NodeDeploymentRuntimeFactoryOptions, } from './node-runtime-factory.js';
19
+ export type { NodeDeploymentRuntimeEnvironment, NodeDeploymentRuntimeEnvironmentResolver, NodeDeploymentRuntimeErrorCode, NodeDeploymentRuntimeFactoryOptions, } from './node-runtime-factory.js';
20
20
  export { createDeploymentRuntimeMaterializer, DeploymentRuntimeMaterializationError, } from './runtime-materialization.js';
21
21
  export type { DeploymentRuntimeArtifactSnapshot, DeploymentRuntimeMaterializationErrorCode, DeploymentRuntimeMaterializer, DeploymentRuntimeMaterializerOptions, DeploymentRuntimeQueryBinding, DeploymentRuntimeRelease, DeploymentRuntimeReleaseReader, DeploymentRuntimeSnapshot, } from './runtime-materialization.js';
22
22
  export { createDeploymentRuntimeSupervisor, DeploymentRuntimeSupervisorError, } from './runtime-supervisor.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -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;AAoSpB,wBAAgB,sBAAsB,CAAC,SAAS,EAC9C,OAAO,EAAE,uBAAuB,CAAC,SAAS,CAAC,GAC1C,gBAAgB,CA6HlB"}
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;AAuSpB,wBAAgB,sBAAsB,CAAC,SAAS,EAC9C,OAAO,EAAE,uBAAuB,CAAC,SAAS,CAAC,GAC1C,gBAAgB,CAiIlB"}
package/dist/intake.js CHANGED
@@ -88,6 +88,7 @@ function requireReconstructablePaths(manifest) {
88
88
  const files = [
89
89
  manifest.manifest.deployment.path,
90
90
  ...manifest.manifest.artifacts.map(artifact => artifact.path),
91
+ ...(manifest.manifest.source?.files.map(file => `${manifest.manifest.source.root}/${file.path}`) ?? []),
91
92
  ];
92
93
  const fileSet = new Set(files);
93
94
  if (fileSet.has(DEPLOYMENT_BUNDLE_MANIFEST)) {
@@ -284,6 +285,10 @@ export function createDeploymentIntake(options) {
284
285
  const files = [
285
286
  manifest.prepared.manifest.deployment,
286
287
  ...manifest.prepared.manifest.artifacts,
288
+ ...(manifest.prepared.manifest.source?.files.map(file => ({
289
+ ...file,
290
+ path: `${manifest.prepared.manifest.source.root}/${file.path}`,
291
+ })) ?? []),
287
292
  ];
288
293
  for (let index = 0; index < files.length; index += 1) {
289
294
  await receiveBundleFile(reader, bundleRoot, files[index], index === 0 ? 'application/json' : 'application/octet-stream', index === files.length - 1);
@@ -1,3 +1,4 @@
1
+ import type { DeploymentRuntimeSnapshot } from './runtime-materialization.js';
1
2
  import type { DeploymentRuntimeFactory } from './runtime-supervisor.js';
2
3
  export type NodeDeploymentRuntimeErrorCode = 'HQ_NODE_RUNTIME_CONFIGURATION' | 'HQ_NODE_RUNTIME_UNSUPPORTED_ARTIFACT' | 'HQ_NODE_RUNTIME_INVALID_ARTIFACT' | 'HQ_NODE_RUNTIME_START_FAILED' | 'HQ_NODE_RUNTIME_WORKER_EXITED' | 'HQ_NODE_RUNTIME_INVOCATION_FAILED' | 'HQ_NODE_RUNTIME_ABORTED' | 'HQ_NODE_RUNTIME_CLOSED';
3
4
  export declare class NodeDeploymentRuntimeError extends Error {
@@ -6,10 +7,20 @@ export declare class NodeDeploymentRuntimeError extends Error {
6
7
  readonly cause?: unknown;
7
8
  });
8
9
  }
10
+ export type NodeDeploymentRuntimeEnvironment = Readonly<Record<string, string>>;
11
+ export type NodeDeploymentRuntimeEnvironmentResolver = (snapshot: DeploymentRuntimeSnapshot, input: {
12
+ readonly signal?: AbortSignal;
13
+ }) => NodeDeploymentRuntimeEnvironment | Promise<NodeDeploymentRuntimeEnvironment>;
9
14
  export interface NodeDeploymentRuntimeFactoryOptions {
10
15
  readonly temporaryDirectory?: string;
11
16
  /** Worker import deadline from 1 through 300,000 milliseconds. */
12
17
  readonly startupTimeoutMs?: number;
18
+ /**
19
+ * Resolve an explicit environment for one immutable runtime snapshot.
20
+ * When configured, this replaces inherited process environment state for
21
+ * the worker. Omit it to preserve Node's default environment inheritance.
22
+ */
23
+ readonly resolveEnvironment?: NodeDeploymentRuntimeEnvironmentResolver;
13
24
  readonly onCleanupError?: (error: unknown, directory: string) => void;
14
25
  }
15
26
  export declare function createNodeWorkerDeploymentRuntimeFactory(options?: NodeDeploymentRuntimeFactoryOptions): DeploymentRuntimeFactory;
@@ -1 +1 @@
1
- {"version":3,"file":"node-runtime-factory.d.ts","sourceRoot":"","sources":["../src/node-runtime-factory.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,wBAAwB,EAGzB,MAAM,yBAAyB,CAAC;AA+CjC,MAAM,MAAM,8BAA8B,GACtC,+BAA+B,GAC/B,sCAAsC,GACtC,kCAAkC,GAClC,8BAA8B,GAC9B,+BAA+B,GAC/B,mCAAmC,GACnC,yBAAyB,GACzB,wBAAwB,CAAC;AAE7B,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,EAAE,8BAA8B,CAAC;gBAG5C,IAAI,EAAE,8BAA8B,EACpC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAM7C;AAED,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,kEAAkE;IAClE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACvE;AAoSD,wBAAgB,wCAAwC,CACtD,OAAO,GAAE,mCAAwC,GAChD,wBAAwB,CAuB1B"}
1
+ {"version":3,"file":"node-runtime-factory.d.ts","sourceRoot":"","sources":["../src/node-runtime-factory.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,KAAK,EACV,wBAAwB,EAGzB,MAAM,yBAAyB,CAAC;AA+CjC,MAAM,MAAM,8BAA8B,GACtC,+BAA+B,GAC/B,sCAAsC,GACtC,kCAAkC,GAClC,8BAA8B,GAC9B,+BAA+B,GAC/B,mCAAmC,GACnC,yBAAyB,GACzB,wBAAwB,CAAC;AAE7B,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,EAAE,8BAA8B,CAAC;gBAG5C,IAAI,EAAE,8BAA8B,EACpC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAM7C;AAED,MAAM,MAAM,gCAAgC,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEhF,MAAM,MAAM,wCAAwC,GAAG,CACrD,QAAQ,EAAE,yBAAyB,EACnC,KAAK,EAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,KACrC,gCAAgC,GAAG,OAAO,CAAC,gCAAgC,CAAC,CAAC;AAElF,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,kEAAkE;IAClE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,wCAAwC,CAAC;IACvE,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACvE;AA6XD,wBAAgB,wCAAwC,CACtD,OAAO,GAAE,mCAAwC,GAChD,wBAAwB,CA6B1B"}
@@ -67,6 +67,63 @@ function startupTimeout(input) {
67
67
  function sha256(bytes) {
68
68
  return createHash('sha256').update(bytes).digest('hex');
69
69
  }
70
+ function invalidEnvironment() {
71
+ return nodeRuntimeError('HQ_NODE_RUNTIME_START_FAILED', 'The Node deployment runtime environment is invalid.');
72
+ }
73
+ function validateEnvironment(input) {
74
+ if (typeof input !== 'object' || input === null || Array.isArray(input)) {
75
+ throw invalidEnvironment();
76
+ }
77
+ let keys;
78
+ try {
79
+ keys = Reflect.ownKeys(input);
80
+ }
81
+ catch {
82
+ throw invalidEnvironment();
83
+ }
84
+ const environment = Object.create(null);
85
+ for (const key of keys) {
86
+ if (typeof key !== 'string' || key.length === 0 || key.includes('\0') || key.includes('=')) {
87
+ throw invalidEnvironment();
88
+ }
89
+ let descriptor;
90
+ try {
91
+ descriptor = Object.getOwnPropertyDescriptor(input, key);
92
+ }
93
+ catch {
94
+ throw invalidEnvironment();
95
+ }
96
+ if (!descriptor?.enumerable
97
+ || !Object.hasOwn(descriptor, 'value')
98
+ || typeof descriptor.value !== 'string'
99
+ || descriptor.value.includes('\0')) {
100
+ throw invalidEnvironment();
101
+ }
102
+ environment[key] = descriptor.value;
103
+ }
104
+ return environment;
105
+ }
106
+ async function resolveWorkerEnvironment(resolver, snapshot, signal) {
107
+ if (!resolver)
108
+ return undefined;
109
+ if (signal?.aborted) {
110
+ throw nodeRuntimeError('HQ_NODE_RUNTIME_ABORTED', 'Node runtime startup was aborted.', signal.reason);
111
+ }
112
+ let resolved;
113
+ try {
114
+ resolved = await resolver(snapshot, { signal });
115
+ }
116
+ catch (error) {
117
+ if (signal?.aborted) {
118
+ throw nodeRuntimeError('HQ_NODE_RUNTIME_ABORTED', 'Node runtime startup was aborted.', signal.reason);
119
+ }
120
+ throw nodeRuntimeError('HQ_NODE_RUNTIME_START_FAILED', 'The Node deployment runtime environment could not be resolved.', error);
121
+ }
122
+ if (signal?.aborted) {
123
+ throw nodeRuntimeError('HQ_NODE_RUNTIME_ABORTED', 'Node runtime startup was aborted.', signal.reason);
124
+ }
125
+ return validateEnvironment(resolved);
126
+ }
70
127
  async function ensureTemporaryDirectory(input) {
71
128
  const directory = path.resolve(input ?? tmpdir());
72
129
  await mkdir(directory, { recursive: true, mode: 0o700 });
@@ -180,7 +237,7 @@ function workerInstance(worker, directory, ready) {
180
237
  },
181
238
  };
182
239
  }
183
- async function startWorker(snapshot, directory, timeoutMs, signal) {
240
+ async function startWorker(snapshot, directory, timeoutMs, signal, resolveEnvironment) {
184
241
  if (signal?.aborted) {
185
242
  throw nodeRuntimeError('HQ_NODE_RUNTIME_ABORTED', 'Node runtime startup was aborted.', signal.reason);
186
243
  }
@@ -200,9 +257,14 @@ async function startWorker(snapshot, directory, timeoutMs, signal) {
200
257
  if (artifacts.length === 0) {
201
258
  throw nodeRuntimeError('HQ_NODE_RUNTIME_UNSUPPORTED_ARTIFACT', 'The deployment snapshot contains no Node runtime artifacts.');
202
259
  }
260
+ const environment = await resolveWorkerEnvironment(resolveEnvironment, snapshot, signal);
261
+ if (signal?.aborted) {
262
+ throw nodeRuntimeError('HQ_NODE_RUNTIME_ABORTED', 'Node runtime startup was aborted.', signal.reason);
263
+ }
203
264
  const worker = new Worker(WORKER_SOURCE, {
204
265
  eval: true,
205
266
  workerData: { artifacts },
267
+ ...(environment === undefined ? {} : { env: environment }),
206
268
  });
207
269
  let resolveReady;
208
270
  let rejectReady;
@@ -257,7 +319,7 @@ export function createNodeWorkerDeploymentRuntimeFactory(options = {}) {
257
319
  const directory = await mkdtemp(path.join(root, 'hypequery-node-runtime-'));
258
320
  try {
259
321
  await chmod(directory, 0o700);
260
- return await startWorker(snapshot, directory, timeoutMs, input.signal);
322
+ return await startWorker(snapshot, directory, timeoutMs, input.signal, options.resolveEnvironment);
261
323
  }
262
324
  catch (error) {
263
325
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypequery/deployment",
3
- "version": "0.5.1",
3
+ "version": "0.7.0",
4
4
  "description": "Provider-neutral deployment verification and intake for Hypequery",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -18,7 +18,7 @@
18
18
  "README.md"
19
19
  ],
20
20
  "dependencies": {
21
- "@hypequery/protocol": "0.9.0"
21
+ "@hypequery/protocol": "0.10.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/node": "^22.5.0",