@keystrokehq/hosting 0.1.19 → 0.1.21
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/docker.cjs +1 -1
- package/dist/docker.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{wait-for-health-B4-AM1NR.mjs → wait-for-health-CgCfteR7.mjs} +2 -1
- package/dist/wait-for-health-CgCfteR7.mjs.map +1 -0
- package/dist/{wait-for-health-CObmNF8o.cjs → wait-for-health-UXzWgWhs.cjs} +2 -1
- package/dist/wait-for-health-UXzWgWhs.cjs.map +1 -0
- package/package.json +2 -2
- package/dist/wait-for-health-B4-AM1NR.mjs.map +0 -1
- package/dist/wait-for-health-CObmNF8o.cjs.map +0 -1
package/dist/docker.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_wait_for_health = require("./wait-for-health-
|
|
2
|
+
const require_wait_for_health = require("./wait-for-health-UXzWgWhs.cjs");
|
|
3
3
|
let node_fs_promises = require("node:fs/promises");
|
|
4
4
|
//#region src/docker/create-docker-runtime.ts
|
|
5
5
|
const MINIO_DOCKER_NETWORK = process.env.MINIO_DOCKER_NETWORK ?? "keystroke";
|
package/dist/docker.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as formatDockerEnv, c as resolveRuntimeLaunch, h as resolveWorkerRuntimeConfig, t as waitForHealth } from "./wait-for-health-
|
|
1
|
+
import { a as formatDockerEnv, c as resolveRuntimeLaunch, h as resolveWorkerRuntimeConfig, t as waitForHealth } from "./wait-for-health-CgCfteR7.mjs";
|
|
2
2
|
import { mkdir } from "node:fs/promises";
|
|
3
3
|
//#region src/docker/create-docker-runtime.ts
|
|
4
4
|
const MINIO_DOCKER_NETWORK = process.env.MINIO_DOCKER_NETWORK ?? "keystroke";
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_wait_for_health = require("./wait-for-health-
|
|
2
|
+
const require_wait_for_health = require("./wait-for-health-UXzWgWhs.cjs");
|
|
3
3
|
const require_runtime = require("./runtime-CV7pSfMl.cjs");
|
|
4
4
|
//#region src/runtime-constants.ts
|
|
5
5
|
/** Timeout for a single project runtime `/health` probe. */
|
package/dist/index.d.cts
CHANGED
|
@@ -50,7 +50,7 @@ declare function pingRuntimeHealth(baseUrl: string, options?: RuntimeControlOpti
|
|
|
50
50
|
//#endregion
|
|
51
51
|
//#region src/runtime-env.d.ts
|
|
52
52
|
/** Env keys that must never be forwarded into untrusted org workers. */
|
|
53
|
-
declare const FORBIDDEN_WORKER_ENV_KEYS: readonly ["BETTER_AUTH_SECRET", "DATABASE_URL", "POSTHOG_API_KEY", "POSTGRES_PASSWORD", "PLATFORM_WORKER_TOKEN", "STRIPE_SECRET_KEY", "CREDENTIAL_ENCRYPTION_KEY", "TURNSTILE_SECRET"];
|
|
53
|
+
declare const FORBIDDEN_WORKER_ENV_KEYS: readonly ["BETTER_AUTH_SECRET", "BETTER_AUTH_API_KEY", "DATABASE_URL", "POSTHOG_API_KEY", "POSTGRES_PASSWORD", "PLATFORM_WORKER_TOKEN", "STRIPE_SECRET_KEY", "CREDENTIAL_ENCRYPTION_KEY", "TURNSTILE_SECRET"];
|
|
54
54
|
/** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */
|
|
55
55
|
declare const DEV_PLATFORM_WORKER_TOKEN = "dev-platform-worker-token";
|
|
56
56
|
type RuntimeLaunchSpec = {
|
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,iBAoCoB,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;ADpEV;AAAA,iBCyEsB,iBAAA,CACpB,OAAA,UACA,OAAA,GAAS,qBAAA,GACR,OAAO;;;ADtFV;AAAA,cEyCa,yBAAA;;
|
|
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
|
@@ -50,7 +50,7 @@ declare function pingRuntimeHealth(baseUrl: string, options?: RuntimeControlOpti
|
|
|
50
50
|
//#endregion
|
|
51
51
|
//#region src/runtime-env.d.ts
|
|
52
52
|
/** Env keys that must never be forwarded into untrusted org workers. */
|
|
53
|
-
declare const FORBIDDEN_WORKER_ENV_KEYS: readonly ["BETTER_AUTH_SECRET", "DATABASE_URL", "POSTHOG_API_KEY", "POSTGRES_PASSWORD", "PLATFORM_WORKER_TOKEN", "STRIPE_SECRET_KEY", "CREDENTIAL_ENCRYPTION_KEY", "TURNSTILE_SECRET"];
|
|
53
|
+
declare const FORBIDDEN_WORKER_ENV_KEYS: readonly ["BETTER_AUTH_SECRET", "BETTER_AUTH_API_KEY", "DATABASE_URL", "POSTHOG_API_KEY", "POSTGRES_PASSWORD", "PLATFORM_WORKER_TOKEN", "STRIPE_SECRET_KEY", "CREDENTIAL_ENCRYPTION_KEY", "TURNSTILE_SECRET"];
|
|
54
54
|
/** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */
|
|
55
55
|
declare const DEV_PLATFORM_WORKER_TOKEN = "dev-platform-worker-token";
|
|
56
56
|
type RuntimeLaunchSpec = {
|
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,iBAoCoB,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;ADpEV;AAAA,iBCyEsB,iBAAA,CACpB,OAAA,UACA,OAAA,GAAS,qBAAA,GACR,OAAO;;;ADtFV;AAAA,cEyCa,yBAAA;;
|
|
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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as PROJECT_SERVER_ROOT, _ as PROJECT_SERVER_FRAMEWORK_NODE_MODULES, a as formatDockerEnv, b as PROJECT_SERVER_IMAGE, c as resolveRuntimeLaunch, d as rewriteLoopbackUrl, f as mintOrgWorkerToken, g as PROJECT_SERVER_DEPLOY_STATUS, h as resolveWorkerRuntimeConfig, i as buildRuntimeEnv, l as resolveWorkerPlatformUrl, m as WorkerRuntimeConfigError, n as DEV_PLATFORM_WORKER_TOKEN, o as resolvePlatformWorkerToken, p as verifyOrgWorkerToken, r as FORBIDDEN_WORKER_ENV_KEYS, s as resolveProjectServerImage, t as waitForHealth, u as rewriteLoopbackHost, v as PROJECT_SERVER_FRAMEWORK_ROOT, x as PROJECT_SERVER_PORT, y as PROJECT_SERVER_HEALTH } from "./wait-for-health-
|
|
1
|
+
import { S as PROJECT_SERVER_ROOT, _ as PROJECT_SERVER_FRAMEWORK_NODE_MODULES, a as formatDockerEnv, b as PROJECT_SERVER_IMAGE, c as resolveRuntimeLaunch, d as rewriteLoopbackUrl, f as mintOrgWorkerToken, g as PROJECT_SERVER_DEPLOY_STATUS, h as resolveWorkerRuntimeConfig, i as buildRuntimeEnv, l as resolveWorkerPlatformUrl, m as WorkerRuntimeConfigError, n as DEV_PLATFORM_WORKER_TOKEN, o as resolvePlatformWorkerToken, p as verifyOrgWorkerToken, r as FORBIDDEN_WORKER_ENV_KEYS, s as resolveProjectServerImage, t as waitForHealth, u as rewriteLoopbackHost, v as PROJECT_SERVER_FRAMEWORK_ROOT, x as PROJECT_SERVER_PORT, y as PROJECT_SERVER_HEALTH } from "./wait-for-health-CgCfteR7.mjs";
|
|
2
2
|
import { n as parseOrgArtifactsFromEnv, t as encodeOrgArtifacts } from "./runtime-BmfsHLrk.mjs";
|
|
3
3
|
//#region src/runtime-constants.ts
|
|
4
4
|
/** Timeout for a single project runtime `/health` probe. */
|
|
@@ -86,6 +86,7 @@ const OBSERVABILITY_ENV_KEYS = [
|
|
|
86
86
|
/** Env keys that must never be forwarded into untrusted org workers. */
|
|
87
87
|
const FORBIDDEN_WORKER_ENV_KEYS = [
|
|
88
88
|
"BETTER_AUTH_SECRET",
|
|
89
|
+
"BETTER_AUTH_API_KEY",
|
|
89
90
|
"DATABASE_URL",
|
|
90
91
|
"POSTHOG_API_KEY",
|
|
91
92
|
"POSTGRES_PASSWORD",
|
|
@@ -207,4 +208,4 @@ function sleep(ms) {
|
|
|
207
208
|
//#endregion
|
|
208
209
|
export { PROJECT_SERVER_ROOT as S, PROJECT_SERVER_FRAMEWORK_NODE_MODULES as _, formatDockerEnv as a, PROJECT_SERVER_IMAGE as b, resolveRuntimeLaunch as c, rewriteLoopbackUrl as d, mintOrgWorkerToken as f, PROJECT_SERVER_DEPLOY_STATUS as g, resolveWorkerRuntimeConfig as h, buildRuntimeEnv as i, resolveWorkerPlatformUrl as l, WorkerRuntimeConfigError as m, DEV_PLATFORM_WORKER_TOKEN as n, resolvePlatformWorkerToken as o, verifyOrgWorkerToken as p, FORBIDDEN_WORKER_ENV_KEYS as r, resolveProjectServerImage as s, waitForHealth as t, rewriteLoopbackHost as u, PROJECT_SERVER_FRAMEWORK_ROOT as v, PROJECT_SERVER_PORT as x, PROJECT_SERVER_HEALTH as y };
|
|
209
210
|
|
|
210
|
-
//# sourceMappingURL=wait-for-health-
|
|
211
|
+
//# sourceMappingURL=wait-for-health-CgCfteR7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait-for-health-CgCfteR7.mjs","names":[],"sources":["../src/constants.ts","../src/worker-runtime-config.ts","../src/org-worker-token.ts","../src/runtime-env.ts","../src/wait-for-health.ts"],"sourcesContent":["export const PROJECT_SERVER_IMAGE = \"keystroke/project-server:local\";\n\nexport const PROJECT_SERVER_PORT = 3000;\n\nexport const PROJECT_SERVER_ROOT = \"/app\";\n\nexport const PROJECT_SERVER_FRAMEWORK_ROOT = \"/opt/keystroke\";\n\nexport const PROJECT_SERVER_FRAMEWORK_NODE_MODULES = `${PROJECT_SERVER_FRAMEWORK_ROOT}/node_modules`;\n\nexport const PROJECT_SERVER_HEALTH = {\n path: \"/health\",\n port: PROJECT_SERVER_PORT,\n} as const;\n\nexport const PROJECT_SERVER_DEPLOY_STATUS = {\n path: \"/deploy-status\",\n port: PROJECT_SERVER_PORT,\n} as const;\n","import { resolvePlatformWorkerToken, resolveWorkerPlatformUrl } from \"./runtime-env\";\n\n/** Resolved platform ↔ project-server worker auth contract. */\nexport type WorkerRuntimeConfig = {\n /** Platform API base URL reachable from the project-server runtime. */\n platformUrl: string;\n /** Bearer token for platform `/internal` routes. */\n workerToken: string;\n};\n\nexport class WorkerRuntimeConfigError extends Error {\n readonly missing: readonly string[];\n\n constructor(missing: string[]) {\n super(\n `Worker runtime config incomplete (missing: ${missing.join(\", \")}). ` +\n \"In production set PLATFORM_WORKER_TOKEN and PUBLIC_PLATFORM_URL (or PLATFORM_URL).\",\n );\n this.name = \"WorkerRuntimeConfigError\";\n this.missing = missing;\n }\n}\n\n/** Fail fast when the platform cannot start worker-mode project servers. */\nexport function resolveWorkerRuntimeConfig(\n source: NodeJS.ProcessEnv = process.env,\n): WorkerRuntimeConfig {\n const platformUrl = resolveWorkerPlatformUrl(source);\n const workerToken = resolvePlatformWorkerToken(source);\n const missing: string[] = [];\n\n if (!platformUrl) {\n missing.push(\"PUBLIC_PLATFORM_URL or PLATFORM_URL\");\n }\n\n if (!workerToken) {\n missing.push(\"PLATFORM_WORKER_TOKEN\");\n }\n\n if (missing.length > 0) {\n throw new WorkerRuntimeConfigError(missing);\n }\n\n return { platformUrl: platformUrl!, workerToken: workerToken! };\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nfunction sign(secret: string, organizationId: string): string {\n return createHmac(\"sha256\", secret).update(`org-worker:${organizationId}`).digest(\"base64url\");\n}\n\n/**\n * Per-org worker token: `{organizationId}.{hmac}`. Self-describing so the\n * platform can tell which org a machine is calling as, and stateless — verified\n * by re-signing with the shared `PLATFORM_WORKER_TOKEN` secret.\n */\nexport function mintOrgWorkerToken(secret: string, organizationId: string): string {\n return `${organizationId}.${sign(secret, organizationId)}`;\n}\n\nexport type VerifiedOrgWorkerToken = {\n organizationId: string;\n};\n\nexport function verifyOrgWorkerToken(\n secret: string | undefined,\n token: string | undefined,\n): VerifiedOrgWorkerToken | undefined {\n if (!secret || !token) {\n return undefined;\n }\n\n // The signature is base64url (no dots), so the last dot ends the org id.\n const separator = token.lastIndexOf(\".\");\n if (separator <= 0) {\n return undefined;\n }\n\n const organizationId = token.slice(0, separator);\n const signature = Buffer.from(token.slice(separator + 1));\n const expected = Buffer.from(sign(secret, organizationId));\n if (signature.length !== expected.length || !timingSafeEqual(signature, expected)) {\n return undefined;\n }\n\n return { organizationId };\n}\n","import {\n LOCAL_PLATFORM_ORIGIN,\n resolveExplicitPublicPlatformOrigin,\n} from \"@keystrokehq/shared/platform-origin\";\n\nimport type { ProjectRuntimeDatabase } from \"./runtime\";\nimport { encodeOrgArtifacts, type OrgArtifactSpec } from \"./runtime\";\nimport {\n PROJECT_SERVER_FRAMEWORK_NODE_MODULES,\n PROJECT_SERVER_HEALTH,\n PROJECT_SERVER_IMAGE,\n PROJECT_SERVER_PORT,\n PROJECT_SERVER_ROOT,\n} from \"./constants\";\nimport type { HostingOptions } from \"./plugin\";\nimport { resolveWorkerRuntimeConfig } from \"./worker-runtime-config\";\nimport { mintOrgWorkerToken } from \"./org-worker-token\";\n\n/** Non-secret runtime config forwarded into org workers. Never include platform secrets. */\nconst RUNTIME_ENV_KEYS = [\n \"PUBLIC_PLATFORM_URL\",\n \"PUBLIC_PLATFORM_PROXY_URL\",\n \"PUBLIC_WEB_URL\",\n \"UPSTASH_REDIS_URL\",\n \"REDIS_URL\",\n \"KEYSTROKE_QUEUE_PREFIX\",\n] as const;\n\n/**\n * Observability ingest config for org workers (PostHog error tracking + crash reports).\n * Ingest tokens only — never forward `POSTHOG_API_KEY` (management) into workers.\n */\nconst OBSERVABILITY_ENV_KEYS = [\n \"POSTHOG_PROJECT_TOKEN\",\n \"POSTHOG_HOST\",\n \"POSTHOG_FLUSH_MODE\",\n \"KEYSTROKE_ENVIRONMENT\",\n \"KEYSTROKE_RELEASE\",\n] as const;\n\n/** Env keys that must never be forwarded into untrusted org workers. */\nexport const FORBIDDEN_WORKER_ENV_KEYS = [\n \"BETTER_AUTH_SECRET\",\n \"BETTER_AUTH_API_KEY\",\n \"DATABASE_URL\",\n \"POSTHOG_API_KEY\",\n \"POSTGRES_PASSWORD\",\n \"PLATFORM_WORKER_TOKEN\",\n \"STRIPE_SECRET_KEY\",\n \"CREDENTIAL_ENCRYPTION_KEY\",\n \"TURNSTILE_SECRET\",\n] as const;\n\n/** Provider and gateway env forwarded from the platform into project servers. */\nconst PROVIDER_ENV_KEYS = [\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n \"AI_GATEWAY_API_KEY\",\n \"AI_GATEWAY_BASE_URL\",\n] as const;\n\n/** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */\nexport const DEV_PLATFORM_WORKER_TOKEN = \"dev-platform-worker-token\";\n\nexport type RuntimeLaunchSpec = {\n image: string;\n env: Record<string, string>;\n port: number;\n health: typeof PROJECT_SERVER_HEALTH;\n};\n\n/**\n * Builds the launch spec for an org worker. Each deploy artifact is encoded in\n * `KEYSTROKE_ORG_ARTIFACTS` — there is no base image, so at least one artifact is required.\n */\nexport function resolveRuntimeLaunch(\n options: HostingOptions,\n artifacts: OrgArtifactSpec[],\n database: ProjectRuntimeDatabase,\n extraEnv?: Record<string, string>,\n): RuntimeLaunchSpec {\n if (artifacts.length === 0) {\n throw new Error(\"Cannot start an org worker without at least one artifact\");\n }\n\n const env = options.env ?? process.env;\n\n return {\n image: resolveProjectServerImage(env, options.image),\n env: buildRuntimeEnv(env, artifacts, database, extraEnv),\n port: PROJECT_SERVER_PORT,\n health: PROJECT_SERVER_HEALTH,\n };\n}\n\n/** @deprecated Single-project launch — prefer org {@link resolveRuntimeLaunch}. */\nexport function resolveSingleProjectRuntimeLaunch(\n options: HostingOptions,\n artifact: { storageKey: string; artifactId: string; artifactVersion: number },\n database: ProjectRuntimeDatabase & { projectId: string },\n extraEnv?: Record<string, string>,\n): RuntimeLaunchSpec {\n return resolveRuntimeLaunch(\n options,\n [\n {\n projectId: database.projectId,\n artifactStorageKey: artifact.storageKey,\n artifactId: artifact.artifactId,\n artifactVersion: artifact.artifactVersion,\n },\n ],\n database,\n extraEnv,\n );\n}\n\n/** Env vars passed into the org worker container/machine. */\nexport function buildRuntimeEnv(\n source: NodeJS.ProcessEnv,\n artifacts: OrgArtifactSpec[],\n database: ProjectRuntimeDatabase,\n extraEnv?: Record<string, string>,\n): Record<string, string> {\n const entries = new Map<string, string>([\n [\"PORT\", String(PROJECT_SERVER_PORT)],\n [\"KEYSTROKE_ROOT\", PROJECT_SERVER_ROOT],\n [\"KEYSTROKE_RUNTIME_NODE_MODULES\", PROJECT_SERVER_FRAMEWORK_NODE_MODULES],\n [\"KEYSTROKE_ORG_ARTIFACTS\", encodeOrgArtifacts(artifacts)],\n [\"ORGANIZATION_ID\", database.organizationId],\n [\"TENANT_ID\", database.organizationId],\n ]);\n\n for (const key of RUNTIME_ENV_KEYS) {\n const value = source[key]?.trim();\n if (!value) {\n continue;\n }\n entries.set(key, value);\n }\n\n for (const key of OBSERVABILITY_ENV_KEYS) {\n const value = source[key]?.trim();\n if (!value) {\n continue;\n }\n entries.set(key, value);\n }\n\n // OSS self-host: forward BYO provider/gateway env. Cloud llmProxy supplies extraEnv instead.\n if (!extraEnv) {\n for (const key of PROVIDER_ENV_KEYS) {\n const value = source[key]?.trim();\n if (value) {\n entries.set(key, value);\n }\n }\n }\n\n // Project containers always run as workers: they resolve credentials/secrets through\n // the platform internal API and are deliberately never given the decryption key.\n // The token is minted per org so the platform knows which org a machine calls as.\n const worker = resolveWorkerRuntimeConfig(source);\n entries.set(\"PLATFORM_URL\", worker.platformUrl);\n entries.set(\n \"WORKER_INTERNAL_TOKEN\",\n mintOrgWorkerToken(worker.workerToken, database.organizationId),\n );\n\n if (extraEnv) {\n for (const [key, value] of Object.entries(extraEnv)) {\n entries.set(key, value);\n }\n }\n\n for (const key of FORBIDDEN_WORKER_ENV_KEYS) {\n entries.delete(key);\n }\n\n return Object.fromEntries(entries);\n}\n\nexport function resolvePlatformWorkerToken(\n source: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const explicit = source.PLATFORM_WORKER_TOKEN?.trim() ?? source.WORKER_INTERNAL_TOKEN?.trim();\n if (explicit) {\n return explicit;\n }\n\n if (source.NODE_ENV === \"production\") {\n return undefined;\n }\n\n return DEV_PLATFORM_WORKER_TOKEN;\n}\n\n/** Platform API URL reachable from a project-server container. */\nexport function resolveWorkerPlatformUrl(\n source: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const raw =\n source.PLATFORM_URL?.trim() ??\n resolveExplicitPublicPlatformOrigin(source) ??\n (source.NODE_ENV === \"production\" ? undefined : LOCAL_PLATFORM_ORIGIN);\n if (!raw) {\n return undefined;\n }\n\n return rewriteLoopbackUrl(raw);\n}\n\n/** Rewrite loopback hosts so containers can reach Postgres and other host services. */\nexport function rewriteLoopbackHost(host: string): string {\n if (host === \"localhost\" || host === \"127.0.0.1\") {\n return \"host.docker.internal\";\n }\n\n return host;\n}\n\nexport function rewriteLoopbackUrl(url: string): string {\n try {\n const parsed = new URL(url);\n parsed.hostname = rewriteLoopbackHost(parsed.hostname);\n return parsed.toString().replace(/\\/$/, \"\");\n } catch {\n return url;\n }\n}\n\n/** dockerode expects `KEY=value` strings. */\nexport function formatDockerEnv(env: Record<string, string>): string[] {\n return Object.entries(env).map(([key, value]) => `${key}=${value}`);\n}\n\nexport function resolveProjectServerImage(\n env: NodeJS.ProcessEnv = process.env,\n override?: string,\n): string {\n return override ?? env.PROJECT_DOCKER_IMAGE ?? env.TENANT_DOCKER_IMAGE ?? PROJECT_SERVER_IMAGE;\n}\n","import { PROJECT_SERVER_HEALTH } from \"./constants\";\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst DEFAULT_INTERVAL_MS = 500;\n\nexport type WaitForHealthOptions = {\n timeoutMs?: number;\n intervalMs?: number;\n fetchImpl?: typeof fetch;\n};\n\nexport async function waitForHealth(\n baseUrl: string,\n options: WaitForHealthOptions = {},\n): Promise<void> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;\n const deadline = Date.now() + timeoutMs;\n const url = new URL(PROJECT_SERVER_HEALTH.path, baseUrl);\n\n while (Date.now() < deadline) {\n try {\n const response = await fetchImpl(url, { signal: AbortSignal.timeout(2_000) });\n if (response.ok) {\n return;\n }\n } catch {\n // retry until timeout\n }\n\n await sleep(intervalMs);\n }\n\n throw new Error(`Project server health check timed out after ${timeoutMs}ms (${url})`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n"],"mappings":"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"}
|
|
@@ -86,6 +86,7 @@ const OBSERVABILITY_ENV_KEYS = [
|
|
|
86
86
|
/** Env keys that must never be forwarded into untrusted org workers. */
|
|
87
87
|
const FORBIDDEN_WORKER_ENV_KEYS = [
|
|
88
88
|
"BETTER_AUTH_SECRET",
|
|
89
|
+
"BETTER_AUTH_API_KEY",
|
|
89
90
|
"DATABASE_URL",
|
|
90
91
|
"POSTHOG_API_KEY",
|
|
91
92
|
"POSTGRES_PASSWORD",
|
|
@@ -338,4 +339,4 @@ Object.defineProperty(exports, "waitForHealth", {
|
|
|
338
339
|
}
|
|
339
340
|
});
|
|
340
341
|
|
|
341
|
-
//# sourceMappingURL=wait-for-health-
|
|
342
|
+
//# sourceMappingURL=wait-for-health-UXzWgWhs.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait-for-health-UXzWgWhs.cjs","names":["encodeOrgArtifacts","LOCAL_PLATFORM_ORIGIN"],"sources":["../src/constants.ts","../src/worker-runtime-config.ts","../src/org-worker-token.ts","../src/runtime-env.ts","../src/wait-for-health.ts"],"sourcesContent":["export const PROJECT_SERVER_IMAGE = \"keystroke/project-server:local\";\n\nexport const PROJECT_SERVER_PORT = 3000;\n\nexport const PROJECT_SERVER_ROOT = \"/app\";\n\nexport const PROJECT_SERVER_FRAMEWORK_ROOT = \"/opt/keystroke\";\n\nexport const PROJECT_SERVER_FRAMEWORK_NODE_MODULES = `${PROJECT_SERVER_FRAMEWORK_ROOT}/node_modules`;\n\nexport const PROJECT_SERVER_HEALTH = {\n path: \"/health\",\n port: PROJECT_SERVER_PORT,\n} as const;\n\nexport const PROJECT_SERVER_DEPLOY_STATUS = {\n path: \"/deploy-status\",\n port: PROJECT_SERVER_PORT,\n} as const;\n","import { resolvePlatformWorkerToken, resolveWorkerPlatformUrl } from \"./runtime-env\";\n\n/** Resolved platform ↔ project-server worker auth contract. */\nexport type WorkerRuntimeConfig = {\n /** Platform API base URL reachable from the project-server runtime. */\n platformUrl: string;\n /** Bearer token for platform `/internal` routes. */\n workerToken: string;\n};\n\nexport class WorkerRuntimeConfigError extends Error {\n readonly missing: readonly string[];\n\n constructor(missing: string[]) {\n super(\n `Worker runtime config incomplete (missing: ${missing.join(\", \")}). ` +\n \"In production set PLATFORM_WORKER_TOKEN and PUBLIC_PLATFORM_URL (or PLATFORM_URL).\",\n );\n this.name = \"WorkerRuntimeConfigError\";\n this.missing = missing;\n }\n}\n\n/** Fail fast when the platform cannot start worker-mode project servers. */\nexport function resolveWorkerRuntimeConfig(\n source: NodeJS.ProcessEnv = process.env,\n): WorkerRuntimeConfig {\n const platformUrl = resolveWorkerPlatformUrl(source);\n const workerToken = resolvePlatformWorkerToken(source);\n const missing: string[] = [];\n\n if (!platformUrl) {\n missing.push(\"PUBLIC_PLATFORM_URL or PLATFORM_URL\");\n }\n\n if (!workerToken) {\n missing.push(\"PLATFORM_WORKER_TOKEN\");\n }\n\n if (missing.length > 0) {\n throw new WorkerRuntimeConfigError(missing);\n }\n\n return { platformUrl: platformUrl!, workerToken: workerToken! };\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nfunction sign(secret: string, organizationId: string): string {\n return createHmac(\"sha256\", secret).update(`org-worker:${organizationId}`).digest(\"base64url\");\n}\n\n/**\n * Per-org worker token: `{organizationId}.{hmac}`. Self-describing so the\n * platform can tell which org a machine is calling as, and stateless — verified\n * by re-signing with the shared `PLATFORM_WORKER_TOKEN` secret.\n */\nexport function mintOrgWorkerToken(secret: string, organizationId: string): string {\n return `${organizationId}.${sign(secret, organizationId)}`;\n}\n\nexport type VerifiedOrgWorkerToken = {\n organizationId: string;\n};\n\nexport function verifyOrgWorkerToken(\n secret: string | undefined,\n token: string | undefined,\n): VerifiedOrgWorkerToken | undefined {\n if (!secret || !token) {\n return undefined;\n }\n\n // The signature is base64url (no dots), so the last dot ends the org id.\n const separator = token.lastIndexOf(\".\");\n if (separator <= 0) {\n return undefined;\n }\n\n const organizationId = token.slice(0, separator);\n const signature = Buffer.from(token.slice(separator + 1));\n const expected = Buffer.from(sign(secret, organizationId));\n if (signature.length !== expected.length || !timingSafeEqual(signature, expected)) {\n return undefined;\n }\n\n return { organizationId };\n}\n","import {\n LOCAL_PLATFORM_ORIGIN,\n resolveExplicitPublicPlatformOrigin,\n} from \"@keystrokehq/shared/platform-origin\";\n\nimport type { ProjectRuntimeDatabase } from \"./runtime\";\nimport { encodeOrgArtifacts, type OrgArtifactSpec } from \"./runtime\";\nimport {\n PROJECT_SERVER_FRAMEWORK_NODE_MODULES,\n PROJECT_SERVER_HEALTH,\n PROJECT_SERVER_IMAGE,\n PROJECT_SERVER_PORT,\n PROJECT_SERVER_ROOT,\n} from \"./constants\";\nimport type { HostingOptions } from \"./plugin\";\nimport { resolveWorkerRuntimeConfig } from \"./worker-runtime-config\";\nimport { mintOrgWorkerToken } from \"./org-worker-token\";\n\n/** Non-secret runtime config forwarded into org workers. Never include platform secrets. */\nconst RUNTIME_ENV_KEYS = [\n \"PUBLIC_PLATFORM_URL\",\n \"PUBLIC_PLATFORM_PROXY_URL\",\n \"PUBLIC_WEB_URL\",\n \"UPSTASH_REDIS_URL\",\n \"REDIS_URL\",\n \"KEYSTROKE_QUEUE_PREFIX\",\n] as const;\n\n/**\n * Observability ingest config for org workers (PostHog error tracking + crash reports).\n * Ingest tokens only — never forward `POSTHOG_API_KEY` (management) into workers.\n */\nconst OBSERVABILITY_ENV_KEYS = [\n \"POSTHOG_PROJECT_TOKEN\",\n \"POSTHOG_HOST\",\n \"POSTHOG_FLUSH_MODE\",\n \"KEYSTROKE_ENVIRONMENT\",\n \"KEYSTROKE_RELEASE\",\n] as const;\n\n/** Env keys that must never be forwarded into untrusted org workers. */\nexport const FORBIDDEN_WORKER_ENV_KEYS = [\n \"BETTER_AUTH_SECRET\",\n \"BETTER_AUTH_API_KEY\",\n \"DATABASE_URL\",\n \"POSTHOG_API_KEY\",\n \"POSTGRES_PASSWORD\",\n \"PLATFORM_WORKER_TOKEN\",\n \"STRIPE_SECRET_KEY\",\n \"CREDENTIAL_ENCRYPTION_KEY\",\n \"TURNSTILE_SECRET\",\n] as const;\n\n/** Provider and gateway env forwarded from the platform into project servers. */\nconst PROVIDER_ENV_KEYS = [\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n \"AI_GATEWAY_API_KEY\",\n \"AI_GATEWAY_BASE_URL\",\n] as const;\n\n/** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */\nexport const DEV_PLATFORM_WORKER_TOKEN = \"dev-platform-worker-token\";\n\nexport type RuntimeLaunchSpec = {\n image: string;\n env: Record<string, string>;\n port: number;\n health: typeof PROJECT_SERVER_HEALTH;\n};\n\n/**\n * Builds the launch spec for an org worker. Each deploy artifact is encoded in\n * `KEYSTROKE_ORG_ARTIFACTS` — there is no base image, so at least one artifact is required.\n */\nexport function resolveRuntimeLaunch(\n options: HostingOptions,\n artifacts: OrgArtifactSpec[],\n database: ProjectRuntimeDatabase,\n extraEnv?: Record<string, string>,\n): RuntimeLaunchSpec {\n if (artifacts.length === 0) {\n throw new Error(\"Cannot start an org worker without at least one artifact\");\n }\n\n const env = options.env ?? process.env;\n\n return {\n image: resolveProjectServerImage(env, options.image),\n env: buildRuntimeEnv(env, artifacts, database, extraEnv),\n port: PROJECT_SERVER_PORT,\n health: PROJECT_SERVER_HEALTH,\n };\n}\n\n/** @deprecated Single-project launch — prefer org {@link resolveRuntimeLaunch}. */\nexport function resolveSingleProjectRuntimeLaunch(\n options: HostingOptions,\n artifact: { storageKey: string; artifactId: string; artifactVersion: number },\n database: ProjectRuntimeDatabase & { projectId: string },\n extraEnv?: Record<string, string>,\n): RuntimeLaunchSpec {\n return resolveRuntimeLaunch(\n options,\n [\n {\n projectId: database.projectId,\n artifactStorageKey: artifact.storageKey,\n artifactId: artifact.artifactId,\n artifactVersion: artifact.artifactVersion,\n },\n ],\n database,\n extraEnv,\n );\n}\n\n/** Env vars passed into the org worker container/machine. */\nexport function buildRuntimeEnv(\n source: NodeJS.ProcessEnv,\n artifacts: OrgArtifactSpec[],\n database: ProjectRuntimeDatabase,\n extraEnv?: Record<string, string>,\n): Record<string, string> {\n const entries = new Map<string, string>([\n [\"PORT\", String(PROJECT_SERVER_PORT)],\n [\"KEYSTROKE_ROOT\", PROJECT_SERVER_ROOT],\n [\"KEYSTROKE_RUNTIME_NODE_MODULES\", PROJECT_SERVER_FRAMEWORK_NODE_MODULES],\n [\"KEYSTROKE_ORG_ARTIFACTS\", encodeOrgArtifacts(artifacts)],\n [\"ORGANIZATION_ID\", database.organizationId],\n [\"TENANT_ID\", database.organizationId],\n ]);\n\n for (const key of RUNTIME_ENV_KEYS) {\n const value = source[key]?.trim();\n if (!value) {\n continue;\n }\n entries.set(key, value);\n }\n\n for (const key of OBSERVABILITY_ENV_KEYS) {\n const value = source[key]?.trim();\n if (!value) {\n continue;\n }\n entries.set(key, value);\n }\n\n // OSS self-host: forward BYO provider/gateway env. Cloud llmProxy supplies extraEnv instead.\n if (!extraEnv) {\n for (const key of PROVIDER_ENV_KEYS) {\n const value = source[key]?.trim();\n if (value) {\n entries.set(key, value);\n }\n }\n }\n\n // Project containers always run as workers: they resolve credentials/secrets through\n // the platform internal API and are deliberately never given the decryption key.\n // The token is minted per org so the platform knows which org a machine calls as.\n const worker = resolveWorkerRuntimeConfig(source);\n entries.set(\"PLATFORM_URL\", worker.platformUrl);\n entries.set(\n \"WORKER_INTERNAL_TOKEN\",\n mintOrgWorkerToken(worker.workerToken, database.organizationId),\n );\n\n if (extraEnv) {\n for (const [key, value] of Object.entries(extraEnv)) {\n entries.set(key, value);\n }\n }\n\n for (const key of FORBIDDEN_WORKER_ENV_KEYS) {\n entries.delete(key);\n }\n\n return Object.fromEntries(entries);\n}\n\nexport function resolvePlatformWorkerToken(\n source: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const explicit = source.PLATFORM_WORKER_TOKEN?.trim() ?? source.WORKER_INTERNAL_TOKEN?.trim();\n if (explicit) {\n return explicit;\n }\n\n if (source.NODE_ENV === \"production\") {\n return undefined;\n }\n\n return DEV_PLATFORM_WORKER_TOKEN;\n}\n\n/** Platform API URL reachable from a project-server container. */\nexport function resolveWorkerPlatformUrl(\n source: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const raw =\n source.PLATFORM_URL?.trim() ??\n resolveExplicitPublicPlatformOrigin(source) ??\n (source.NODE_ENV === \"production\" ? undefined : LOCAL_PLATFORM_ORIGIN);\n if (!raw) {\n return undefined;\n }\n\n return rewriteLoopbackUrl(raw);\n}\n\n/** Rewrite loopback hosts so containers can reach Postgres and other host services. */\nexport function rewriteLoopbackHost(host: string): string {\n if (host === \"localhost\" || host === \"127.0.0.1\") {\n return \"host.docker.internal\";\n }\n\n return host;\n}\n\nexport function rewriteLoopbackUrl(url: string): string {\n try {\n const parsed = new URL(url);\n parsed.hostname = rewriteLoopbackHost(parsed.hostname);\n return parsed.toString().replace(/\\/$/, \"\");\n } catch {\n return url;\n }\n}\n\n/** dockerode expects `KEY=value` strings. */\nexport function formatDockerEnv(env: Record<string, string>): string[] {\n return Object.entries(env).map(([key, value]) => `${key}=${value}`);\n}\n\nexport function resolveProjectServerImage(\n env: NodeJS.ProcessEnv = process.env,\n override?: string,\n): string {\n return override ?? env.PROJECT_DOCKER_IMAGE ?? env.TENANT_DOCKER_IMAGE ?? PROJECT_SERVER_IMAGE;\n}\n","import { PROJECT_SERVER_HEALTH } from \"./constants\";\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst DEFAULT_INTERVAL_MS = 500;\n\nexport type WaitForHealthOptions = {\n timeoutMs?: number;\n intervalMs?: number;\n fetchImpl?: typeof fetch;\n};\n\nexport async function waitForHealth(\n baseUrl: string,\n options: WaitForHealthOptions = {},\n): Promise<void> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;\n const deadline = Date.now() + timeoutMs;\n const url = new URL(PROJECT_SERVER_HEALTH.path, baseUrl);\n\n while (Date.now() < deadline) {\n try {\n const response = await fetchImpl(url, { signal: AbortSignal.timeout(2_000) });\n if (response.ok) {\n return;\n }\n } catch {\n // retry until timeout\n }\n\n await sleep(intervalMs);\n }\n\n throw new Error(`Project server health check timed out after ${timeoutMs}ms (${url})`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\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.21",
|
|
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.56"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/dockerode": "^3.3.47",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"wait-for-health-B4-AM1NR.mjs","names":[],"sources":["../src/constants.ts","../src/worker-runtime-config.ts","../src/org-worker-token.ts","../src/runtime-env.ts","../src/wait-for-health.ts"],"sourcesContent":["export const PROJECT_SERVER_IMAGE = \"keystroke/project-server:local\";\n\nexport const PROJECT_SERVER_PORT = 3000;\n\nexport const PROJECT_SERVER_ROOT = \"/app\";\n\nexport const PROJECT_SERVER_FRAMEWORK_ROOT = \"/opt/keystroke\";\n\nexport const PROJECT_SERVER_FRAMEWORK_NODE_MODULES = `${PROJECT_SERVER_FRAMEWORK_ROOT}/node_modules`;\n\nexport const PROJECT_SERVER_HEALTH = {\n path: \"/health\",\n port: PROJECT_SERVER_PORT,\n} as const;\n\nexport const PROJECT_SERVER_DEPLOY_STATUS = {\n path: \"/deploy-status\",\n port: PROJECT_SERVER_PORT,\n} as const;\n","import { resolvePlatformWorkerToken, resolveWorkerPlatformUrl } from \"./runtime-env\";\n\n/** Resolved platform ↔ project-server worker auth contract. */\nexport type WorkerRuntimeConfig = {\n /** Platform API base URL reachable from the project-server runtime. */\n platformUrl: string;\n /** Bearer token for platform `/internal` routes. */\n workerToken: string;\n};\n\nexport class WorkerRuntimeConfigError extends Error {\n readonly missing: readonly string[];\n\n constructor(missing: string[]) {\n super(\n `Worker runtime config incomplete (missing: ${missing.join(\", \")}). ` +\n \"In production set PLATFORM_WORKER_TOKEN and PUBLIC_PLATFORM_URL (or PLATFORM_URL).\",\n );\n this.name = \"WorkerRuntimeConfigError\";\n this.missing = missing;\n }\n}\n\n/** Fail fast when the platform cannot start worker-mode project servers. */\nexport function resolveWorkerRuntimeConfig(\n source: NodeJS.ProcessEnv = process.env,\n): WorkerRuntimeConfig {\n const platformUrl = resolveWorkerPlatformUrl(source);\n const workerToken = resolvePlatformWorkerToken(source);\n const missing: string[] = [];\n\n if (!platformUrl) {\n missing.push(\"PUBLIC_PLATFORM_URL or PLATFORM_URL\");\n }\n\n if (!workerToken) {\n missing.push(\"PLATFORM_WORKER_TOKEN\");\n }\n\n if (missing.length > 0) {\n throw new WorkerRuntimeConfigError(missing);\n }\n\n return { platformUrl: platformUrl!, workerToken: workerToken! };\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nfunction sign(secret: string, organizationId: string): string {\n return createHmac(\"sha256\", secret).update(`org-worker:${organizationId}`).digest(\"base64url\");\n}\n\n/**\n * Per-org worker token: `{organizationId}.{hmac}`. Self-describing so the\n * platform can tell which org a machine is calling as, and stateless — verified\n * by re-signing with the shared `PLATFORM_WORKER_TOKEN` secret.\n */\nexport function mintOrgWorkerToken(secret: string, organizationId: string): string {\n return `${organizationId}.${sign(secret, organizationId)}`;\n}\n\nexport type VerifiedOrgWorkerToken = {\n organizationId: string;\n};\n\nexport function verifyOrgWorkerToken(\n secret: string | undefined,\n token: string | undefined,\n): VerifiedOrgWorkerToken | undefined {\n if (!secret || !token) {\n return undefined;\n }\n\n // The signature is base64url (no dots), so the last dot ends the org id.\n const separator = token.lastIndexOf(\".\");\n if (separator <= 0) {\n return undefined;\n }\n\n const organizationId = token.slice(0, separator);\n const signature = Buffer.from(token.slice(separator + 1));\n const expected = Buffer.from(sign(secret, organizationId));\n if (signature.length !== expected.length || !timingSafeEqual(signature, expected)) {\n return undefined;\n }\n\n return { organizationId };\n}\n","import {\n LOCAL_PLATFORM_ORIGIN,\n resolveExplicitPublicPlatformOrigin,\n} from \"@keystrokehq/shared/platform-origin\";\n\nimport type { ProjectRuntimeDatabase } from \"./runtime\";\nimport { encodeOrgArtifacts, type OrgArtifactSpec } from \"./runtime\";\nimport {\n PROJECT_SERVER_FRAMEWORK_NODE_MODULES,\n PROJECT_SERVER_HEALTH,\n PROJECT_SERVER_IMAGE,\n PROJECT_SERVER_PORT,\n PROJECT_SERVER_ROOT,\n} from \"./constants\";\nimport type { HostingOptions } from \"./plugin\";\nimport { resolveWorkerRuntimeConfig } from \"./worker-runtime-config\";\nimport { mintOrgWorkerToken } from \"./org-worker-token\";\n\n/** Non-secret runtime config forwarded into org workers. Never include platform secrets. */\nconst RUNTIME_ENV_KEYS = [\n \"PUBLIC_PLATFORM_URL\",\n \"PUBLIC_PLATFORM_PROXY_URL\",\n \"PUBLIC_WEB_URL\",\n \"UPSTASH_REDIS_URL\",\n \"REDIS_URL\",\n \"KEYSTROKE_QUEUE_PREFIX\",\n] as const;\n\n/**\n * Observability ingest config for org workers (PostHog error tracking + crash reports).\n * Ingest tokens only — never forward `POSTHOG_API_KEY` (management) into workers.\n */\nconst OBSERVABILITY_ENV_KEYS = [\n \"POSTHOG_PROJECT_TOKEN\",\n \"POSTHOG_HOST\",\n \"POSTHOG_FLUSH_MODE\",\n \"KEYSTROKE_ENVIRONMENT\",\n \"KEYSTROKE_RELEASE\",\n] as const;\n\n/** Env keys that must never be forwarded into untrusted org workers. */\nexport const FORBIDDEN_WORKER_ENV_KEYS = [\n \"BETTER_AUTH_SECRET\",\n \"DATABASE_URL\",\n \"POSTHOG_API_KEY\",\n \"POSTGRES_PASSWORD\",\n \"PLATFORM_WORKER_TOKEN\",\n \"STRIPE_SECRET_KEY\",\n \"CREDENTIAL_ENCRYPTION_KEY\",\n \"TURNSTILE_SECRET\",\n] as const;\n\n/** Provider and gateway env forwarded from the platform into project servers. */\nconst PROVIDER_ENV_KEYS = [\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n \"AI_GATEWAY_API_KEY\",\n \"AI_GATEWAY_BASE_URL\",\n] as const;\n\n/** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */\nexport const DEV_PLATFORM_WORKER_TOKEN = \"dev-platform-worker-token\";\n\nexport type RuntimeLaunchSpec = {\n image: string;\n env: Record<string, string>;\n port: number;\n health: typeof PROJECT_SERVER_HEALTH;\n};\n\n/**\n * Builds the launch spec for an org worker. Each deploy artifact is encoded in\n * `KEYSTROKE_ORG_ARTIFACTS` — there is no base image, so at least one artifact is required.\n */\nexport function resolveRuntimeLaunch(\n options: HostingOptions,\n artifacts: OrgArtifactSpec[],\n database: ProjectRuntimeDatabase,\n extraEnv?: Record<string, string>,\n): RuntimeLaunchSpec {\n if (artifacts.length === 0) {\n throw new Error(\"Cannot start an org worker without at least one artifact\");\n }\n\n const env = options.env ?? process.env;\n\n return {\n image: resolveProjectServerImage(env, options.image),\n env: buildRuntimeEnv(env, artifacts, database, extraEnv),\n port: PROJECT_SERVER_PORT,\n health: PROJECT_SERVER_HEALTH,\n };\n}\n\n/** @deprecated Single-project launch — prefer org {@link resolveRuntimeLaunch}. */\nexport function resolveSingleProjectRuntimeLaunch(\n options: HostingOptions,\n artifact: { storageKey: string; artifactId: string; artifactVersion: number },\n database: ProjectRuntimeDatabase & { projectId: string },\n extraEnv?: Record<string, string>,\n): RuntimeLaunchSpec {\n return resolveRuntimeLaunch(\n options,\n [\n {\n projectId: database.projectId,\n artifactStorageKey: artifact.storageKey,\n artifactId: artifact.artifactId,\n artifactVersion: artifact.artifactVersion,\n },\n ],\n database,\n extraEnv,\n );\n}\n\n/** Env vars passed into the org worker container/machine. */\nexport function buildRuntimeEnv(\n source: NodeJS.ProcessEnv,\n artifacts: OrgArtifactSpec[],\n database: ProjectRuntimeDatabase,\n extraEnv?: Record<string, string>,\n): Record<string, string> {\n const entries = new Map<string, string>([\n [\"PORT\", String(PROJECT_SERVER_PORT)],\n [\"KEYSTROKE_ROOT\", PROJECT_SERVER_ROOT],\n [\"KEYSTROKE_RUNTIME_NODE_MODULES\", PROJECT_SERVER_FRAMEWORK_NODE_MODULES],\n [\"KEYSTROKE_ORG_ARTIFACTS\", encodeOrgArtifacts(artifacts)],\n [\"ORGANIZATION_ID\", database.organizationId],\n [\"TENANT_ID\", database.organizationId],\n ]);\n\n for (const key of RUNTIME_ENV_KEYS) {\n const value = source[key]?.trim();\n if (!value) {\n continue;\n }\n entries.set(key, value);\n }\n\n for (const key of OBSERVABILITY_ENV_KEYS) {\n const value = source[key]?.trim();\n if (!value) {\n continue;\n }\n entries.set(key, value);\n }\n\n // OSS self-host: forward BYO provider/gateway env. Cloud llmProxy supplies extraEnv instead.\n if (!extraEnv) {\n for (const key of PROVIDER_ENV_KEYS) {\n const value = source[key]?.trim();\n if (value) {\n entries.set(key, value);\n }\n }\n }\n\n // Project containers always run as workers: they resolve credentials/secrets through\n // the platform internal API and are deliberately never given the decryption key.\n // The token is minted per org so the platform knows which org a machine calls as.\n const worker = resolveWorkerRuntimeConfig(source);\n entries.set(\"PLATFORM_URL\", worker.platformUrl);\n entries.set(\n \"WORKER_INTERNAL_TOKEN\",\n mintOrgWorkerToken(worker.workerToken, database.organizationId),\n );\n\n if (extraEnv) {\n for (const [key, value] of Object.entries(extraEnv)) {\n entries.set(key, value);\n }\n }\n\n for (const key of FORBIDDEN_WORKER_ENV_KEYS) {\n entries.delete(key);\n }\n\n return Object.fromEntries(entries);\n}\n\nexport function resolvePlatformWorkerToken(\n source: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const explicit = source.PLATFORM_WORKER_TOKEN?.trim() ?? source.WORKER_INTERNAL_TOKEN?.trim();\n if (explicit) {\n return explicit;\n }\n\n if (source.NODE_ENV === \"production\") {\n return undefined;\n }\n\n return DEV_PLATFORM_WORKER_TOKEN;\n}\n\n/** Platform API URL reachable from a project-server container. */\nexport function resolveWorkerPlatformUrl(\n source: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const raw =\n source.PLATFORM_URL?.trim() ??\n resolveExplicitPublicPlatformOrigin(source) ??\n (source.NODE_ENV === \"production\" ? undefined : LOCAL_PLATFORM_ORIGIN);\n if (!raw) {\n return undefined;\n }\n\n return rewriteLoopbackUrl(raw);\n}\n\n/** Rewrite loopback hosts so containers can reach Postgres and other host services. */\nexport function rewriteLoopbackHost(host: string): string {\n if (host === \"localhost\" || host === \"127.0.0.1\") {\n return \"host.docker.internal\";\n }\n\n return host;\n}\n\nexport function rewriteLoopbackUrl(url: string): string {\n try {\n const parsed = new URL(url);\n parsed.hostname = rewriteLoopbackHost(parsed.hostname);\n return parsed.toString().replace(/\\/$/, \"\");\n } catch {\n return url;\n }\n}\n\n/** dockerode expects `KEY=value` strings. */\nexport function formatDockerEnv(env: Record<string, string>): string[] {\n return Object.entries(env).map(([key, value]) => `${key}=${value}`);\n}\n\nexport function resolveProjectServerImage(\n env: NodeJS.ProcessEnv = process.env,\n override?: string,\n): string {\n return override ?? env.PROJECT_DOCKER_IMAGE ?? env.TENANT_DOCKER_IMAGE ?? PROJECT_SERVER_IMAGE;\n}\n","import { PROJECT_SERVER_HEALTH } from \"./constants\";\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst DEFAULT_INTERVAL_MS = 500;\n\nexport type WaitForHealthOptions = {\n timeoutMs?: number;\n intervalMs?: number;\n fetchImpl?: typeof fetch;\n};\n\nexport async function waitForHealth(\n baseUrl: string,\n options: WaitForHealthOptions = {},\n): Promise<void> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;\n const deadline = Date.now() + timeoutMs;\n const url = new URL(PROJECT_SERVER_HEALTH.path, baseUrl);\n\n while (Date.now() < deadline) {\n try {\n const response = await fetchImpl(url, { signal: AbortSignal.timeout(2_000) });\n if (response.ok) {\n return;\n }\n } catch {\n // retry until timeout\n }\n\n await sleep(intervalMs);\n }\n\n throw new Error(`Project server health check timed out after ${timeoutMs}ms (${url})`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"wait-for-health-CObmNF8o.cjs","names":["encodeOrgArtifacts","LOCAL_PLATFORM_ORIGIN"],"sources":["../src/constants.ts","../src/worker-runtime-config.ts","../src/org-worker-token.ts","../src/runtime-env.ts","../src/wait-for-health.ts"],"sourcesContent":["export const PROJECT_SERVER_IMAGE = \"keystroke/project-server:local\";\n\nexport const PROJECT_SERVER_PORT = 3000;\n\nexport const PROJECT_SERVER_ROOT = \"/app\";\n\nexport const PROJECT_SERVER_FRAMEWORK_ROOT = \"/opt/keystroke\";\n\nexport const PROJECT_SERVER_FRAMEWORK_NODE_MODULES = `${PROJECT_SERVER_FRAMEWORK_ROOT}/node_modules`;\n\nexport const PROJECT_SERVER_HEALTH = {\n path: \"/health\",\n port: PROJECT_SERVER_PORT,\n} as const;\n\nexport const PROJECT_SERVER_DEPLOY_STATUS = {\n path: \"/deploy-status\",\n port: PROJECT_SERVER_PORT,\n} as const;\n","import { resolvePlatformWorkerToken, resolveWorkerPlatformUrl } from \"./runtime-env\";\n\n/** Resolved platform ↔ project-server worker auth contract. */\nexport type WorkerRuntimeConfig = {\n /** Platform API base URL reachable from the project-server runtime. */\n platformUrl: string;\n /** Bearer token for platform `/internal` routes. */\n workerToken: string;\n};\n\nexport class WorkerRuntimeConfigError extends Error {\n readonly missing: readonly string[];\n\n constructor(missing: string[]) {\n super(\n `Worker runtime config incomplete (missing: ${missing.join(\", \")}). ` +\n \"In production set PLATFORM_WORKER_TOKEN and PUBLIC_PLATFORM_URL (or PLATFORM_URL).\",\n );\n this.name = \"WorkerRuntimeConfigError\";\n this.missing = missing;\n }\n}\n\n/** Fail fast when the platform cannot start worker-mode project servers. */\nexport function resolveWorkerRuntimeConfig(\n source: NodeJS.ProcessEnv = process.env,\n): WorkerRuntimeConfig {\n const platformUrl = resolveWorkerPlatformUrl(source);\n const workerToken = resolvePlatformWorkerToken(source);\n const missing: string[] = [];\n\n if (!platformUrl) {\n missing.push(\"PUBLIC_PLATFORM_URL or PLATFORM_URL\");\n }\n\n if (!workerToken) {\n missing.push(\"PLATFORM_WORKER_TOKEN\");\n }\n\n if (missing.length > 0) {\n throw new WorkerRuntimeConfigError(missing);\n }\n\n return { platformUrl: platformUrl!, workerToken: workerToken! };\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nfunction sign(secret: string, organizationId: string): string {\n return createHmac(\"sha256\", secret).update(`org-worker:${organizationId}`).digest(\"base64url\");\n}\n\n/**\n * Per-org worker token: `{organizationId}.{hmac}`. Self-describing so the\n * platform can tell which org a machine is calling as, and stateless — verified\n * by re-signing with the shared `PLATFORM_WORKER_TOKEN` secret.\n */\nexport function mintOrgWorkerToken(secret: string, organizationId: string): string {\n return `${organizationId}.${sign(secret, organizationId)}`;\n}\n\nexport type VerifiedOrgWorkerToken = {\n organizationId: string;\n};\n\nexport function verifyOrgWorkerToken(\n secret: string | undefined,\n token: string | undefined,\n): VerifiedOrgWorkerToken | undefined {\n if (!secret || !token) {\n return undefined;\n }\n\n // The signature is base64url (no dots), so the last dot ends the org id.\n const separator = token.lastIndexOf(\".\");\n if (separator <= 0) {\n return undefined;\n }\n\n const organizationId = token.slice(0, separator);\n const signature = Buffer.from(token.slice(separator + 1));\n const expected = Buffer.from(sign(secret, organizationId));\n if (signature.length !== expected.length || !timingSafeEqual(signature, expected)) {\n return undefined;\n }\n\n return { organizationId };\n}\n","import {\n LOCAL_PLATFORM_ORIGIN,\n resolveExplicitPublicPlatformOrigin,\n} from \"@keystrokehq/shared/platform-origin\";\n\nimport type { ProjectRuntimeDatabase } from \"./runtime\";\nimport { encodeOrgArtifacts, type OrgArtifactSpec } from \"./runtime\";\nimport {\n PROJECT_SERVER_FRAMEWORK_NODE_MODULES,\n PROJECT_SERVER_HEALTH,\n PROJECT_SERVER_IMAGE,\n PROJECT_SERVER_PORT,\n PROJECT_SERVER_ROOT,\n} from \"./constants\";\nimport type { HostingOptions } from \"./plugin\";\nimport { resolveWorkerRuntimeConfig } from \"./worker-runtime-config\";\nimport { mintOrgWorkerToken } from \"./org-worker-token\";\n\n/** Non-secret runtime config forwarded into org workers. Never include platform secrets. */\nconst RUNTIME_ENV_KEYS = [\n \"PUBLIC_PLATFORM_URL\",\n \"PUBLIC_PLATFORM_PROXY_URL\",\n \"PUBLIC_WEB_URL\",\n \"UPSTASH_REDIS_URL\",\n \"REDIS_URL\",\n \"KEYSTROKE_QUEUE_PREFIX\",\n] as const;\n\n/**\n * Observability ingest config for org workers (PostHog error tracking + crash reports).\n * Ingest tokens only — never forward `POSTHOG_API_KEY` (management) into workers.\n */\nconst OBSERVABILITY_ENV_KEYS = [\n \"POSTHOG_PROJECT_TOKEN\",\n \"POSTHOG_HOST\",\n \"POSTHOG_FLUSH_MODE\",\n \"KEYSTROKE_ENVIRONMENT\",\n \"KEYSTROKE_RELEASE\",\n] as const;\n\n/** Env keys that must never be forwarded into untrusted org workers. */\nexport const FORBIDDEN_WORKER_ENV_KEYS = [\n \"BETTER_AUTH_SECRET\",\n \"DATABASE_URL\",\n \"POSTHOG_API_KEY\",\n \"POSTGRES_PASSWORD\",\n \"PLATFORM_WORKER_TOKEN\",\n \"STRIPE_SECRET_KEY\",\n \"CREDENTIAL_ENCRYPTION_KEY\",\n \"TURNSTILE_SECRET\",\n] as const;\n\n/** Provider and gateway env forwarded from the platform into project servers. */\nconst PROVIDER_ENV_KEYS = [\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n \"AI_GATEWAY_API_KEY\",\n \"AI_GATEWAY_BASE_URL\",\n] as const;\n\n/** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */\nexport const DEV_PLATFORM_WORKER_TOKEN = \"dev-platform-worker-token\";\n\nexport type RuntimeLaunchSpec = {\n image: string;\n env: Record<string, string>;\n port: number;\n health: typeof PROJECT_SERVER_HEALTH;\n};\n\n/**\n * Builds the launch spec for an org worker. Each deploy artifact is encoded in\n * `KEYSTROKE_ORG_ARTIFACTS` — there is no base image, so at least one artifact is required.\n */\nexport function resolveRuntimeLaunch(\n options: HostingOptions,\n artifacts: OrgArtifactSpec[],\n database: ProjectRuntimeDatabase,\n extraEnv?: Record<string, string>,\n): RuntimeLaunchSpec {\n if (artifacts.length === 0) {\n throw new Error(\"Cannot start an org worker without at least one artifact\");\n }\n\n const env = options.env ?? process.env;\n\n return {\n image: resolveProjectServerImage(env, options.image),\n env: buildRuntimeEnv(env, artifacts, database, extraEnv),\n port: PROJECT_SERVER_PORT,\n health: PROJECT_SERVER_HEALTH,\n };\n}\n\n/** @deprecated Single-project launch — prefer org {@link resolveRuntimeLaunch}. */\nexport function resolveSingleProjectRuntimeLaunch(\n options: HostingOptions,\n artifact: { storageKey: string; artifactId: string; artifactVersion: number },\n database: ProjectRuntimeDatabase & { projectId: string },\n extraEnv?: Record<string, string>,\n): RuntimeLaunchSpec {\n return resolveRuntimeLaunch(\n options,\n [\n {\n projectId: database.projectId,\n artifactStorageKey: artifact.storageKey,\n artifactId: artifact.artifactId,\n artifactVersion: artifact.artifactVersion,\n },\n ],\n database,\n extraEnv,\n );\n}\n\n/** Env vars passed into the org worker container/machine. */\nexport function buildRuntimeEnv(\n source: NodeJS.ProcessEnv,\n artifacts: OrgArtifactSpec[],\n database: ProjectRuntimeDatabase,\n extraEnv?: Record<string, string>,\n): Record<string, string> {\n const entries = new Map<string, string>([\n [\"PORT\", String(PROJECT_SERVER_PORT)],\n [\"KEYSTROKE_ROOT\", PROJECT_SERVER_ROOT],\n [\"KEYSTROKE_RUNTIME_NODE_MODULES\", PROJECT_SERVER_FRAMEWORK_NODE_MODULES],\n [\"KEYSTROKE_ORG_ARTIFACTS\", encodeOrgArtifacts(artifacts)],\n [\"ORGANIZATION_ID\", database.organizationId],\n [\"TENANT_ID\", database.organizationId],\n ]);\n\n for (const key of RUNTIME_ENV_KEYS) {\n const value = source[key]?.trim();\n if (!value) {\n continue;\n }\n entries.set(key, value);\n }\n\n for (const key of OBSERVABILITY_ENV_KEYS) {\n const value = source[key]?.trim();\n if (!value) {\n continue;\n }\n entries.set(key, value);\n }\n\n // OSS self-host: forward BYO provider/gateway env. Cloud llmProxy supplies extraEnv instead.\n if (!extraEnv) {\n for (const key of PROVIDER_ENV_KEYS) {\n const value = source[key]?.trim();\n if (value) {\n entries.set(key, value);\n }\n }\n }\n\n // Project containers always run as workers: they resolve credentials/secrets through\n // the platform internal API and are deliberately never given the decryption key.\n // The token is minted per org so the platform knows which org a machine calls as.\n const worker = resolveWorkerRuntimeConfig(source);\n entries.set(\"PLATFORM_URL\", worker.platformUrl);\n entries.set(\n \"WORKER_INTERNAL_TOKEN\",\n mintOrgWorkerToken(worker.workerToken, database.organizationId),\n );\n\n if (extraEnv) {\n for (const [key, value] of Object.entries(extraEnv)) {\n entries.set(key, value);\n }\n }\n\n for (const key of FORBIDDEN_WORKER_ENV_KEYS) {\n entries.delete(key);\n }\n\n return Object.fromEntries(entries);\n}\n\nexport function resolvePlatformWorkerToken(\n source: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const explicit = source.PLATFORM_WORKER_TOKEN?.trim() ?? source.WORKER_INTERNAL_TOKEN?.trim();\n if (explicit) {\n return explicit;\n }\n\n if (source.NODE_ENV === \"production\") {\n return undefined;\n }\n\n return DEV_PLATFORM_WORKER_TOKEN;\n}\n\n/** Platform API URL reachable from a project-server container. */\nexport function resolveWorkerPlatformUrl(\n source: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const raw =\n source.PLATFORM_URL?.trim() ??\n resolveExplicitPublicPlatformOrigin(source) ??\n (source.NODE_ENV === \"production\" ? undefined : LOCAL_PLATFORM_ORIGIN);\n if (!raw) {\n return undefined;\n }\n\n return rewriteLoopbackUrl(raw);\n}\n\n/** Rewrite loopback hosts so containers can reach Postgres and other host services. */\nexport function rewriteLoopbackHost(host: string): string {\n if (host === \"localhost\" || host === \"127.0.0.1\") {\n return \"host.docker.internal\";\n }\n\n return host;\n}\n\nexport function rewriteLoopbackUrl(url: string): string {\n try {\n const parsed = new URL(url);\n parsed.hostname = rewriteLoopbackHost(parsed.hostname);\n return parsed.toString().replace(/\\/$/, \"\");\n } catch {\n return url;\n }\n}\n\n/** dockerode expects `KEY=value` strings. */\nexport function formatDockerEnv(env: Record<string, string>): string[] {\n return Object.entries(env).map(([key, value]) => `${key}=${value}`);\n}\n\nexport function resolveProjectServerImage(\n env: NodeJS.ProcessEnv = process.env,\n override?: string,\n): string {\n return override ?? env.PROJECT_DOCKER_IMAGE ?? env.TENANT_DOCKER_IMAGE ?? PROJECT_SERVER_IMAGE;\n}\n","import { PROJECT_SERVER_HEALTH } from \"./constants\";\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst DEFAULT_INTERVAL_MS = 500;\n\nexport type WaitForHealthOptions = {\n timeoutMs?: number;\n intervalMs?: number;\n fetchImpl?: typeof fetch;\n};\n\nexport async function waitForHealth(\n baseUrl: string,\n options: WaitForHealthOptions = {},\n): Promise<void> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;\n const deadline = Date.now() + timeoutMs;\n const url = new URL(PROJECT_SERVER_HEALTH.path, baseUrl);\n\n while (Date.now() < deadline) {\n try {\n const response = await fetchImpl(url, { signal: AbortSignal.timeout(2_000) });\n if (response.ok) {\n return;\n }\n } catch {\n // retry until timeout\n }\n\n await sleep(intervalMs);\n }\n\n throw new Error(`Project server health check timed out after ${timeoutMs}ms (${url})`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n"],"mappings":"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"}
|