@hypequery/deployment 0.2.0 → 0.3.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.
@@ -0,0 +1,362 @@
1
+ import { validateProtocolDeploymentReleaseTarget, } from '@hypequery/protocol';
2
+ import { DeploymentActivationError, } from './activation.js';
3
+ import { resolveDeploymentControlPlaneLimits, } from './control-plane-limits.js';
4
+ const IDENTITY_PATTERN = /^[0-9a-f]{64}$/;
5
+ const JSON_CONTENT_TYPE = /^application\/json(?:;\s*charset=utf-8)?$/i;
6
+ const textDecoder = new TextDecoder('utf-8', { fatal: true });
7
+ const ERROR_STATUS = Object.freeze({
8
+ HQ_CONTROL_BAD_REQUEST: 400,
9
+ HQ_CONTROL_UNAUTHENTICATED: 401,
10
+ HQ_CONTROL_FORBIDDEN: 403,
11
+ HQ_CONTROL_NOT_FOUND: 404,
12
+ HQ_CONTROL_METHOD_NOT_ALLOWED: 405,
13
+ HQ_CONTROL_TOO_LARGE: 413,
14
+ HQ_CONTROL_RELEASE_NOT_FOUND: 404,
15
+ HQ_CONTROL_RELEASE_UNAVAILABLE: 503,
16
+ HQ_CONTROL_INTERNAL: 500,
17
+ });
18
+ class ControlPlaneError extends Error {
19
+ code;
20
+ status;
21
+ expose;
22
+ headers;
23
+ constructor(code, message, options = {}) {
24
+ super(message, options.cause === undefined ? undefined : { cause: options.cause });
25
+ this.name = 'DeploymentControlPlaneError';
26
+ this.code = code;
27
+ this.status = ERROR_STATUS[code];
28
+ this.expose = options.expose ?? this.status < 500;
29
+ this.headers = Object.freeze({ ...options.headers });
30
+ }
31
+ }
32
+ function requestHeader(headers, expectedName) {
33
+ const values = Object.entries(headers)
34
+ .filter(([name, value]) => value !== undefined && name.toLowerCase() === expectedName)
35
+ .map(([, value]) => value);
36
+ if (values.length > 1) {
37
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', `Duplicate ${expectedName} header.`);
38
+ }
39
+ return values[0];
40
+ }
41
+ function bearerToken(headers) {
42
+ const authorization = requestHeader(headers, 'authorization');
43
+ const token = authorization?.startsWith('Bearer ') ? authorization.slice(7) : '';
44
+ if (token.length < 1 || token.length > 4096 || token.trim() !== token
45
+ || [...token].some(character => {
46
+ const code = character.charCodeAt(0);
47
+ return code < 0x21 || code > 0x7e;
48
+ })) {
49
+ throw new ControlPlaneError('HQ_CONTROL_UNAUTHENTICATED', 'A valid bearer credential is required.', { headers: { 'www-authenticate': 'Bearer' } });
50
+ }
51
+ return token;
52
+ }
53
+ function jsonResponse(status, body, headers = {}) {
54
+ const encoded = `${JSON.stringify(body)}\n`;
55
+ return Object.freeze({
56
+ status,
57
+ headers: Object.freeze({
58
+ 'content-type': 'application/json; charset=utf-8',
59
+ 'content-length': String(Buffer.byteLength(encoded)),
60
+ 'cache-control': 'no-store',
61
+ ...headers,
62
+ }),
63
+ body: encoded,
64
+ });
65
+ }
66
+ function sanitizeMessage(input) {
67
+ return [...input].map(character => {
68
+ const code = character.codePointAt(0) ?? 0;
69
+ return code < 0x20 || code === 0x7f ? ' ' : character;
70
+ }).join('').slice(0, 1024).trim() || 'The deployment control-plane request was rejected.';
71
+ }
72
+ function errorResponse(error) {
73
+ const value = error instanceof ControlPlaneError
74
+ ? error
75
+ : new ControlPlaneError('HQ_CONTROL_INTERNAL', 'The deployment control-plane request could not be processed.', { expose: false, cause: error });
76
+ return jsonResponse(value.status, {
77
+ error: {
78
+ code: value.code,
79
+ message: sanitizeMessage(value.expose
80
+ ? value.message
81
+ : 'The deployment control-plane request could not be processed.'),
82
+ },
83
+ }, value.headers);
84
+ }
85
+ function decodeTargetSegment(input) {
86
+ try {
87
+ return decodeURIComponent(input);
88
+ }
89
+ catch (error) {
90
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'Deployment target path encoding is invalid.', { cause: error });
91
+ }
92
+ }
93
+ function validatedTarget(project, environment) {
94
+ try {
95
+ return validateProtocolDeploymentReleaseTarget({
96
+ project: decodeTargetSegment(project),
97
+ environment: decodeTargetSegment(environment),
98
+ });
99
+ }
100
+ catch (error) {
101
+ if (error instanceof ControlPlaneError)
102
+ throw error;
103
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'Deployment target path is invalid.', { cause: error });
104
+ }
105
+ }
106
+ function parseRoute(path) {
107
+ if (path === '/v1/deployments/submissions')
108
+ return Object.freeze({ kind: 'submission' });
109
+ const segments = path.split('/');
110
+ if (segments.length !== 7 || segments[0] !== '' || segments[1] !== 'v1'
111
+ || segments[2] !== 'deployments' || segments[3] !== 'targets')
112
+ return undefined;
113
+ if (segments[6] !== 'activation' && segments[6] !== 'activations')
114
+ return undefined;
115
+ const target = validatedTarget(segments[4], segments[5]);
116
+ if (segments[6] === 'activation')
117
+ return Object.freeze({ kind: 'activation', target });
118
+ if (segments[6] === 'activations')
119
+ return Object.freeze({ kind: 'history', target });
120
+ return undefined;
121
+ }
122
+ function requireMethod(method, ...expected) {
123
+ if (!expected.includes(method)) {
124
+ const allowed = expected.join(', ');
125
+ throw new ControlPlaneError('HQ_CONTROL_METHOD_NOT_ALLOWED', `This deployment control-plane route requires ${allowed}.`, { headers: { allow: allowed } });
126
+ }
127
+ }
128
+ function requireNoQuery(request) {
129
+ if (request.query && Object.keys(request.query).length > 0) {
130
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'This deployment control-plane route does not accept query parameters.');
131
+ }
132
+ }
133
+ function requireNoBody(request) {
134
+ const length = requestHeader(request.headers, 'content-length');
135
+ const transferEncoding = requestHeader(request.headers, 'transfer-encoding');
136
+ if (request.hasBody || transferEncoding !== undefined || (length !== undefined && length !== '0')) {
137
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'This deployment control-plane route does not accept a request body.');
138
+ }
139
+ }
140
+ function throwIfAborted(signal) {
141
+ if (signal?.aborted) {
142
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'The deployment control-plane request was aborted.', { cause: signal.reason });
143
+ }
144
+ }
145
+ async function readBoundedBody(request, maximum) {
146
+ const declared = requestHeader(request.headers, 'content-length');
147
+ let declaredLength;
148
+ if (declared !== undefined) {
149
+ if (!/^(?:0|[1-9][0-9]*)$/.test(declared)) {
150
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'Content-Length must be a non-negative decimal integer.');
151
+ }
152
+ declaredLength = Number(declared);
153
+ if (!Number.isSafeInteger(declaredLength) || declaredLength > maximum) {
154
+ throw new ControlPlaneError('HQ_CONTROL_TOO_LARGE', 'The activation request exceeds its byte limit.');
155
+ }
156
+ }
157
+ const chunks = [];
158
+ let total = 0;
159
+ try {
160
+ for await (const chunk of request.body) {
161
+ throwIfAborted(request.signal);
162
+ if (!(chunk instanceof Uint8Array)) {
163
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'The activation request body yielded a non-byte chunk.');
164
+ }
165
+ total += chunk.byteLength;
166
+ if (total > maximum) {
167
+ throw new ControlPlaneError('HQ_CONTROL_TOO_LARGE', 'The activation request exceeds its byte limit.');
168
+ }
169
+ if (declaredLength !== undefined && total > declaredLength) {
170
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'The activation request body does not match Content-Length.');
171
+ }
172
+ chunks.push(Buffer.from(chunk));
173
+ }
174
+ }
175
+ catch (error) {
176
+ if (error instanceof ControlPlaneError)
177
+ throw error;
178
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'The activation request body could not be read.', { cause: error });
179
+ }
180
+ throwIfAborted(request.signal);
181
+ if (declaredLength !== undefined && total !== declaredLength) {
182
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'The activation request body does not match Content-Length.');
183
+ }
184
+ return Buffer.concat(chunks, total);
185
+ }
186
+ function parseActivationBody(bytes) {
187
+ let input;
188
+ try {
189
+ input = JSON.parse(textDecoder.decode(bytes));
190
+ }
191
+ catch (error) {
192
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'The activation request must be valid UTF-8 JSON.', { cause: error });
193
+ }
194
+ if (typeof input !== 'object' || input === null || Array.isArray(input)) {
195
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'The activation request is invalid.');
196
+ }
197
+ const value = input;
198
+ const expected = ['expectedRevision', 'kind', 'releaseIdentity', 'version'];
199
+ if (Object.keys(value).sort().join('\0') !== expected.join('\0')
200
+ || value.kind !== 'hypequery-deployment-activation-request' || value.version !== 1
201
+ || typeof value.releaseIdentity !== 'string'
202
+ || !IDENTITY_PATTERN.test(value.releaseIdentity)
203
+ || (value.expectedRevision !== null
204
+ && (typeof value.expectedRevision !== 'string'
205
+ || !IDENTITY_PATTERN.test(value.expectedRevision)))) {
206
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'The activation request is invalid.');
207
+ }
208
+ return Object.freeze({
209
+ releaseIdentity: value.releaseIdentity,
210
+ expectedRevision: value.expectedRevision,
211
+ });
212
+ }
213
+ function activationError(error) {
214
+ switch (error.code) {
215
+ case 'HQ_DEPLOYMENT_ACTIVATION_INVALID_REQUEST':
216
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'The deployment activation request is invalid.', { cause: error });
217
+ case 'HQ_DEPLOYMENT_ACTIVATION_TARGET_MISMATCH':
218
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'The deployment release does not match the requested target.', { cause: error });
219
+ case 'HQ_DEPLOYMENT_ACTIVATION_RELEASE_NOT_FOUND':
220
+ throw new ControlPlaneError('HQ_CONTROL_RELEASE_NOT_FOUND', 'The deployment release was not found.', { cause: error });
221
+ case 'HQ_DEPLOYMENT_ACTIVATION_RELEASE_UNAVAILABLE':
222
+ throw new ControlPlaneError('HQ_CONTROL_RELEASE_UNAVAILABLE', 'The deployment release is temporarily unavailable.', { cause: error });
223
+ default:
224
+ throw new ControlPlaneError('HQ_CONTROL_INTERNAL', 'The deployment activation state could not be processed.', { expose: false, cause: error });
225
+ }
226
+ }
227
+ async function activationCall(operation) {
228
+ try {
229
+ return await operation();
230
+ }
231
+ catch (error) {
232
+ if (error instanceof DeploymentActivationError)
233
+ activationError(error);
234
+ throw error;
235
+ }
236
+ }
237
+ function activationResponse(status, activation) {
238
+ return jsonResponse(status === 'activated' ? 201 : 200, {
239
+ kind: 'hypequery-deployment-activation-response',
240
+ version: 1,
241
+ status,
242
+ activation,
243
+ });
244
+ }
245
+ function validatedHistoryQuery(query, maximum) {
246
+ const values = query ?? {};
247
+ if (Object.keys(values).some(key => key !== 'limit' && key !== 'before')) {
248
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'History query parameters are invalid.');
249
+ }
250
+ const limitInput = values.limit;
251
+ if (limitInput !== undefined && typeof limitInput !== 'string') {
252
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'History limit is invalid.');
253
+ }
254
+ const limit = limitInput === undefined ? maximum : Number(limitInput);
255
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > maximum
256
+ || (limitInput !== undefined && String(limit) !== limitInput)) {
257
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'History limit is invalid.');
258
+ }
259
+ const before = values.before;
260
+ if (before !== undefined && typeof before !== 'string') {
261
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'History cursor is invalid.');
262
+ }
263
+ if (before !== undefined) {
264
+ if (!IDENTITY_PATTERN.test(before)) {
265
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'History cursor is invalid.');
266
+ }
267
+ }
268
+ return Object.freeze({ limit, ...(before === undefined ? {} : { before }) });
269
+ }
270
+ export function createDeploymentControlPlane(options) {
271
+ const limits = resolveDeploymentControlPlaneLimits(options.limits);
272
+ async function authenticateAndAuthorize(request, action, target) {
273
+ throwIfAborted(request.signal);
274
+ const token = bearerToken(request.headers);
275
+ const principal = await options.authenticator.authenticate({ token, signal: request.signal });
276
+ if (principal === null) {
277
+ throw new ControlPlaneError('HQ_CONTROL_UNAUTHENTICATED', 'The bearer credential is invalid.', { headers: { 'www-authenticate': 'Bearer' } });
278
+ }
279
+ throwIfAborted(request.signal);
280
+ const allowed = await options.authorizer.authorize({
281
+ principal,
282
+ action,
283
+ target,
284
+ signal: request.signal,
285
+ });
286
+ if (!allowed) {
287
+ throw new ControlPlaneError('HQ_CONTROL_FORBIDDEN', 'The caller is not authorized for the deployment target.');
288
+ }
289
+ throwIfAborted(request.signal);
290
+ }
291
+ async function process(request) {
292
+ const method = request.method.toUpperCase();
293
+ const route = parseRoute(request.path);
294
+ if (!route) {
295
+ throw new ControlPlaneError('HQ_CONTROL_NOT_FOUND', 'Deployment route not found.');
296
+ }
297
+ if (route.kind === 'submission') {
298
+ requireMethod(method, 'POST');
299
+ requireNoQuery(request);
300
+ return options.intake.handle(request);
301
+ }
302
+ const target = route.target;
303
+ if (route.kind === 'activation') {
304
+ if (method === 'GET') {
305
+ requireNoQuery(request);
306
+ requireNoBody(request);
307
+ await authenticateAndAuthorize(request, 'read-current-activation', target);
308
+ const current = await activationCall(() => options.activations.current(target));
309
+ return jsonResponse(200, {
310
+ kind: 'hypequery-deployment-current-activation',
311
+ version: 1,
312
+ target,
313
+ activation: current ?? null,
314
+ });
315
+ }
316
+ requireMethod(method, 'GET', 'PUT');
317
+ requireNoQuery(request);
318
+ await authenticateAndAuthorize(request, 'activate', target);
319
+ const contentType = requestHeader(request.headers, 'content-type');
320
+ if (!contentType || !JSON_CONTENT_TYPE.test(contentType)) {
321
+ throw new ControlPlaneError('HQ_CONTROL_BAD_REQUEST', 'Activation requests require application/json with UTF-8 encoding.');
322
+ }
323
+ const body = parseActivationBody(await readBoundedBody(request, limits.maxActivationRequestBytes));
324
+ const result = await activationCall(() => options.activations.activate({
325
+ target,
326
+ releaseIdentity: body.releaseIdentity,
327
+ expectedRevision: body.expectedRevision,
328
+ }));
329
+ if (result.status === 'conflict') {
330
+ return jsonResponse(409, {
331
+ kind: 'hypequery-deployment-activation-response',
332
+ version: 1,
333
+ status: 'conflict',
334
+ current: result.current,
335
+ });
336
+ }
337
+ return activationResponse(result.status, result.activation);
338
+ }
339
+ requireMethod(method, 'GET');
340
+ requireNoBody(request);
341
+ await authenticateAndAuthorize(request, 'read-activation-history', target);
342
+ const historyQuery = validatedHistoryQuery(request.query, limits.maxHistoryPageSize);
343
+ const page = await activationCall(() => (options.activations.historyPage(target, historyQuery)));
344
+ return jsonResponse(200, {
345
+ kind: 'hypequery-deployment-activation-history',
346
+ version: 1,
347
+ target,
348
+ activations: page.activations,
349
+ nextBefore: page.nextBefore,
350
+ });
351
+ }
352
+ return Object.freeze({
353
+ async handle(request) {
354
+ try {
355
+ return await process(request);
356
+ }
357
+ catch (error) {
358
+ return errorResponse(error);
359
+ }
360
+ },
361
+ });
362
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { createFileSystemDeploymentActivationRegistry, DeploymentActivationError, } from './activation.js';
2
- export type { DeploymentActivationErrorCode, DeploymentActivationRegistry, DeploymentActivationRelease, DeploymentActivationRecord, DeploymentActivationRequest, DeploymentActivationResult, DeploymentReleaseReader, FileSystemDeploymentActivationRegistryOptions, } from './activation.js';
1
+ export { createFileSystemDeploymentActivationRegistry, DeploymentActivationError, validateDeploymentActivationRecord, } from './activation.js';
2
+ export type { DeploymentActivationErrorCode, DeploymentActivationHistoryPage, DeploymentActivationHistoryQuery, DeploymentActivationRegistry, DeploymentActivationRelease, DeploymentActivationRecord, DeploymentActivationRequest, DeploymentActivationResult, DeploymentReleaseReader, FileSystemDeploymentActivationRegistryOptions, } from './activation.js';
3
3
  export { DEPLOYMENT_BUNDLE_CONTRACT, DEPLOYMENT_BUNDLE_MANIFEST, verifyDeploymentBundle, } from './bundle.js';
4
4
  export type { VerifiedDeploymentBundle } from './bundle.js';
5
5
  export { DeploymentIntakeError, } from './errors.js';
@@ -7,7 +7,19 @@ export type { DeploymentIntakeErrorCode } from './errors.js';
7
7
  export { createFileSystemDeploymentSubmissionStore, FileSystemDeploymentStoreError, } from './filesystem-store.js';
8
8
  export type { FileSystemDeploymentStoreErrorCode, FileSystemDeploymentSubmissionStore, FileSystemDeploymentSubmissionStoreOptions, StoredDeploymentSubmission, } from './filesystem-store.js';
9
9
  export { createDeploymentIntake, } from './intake.js';
10
+ export { createDeploymentControlPlaneFetchHandler, createDeploymentControlPlaneNodeHandler, } from './control-plane-adapters.js';
11
+ export type { DeploymentControlPlaneFetchHandler, DeploymentControlPlaneNodeHandler, } from './control-plane-adapters.js';
12
+ export { createDeploymentControlPlane, } from './control-plane.js';
13
+ export type { DeploymentControlPlane, DeploymentControlPlaneAction, DeploymentControlPlaneAuthorizationInput, DeploymentControlPlaneAuthorizer, DeploymentControlPlaneErrorCode, DeploymentControlPlaneOptions, DeploymentControlPlaneRequest, DeploymentControlPlaneResponse, } from './control-plane.js';
14
+ export { DEFAULT_DEPLOYMENT_CONTROL_PLANE_LIMITS, resolveDeploymentControlPlaneLimits, } from './control-plane-limits.js';
15
+ export type { DeploymentControlPlaneLimits } from './control-plane-limits.js';
10
16
  export { DEFAULT_DEPLOYMENT_INTAKE_LIMITS, resolveDeploymentIntakeLimits, } from './limits.js';
11
17
  export type { DeploymentIntakeLimits } from './limits.js';
18
+ export { createNodeWorkerDeploymentRuntimeFactory, NodeDeploymentRuntimeError, } from './node-runtime-factory.js';
19
+ export type { 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, DeploymentRuntimeInstance, DeploymentRuntimeInstanceInvocation, DeploymentRuntimeInvocation, DeploymentRuntimeReconcileResult, DeploymentRuntimeStatus, DeploymentRuntimeSupervisor, DeploymentRuntimeSupervisorErrorCode, DeploymentRuntimeSupervisorOptions, } from './runtime-supervisor.js';
12
24
  export type { DeploymentAuthenticationInput, DeploymentAuthenticator, DeploymentAuthorizationInput, DeploymentAuthorizer, DeploymentIntake, DeploymentIntakeOptions, DeploymentIntakeRequest, DeploymentIntakeResponse, DeploymentSubmissionResponse, DeploymentSubmissionStore, VerifiedDeploymentSubmission, } from './types.js';
13
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4CAA4C,EAC5C,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,6BAA6B,EAC7B,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,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"}
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,OAAO,EACL,wCAAwC,EACxC,0BAA0B,GAC3B,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,8BAA8B,EAC9B,mCAAmC,GACpC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,mCAAmC,EACnC,qCAAqC,GACtC,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,iCAAiC,EACjC,yCAAyC,EACzC,6BAA6B,EAC7B,oCAAoC,EACpC,6BAA6B,EAC7B,wBAAwB,EACxB,8BAA8B,EAC9B,yBAAyB,GAC1B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,iCAAiC,EACjC,gCAAgC,GACjC,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,wBAAwB,EACxB,yBAAyB,EACzB,mCAAmC,EACnC,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,2BAA2B,EAC3B,oCAAoC,EACpC,kCAAkC,GACnC,MAAM,yBAAyB,CAAC;AACjC,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"}
package/dist/index.js CHANGED
@@ -1,6 +1,12 @@
1
- export { createFileSystemDeploymentActivationRegistry, DeploymentActivationError, } from './activation.js';
1
+ export { createFileSystemDeploymentActivationRegistry, DeploymentActivationError, validateDeploymentActivationRecord, } from './activation.js';
2
2
  export { DEPLOYMENT_BUNDLE_CONTRACT, DEPLOYMENT_BUNDLE_MANIFEST, verifyDeploymentBundle, } from './bundle.js';
3
3
  export { DeploymentIntakeError, } from './errors.js';
4
4
  export { createFileSystemDeploymentSubmissionStore, FileSystemDeploymentStoreError, } from './filesystem-store.js';
5
5
  export { createDeploymentIntake, } from './intake.js';
6
+ export { createDeploymentControlPlaneFetchHandler, createDeploymentControlPlaneNodeHandler, } from './control-plane-adapters.js';
7
+ export { createDeploymentControlPlane, } from './control-plane.js';
8
+ export { DEFAULT_DEPLOYMENT_CONTROL_PLANE_LIMITS, resolveDeploymentControlPlaneLimits, } from './control-plane-limits.js';
6
9
  export { DEFAULT_DEPLOYMENT_INTAKE_LIMITS, resolveDeploymentIntakeLimits, } from './limits.js';
10
+ export { createNodeWorkerDeploymentRuntimeFactory, NodeDeploymentRuntimeError, } from './node-runtime-factory.js';
11
+ export { createDeploymentRuntimeMaterializer, DeploymentRuntimeMaterializationError, } from './runtime-materialization.js';
12
+ export { createDeploymentRuntimeSupervisor, DeploymentRuntimeSupervisorError, } from './runtime-supervisor.js';
@@ -0,0 +1,16 @@
1
+ import type { DeploymentRuntimeFactory } from './runtime-supervisor.js';
2
+ 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
+ export declare class NodeDeploymentRuntimeError extends Error {
4
+ readonly code: NodeDeploymentRuntimeErrorCode;
5
+ constructor(code: NodeDeploymentRuntimeErrorCode, message: string, options?: {
6
+ readonly cause?: unknown;
7
+ });
8
+ }
9
+ export interface NodeDeploymentRuntimeFactoryOptions {
10
+ readonly temporaryDirectory?: string;
11
+ /** Worker import deadline from 1 through 300,000 milliseconds. */
12
+ readonly startupTimeoutMs?: number;
13
+ readonly onCleanupError?: (error: unknown, directory: string) => void;
14
+ }
15
+ export declare function createNodeWorkerDeploymentRuntimeFactory(options?: NodeDeploymentRuntimeFactoryOptions): DeploymentRuntimeFactory;
16
+ //# sourceMappingURL=node-runtime-factory.d.ts.map
@@ -0,0 +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"}