@keystrokehq/hosting 0.1.25 → 0.1.27

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/dist/index.cjs CHANGED
@@ -12,18 +12,35 @@ const PROJECT_SERVER_CONTROL = {
12
12
  unload: "/control/projects/unload",
13
13
  port: require_wait_for_health.PROJECT_SERVER_PORT
14
14
  };
15
+ var RuntimeControlUnavailableError = class extends Error {
16
+ status;
17
+ constructor(message, options = {}) {
18
+ super(message, { cause: options.cause });
19
+ this.name = "RuntimeControlUnavailableError";
20
+ this.status = options.status;
21
+ }
22
+ };
15
23
  async function postControl(baseUrl, path, body, options = {}) {
16
24
  const timeoutMs = options.timeoutMs ?? 15e3;
17
25
  const headers = { "content-type": "application/json" };
18
26
  if (options.workerToken) headers.authorization = `Bearer ${options.workerToken}`;
19
- const response = await (options.fetchImpl ?? fetch)(new URL(path, baseUrl), {
20
- method: "POST",
21
- headers,
22
- body: JSON.stringify(body),
23
- signal: AbortSignal.timeout(timeoutMs)
24
- });
27
+ let response;
28
+ try {
29
+ response = await (options.fetchImpl ?? fetch)(new URL(path, baseUrl), {
30
+ method: "POST",
31
+ headers,
32
+ body: JSON.stringify(body),
33
+ signal: AbortSignal.timeout(timeoutMs)
34
+ });
35
+ } catch (cause) {
36
+ throw new RuntimeControlUnavailableError(`Runtime control ${path} unavailable`, { cause });
37
+ }
25
38
  const data = await response.json().catch(() => ({}));
26
- if (!response.ok || data.ok === false) throw new Error(typeof data.error === "string" ? data.error : `Runtime control ${path} failed (${response.status})`);
39
+ const message = typeof data.error === "string" ? data.error : `Runtime control ${path} failed (${response.status})`;
40
+ if (!response.ok || data.ok === false) {
41
+ if (response.status === 404 || response.status >= 500) throw new RuntimeControlUnavailableError(message, { status: response.status });
42
+ throw new Error(message);
43
+ }
27
44
  return data;
28
45
  }
29
46
  async function loadProjectOnRuntime(baseUrl, input, options = {}) {
@@ -170,6 +187,7 @@ exports.PROJECT_SERVER_IMAGE = require_wait_for_health.PROJECT_SERVER_IMAGE;
170
187
  exports.PROJECT_SERVER_PORT = require_wait_for_health.PROJECT_SERVER_PORT;
171
188
  exports.PROJECT_SERVER_ROOT = require_wait_for_health.PROJECT_SERVER_ROOT;
172
189
  exports.RUNTIME_PING_TIMEOUT_MS = RUNTIME_PING_TIMEOUT_MS;
190
+ exports.RuntimeControlUnavailableError = RuntimeControlUnavailableError;
173
191
  exports.WorkerRuntimeConfigError = require_wait_for_health.WorkerRuntimeConfigError;
174
192
  exports.buildRuntimeEnv = require_wait_for_health.buildRuntimeEnv;
175
193
  exports.canPingProjectTarget = canPingProjectTarget;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["PROJECT_SERVER_PORT","PROJECT_SERVER_HEALTH","PROJECT_SERVER_DEPLOY_STATUS"],"sources":["../src/runtime-constants.ts","../src/runtime-control.ts","../src/ping-project.ts","../src/ping-project-target.ts","../src/deploy-status.ts"],"sourcesContent":["/** Timeout for a single project runtime `/health` probe. */\nexport const RUNTIME_PING_TIMEOUT_MS = 15_000;\n","import { PROJECT_SERVER_PORT } from \"./constants\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nexport const PROJECT_SERVER_CONTROL = {\n load: \"/control/projects/load\",\n promote: \"/control/projects/promote\",\n unload: \"/control/projects/unload\",\n port: PROJECT_SERVER_PORT,\n} as const;\n\nexport type LoadProjectOnRuntimeInput = {\n projectId: string;\n artifactId: string;\n artifactVersion: number;\n storageKey: string;\n activate?: boolean;\n};\n\nexport type RuntimeControlOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n /** Bearer token — typically the org's WORKER_INTERNAL_TOKEN. */\n workerToken?: string;\n};\n\nasync function postControl<T>(\n baseUrl: string,\n path: string,\n body: unknown,\n options: RuntimeControlOptions = {},\n): Promise<T> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n };\n if (options.workerToken) {\n headers.authorization = `Bearer ${options.workerToken}`;\n }\n\n const response = await (options.fetchImpl ?? fetch)(new URL(path, baseUrl), {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(timeoutMs),\n });\n\n const data = (await response.json().catch(() => ({}))) as T & { ok?: boolean; error?: string };\n if (!response.ok || data.ok === false) {\n throw new Error(\n typeof data.error === \"string\"\n ? data.error\n : `Runtime control ${path} failed (${response.status})`,\n );\n }\n\n return data;\n}\n\nexport async function loadProjectOnRuntime(\n baseUrl: string,\n input: LoadProjectOnRuntimeInput,\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.load, input, options);\n}\n\nexport async function promoteProjectOnRuntime(\n baseUrl: string,\n input: { projectId: string; artifactId: string },\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.promote, input, options);\n}\n\nexport async function unloadProjectOnRuntime(\n baseUrl: string,\n input: { projectId: string; artifactId: string; force?: boolean },\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.unload, input, options);\n}\n\n/** True when the org runtime answers /health. */\nexport async function pingRuntimeHealth(\n baseUrl: string,\n options: RuntimeControlOptions = {},\n): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n try {\n const response = await (options.fetchImpl ?? fetch)(new URL(\"/health\", baseUrl), {\n signal: AbortSignal.timeout(timeoutMs),\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n","import { PROJECT_SERVER_HEALTH } from \"./constants\";\nimport type { HostingPlugin } from \"./plugin\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nexport type PingProjectOptions = {\n runtimeId?: string | null;\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n plugin?: Pick<HostingPlugin, \"pingRequestHeaders\">;\n};\n\nexport async function pingProject(\n baseUrl: string,\n options: PingProjectOptions = {},\n): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n const headers = options.plugin?.pingRequestHeaders?.(options.runtimeId ?? null) ?? {};\n\n try {\n const response = await (options.fetchImpl ?? fetch)(\n new URL(PROJECT_SERVER_HEALTH.path, baseUrl),\n {\n signal: AbortSignal.timeout(timeoutMs),\n headers,\n },\n );\n\n return response.ok;\n } catch {\n return false;\n }\n}\n","import type { HostingPlugin } from \"./plugin\";\nimport type { ProjectPingTarget } from \"./runtime\";\nimport { pingProject, type PingProjectOptions } from \"./ping-project\";\n\nexport function canPingProjectTarget(\n target: ProjectPingTarget,\n plugin?: Pick<HostingPlugin, \"canPingTarget\">,\n): target is { baseUrl: string; runtimeId: string | null } {\n if (plugin?.canPingTarget) {\n return plugin.canPingTarget(target);\n }\n\n return !!target.baseUrl;\n}\n\nexport async function pingProjectTarget(\n target: ProjectPingTarget,\n options: PingProjectOptions & {\n plugin?: Pick<HostingPlugin, \"canPingTarget\" | \"pingRequestHeaders\">;\n } = {},\n): Promise<boolean> {\n if (!canPingProjectTarget(target, options.plugin)) {\n return false;\n }\n\n return pingProject(target.baseUrl, {\n ...options,\n runtimeId: target.runtimeId,\n });\n}\n","import { PROJECT_SERVER_DEPLOY_STATUS } from \"./constants\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nconst DEFAULT_WAIT_TIMEOUT_MS = 120_000;\nconst DEFAULT_WAIT_INTERVAL_MS = 500;\nconst REQUEST_TIMEOUT_MS = 2_000;\n\n/** Per-project bootstrap outcome reported by an org runtime machine. */\nexport type ProjectDeployStatus = {\n projectId: string;\n ok: boolean;\n error?: string;\n};\n\nexport type VersionDeployStatus = {\n projectId: string;\n artifactId: string;\n state: \"active\" | \"resident\" | \"indexed\";\n ok: boolean;\n activeJobCount?: number;\n error?: string;\n};\n\nexport type DeployStatusResponse = {\n projects: ProjectDeployStatus[];\n versions?: VersionDeployStatus[];\n};\n\nexport type FetchDeployStatusOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n};\n\nexport type WaitForDeployStatusOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n intervalMs?: number;\n};\n\n/**\n * Ask a running org machine which projects bootstrapped and which failed.\n * Returns undefined when the endpoint is unreachable, non-OK, times out, or\n * returns an unusable payload — callers must treat that as non-affirmative\n * health for every pending project (never promote on silence).\n */\nexport async function fetchDeployStatus(\n baseUrl: string,\n options: FetchDeployStatusOptions = {},\n): Promise<DeployStatusResponse | undefined> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n\n try {\n const response = await (options.fetchImpl ?? fetch)(\n new URL(PROJECT_SERVER_DEPLOY_STATUS.path, baseUrl),\n { signal: AbortSignal.timeout(timeoutMs) },\n );\n\n if (!response.ok) {\n return undefined;\n }\n\n const data = (await response.json()) as DeployStatusResponse;\n if (!data || !Array.isArray(data.projects)) {\n return undefined;\n }\n\n return data;\n } catch (error) {\n console.warn(`[deploy-status] failed to fetch from ${baseUrl}:`, error);\n return undefined;\n }\n}\n\n/**\n * Poll `/deploy-status` until the real worker returns a usable payload or the\n * deadline expires. Retries only transient unavailability (network errors,\n * non-2xx including early-health 404, timeouts, malformed bodies). Any valid\n * `{ projects: [...] }` response — including empty or explicit failures — is\n * terminal so genuine bootstrap errors surface immediately.\n */\nexport async function waitForDeployStatus(\n baseUrl: string,\n options: WaitForDeployStatusOptions = {},\n): Promise<DeployStatusResponse | undefined> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const intervalMs = options.intervalMs ?? DEFAULT_WAIT_INTERVAL_MS;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n const remainingMs = deadline - Date.now();\n const requestTimeoutMs = Math.min(REQUEST_TIMEOUT_MS, Math.max(1, remainingMs));\n const status = await fetchDeployStatus(baseUrl, {\n fetchImpl: options.fetchImpl,\n timeoutMs: requestTimeoutMs,\n });\n if (status) {\n return status;\n }\n\n if (Date.now() + intervalMs >= deadline) {\n break;\n }\n await sleep(intervalMs);\n }\n\n return undefined;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport type DeployHealthVerdict = { ok: true } | { ok: false; error: string };\n\n/**\n * Require an explicit `{ projectId, ok: true }` entry for each candidate.\n * Missing entries, `ok: false`, empty `projects`, or an unavailable status\n * response all fail closed for that project.\n */\nexport function classifyDeployHealth(input: {\n projectIds: string[];\n deployStatus: DeployStatusResponse | undefined;\n}): Map<string, DeployHealthVerdict> {\n const verdicts = new Map<string, DeployHealthVerdict>();\n\n if (!input.deployStatus) {\n for (const projectId of input.projectIds) {\n verdicts.set(projectId, {\n ok: false,\n error: \"Deploy health status unavailable\",\n });\n }\n return verdicts;\n }\n\n const byId = new Map(\n input.deployStatus.projects\n .filter((entry) => typeof entry?.projectId === \"string\" && entry.projectId.length > 0)\n .map((entry) => [entry.projectId, entry]),\n );\n\n for (const projectId of input.projectIds) {\n const entry = byId.get(projectId);\n if (!entry) {\n verdicts.set(projectId, {\n ok: false,\n error: \"Deploy health status omitted project\",\n });\n continue;\n }\n if (entry.ok !== true) {\n verdicts.set(projectId, {\n ok: false,\n error: entry.error?.trim() || \"Project failed to start\",\n });\n continue;\n }\n verdicts.set(projectId, { ok: true });\n }\n\n return verdicts;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["PROJECT_SERVER_PORT","PROJECT_SERVER_HEALTH","PROJECT_SERVER_DEPLOY_STATUS"],"sources":["../src/runtime-constants.ts","../src/runtime-control.ts","../src/ping-project.ts","../src/ping-project-target.ts","../src/deploy-status.ts"],"sourcesContent":["/** Timeout for a single project runtime `/health` probe. */\nexport const RUNTIME_PING_TIMEOUT_MS = 15_000;\n","import { PROJECT_SERVER_PORT } from \"./constants\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nexport const PROJECT_SERVER_CONTROL = {\n load: \"/control/projects/load\",\n promote: \"/control/projects/promote\",\n unload: \"/control/projects/unload\",\n port: PROJECT_SERVER_PORT,\n} as const;\n\nexport type LoadProjectOnRuntimeInput = {\n projectId: string;\n artifactId: string;\n artifactVersion: number;\n storageKey: string;\n activate?: boolean;\n};\n\nexport type RuntimeControlOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n /** Bearer token — typically the org's WORKER_INTERNAL_TOKEN. */\n workerToken?: string;\n};\n\nexport class RuntimeControlUnavailableError extends Error {\n readonly status: number | undefined;\n\n constructor(message: string, options: { status?: number; cause?: unknown } = {}) {\n super(message, { cause: options.cause });\n this.name = \"RuntimeControlUnavailableError\";\n this.status = options.status;\n }\n}\n\nasync function postControl<T>(\n baseUrl: string,\n path: string,\n body: unknown,\n options: RuntimeControlOptions = {},\n): Promise<T> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n };\n if (options.workerToken) {\n headers.authorization = `Bearer ${options.workerToken}`;\n }\n\n let response: Response;\n try {\n response = await (options.fetchImpl ?? fetch)(new URL(path, baseUrl), {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (cause) {\n throw new RuntimeControlUnavailableError(`Runtime control ${path} unavailable`, { cause });\n }\n\n const data = (await response.json().catch(() => ({}))) as T & { ok?: boolean; error?: string };\n const message =\n typeof data.error === \"string\"\n ? data.error\n : `Runtime control ${path} failed (${response.status})`;\n if (!response.ok || data.ok === false) {\n if (response.status === 404 || response.status >= 500) {\n throw new RuntimeControlUnavailableError(message, { status: response.status });\n }\n throw new Error(message);\n }\n\n return data;\n}\n\nexport async function loadProjectOnRuntime(\n baseUrl: string,\n input: LoadProjectOnRuntimeInput,\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.load, input, options);\n}\n\nexport async function promoteProjectOnRuntime(\n baseUrl: string,\n input: { projectId: string; artifactId: string },\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.promote, input, options);\n}\n\nexport async function unloadProjectOnRuntime(\n baseUrl: string,\n input: { projectId: string; artifactId: string; force?: boolean },\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.unload, input, options);\n}\n\n/** True when the org runtime answers /health. */\nexport async function pingRuntimeHealth(\n baseUrl: string,\n options: RuntimeControlOptions = {},\n): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n try {\n const response = await (options.fetchImpl ?? fetch)(new URL(\"/health\", baseUrl), {\n signal: AbortSignal.timeout(timeoutMs),\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n","import { PROJECT_SERVER_HEALTH } from \"./constants\";\nimport type { HostingPlugin } from \"./plugin\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nexport type PingProjectOptions = {\n runtimeId?: string | null;\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n plugin?: Pick<HostingPlugin, \"pingRequestHeaders\">;\n};\n\nexport async function pingProject(\n baseUrl: string,\n options: PingProjectOptions = {},\n): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n const headers = options.plugin?.pingRequestHeaders?.(options.runtimeId ?? null) ?? {};\n\n try {\n const response = await (options.fetchImpl ?? fetch)(\n new URL(PROJECT_SERVER_HEALTH.path, baseUrl),\n {\n signal: AbortSignal.timeout(timeoutMs),\n headers,\n },\n );\n\n return response.ok;\n } catch {\n return false;\n }\n}\n","import type { HostingPlugin } from \"./plugin\";\nimport type { ProjectPingTarget } from \"./runtime\";\nimport { pingProject, type PingProjectOptions } from \"./ping-project\";\n\nexport function canPingProjectTarget(\n target: ProjectPingTarget,\n plugin?: Pick<HostingPlugin, \"canPingTarget\">,\n): target is { baseUrl: string; runtimeId: string | null } {\n if (plugin?.canPingTarget) {\n return plugin.canPingTarget(target);\n }\n\n return !!target.baseUrl;\n}\n\nexport async function pingProjectTarget(\n target: ProjectPingTarget,\n options: PingProjectOptions & {\n plugin?: Pick<HostingPlugin, \"canPingTarget\" | \"pingRequestHeaders\">;\n } = {},\n): Promise<boolean> {\n if (!canPingProjectTarget(target, options.plugin)) {\n return false;\n }\n\n return pingProject(target.baseUrl, {\n ...options,\n runtimeId: target.runtimeId,\n });\n}\n","import { PROJECT_SERVER_DEPLOY_STATUS } from \"./constants\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nconst DEFAULT_WAIT_TIMEOUT_MS = 120_000;\nconst DEFAULT_WAIT_INTERVAL_MS = 500;\nconst REQUEST_TIMEOUT_MS = 2_000;\n\n/** Per-project bootstrap outcome reported by an org runtime machine. */\nexport type ProjectDeployStatus = {\n projectId: string;\n ok: boolean;\n error?: string;\n};\n\nexport type VersionDeployStatus = {\n projectId: string;\n artifactId: string;\n state: \"active\" | \"resident\" | \"indexed\";\n ok: boolean;\n activeJobCount?: number;\n error?: string;\n};\n\nexport type DeployStatusResponse = {\n projects: ProjectDeployStatus[];\n versions?: VersionDeployStatus[];\n};\n\nexport type FetchDeployStatusOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n};\n\nexport type WaitForDeployStatusOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n intervalMs?: number;\n};\n\n/**\n * Ask a running org machine which projects bootstrapped and which failed.\n * Returns undefined when the endpoint is unreachable, non-OK, times out, or\n * returns an unusable payload — callers must treat that as non-affirmative\n * health for every pending project (never promote on silence).\n */\nexport async function fetchDeployStatus(\n baseUrl: string,\n options: FetchDeployStatusOptions = {},\n): Promise<DeployStatusResponse | undefined> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n\n try {\n const response = await (options.fetchImpl ?? fetch)(\n new URL(PROJECT_SERVER_DEPLOY_STATUS.path, baseUrl),\n { signal: AbortSignal.timeout(timeoutMs) },\n );\n\n if (!response.ok) {\n return undefined;\n }\n\n const data = (await response.json()) as DeployStatusResponse;\n if (!data || !Array.isArray(data.projects)) {\n return undefined;\n }\n\n return data;\n } catch (error) {\n console.warn(`[deploy-status] failed to fetch from ${baseUrl}:`, error);\n return undefined;\n }\n}\n\n/**\n * Poll `/deploy-status` until the real worker returns a usable payload or the\n * deadline expires. Retries only transient unavailability (network errors,\n * non-2xx including early-health 404, timeouts, malformed bodies). Any valid\n * `{ projects: [...] }` response — including empty or explicit failures — is\n * terminal so genuine bootstrap errors surface immediately.\n */\nexport async function waitForDeployStatus(\n baseUrl: string,\n options: WaitForDeployStatusOptions = {},\n): Promise<DeployStatusResponse | undefined> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const intervalMs = options.intervalMs ?? DEFAULT_WAIT_INTERVAL_MS;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n const remainingMs = deadline - Date.now();\n const requestTimeoutMs = Math.min(REQUEST_TIMEOUT_MS, Math.max(1, remainingMs));\n const status = await fetchDeployStatus(baseUrl, {\n fetchImpl: options.fetchImpl,\n timeoutMs: requestTimeoutMs,\n });\n if (status) {\n return status;\n }\n\n if (Date.now() + intervalMs >= deadline) {\n break;\n }\n await sleep(intervalMs);\n }\n\n return undefined;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport type DeployHealthVerdict = { ok: true } | { ok: false; error: string };\n\n/**\n * Require an explicit `{ projectId, ok: true }` entry for each candidate.\n * Missing entries, `ok: false`, empty `projects`, or an unavailable status\n * response all fail closed for that project.\n */\nexport function classifyDeployHealth(input: {\n projectIds: string[];\n deployStatus: DeployStatusResponse | undefined;\n}): Map<string, DeployHealthVerdict> {\n const verdicts = new Map<string, DeployHealthVerdict>();\n\n if (!input.deployStatus) {\n for (const projectId of input.projectIds) {\n verdicts.set(projectId, {\n ok: false,\n error: \"Deploy health status unavailable\",\n });\n }\n return verdicts;\n }\n\n const byId = new Map(\n input.deployStatus.projects\n .filter((entry) => typeof entry?.projectId === \"string\" && entry.projectId.length > 0)\n .map((entry) => [entry.projectId, entry]),\n );\n\n for (const projectId of input.projectIds) {\n const entry = byId.get(projectId);\n if (!entry) {\n verdicts.set(projectId, {\n ok: false,\n error: \"Deploy health status omitted project\",\n });\n continue;\n }\n if (entry.ok !== true) {\n verdicts.set(projectId, {\n ok: false,\n error: entry.error?.trim() || \"Project failed to start\",\n });\n continue;\n }\n verdicts.set(projectId, { ok: true });\n }\n\n return verdicts;\n}\n"],"mappings":";;;;;AACA,MAAa,0BAA0B;;;ACEvC,MAAa,yBAAyB;CACpC,MAAM;CACN,SAAS;CACT,QAAQ;CACR,MAAMA,wBAAAA;AACR;AAiBA,IAAa,iCAAb,cAAoD,MAAM;CACxD;CAEA,YAAY,SAAiB,UAAgD,CAAC,GAAG;EAC/E,MAAM,SAAS,EAAE,OAAO,QAAQ,MAAM,CAAC;EACvC,KAAK,OAAO;EACZ,KAAK,SAAS,QAAQ;CACxB;AACF;AAEA,eAAe,YACb,SACA,MACA,MACA,UAAiC,CAAC,GACtB;CACZ,MAAM,YAAY,QAAQ,aAAA;CAC1B,MAAM,UAAkC,EACtC,gBAAgB,mBAClB;CACA,IAAI,QAAQ,aACV,QAAQ,gBAAgB,UAAU,QAAQ;CAG5C,IAAI;CACJ,IAAI;EACF,WAAW,OAAO,QAAQ,aAAa,OAAO,IAAI,IAAI,MAAM,OAAO,GAAG;GACpE,QAAQ;GACR;GACA,MAAM,KAAK,UAAU,IAAI;GACzB,QAAQ,YAAY,QAAQ,SAAS;EACvC,CAAC;CACH,SAAS,OAAO;EACd,MAAM,IAAI,+BAA+B,mBAAmB,KAAK,eAAe,EAAE,MAAM,CAAC;CAC3F;CAEA,MAAM,OAAQ,MAAM,SAAS,KAAK,EAAE,aAAa,CAAC,EAAE;CACpD,MAAM,UACJ,OAAO,KAAK,UAAU,WAClB,KAAK,QACL,mBAAmB,KAAK,WAAW,SAAS,OAAO;CACzD,IAAI,CAAC,SAAS,MAAM,KAAK,OAAO,OAAO;EACrC,IAAI,SAAS,WAAW,OAAO,SAAS,UAAU,KAChD,MAAM,IAAI,+BAA+B,SAAS,EAAE,QAAQ,SAAS,OAAO,CAAC;EAE/E,MAAM,IAAI,MAAM,OAAO;CACzB;CAEA,OAAO;AACT;AAEA,eAAsB,qBACpB,SACA,OACA,UAAiC,CAAC,GACnB;CACf,MAAM,YAAY,SAAS,uBAAuB,MAAM,OAAO,OAAO;AACxE;AAEA,eAAsB,wBACpB,SACA,OACA,UAAiC,CAAC,GACnB;CACf,MAAM,YAAY,SAAS,uBAAuB,SAAS,OAAO,OAAO;AAC3E;AAEA,eAAsB,uBACpB,SACA,OACA,UAAiC,CAAC,GACnB;CACf,MAAM,YAAY,SAAS,uBAAuB,QAAQ,OAAO,OAAO;AAC1E;;AAGA,eAAsB,kBACpB,SACA,UAAiC,CAAC,GAChB;CAClB,MAAM,YAAY,QAAQ,aAAA;CAC1B,IAAI;EAIF,QAAO,OAHiB,QAAQ,aAAa,OAAO,IAAI,IAAI,WAAW,OAAO,GAAG,EAC/E,QAAQ,YAAY,QAAQ,SAAS,EACvC,CAAC,GACe;CAClB,QAAQ;EACN,OAAO;CACT;AACF;;;ACvGA,eAAsB,YACpB,SACA,UAA8B,CAAC,GACb;CAClB,MAAM,YAAY,QAAQ,aAAA;CAC1B,MAAM,UAAU,QAAQ,QAAQ,qBAAqB,QAAQ,aAAa,IAAI,KAAK,CAAC;CAEpF,IAAI;EASF,QAAO,OARiB,QAAQ,aAAa,OAC3C,IAAI,IAAIC,wBAAAA,sBAAsB,MAAM,OAAO,GAC3C;GACE,QAAQ,YAAY,QAAQ,SAAS;GACrC;EACF,CACF,GAEgB;CAClB,QAAQ;EACN,OAAO;CACT;AACF;;;AC3BA,SAAgB,qBACd,QACA,QACyD;CACzD,IAAI,QAAQ,eACV,OAAO,OAAO,cAAc,MAAM;CAGpC,OAAO,CAAC,CAAC,OAAO;AAClB;AAEA,eAAsB,kBACpB,QACA,UAEI,CAAC,GACa;CAClB,IAAI,CAAC,qBAAqB,QAAQ,QAAQ,MAAM,GAC9C,OAAO;CAGT,OAAO,YAAY,OAAO,SAAS;EACjC,GAAG;EACH,WAAW,OAAO;CACpB,CAAC;AACH;;;AC1BA,MAAM,0BAA0B;AAChC,MAAM,2BAA2B;AACjC,MAAM,qBAAqB;;;;;;;AAwC3B,eAAsB,kBACpB,SACA,UAAoC,CAAC,GACM;CAC3C,MAAM,YAAY,QAAQ,aAAA;CAE1B,IAAI;EACF,MAAM,WAAW,OAAO,QAAQ,aAAa,OAC3C,IAAI,IAAIC,wBAAAA,6BAA6B,MAAM,OAAO,GAClD,EAAE,QAAQ,YAAY,QAAQ,SAAS,EAAE,CAC3C;EAEA,IAAI,CAAC,SAAS,IACZ;EAGF,MAAM,OAAQ,MAAM,SAAS,KAAK;EAClC,IAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,KAAK,QAAQ,GACvC;EAGF,OAAO;CACT,SAAS,OAAO;EACd,QAAQ,KAAK,wCAAwC,QAAQ,IAAI,KAAK;EACtE;CACF;AACF;;;;;;;;AASA,eAAsB,oBACpB,SACA,UAAsC,CAAC,GACI;CAC3C,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,WAAW,KAAK,IAAI,IAAI;CAE9B,OAAO,KAAK,IAAI,IAAI,UAAU;EAC5B,MAAM,cAAc,WAAW,KAAK,IAAI;EACxC,MAAM,mBAAmB,KAAK,IAAI,oBAAoB,KAAK,IAAI,GAAG,WAAW,CAAC;EAC9E,MAAM,SAAS,MAAM,kBAAkB,SAAS;GAC9C,WAAW,QAAQ;GACnB,WAAW;EACb,CAAC;EACD,IAAI,QACF,OAAO;EAGT,IAAI,KAAK,IAAI,IAAI,cAAc,UAC7B;EAEF,MAAM,MAAM,UAAU;CACxB;AAGF;AAEA,SAAS,MAAM,IAA2B;CACxC,OAAO,IAAI,SAAS,YAAY;EAC9B,WAAW,SAAS,EAAE;CACxB,CAAC;AACH;;;;;;AASA,SAAgB,qBAAqB,OAGA;CACnC,MAAM,2BAAW,IAAI,IAAiC;CAEtD,IAAI,CAAC,MAAM,cAAc;EACvB,KAAK,MAAM,aAAa,MAAM,YAC5B,SAAS,IAAI,WAAW;GACtB,IAAI;GACJ,OAAO;EACT,CAAC;EAEH,OAAO;CACT;CAEA,MAAM,OAAO,IAAI,IACf,MAAM,aAAa,SAChB,QAAQ,UAAU,OAAO,OAAO,cAAc,YAAY,MAAM,UAAU,SAAS,CAAC,EACpF,KAAK,UAAU,CAAC,MAAM,WAAW,KAAK,CAAC,CAC5C;CAEA,KAAK,MAAM,aAAa,MAAM,YAAY;EACxC,MAAM,QAAQ,KAAK,IAAI,SAAS;EAChC,IAAI,CAAC,OAAO;GACV,SAAS,IAAI,WAAW;IACtB,IAAI;IACJ,OAAO;GACT,CAAC;GACD;EACF;EACA,IAAI,MAAM,OAAO,MAAM;GACrB,SAAS,IAAI,WAAW;IACtB,IAAI;IACJ,OAAO,MAAM,OAAO,KAAK,KAAK;GAChC,CAAC;GACD;EACF;EACA,SAAS,IAAI,WAAW,EAAE,IAAI,KAAK,CAAC;CACtC;CAEA,OAAO;AACT"}
package/dist/index.d.cts CHANGED
@@ -35,6 +35,13 @@ type RuntimeControlOptions = {
35
35
  timeoutMs?: number; /** Bearer token — typically the org's WORKER_INTERNAL_TOKEN. */
36
36
  workerToken?: string;
37
37
  };
38
+ declare class RuntimeControlUnavailableError extends Error {
39
+ readonly status: number | undefined;
40
+ constructor(message: string, options?: {
41
+ status?: number;
42
+ cause?: unknown;
43
+ });
44
+ }
38
45
  declare function loadProjectOnRuntime(baseUrl: string, input: LoadProjectOnRuntimeInput, options?: RuntimeControlOptions): Promise<void>;
39
46
  declare function promoteProjectOnRuntime(baseUrl: string, input: {
40
47
  projectId: string;
@@ -177,5 +184,5 @@ declare function classifyDeployHealth(input: {
177
184
  deployStatus: DeployStatusResponse | undefined;
178
185
  }): Map<string, DeployHealthVerdict>;
179
186
  //#endregion
180
- export { DEV_PLATFORM_WORKER_TOKEN, type DeployHealthVerdict, type DeployStatusResponse, FORBIDDEN_WORKER_ENV_KEYS, type FetchDeployStatusOptions, type HostingOptions, type HostingPlugin, type LoadProjectOnRuntimeInput, type OrgArtifactSpec, type OrgProjectDeploy, type OrganizationHostingInput, type OrganizationHostingResult, PROJECT_SERVER_CONTROL, PROJECT_SERVER_DEPLOY_STATUS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, type PingProjectOptions, type ProjectDeployStatus, type ProjectPingTarget, type ProjectRuntime, type ProjectRuntimeDatabase, type ProjectRuntimeDestroyInput, type ProjectRuntimeHosting, type ProjectRuntimeInput, type ProjectRuntimeReconcileInput, type ProjectRuntimeResult, type ProjectRuntimeSleepInput, type ProjectRuntimeWakeInput, RUNTIME_PING_TIMEOUT_MS, type RuntimeControlOptions, type RuntimeLaunchSpec, type VerifiedOrgWorkerToken, type VersionDeployStatus, type WaitForDeployStatusOptions, type WaitForHealthOptions, type WorkerRuntimeConfig, WorkerRuntimeConfigError, buildRuntimeEnv, canPingProjectTarget, classifyDeployHealth, encodeOrgArtifacts, fetchDeployStatus, formatDockerEnv, loadProjectOnRuntime, mintOrgWorkerToken, parseOrgArtifactsFromEnv, pingProject, pingProjectTarget, pingRuntimeHealth, promoteProjectOnRuntime, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, unloadProjectOnRuntime, verifyOrgWorkerToken, waitForDeployStatus, waitForHealth };
187
+ export { DEV_PLATFORM_WORKER_TOKEN, type DeployHealthVerdict, type DeployStatusResponse, FORBIDDEN_WORKER_ENV_KEYS, type FetchDeployStatusOptions, type HostingOptions, type HostingPlugin, type LoadProjectOnRuntimeInput, type OrgArtifactSpec, type OrgProjectDeploy, type OrganizationHostingInput, type OrganizationHostingResult, PROJECT_SERVER_CONTROL, PROJECT_SERVER_DEPLOY_STATUS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, type PingProjectOptions, type ProjectDeployStatus, type ProjectPingTarget, type ProjectRuntime, type ProjectRuntimeDatabase, type ProjectRuntimeDestroyInput, type ProjectRuntimeHosting, type ProjectRuntimeInput, type ProjectRuntimeReconcileInput, type ProjectRuntimeResult, type ProjectRuntimeSleepInput, type ProjectRuntimeWakeInput, RUNTIME_PING_TIMEOUT_MS, type RuntimeControlOptions, RuntimeControlUnavailableError, type RuntimeLaunchSpec, type VerifiedOrgWorkerToken, type VersionDeployStatus, type WaitForDeployStatusOptions, type WaitForHealthOptions, type WorkerRuntimeConfig, WorkerRuntimeConfigError, buildRuntimeEnv, canPingProjectTarget, classifyDeployHealth, encodeOrgArtifacts, fetchDeployStatus, formatDockerEnv, loadProjectOnRuntime, mintOrgWorkerToken, parseOrgArtifactsFromEnv, pingProject, pingProjectTarget, pingRuntimeHealth, promoteProjectOnRuntime, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, unloadProjectOnRuntime, verifyOrgWorkerToken, waitForDeployStatus, waitForHealth };
181
188
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/constants.ts","../src/runtime-control.ts","../src/runtime-env.ts","../src/org-worker-token.ts","../src/wait-for-health.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.ts","../src/deploy-status.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/constants.ts","../src/runtime-control.ts","../src/runtime-env.ts","../src/org-worker-token.ts","../src/wait-for-health.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.ts","../src/deploy-status.ts"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -35,6 +35,13 @@ type RuntimeControlOptions = {
35
35
  timeoutMs?: number; /** Bearer token — typically the org's WORKER_INTERNAL_TOKEN. */
36
36
  workerToken?: string;
37
37
  };
38
+ declare class RuntimeControlUnavailableError extends Error {
39
+ readonly status: number | undefined;
40
+ constructor(message: string, options?: {
41
+ status?: number;
42
+ cause?: unknown;
43
+ });
44
+ }
38
45
  declare function loadProjectOnRuntime(baseUrl: string, input: LoadProjectOnRuntimeInput, options?: RuntimeControlOptions): Promise<void>;
39
46
  declare function promoteProjectOnRuntime(baseUrl: string, input: {
40
47
  projectId: string;
@@ -177,5 +184,5 @@ declare function classifyDeployHealth(input: {
177
184
  deployStatus: DeployStatusResponse | undefined;
178
185
  }): Map<string, DeployHealthVerdict>;
179
186
  //#endregion
180
- export { DEV_PLATFORM_WORKER_TOKEN, type DeployHealthVerdict, type DeployStatusResponse, FORBIDDEN_WORKER_ENV_KEYS, type FetchDeployStatusOptions, type HostingOptions, type HostingPlugin, type LoadProjectOnRuntimeInput, type OrgArtifactSpec, type OrgProjectDeploy, type OrganizationHostingInput, type OrganizationHostingResult, PROJECT_SERVER_CONTROL, PROJECT_SERVER_DEPLOY_STATUS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, type PingProjectOptions, type ProjectDeployStatus, type ProjectPingTarget, type ProjectRuntime, type ProjectRuntimeDatabase, type ProjectRuntimeDestroyInput, type ProjectRuntimeHosting, type ProjectRuntimeInput, type ProjectRuntimeReconcileInput, type ProjectRuntimeResult, type ProjectRuntimeSleepInput, type ProjectRuntimeWakeInput, RUNTIME_PING_TIMEOUT_MS, type RuntimeControlOptions, type RuntimeLaunchSpec, type VerifiedOrgWorkerToken, type VersionDeployStatus, type WaitForDeployStatusOptions, type WaitForHealthOptions, type WorkerRuntimeConfig, WorkerRuntimeConfigError, buildRuntimeEnv, canPingProjectTarget, classifyDeployHealth, encodeOrgArtifacts, fetchDeployStatus, formatDockerEnv, loadProjectOnRuntime, mintOrgWorkerToken, parseOrgArtifactsFromEnv, pingProject, pingProjectTarget, pingRuntimeHealth, promoteProjectOnRuntime, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, unloadProjectOnRuntime, verifyOrgWorkerToken, waitForDeployStatus, waitForHealth };
187
+ export { DEV_PLATFORM_WORKER_TOKEN, type DeployHealthVerdict, type DeployStatusResponse, FORBIDDEN_WORKER_ENV_KEYS, type FetchDeployStatusOptions, type HostingOptions, type HostingPlugin, type LoadProjectOnRuntimeInput, type OrgArtifactSpec, type OrgProjectDeploy, type OrganizationHostingInput, type OrganizationHostingResult, PROJECT_SERVER_CONTROL, PROJECT_SERVER_DEPLOY_STATUS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, type PingProjectOptions, type ProjectDeployStatus, type ProjectPingTarget, type ProjectRuntime, type ProjectRuntimeDatabase, type ProjectRuntimeDestroyInput, type ProjectRuntimeHosting, type ProjectRuntimeInput, type ProjectRuntimeReconcileInput, type ProjectRuntimeResult, type ProjectRuntimeSleepInput, type ProjectRuntimeWakeInput, RUNTIME_PING_TIMEOUT_MS, type RuntimeControlOptions, RuntimeControlUnavailableError, type RuntimeLaunchSpec, type VerifiedOrgWorkerToken, type VersionDeployStatus, type WaitForDeployStatusOptions, type WaitForHealthOptions, type WorkerRuntimeConfig, WorkerRuntimeConfigError, buildRuntimeEnv, canPingProjectTarget, classifyDeployHealth, encodeOrgArtifacts, fetchDeployStatus, formatDockerEnv, loadProjectOnRuntime, mintOrgWorkerToken, parseOrgArtifactsFromEnv, pingProject, pingProjectTarget, pingRuntimeHealth, promoteProjectOnRuntime, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, unloadProjectOnRuntime, verifyOrgWorkerToken, waitForDeployStatus, waitForHealth };
181
188
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/constants.ts","../src/runtime-control.ts","../src/runtime-env.ts","../src/org-worker-token.ts","../src/wait-for-health.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.ts","../src/deploy-status.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/constants.ts","../src/runtime-control.ts","../src/runtime-env.ts","../src/org-worker-token.ts","../src/wait-for-health.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.ts","../src/deploy-status.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -11,18 +11,35 @@ const PROJECT_SERVER_CONTROL = {
11
11
  unload: "/control/projects/unload",
12
12
  port: PROJECT_SERVER_PORT
13
13
  };
14
+ var RuntimeControlUnavailableError = class extends Error {
15
+ status;
16
+ constructor(message, options = {}) {
17
+ super(message, { cause: options.cause });
18
+ this.name = "RuntimeControlUnavailableError";
19
+ this.status = options.status;
20
+ }
21
+ };
14
22
  async function postControl(baseUrl, path, body, options = {}) {
15
23
  const timeoutMs = options.timeoutMs ?? 15e3;
16
24
  const headers = { "content-type": "application/json" };
17
25
  if (options.workerToken) headers.authorization = `Bearer ${options.workerToken}`;
18
- const response = await (options.fetchImpl ?? fetch)(new URL(path, baseUrl), {
19
- method: "POST",
20
- headers,
21
- body: JSON.stringify(body),
22
- signal: AbortSignal.timeout(timeoutMs)
23
- });
26
+ let response;
27
+ try {
28
+ response = await (options.fetchImpl ?? fetch)(new URL(path, baseUrl), {
29
+ method: "POST",
30
+ headers,
31
+ body: JSON.stringify(body),
32
+ signal: AbortSignal.timeout(timeoutMs)
33
+ });
34
+ } catch (cause) {
35
+ throw new RuntimeControlUnavailableError(`Runtime control ${path} unavailable`, { cause });
36
+ }
24
37
  const data = await response.json().catch(() => ({}));
25
- if (!response.ok || data.ok === false) throw new Error(typeof data.error === "string" ? data.error : `Runtime control ${path} failed (${response.status})`);
38
+ const message = typeof data.error === "string" ? data.error : `Runtime control ${path} failed (${response.status})`;
39
+ if (!response.ok || data.ok === false) {
40
+ if (response.status === 404 || response.status >= 500) throw new RuntimeControlUnavailableError(message, { status: response.status });
41
+ throw new Error(message);
42
+ }
26
43
  return data;
27
44
  }
28
45
  async function loadProjectOnRuntime(baseUrl, input, options = {}) {
@@ -158,6 +175,6 @@ function classifyDeployHealth(input) {
158
175
  return verdicts;
159
176
  }
160
177
  //#endregion
161
- export { DEV_PLATFORM_WORKER_TOKEN, FORBIDDEN_WORKER_ENV_KEYS, PROJECT_SERVER_CONTROL, PROJECT_SERVER_DEPLOY_STATUS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, RUNTIME_PING_TIMEOUT_MS, WorkerRuntimeConfigError, buildRuntimeEnv, canPingProjectTarget, classifyDeployHealth, encodeOrgArtifacts, fetchDeployStatus, formatDockerEnv, loadProjectOnRuntime, mintOrgWorkerToken, parseOrgArtifactsFromEnv, pingProject, pingProjectTarget, pingRuntimeHealth, promoteProjectOnRuntime, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, unloadProjectOnRuntime, verifyOrgWorkerToken, waitForDeployStatus, waitForHealth };
178
+ export { DEV_PLATFORM_WORKER_TOKEN, FORBIDDEN_WORKER_ENV_KEYS, PROJECT_SERVER_CONTROL, PROJECT_SERVER_DEPLOY_STATUS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, RUNTIME_PING_TIMEOUT_MS, RuntimeControlUnavailableError, WorkerRuntimeConfigError, buildRuntimeEnv, canPingProjectTarget, classifyDeployHealth, encodeOrgArtifacts, fetchDeployStatus, formatDockerEnv, loadProjectOnRuntime, mintOrgWorkerToken, parseOrgArtifactsFromEnv, pingProject, pingProjectTarget, pingRuntimeHealth, promoteProjectOnRuntime, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, unloadProjectOnRuntime, verifyOrgWorkerToken, waitForDeployStatus, waitForHealth };
162
179
 
163
180
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/runtime-constants.ts","../src/runtime-control.ts","../src/ping-project.ts","../src/ping-project-target.ts","../src/deploy-status.ts"],"sourcesContent":["/** Timeout for a single project runtime `/health` probe. */\nexport const RUNTIME_PING_TIMEOUT_MS = 15_000;\n","import { PROJECT_SERVER_PORT } from \"./constants\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nexport const PROJECT_SERVER_CONTROL = {\n load: \"/control/projects/load\",\n promote: \"/control/projects/promote\",\n unload: \"/control/projects/unload\",\n port: PROJECT_SERVER_PORT,\n} as const;\n\nexport type LoadProjectOnRuntimeInput = {\n projectId: string;\n artifactId: string;\n artifactVersion: number;\n storageKey: string;\n activate?: boolean;\n};\n\nexport type RuntimeControlOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n /** Bearer token — typically the org's WORKER_INTERNAL_TOKEN. */\n workerToken?: string;\n};\n\nasync function postControl<T>(\n baseUrl: string,\n path: string,\n body: unknown,\n options: RuntimeControlOptions = {},\n): Promise<T> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n };\n if (options.workerToken) {\n headers.authorization = `Bearer ${options.workerToken}`;\n }\n\n const response = await (options.fetchImpl ?? fetch)(new URL(path, baseUrl), {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(timeoutMs),\n });\n\n const data = (await response.json().catch(() => ({}))) as T & { ok?: boolean; error?: string };\n if (!response.ok || data.ok === false) {\n throw new Error(\n typeof data.error === \"string\"\n ? data.error\n : `Runtime control ${path} failed (${response.status})`,\n );\n }\n\n return data;\n}\n\nexport async function loadProjectOnRuntime(\n baseUrl: string,\n input: LoadProjectOnRuntimeInput,\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.load, input, options);\n}\n\nexport async function promoteProjectOnRuntime(\n baseUrl: string,\n input: { projectId: string; artifactId: string },\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.promote, input, options);\n}\n\nexport async function unloadProjectOnRuntime(\n baseUrl: string,\n input: { projectId: string; artifactId: string; force?: boolean },\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.unload, input, options);\n}\n\n/** True when the org runtime answers /health. */\nexport async function pingRuntimeHealth(\n baseUrl: string,\n options: RuntimeControlOptions = {},\n): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n try {\n const response = await (options.fetchImpl ?? fetch)(new URL(\"/health\", baseUrl), {\n signal: AbortSignal.timeout(timeoutMs),\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n","import { PROJECT_SERVER_HEALTH } from \"./constants\";\nimport type { HostingPlugin } from \"./plugin\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nexport type PingProjectOptions = {\n runtimeId?: string | null;\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n plugin?: Pick<HostingPlugin, \"pingRequestHeaders\">;\n};\n\nexport async function pingProject(\n baseUrl: string,\n options: PingProjectOptions = {},\n): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n const headers = options.plugin?.pingRequestHeaders?.(options.runtimeId ?? null) ?? {};\n\n try {\n const response = await (options.fetchImpl ?? fetch)(\n new URL(PROJECT_SERVER_HEALTH.path, baseUrl),\n {\n signal: AbortSignal.timeout(timeoutMs),\n headers,\n },\n );\n\n return response.ok;\n } catch {\n return false;\n }\n}\n","import type { HostingPlugin } from \"./plugin\";\nimport type { ProjectPingTarget } from \"./runtime\";\nimport { pingProject, type PingProjectOptions } from \"./ping-project\";\n\nexport function canPingProjectTarget(\n target: ProjectPingTarget,\n plugin?: Pick<HostingPlugin, \"canPingTarget\">,\n): target is { baseUrl: string; runtimeId: string | null } {\n if (plugin?.canPingTarget) {\n return plugin.canPingTarget(target);\n }\n\n return !!target.baseUrl;\n}\n\nexport async function pingProjectTarget(\n target: ProjectPingTarget,\n options: PingProjectOptions & {\n plugin?: Pick<HostingPlugin, \"canPingTarget\" | \"pingRequestHeaders\">;\n } = {},\n): Promise<boolean> {\n if (!canPingProjectTarget(target, options.plugin)) {\n return false;\n }\n\n return pingProject(target.baseUrl, {\n ...options,\n runtimeId: target.runtimeId,\n });\n}\n","import { PROJECT_SERVER_DEPLOY_STATUS } from \"./constants\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nconst DEFAULT_WAIT_TIMEOUT_MS = 120_000;\nconst DEFAULT_WAIT_INTERVAL_MS = 500;\nconst REQUEST_TIMEOUT_MS = 2_000;\n\n/** Per-project bootstrap outcome reported by an org runtime machine. */\nexport type ProjectDeployStatus = {\n projectId: string;\n ok: boolean;\n error?: string;\n};\n\nexport type VersionDeployStatus = {\n projectId: string;\n artifactId: string;\n state: \"active\" | \"resident\" | \"indexed\";\n ok: boolean;\n activeJobCount?: number;\n error?: string;\n};\n\nexport type DeployStatusResponse = {\n projects: ProjectDeployStatus[];\n versions?: VersionDeployStatus[];\n};\n\nexport type FetchDeployStatusOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n};\n\nexport type WaitForDeployStatusOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n intervalMs?: number;\n};\n\n/**\n * Ask a running org machine which projects bootstrapped and which failed.\n * Returns undefined when the endpoint is unreachable, non-OK, times out, or\n * returns an unusable payload — callers must treat that as non-affirmative\n * health for every pending project (never promote on silence).\n */\nexport async function fetchDeployStatus(\n baseUrl: string,\n options: FetchDeployStatusOptions = {},\n): Promise<DeployStatusResponse | undefined> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n\n try {\n const response = await (options.fetchImpl ?? fetch)(\n new URL(PROJECT_SERVER_DEPLOY_STATUS.path, baseUrl),\n { signal: AbortSignal.timeout(timeoutMs) },\n );\n\n if (!response.ok) {\n return undefined;\n }\n\n const data = (await response.json()) as DeployStatusResponse;\n if (!data || !Array.isArray(data.projects)) {\n return undefined;\n }\n\n return data;\n } catch (error) {\n console.warn(`[deploy-status] failed to fetch from ${baseUrl}:`, error);\n return undefined;\n }\n}\n\n/**\n * Poll `/deploy-status` until the real worker returns a usable payload or the\n * deadline expires. Retries only transient unavailability (network errors,\n * non-2xx including early-health 404, timeouts, malformed bodies). Any valid\n * `{ projects: [...] }` response — including empty or explicit failures — is\n * terminal so genuine bootstrap errors surface immediately.\n */\nexport async function waitForDeployStatus(\n baseUrl: string,\n options: WaitForDeployStatusOptions = {},\n): Promise<DeployStatusResponse | undefined> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const intervalMs = options.intervalMs ?? DEFAULT_WAIT_INTERVAL_MS;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n const remainingMs = deadline - Date.now();\n const requestTimeoutMs = Math.min(REQUEST_TIMEOUT_MS, Math.max(1, remainingMs));\n const status = await fetchDeployStatus(baseUrl, {\n fetchImpl: options.fetchImpl,\n timeoutMs: requestTimeoutMs,\n });\n if (status) {\n return status;\n }\n\n if (Date.now() + intervalMs >= deadline) {\n break;\n }\n await sleep(intervalMs);\n }\n\n return undefined;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport type DeployHealthVerdict = { ok: true } | { ok: false; error: string };\n\n/**\n * Require an explicit `{ projectId, ok: true }` entry for each candidate.\n * Missing entries, `ok: false`, empty `projects`, or an unavailable status\n * response all fail closed for that project.\n */\nexport function classifyDeployHealth(input: {\n projectIds: string[];\n deployStatus: DeployStatusResponse | undefined;\n}): Map<string, DeployHealthVerdict> {\n const verdicts = new Map<string, DeployHealthVerdict>();\n\n if (!input.deployStatus) {\n for (const projectId of input.projectIds) {\n verdicts.set(projectId, {\n ok: false,\n error: \"Deploy health status unavailable\",\n });\n }\n return verdicts;\n }\n\n const byId = new Map(\n input.deployStatus.projects\n .filter((entry) => typeof entry?.projectId === \"string\" && entry.projectId.length > 0)\n .map((entry) => [entry.projectId, entry]),\n );\n\n for (const projectId of input.projectIds) {\n const entry = byId.get(projectId);\n if (!entry) {\n verdicts.set(projectId, {\n ok: false,\n error: \"Deploy health status omitted project\",\n });\n continue;\n }\n if (entry.ok !== true) {\n verdicts.set(projectId, {\n ok: false,\n error: entry.error?.trim() || \"Project failed to start\",\n });\n continue;\n }\n verdicts.set(projectId, { ok: true });\n }\n\n return verdicts;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/runtime-constants.ts","../src/runtime-control.ts","../src/ping-project.ts","../src/ping-project-target.ts","../src/deploy-status.ts"],"sourcesContent":["/** Timeout for a single project runtime `/health` probe. */\nexport const RUNTIME_PING_TIMEOUT_MS = 15_000;\n","import { PROJECT_SERVER_PORT } from \"./constants\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nexport const PROJECT_SERVER_CONTROL = {\n load: \"/control/projects/load\",\n promote: \"/control/projects/promote\",\n unload: \"/control/projects/unload\",\n port: PROJECT_SERVER_PORT,\n} as const;\n\nexport type LoadProjectOnRuntimeInput = {\n projectId: string;\n artifactId: string;\n artifactVersion: number;\n storageKey: string;\n activate?: boolean;\n};\n\nexport type RuntimeControlOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n /** Bearer token — typically the org's WORKER_INTERNAL_TOKEN. */\n workerToken?: string;\n};\n\nexport class RuntimeControlUnavailableError extends Error {\n readonly status: number | undefined;\n\n constructor(message: string, options: { status?: number; cause?: unknown } = {}) {\n super(message, { cause: options.cause });\n this.name = \"RuntimeControlUnavailableError\";\n this.status = options.status;\n }\n}\n\nasync function postControl<T>(\n baseUrl: string,\n path: string,\n body: unknown,\n options: RuntimeControlOptions = {},\n): Promise<T> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n };\n if (options.workerToken) {\n headers.authorization = `Bearer ${options.workerToken}`;\n }\n\n let response: Response;\n try {\n response = await (options.fetchImpl ?? fetch)(new URL(path, baseUrl), {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (cause) {\n throw new RuntimeControlUnavailableError(`Runtime control ${path} unavailable`, { cause });\n }\n\n const data = (await response.json().catch(() => ({}))) as T & { ok?: boolean; error?: string };\n const message =\n typeof data.error === \"string\"\n ? data.error\n : `Runtime control ${path} failed (${response.status})`;\n if (!response.ok || data.ok === false) {\n if (response.status === 404 || response.status >= 500) {\n throw new RuntimeControlUnavailableError(message, { status: response.status });\n }\n throw new Error(message);\n }\n\n return data;\n}\n\nexport async function loadProjectOnRuntime(\n baseUrl: string,\n input: LoadProjectOnRuntimeInput,\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.load, input, options);\n}\n\nexport async function promoteProjectOnRuntime(\n baseUrl: string,\n input: { projectId: string; artifactId: string },\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.promote, input, options);\n}\n\nexport async function unloadProjectOnRuntime(\n baseUrl: string,\n input: { projectId: string; artifactId: string; force?: boolean },\n options: RuntimeControlOptions = {},\n): Promise<void> {\n await postControl(baseUrl, PROJECT_SERVER_CONTROL.unload, input, options);\n}\n\n/** True when the org runtime answers /health. */\nexport async function pingRuntimeHealth(\n baseUrl: string,\n options: RuntimeControlOptions = {},\n): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n try {\n const response = await (options.fetchImpl ?? fetch)(new URL(\"/health\", baseUrl), {\n signal: AbortSignal.timeout(timeoutMs),\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n","import { PROJECT_SERVER_HEALTH } from \"./constants\";\nimport type { HostingPlugin } from \"./plugin\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nexport type PingProjectOptions = {\n runtimeId?: string | null;\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n plugin?: Pick<HostingPlugin, \"pingRequestHeaders\">;\n};\n\nexport async function pingProject(\n baseUrl: string,\n options: PingProjectOptions = {},\n): Promise<boolean> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n const headers = options.plugin?.pingRequestHeaders?.(options.runtimeId ?? null) ?? {};\n\n try {\n const response = await (options.fetchImpl ?? fetch)(\n new URL(PROJECT_SERVER_HEALTH.path, baseUrl),\n {\n signal: AbortSignal.timeout(timeoutMs),\n headers,\n },\n );\n\n return response.ok;\n } catch {\n return false;\n }\n}\n","import type { HostingPlugin } from \"./plugin\";\nimport type { ProjectPingTarget } from \"./runtime\";\nimport { pingProject, type PingProjectOptions } from \"./ping-project\";\n\nexport function canPingProjectTarget(\n target: ProjectPingTarget,\n plugin?: Pick<HostingPlugin, \"canPingTarget\">,\n): target is { baseUrl: string; runtimeId: string | null } {\n if (plugin?.canPingTarget) {\n return plugin.canPingTarget(target);\n }\n\n return !!target.baseUrl;\n}\n\nexport async function pingProjectTarget(\n target: ProjectPingTarget,\n options: PingProjectOptions & {\n plugin?: Pick<HostingPlugin, \"canPingTarget\" | \"pingRequestHeaders\">;\n } = {},\n): Promise<boolean> {\n if (!canPingProjectTarget(target, options.plugin)) {\n return false;\n }\n\n return pingProject(target.baseUrl, {\n ...options,\n runtimeId: target.runtimeId,\n });\n}\n","import { PROJECT_SERVER_DEPLOY_STATUS } from \"./constants\";\nimport { RUNTIME_PING_TIMEOUT_MS } from \"./runtime-constants\";\n\nconst DEFAULT_WAIT_TIMEOUT_MS = 120_000;\nconst DEFAULT_WAIT_INTERVAL_MS = 500;\nconst REQUEST_TIMEOUT_MS = 2_000;\n\n/** Per-project bootstrap outcome reported by an org runtime machine. */\nexport type ProjectDeployStatus = {\n projectId: string;\n ok: boolean;\n error?: string;\n};\n\nexport type VersionDeployStatus = {\n projectId: string;\n artifactId: string;\n state: \"active\" | \"resident\" | \"indexed\";\n ok: boolean;\n activeJobCount?: number;\n error?: string;\n};\n\nexport type DeployStatusResponse = {\n projects: ProjectDeployStatus[];\n versions?: VersionDeployStatus[];\n};\n\nexport type FetchDeployStatusOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n};\n\nexport type WaitForDeployStatusOptions = {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n intervalMs?: number;\n};\n\n/**\n * Ask a running org machine which projects bootstrapped and which failed.\n * Returns undefined when the endpoint is unreachable, non-OK, times out, or\n * returns an unusable payload — callers must treat that as non-affirmative\n * health for every pending project (never promote on silence).\n */\nexport async function fetchDeployStatus(\n baseUrl: string,\n options: FetchDeployStatusOptions = {},\n): Promise<DeployStatusResponse | undefined> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PING_TIMEOUT_MS;\n\n try {\n const response = await (options.fetchImpl ?? fetch)(\n new URL(PROJECT_SERVER_DEPLOY_STATUS.path, baseUrl),\n { signal: AbortSignal.timeout(timeoutMs) },\n );\n\n if (!response.ok) {\n return undefined;\n }\n\n const data = (await response.json()) as DeployStatusResponse;\n if (!data || !Array.isArray(data.projects)) {\n return undefined;\n }\n\n return data;\n } catch (error) {\n console.warn(`[deploy-status] failed to fetch from ${baseUrl}:`, error);\n return undefined;\n }\n}\n\n/**\n * Poll `/deploy-status` until the real worker returns a usable payload or the\n * deadline expires. Retries only transient unavailability (network errors,\n * non-2xx including early-health 404, timeouts, malformed bodies). Any valid\n * `{ projects: [...] }` response — including empty or explicit failures — is\n * terminal so genuine bootstrap errors surface immediately.\n */\nexport async function waitForDeployStatus(\n baseUrl: string,\n options: WaitForDeployStatusOptions = {},\n): Promise<DeployStatusResponse | undefined> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const intervalMs = options.intervalMs ?? DEFAULT_WAIT_INTERVAL_MS;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n const remainingMs = deadline - Date.now();\n const requestTimeoutMs = Math.min(REQUEST_TIMEOUT_MS, Math.max(1, remainingMs));\n const status = await fetchDeployStatus(baseUrl, {\n fetchImpl: options.fetchImpl,\n timeoutMs: requestTimeoutMs,\n });\n if (status) {\n return status;\n }\n\n if (Date.now() + intervalMs >= deadline) {\n break;\n }\n await sleep(intervalMs);\n }\n\n return undefined;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport type DeployHealthVerdict = { ok: true } | { ok: false; error: string };\n\n/**\n * Require an explicit `{ projectId, ok: true }` entry for each candidate.\n * Missing entries, `ok: false`, empty `projects`, or an unavailable status\n * response all fail closed for that project.\n */\nexport function classifyDeployHealth(input: {\n projectIds: string[];\n deployStatus: DeployStatusResponse | undefined;\n}): Map<string, DeployHealthVerdict> {\n const verdicts = new Map<string, DeployHealthVerdict>();\n\n if (!input.deployStatus) {\n for (const projectId of input.projectIds) {\n verdicts.set(projectId, {\n ok: false,\n error: \"Deploy health status unavailable\",\n });\n }\n return verdicts;\n }\n\n const byId = new Map(\n input.deployStatus.projects\n .filter((entry) => typeof entry?.projectId === \"string\" && entry.projectId.length > 0)\n .map((entry) => [entry.projectId, entry]),\n );\n\n for (const projectId of input.projectIds) {\n const entry = byId.get(projectId);\n if (!entry) {\n verdicts.set(projectId, {\n ok: false,\n error: \"Deploy health status omitted project\",\n });\n continue;\n }\n if (entry.ok !== true) {\n verdicts.set(projectId, {\n ok: false,\n error: entry.error?.trim() || \"Project failed to start\",\n });\n continue;\n }\n verdicts.set(projectId, { ok: true });\n }\n\n return verdicts;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keystrokehq/hosting",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/keystrokehq/keystroke.git",
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "dockerode": "^4.0.9",
40
- "@keystrokehq/shared": "0.1.60"
40
+ "@keystrokehq/shared": "0.1.61"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/dockerode": "^3.3.47",