@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 +25 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +8 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +25 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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;
|
package/dist/index.cjs.map
CHANGED
|
@@ -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":"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"}
|
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
|
package/dist/index.d.cts.map
CHANGED
|
@@ -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":";;;;cAAa,oBAAA;AAAA,cAEA,mBAAA;AAAA,cAEA,mBAAA;AAAA,cAEA,6BAAA;AAAA,cAEA,qCAAA;AAAA,cAEA,qBAAA;EAAA,SAGH,IAAA;EAAA,SAAA,IAAA;AAAA;AAAA,cAEG,4BAAA;EAAA,SAGH,IAAA;EAAA,SAAA,IAAA;AAAA;;;cCfG,sBAAA;EAAA;;;;;KAOD,yBAAA;EACV,SAAA;EACA,UAAA;EACA,eAAA;EACA,UAAA;EACA,QAAA;AAAA;AAAA,KAGU,qBAAA;EACV,SAAA,UAAmB,KAAK;EACxB,SAAA;EAEA,WAAA;AAAA;AAAA,
|
|
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
|
package/dist/index.d.mts.map
CHANGED
|
@@ -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":";;;;cAAa,oBAAA;AAAA,cAEA,mBAAA;AAAA,cAEA,mBAAA;AAAA,cAEA,6BAAA;AAAA,cAEA,qCAAA;AAAA,cAEA,qBAAA;EAAA,SAGH,IAAA;EAAA,SAAA,IAAA;AAAA;AAAA,cAEG,4BAAA;EAAA,SAGH,IAAA;EAAA,SAAA,IAAA;AAAA;;;cCfG,sBAAA;EAAA;;;;;KAOD,yBAAA;EACV,SAAA;EACA,UAAA;EACA,eAAA;EACA,UAAA;EACA,QAAA;AAAA;AAAA,KAGU,qBAAA;EACV,SAAA,UAAmB,KAAK;EACxB,SAAA;EAEA,WAAA;AAAA;AAAA,
|
|
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":";;;;cAAa,oBAAA;AAAA,cAEA,mBAAA;AAAA,cAEA,mBAAA;AAAA,cAEA,6BAAA;AAAA,cAEA,qCAAA;AAAA,cAEA,qBAAA;EAAA,SAGH,IAAA;EAAA,SAAA,IAAA;AAAA;AAAA,cAEG,4BAAA;EAAA,SAGH,IAAA;EAAA,SAAA,IAAA;AAAA;;;cCfG,sBAAA;EAAA;;;;;KAOD,yBAAA;EACV,SAAA;EACA,UAAA;EACA,eAAA;EACA,UAAA;EACA,QAAA;AAAA;AAAA,KAGU,qBAAA;EACV,SAAA,UAAmB,KAAK;EACxB,SAAA;EAEA,WAAA;AAAA;AAAA,cAGW,8BAAA,SAAuC,KAAK;EAAA,SAC9C,MAAA;cAEG,OAAA,UAAiB,OAAA;IAAW,MAAA;IAAiB,KAAA;EAAA;AAAA;AAAA,iBAgDrC,oBAAA,CACpB,OAAA,UACA,KAAA,EAAO,yBAAA,EACP,OAAA,GAAS,qBAAA,GACR,OAAA;AAAA,iBAImB,uBAAA,CACpB,OAAA,UACA,KAAA;EAAS,SAAA;EAAmB,UAAA;AAAA,GAC5B,OAAA,GAAS,qBAAA,GACR,OAAO;AAAA,iBAIY,sBAAA,CACpB,OAAA,UACA,KAAA;EAAS,SAAA;EAAmB,UAAA;EAAoB,KAAA;AAAA,GAChD,OAAA,GAAS,qBAAA,GACR,OAAO;;iBAKY,iBAAA,CACpB,OAAA,UACA,OAAA,GAAS,qBAAA,GACR,OAAO;;;ADxGV;AAAA,cEyCa,yBAAA;;cAqBA,yBAAA;AAAA,KAED,iBAAA;EACV,KAAA;EACA,GAAA,EAAK,MAAA;EACL,IAAA;EACA,MAAA,SAAe,qBAAqB;AAAA;AFhEtC;;;;AAAA,iBEuEgB,oBAAA,CACd,OAAA,EAAS,cAAA,EACT,SAAA,EAAW,eAAA,IACX,QAAA,EAAU,sBAAA,EACV,QAAA,GAAW,MAAA,mBACV,iBAAA;;iBAsCa,eAAA,CACd,MAAA,EAAQ,MAAA,CAAO,UAAA,EACf,SAAA,EAAW,eAAA,IACX,QAAA,EAAU,sBAAA,EACV,QAAA,GAAW,MAAA,mBACV,MAAA;AAAA,iBA2Da,0BAAA,CACd,MAAA,GAAQ,MAAA,CAAO,UAAwB;;iBAezB,wBAAA,CACd,MAAA,GAAQ,MAAA,CAAO,UAAwB;;iBAczB,mBAAA,CAAoB,IAAY;AAAA,iBAQhC,kBAAA,CAAmB,GAAW;;iBAW9B,eAAA,CAAgB,GAA2B,EAAtB,MAAM;AAAA,iBAI3B,yBAAA,CACd,GAAA,GAAK,MAAA,CAAO,UAAwB,EACpC,QAAA;;;;;;;AF9OF;iBGWgB,kBAAA,CAAmB,MAAA,UAAgB,cAAsB;AAAA,KAI7D,sBAAA;EACV,cAAc;AAAA;AAAA,iBAGA,oBAAA,CACd,MAAA,sBACA,KAAA,uBACC,sBAAsB;;;KCjBb,oBAAA;EACV,SAAA;EACA,UAAA;EACA,SAAA,UAAmB,KAAK;AAAA;AAAA,iBAGJ,aAAA,CACpB,OAAA,UACA,OAAA,GAAS,oBAAA,GACR,OAAO;;;;cCbG,uBAAA;;;KCGD,kBAAA;EACV,SAAA;EACA,SAAA,UAAmB,KAAA;EACnB,SAAA;EACA,MAAA,GAAS,IAAA,CAAK,aAAA;AAAA;AAAA,iBAGM,WAAA,CACpB,OAAA,UACA,OAAA,GAAS,kBAAA,GACR,OAAO;;;iBCVM,oBAAA,CACd,MAAA,EAAQ,iBAAA,EACR,MAAA,GAAS,IAAA,CAAK,aAAA,qBACb,MAAA;EAAY,OAAA;EAAiB,SAAA;AAAA;AAAA,iBAQV,iBAAA,CACpB,MAAA,EAAQ,iBAAA,EACR,OAAA,GAAS,kBAAA;EACP,MAAA,GAAS,IAAA,CAAK,aAAA;AAAA,IAEf,OAAA;;;;KCZS,mBAAA;EACV,SAAA;EACA,EAAA;EACA,KAAA;AAAA;AAAA,KAGU,mBAAA;EACV,SAAA;EACA,UAAA;EACA,KAAA;EACA,EAAA;EACA,cAAA;EACA,KAAA;AAAA;AAAA,KAGU,oBAAA;EACV,QAAA,EAAU,mBAAA;EACV,QAAA,GAAW,mBAAmB;AAAA;AAAA,KAGpB,wBAAA;EACV,SAAA,UAAmB,KAAK;EACxB,SAAA;AAAA;AAAA,KAGU,0BAAA;EACV,SAAA,UAAmB,KAAK;EACxB,SAAA;EACA,UAAA;AAAA;;AR5BgD;AAElD;;;;iBQmCsB,iBAAA,CACpB,OAAA,UACA,OAAA,GAAS,wBAAA,GACR,OAAA,CAAQ,oBAAA;ARjCX;;;;;;;AAAA,iBQiEsB,mBAAA,CACpB,OAAA,UACA,OAAA,GAAS,0BAAA,GACR,OAAA,CAAQ,oBAAA;AAAA,KA+BC,mBAAA;EAAwB,EAAA;AAAA;EAAe,EAAA;EAAW,KAAA;AAAA;;;;;APxG9D;iBO+GgB,oBAAA,CAAqB,KAAA;EACnC,UAAA;EACA,YAAA,EAAc,oBAAA;AAAA,IACZ,GAAA,SAAY,mBAAA"}
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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
|
package/dist/index.mjs.map
CHANGED
|
@@ -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.
|
|
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.
|
|
40
|
+
"@keystrokehq/shared": "0.1.61"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/dockerode": "^3.3.47",
|