@keystrokehq/hosting 0.0.69 → 0.0.75
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 +62 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +21 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +57 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -42,7 +42,8 @@ const RUNTIME_ENV_KEYS = [
|
|
|
42
42
|
"ANTHROPIC_API_KEY",
|
|
43
43
|
"OPENAI_API_KEY"
|
|
44
44
|
];
|
|
45
|
-
|
|
45
|
+
/** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */
|
|
46
|
+
const DEV_PLATFORM_WORKER_TOKEN = "dev-platform-worker-token";
|
|
46
47
|
const PROJECT_DATABASE_ENV_KEYS = [
|
|
47
48
|
"POSTGRES_HOST",
|
|
48
49
|
"POSTGRES_PORT",
|
|
@@ -99,23 +100,40 @@ function buildRuntimeEnv(source, artifactUrl, database) {
|
|
|
99
100
|
if (credentialsKey) entries.set("CREDENTIALS_ENCRYPTION_KEY", credentialsKey);
|
|
100
101
|
}
|
|
101
102
|
if (mode === "worker") {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
const platformUrl = source.PLATFORM_URL ?? source.PUBLIC_WEB_URL;
|
|
107
|
-
if (platformUrl) entries.set("PLATFORM_URL", platformUrl);
|
|
108
|
-
const workerToken = source.PLATFORM_WORKER_TOKEN ?? source.WORKER_INTERNAL_TOKEN;
|
|
109
|
-
if (workerToken) entries.set("WORKER_INTERNAL_TOKEN", workerToken);
|
|
103
|
+
const worker = resolveWorkerRuntimeConfig(source);
|
|
104
|
+
entries.set("PLATFORM_URL", worker.platformUrl);
|
|
105
|
+
entries.set("WORKER_INTERNAL_TOKEN", worker.workerToken);
|
|
110
106
|
}
|
|
111
107
|
for (const [key, value] of Object.entries(projectDatabaseRuntimeEnv(database))) entries.set(key, value);
|
|
112
108
|
return Object.fromEntries(entries);
|
|
113
109
|
}
|
|
110
|
+
function resolvePlatformWorkerToken(source = process.env) {
|
|
111
|
+
const explicit = source.PLATFORM_WORKER_TOKEN?.trim() ?? source.WORKER_INTERNAL_TOKEN?.trim();
|
|
112
|
+
if (explicit) return explicit;
|
|
113
|
+
if (source.NODE_ENV === "production") return;
|
|
114
|
+
return DEV_PLATFORM_WORKER_TOKEN;
|
|
115
|
+
}
|
|
116
|
+
/** Platform API URL reachable from a project-server container. */
|
|
117
|
+
const DEV_PLATFORM_URL = "http://localhost:3002";
|
|
118
|
+
function resolveWorkerPlatformUrl(source = process.env) {
|
|
119
|
+
const raw = source.PLATFORM_URL?.trim() ?? source.PUBLIC_PLATFORM_URL?.trim() ?? (source.NODE_ENV === "production" ? void 0 : DEV_PLATFORM_URL);
|
|
120
|
+
if (!raw) return;
|
|
121
|
+
return rewriteLoopbackUrl(raw);
|
|
122
|
+
}
|
|
114
123
|
/** Rewrite loopback hosts so containers can reach Postgres and other host services. */
|
|
115
124
|
function rewriteLoopbackHost(host) {
|
|
116
125
|
if (host === "localhost" || host === "127.0.0.1") return "host.docker.internal";
|
|
117
126
|
return host;
|
|
118
127
|
}
|
|
128
|
+
function rewriteLoopbackUrl(url) {
|
|
129
|
+
try {
|
|
130
|
+
const parsed = new URL(url);
|
|
131
|
+
parsed.hostname = rewriteLoopbackHost(parsed.hostname);
|
|
132
|
+
return parsed.toString().replace(/\/$/, "");
|
|
133
|
+
} catch {
|
|
134
|
+
return url;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
119
137
|
/** dockerode expects `KEY=value` strings. */
|
|
120
138
|
function formatDockerEnv(env) {
|
|
121
139
|
return Object.entries(env).map(([key, value]) => `${key}=${value}`);
|
|
@@ -124,6 +142,29 @@ function resolveProjectServerImage(env = process.env, override) {
|
|
|
124
142
|
return override ?? env.PROJECT_DOCKER_IMAGE ?? env.TENANT_DOCKER_IMAGE ?? "keystroke/project-server:local";
|
|
125
143
|
}
|
|
126
144
|
//#endregion
|
|
145
|
+
//#region src/worker-runtime-config.ts
|
|
146
|
+
var WorkerRuntimeConfigError = class extends Error {
|
|
147
|
+
missing;
|
|
148
|
+
constructor(missing) {
|
|
149
|
+
super(`Worker runtime config incomplete (missing: ${missing.join(", ")}). In production set PLATFORM_WORKER_TOKEN and PUBLIC_PLATFORM_URL (or PLATFORM_URL).`);
|
|
150
|
+
this.name = "WorkerRuntimeConfigError";
|
|
151
|
+
this.missing = missing;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
/** Fail fast when the platform cannot start worker-mode project servers. */
|
|
155
|
+
function resolveWorkerRuntimeConfig(source = process.env) {
|
|
156
|
+
const platformUrl = resolveWorkerPlatformUrl(source);
|
|
157
|
+
const workerToken = resolvePlatformWorkerToken(source);
|
|
158
|
+
const missing = [];
|
|
159
|
+
if (!platformUrl) missing.push("PUBLIC_PLATFORM_URL or PLATFORM_URL");
|
|
160
|
+
if (!workerToken) missing.push("PLATFORM_WORKER_TOKEN");
|
|
161
|
+
if (missing.length > 0) throw new WorkerRuntimeConfigError(missing);
|
|
162
|
+
return {
|
|
163
|
+
platformUrl,
|
|
164
|
+
workerToken
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
//#endregion
|
|
127
168
|
//#region src/wait-for-health.ts
|
|
128
169
|
const DEFAULT_TIMEOUT_MS = 12e4;
|
|
129
170
|
const DEFAULT_INTERVAL_MS = 500;
|
|
@@ -223,9 +264,14 @@ async function ensureImage(docker, image) {
|
|
|
223
264
|
//#endregion
|
|
224
265
|
//#region src/docker/plugin.ts
|
|
225
266
|
function dockerPlugin(options = {}) {
|
|
267
|
+
const env = options.env ?? process.env;
|
|
226
268
|
return {
|
|
227
269
|
name: "docker",
|
|
228
|
-
|
|
270
|
+
workerRuntime: resolveWorkerRuntimeConfig(env),
|
|
271
|
+
createRuntime: () => createDockerRuntime({
|
|
272
|
+
...options,
|
|
273
|
+
env
|
|
274
|
+
})
|
|
229
275
|
};
|
|
230
276
|
}
|
|
231
277
|
//#endregion
|
|
@@ -266,6 +312,7 @@ async function pingProjectTarget(target, options = {}) {
|
|
|
266
312
|
});
|
|
267
313
|
}
|
|
268
314
|
//#endregion
|
|
315
|
+
exports.DEV_PLATFORM_WORKER_TOKEN = DEV_PLATFORM_WORKER_TOKEN;
|
|
269
316
|
exports.PROJECT_DATABASE_ENV_KEYS = PROJECT_DATABASE_ENV_KEYS;
|
|
270
317
|
exports.PROJECT_SERVER_FRAMEWORK_NODE_MODULES = PROJECT_SERVER_FRAMEWORK_NODE_MODULES;
|
|
271
318
|
exports.PROJECT_SERVER_FRAMEWORK_ROOT = PROJECT_SERVER_FRAMEWORK_ROOT;
|
|
@@ -274,6 +321,7 @@ exports.PROJECT_SERVER_IMAGE = PROJECT_SERVER_IMAGE;
|
|
|
274
321
|
exports.PROJECT_SERVER_PORT = PROJECT_SERVER_PORT;
|
|
275
322
|
exports.PROJECT_SERVER_ROOT = PROJECT_SERVER_ROOT;
|
|
276
323
|
exports.RUNTIME_PING_TIMEOUT_MS = RUNTIME_PING_TIMEOUT_MS;
|
|
324
|
+
exports.WorkerRuntimeConfigError = WorkerRuntimeConfigError;
|
|
277
325
|
exports.buildRuntimeEnv = buildRuntimeEnv;
|
|
278
326
|
exports.canPingProjectTarget = canPingProjectTarget;
|
|
279
327
|
exports.defaultHostingPlugin = defaultHostingPlugin;
|
|
@@ -282,9 +330,13 @@ exports.formatDockerEnv = formatDockerEnv;
|
|
|
282
330
|
exports.pingProject = pingProject;
|
|
283
331
|
exports.pingProjectTarget = pingProjectTarget;
|
|
284
332
|
exports.projectDatabaseRuntimeEnv = projectDatabaseRuntimeEnv;
|
|
333
|
+
exports.resolvePlatformWorkerToken = resolvePlatformWorkerToken;
|
|
285
334
|
exports.resolveProjectServerImage = resolveProjectServerImage;
|
|
286
335
|
exports.resolveRuntimeLaunch = resolveRuntimeLaunch;
|
|
336
|
+
exports.resolveWorkerPlatformUrl = resolveWorkerPlatformUrl;
|
|
337
|
+
exports.resolveWorkerRuntimeConfig = resolveWorkerRuntimeConfig;
|
|
287
338
|
exports.rewriteLoopbackHost = rewriteLoopbackHost;
|
|
339
|
+
exports.rewriteLoopbackUrl = rewriteLoopbackUrl;
|
|
288
340
|
exports.waitForHealth = waitForHealth;
|
|
289
341
|
|
|
290
342
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["Docker"],"sources":["../src/constants.ts","../src/runtime-env.ts","../src/wait-for-health.ts","../src/docker/create-docker-runtime.ts","../src/docker/plugin.ts","../src/default-plugin.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.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","import type { ProjectRuntimeDatabase } 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\";\n\nconst RUNTIME_ENV_KEYS = [\n \"BETTER_AUTH_SECRET\",\n \"PUBLIC_SERVER_URL\",\n \"PUBLIC_WEB_URL\",\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n] as const;\n\nconst WORKER_RUNTIME_ENV_KEYS = [\"PLATFORM_URL\", \"PLATFORM_WORKER_TOKEN\"] as const;\n\nexport const PROJECT_DATABASE_ENV_KEYS = [\n \"POSTGRES_HOST\",\n \"POSTGRES_PORT\",\n \"POSTGRES_DB\",\n \"POSTGRES_USER\",\n \"POSTGRES_PASSWORD\",\n \"DATABASE_SEARCH_PATH\",\n] as const;\n\nexport type RuntimeLaunchSpec = {\n image: string;\n env: Record<string, string>;\n port: number;\n health: typeof PROJECT_SERVER_HEALTH;\n};\n\n/** Per-project postgres env injected into every project server container/machine. */\nexport function projectDatabaseRuntimeEnv(\n database: ProjectRuntimeDatabase,\n): Record<(typeof PROJECT_DATABASE_ENV_KEYS)[number], string> {\n return {\n POSTGRES_HOST: rewriteLoopbackHost(database.host),\n POSTGRES_PORT: String(database.port),\n POSTGRES_DB: database.database,\n POSTGRES_USER: database.user,\n POSTGRES_PASSWORD: database.password,\n DATABASE_SEARCH_PATH: database.searchPath,\n };\n}\n\n/**\n * Builds the launch spec for a single project server. `artifactUrl` is the\n * per-project presigned URL to that deploy's built `dist` — there is no base\n * image, so it is required.\n */\nexport function resolveRuntimeLaunch(\n options: HostingOptions,\n artifactUrl: string,\n database: ProjectRuntimeDatabase,\n): RuntimeLaunchSpec {\n if (!artifactUrl) {\n throw new Error(\"Cannot start a project server without an artifact URL\");\n }\n\n const env = options.env ?? process.env;\n\n return {\n image: resolveProjectServerImage(env, options.image),\n env: buildRuntimeEnv(env, artifactUrl, database),\n port: PROJECT_SERVER_PORT,\n health: PROJECT_SERVER_HEALTH,\n };\n}\n\n/** Env vars passed into the project server container/machine. */\nexport function buildRuntimeEnv(\n source: NodeJS.ProcessEnv,\n artifactUrl: string,\n database: ProjectRuntimeDatabase,\n): Record<string, string> {\n const mode = source.KEYSTROKE_MODE ?? \"worker\";\n const entries = new Map<string, string>([\n // Container bind port — not derived from PUBLIC_SERVER_URL (external URL metadata).\n [\"PORT\", String(PROJECT_SERVER_PORT)],\n [\"KEYSTROKE_ROOT\", PROJECT_SERVER_ROOT],\n [\"KEYSTROKE_RUNTIME_NODE_MODULES\", PROJECT_SERVER_FRAMEWORK_NODE_MODULES],\n [\"ARTIFACT_URL\", artifactUrl],\n [\"KEYSTROKE_MODE\", mode],\n [\"PROJECT_ID\", database.projectId],\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];\n if (value) {\n entries.set(key, value);\n }\n }\n\n if (mode !== \"worker\") {\n const credentialsKey = source.CREDENTIALS_ENCRYPTION_KEY;\n if (credentialsKey) {\n entries.set(\"CREDENTIALS_ENCRYPTION_KEY\", credentialsKey);\n }\n }\n\n if (mode === \"worker\") {\n for (const key of WORKER_RUNTIME_ENV_KEYS) {\n const value = source[key];\n if (value) {\n entries.set(key, value);\n }\n }\n\n const platformUrl = source.PLATFORM_URL ?? source.PUBLIC_WEB_URL;\n if (platformUrl) {\n entries.set(\"PLATFORM_URL\", platformUrl);\n }\n\n const workerToken = source.PLATFORM_WORKER_TOKEN ?? source.WORKER_INTERNAL_TOKEN;\n if (workerToken) {\n entries.set(\"WORKER_INTERNAL_TOKEN\", workerToken);\n }\n }\n\n for (const [key, value] of Object.entries(projectDatabaseRuntimeEnv(database))) {\n entries.set(key, value);\n }\n\n return Object.fromEntries(entries);\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\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","import Docker from \"dockerode\";\n\nimport type { ProjectRuntime } from \"../runtime\";\n\nimport type { HostingOptions } from \"../plugin\";\nimport { formatDockerEnv, resolveRuntimeLaunch } from \"../runtime-env\";\nimport { waitForHealth } from \"../wait-for-health\";\n\nexport type DockerPluginOptions = HostingOptions & {\n docker?: Docker;\n};\n\nconst MINIO_DOCKER_NETWORK = process.env.MINIO_DOCKER_NETWORK ?? \"keystroke\";\n\nexport function createDockerRuntime(options: DockerPluginOptions = {}): ProjectRuntime {\n const docker = options.docker ?? new Docker();\n\n return {\n async start(input) {\n const launch = resolveRuntimeLaunch(options, input.artifactUrl, input.database);\n await ensureImage(docker, launch.image);\n await removeExistingContainer(docker, input.projectId);\n\n const container = await docker.createContainer({\n Image: launch.image,\n name: containerName(input.projectId),\n Labels: {\n \"keystroke.project.id\": input.projectId,\n \"keystroke.project.name\": input.name,\n },\n ExposedPorts: {\n [`${launch.port}/tcp`]: {},\n },\n HostConfig: {\n ExtraHosts: [\"host.docker.internal:host-gateway\"],\n PortBindings: {\n [`${launch.port}/tcp`]: [{ HostPort: \"0\" }],\n },\n },\n NetworkingConfig: {\n EndpointsConfig: {\n [MINIO_DOCKER_NETWORK]: {},\n },\n },\n Env: formatDockerEnv(launch.env),\n });\n\n await container.start();\n\n const inspect = await container.inspect();\n const binding = inspect.NetworkSettings.Ports?.[`${launch.port}/tcp`]?.[0];\n if (!binding?.HostPort) {\n throw new Error(\"Failed to resolve project container host port\");\n }\n\n const baseUrl = `http://127.0.0.1:${binding.HostPort}`;\n await waitForHealth(baseUrl, {\n fetchImpl: options.fetchImpl,\n timeoutMs: options.healthTimeoutMs,\n });\n\n return {\n runtimeId: inspect.Id,\n baseUrl,\n };\n },\n };\n}\n\nfunction containerName(projectId: string): string {\n return `keystroke-project-${projectId}`;\n}\n\nasync function removeExistingContainer(docker: Docker, projectId: string): Promise<void> {\n try {\n const existing = docker.getContainer(containerName(projectId));\n await existing.stop({ t: 5 }).catch(() => undefined);\n await existing.remove({ force: true });\n } catch {\n // no existing container\n }\n}\n\nasync function ensureImage(docker: Docker, image: string): Promise<void> {\n try {\n await docker.getImage(image).inspect();\n return;\n } catch {\n // pull below\n }\n\n await new Promise<void>((resolvePromise, reject) => {\n docker.pull(image, (error: Error | null, stream: NodeJS.ReadableStream | undefined) => {\n if (error) {\n reject(error);\n return;\n }\n\n if (!stream) {\n reject(new Error(`Failed to pull image ${image}`));\n return;\n }\n\n docker.modem.followProgress(stream, (progressError: Error | null) => {\n if (progressError) {\n reject(progressError);\n return;\n }\n\n resolvePromise();\n });\n });\n });\n}\n","import type { HostingPlugin } from \"../plugin\";\n\nimport { createDockerRuntime } from \"./create-docker-runtime\";\nimport type { DockerPluginOptions } from \"./create-docker-runtime\";\n\nexport type { DockerPluginOptions } from \"./create-docker-runtime\";\n\nexport function dockerPlugin(options: DockerPluginOptions = {}): HostingPlugin {\n return {\n name: \"docker\",\n createRuntime: () => createDockerRuntime(options),\n };\n}\n","import type { HostingPlugin } from \"./plugin\";\nimport { dockerPlugin, type DockerPluginOptions } from \"./docker/plugin\";\n\n/** Local Docker hosting — default for platform and dev. */\nexport function defaultHostingPlugin(options: DockerPluginOptions = {}): HostingPlugin {\n return dockerPlugin(options);\n}\n","/** Timeout for a single project runtime `/health` probe. */\nexport const RUNTIME_PING_TIMEOUT_MS = 15_000;\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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Docker"],"sources":["../src/constants.ts","../src/runtime-env.ts","../src/worker-runtime-config.ts","../src/wait-for-health.ts","../src/docker/create-docker-runtime.ts","../src/docker/plugin.ts","../src/default-plugin.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.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","import type { ProjectRuntimeDatabase } 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\";\n\nconst RUNTIME_ENV_KEYS = [\n \"BETTER_AUTH_SECRET\",\n \"PUBLIC_SERVER_URL\",\n \"PUBLIC_WEB_URL\",\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\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 const PROJECT_DATABASE_ENV_KEYS = [\n \"POSTGRES_HOST\",\n \"POSTGRES_PORT\",\n \"POSTGRES_DB\",\n \"POSTGRES_USER\",\n \"POSTGRES_PASSWORD\",\n \"DATABASE_SEARCH_PATH\",\n] as const;\n\nexport type RuntimeLaunchSpec = {\n image: string;\n env: Record<string, string>;\n port: number;\n health: typeof PROJECT_SERVER_HEALTH;\n};\n\n/** Per-project postgres env injected into every project server container/machine. */\nexport function projectDatabaseRuntimeEnv(\n database: ProjectRuntimeDatabase,\n): Record<(typeof PROJECT_DATABASE_ENV_KEYS)[number], string> {\n return {\n POSTGRES_HOST: rewriteLoopbackHost(database.host),\n POSTGRES_PORT: String(database.port),\n POSTGRES_DB: database.database,\n POSTGRES_USER: database.user,\n POSTGRES_PASSWORD: database.password,\n DATABASE_SEARCH_PATH: database.searchPath,\n };\n}\n\n/**\n * Builds the launch spec for a single project server. `artifactUrl` is the\n * per-project presigned URL to that deploy's built `dist` — there is no base\n * image, so it is required.\n */\nexport function resolveRuntimeLaunch(\n options: HostingOptions,\n artifactUrl: string,\n database: ProjectRuntimeDatabase,\n): RuntimeLaunchSpec {\n if (!artifactUrl) {\n throw new Error(\"Cannot start a project server without an artifact URL\");\n }\n\n const env = options.env ?? process.env;\n\n return {\n image: resolveProjectServerImage(env, options.image),\n env: buildRuntimeEnv(env, artifactUrl, database),\n port: PROJECT_SERVER_PORT,\n health: PROJECT_SERVER_HEALTH,\n };\n}\n\n/** Env vars passed into the project server container/machine. */\nexport function buildRuntimeEnv(\n source: NodeJS.ProcessEnv,\n artifactUrl: string,\n database: ProjectRuntimeDatabase,\n): Record<string, string> {\n const mode = source.KEYSTROKE_MODE ?? \"worker\";\n const entries = new Map<string, string>([\n // Container bind port — not derived from PUBLIC_SERVER_URL (external URL metadata).\n [\"PORT\", String(PROJECT_SERVER_PORT)],\n [\"KEYSTROKE_ROOT\", PROJECT_SERVER_ROOT],\n [\"KEYSTROKE_RUNTIME_NODE_MODULES\", PROJECT_SERVER_FRAMEWORK_NODE_MODULES],\n [\"ARTIFACT_URL\", artifactUrl],\n [\"KEYSTROKE_MODE\", mode],\n [\"PROJECT_ID\", database.projectId],\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];\n if (value) {\n entries.set(key, value);\n }\n }\n\n if (mode !== \"worker\") {\n const credentialsKey = source.CREDENTIALS_ENCRYPTION_KEY;\n if (credentialsKey) {\n entries.set(\"CREDENTIALS_ENCRYPTION_KEY\", credentialsKey);\n }\n }\n\n if (mode === \"worker\") {\n const worker = resolveWorkerRuntimeConfig(source);\n entries.set(\"PLATFORM_URL\", worker.platformUrl);\n entries.set(\"WORKER_INTERNAL_TOKEN\", worker.workerToken);\n }\n\n for (const [key, value] of Object.entries(projectDatabaseRuntimeEnv(database))) {\n entries.set(key, value);\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. */\nconst DEV_PLATFORM_URL = \"http://localhost:3002\";\n\nexport function resolveWorkerPlatformUrl(\n source: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const raw =\n source.PLATFORM_URL?.trim() ??\n source.PUBLIC_PLATFORM_URL?.trim() ??\n (source.NODE_ENV === \"production\" ? undefined : DEV_PLATFORM_URL);\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 { 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 { 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","import Docker from \"dockerode\";\n\nimport type { ProjectRuntime } from \"../runtime\";\n\nimport type { HostingOptions } from \"../plugin\";\nimport { formatDockerEnv, resolveRuntimeLaunch } from \"../runtime-env\";\nimport { waitForHealth } from \"../wait-for-health\";\n\nexport type DockerPluginOptions = HostingOptions & {\n docker?: Docker;\n};\n\nconst MINIO_DOCKER_NETWORK = process.env.MINIO_DOCKER_NETWORK ?? \"keystroke\";\n\nexport function createDockerRuntime(options: DockerPluginOptions = {}): ProjectRuntime {\n const docker = options.docker ?? new Docker();\n\n return {\n async start(input) {\n const launch = resolveRuntimeLaunch(options, input.artifactUrl, input.database);\n await ensureImage(docker, launch.image);\n await removeExistingContainer(docker, input.projectId);\n\n const container = await docker.createContainer({\n Image: launch.image,\n name: containerName(input.projectId),\n Labels: {\n \"keystroke.project.id\": input.projectId,\n \"keystroke.project.name\": input.name,\n },\n ExposedPorts: {\n [`${launch.port}/tcp`]: {},\n },\n HostConfig: {\n ExtraHosts: [\"host.docker.internal:host-gateway\"],\n PortBindings: {\n [`${launch.port}/tcp`]: [{ HostPort: \"0\" }],\n },\n },\n NetworkingConfig: {\n EndpointsConfig: {\n [MINIO_DOCKER_NETWORK]: {},\n },\n },\n Env: formatDockerEnv(launch.env),\n });\n\n await container.start();\n\n const inspect = await container.inspect();\n const binding = inspect.NetworkSettings.Ports?.[`${launch.port}/tcp`]?.[0];\n if (!binding?.HostPort) {\n throw new Error(\"Failed to resolve project container host port\");\n }\n\n const baseUrl = `http://127.0.0.1:${binding.HostPort}`;\n await waitForHealth(baseUrl, {\n fetchImpl: options.fetchImpl,\n timeoutMs: options.healthTimeoutMs,\n });\n\n return {\n runtimeId: inspect.Id,\n baseUrl,\n };\n },\n };\n}\n\nfunction containerName(projectId: string): string {\n return `keystroke-project-${projectId}`;\n}\n\nasync function removeExistingContainer(docker: Docker, projectId: string): Promise<void> {\n try {\n const existing = docker.getContainer(containerName(projectId));\n await existing.stop({ t: 5 }).catch(() => undefined);\n await existing.remove({ force: true });\n } catch {\n // no existing container\n }\n}\n\nasync function ensureImage(docker: Docker, image: string): Promise<void> {\n try {\n await docker.getImage(image).inspect();\n return;\n } catch {\n // pull below\n }\n\n await new Promise<void>((resolvePromise, reject) => {\n docker.pull(image, (error: Error | null, stream: NodeJS.ReadableStream | undefined) => {\n if (error) {\n reject(error);\n return;\n }\n\n if (!stream) {\n reject(new Error(`Failed to pull image ${image}`));\n return;\n }\n\n docker.modem.followProgress(stream, (progressError: Error | null) => {\n if (progressError) {\n reject(progressError);\n return;\n }\n\n resolvePromise();\n });\n });\n });\n}\n","import type { HostingPlugin } from \"../plugin\";\nimport { resolveWorkerRuntimeConfig } from \"../worker-runtime-config\";\n\nimport { createDockerRuntime } from \"./create-docker-runtime\";\nimport type { DockerPluginOptions } from \"./create-docker-runtime\";\n\nexport type { DockerPluginOptions } from \"./create-docker-runtime\";\n\nexport function dockerPlugin(options: DockerPluginOptions = {}): HostingPlugin {\n const env = options.env ?? process.env;\n\n return {\n name: \"docker\",\n workerRuntime: resolveWorkerRuntimeConfig(env),\n createRuntime: () => createDockerRuntime({ ...options, env }),\n };\n}\n","import type { HostingPlugin } from \"./plugin\";\nimport { dockerPlugin, type DockerPluginOptions } from \"./docker/plugin\";\n\n/** Local Docker hosting — default for platform and dev. */\nexport function defaultHostingPlugin(options: DockerPluginOptions = {}): HostingPlugin {\n return dockerPlugin(options);\n}\n","/** Timeout for a single project runtime `/health` probe. */\nexport const RUNTIME_PING_TIMEOUT_MS = 15_000;\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"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -44,6 +44,19 @@ type ProjectPingTarget = {
|
|
|
44
44
|
runtimeId: string | null;
|
|
45
45
|
};
|
|
46
46
|
//#endregion
|
|
47
|
+
//#region src/worker-runtime-config.d.ts
|
|
48
|
+
/** Resolved platform ↔ project-server worker auth contract. */
|
|
49
|
+
type WorkerRuntimeConfig = {
|
|
50
|
+
/** Platform API base URL reachable from the project-server runtime. */platformUrl: string; /** Bearer token for platform `/internal` routes. */
|
|
51
|
+
workerToken: string;
|
|
52
|
+
};
|
|
53
|
+
declare class WorkerRuntimeConfigError extends Error {
|
|
54
|
+
readonly missing: readonly string[];
|
|
55
|
+
constructor(missing: string[]);
|
|
56
|
+
}
|
|
57
|
+
/** Fail fast when the platform cannot start worker-mode project servers. */
|
|
58
|
+
declare function resolveWorkerRuntimeConfig(source?: NodeJS.ProcessEnv): WorkerRuntimeConfig;
|
|
59
|
+
//#endregion
|
|
47
60
|
//#region src/plugin.d.ts
|
|
48
61
|
type HostingOptions = {
|
|
49
62
|
image?: string;
|
|
@@ -60,7 +73,8 @@ type OrganizationHostingResult = {
|
|
|
60
73
|
appName: string;
|
|
61
74
|
};
|
|
62
75
|
type HostingPlugin = {
|
|
63
|
-
name: string;
|
|
76
|
+
name: string; /** Validated at plugin creation — shared by platform internal routes and project-server containers. */
|
|
77
|
+
workerRuntime: WorkerRuntimeConfig;
|
|
64
78
|
createRuntime(): ProjectRuntime;
|
|
65
79
|
provisionOrganization?(input: OrganizationHostingInput): Promise<OrganizationHostingResult>;
|
|
66
80
|
deprovisionOrganization?(result: OrganizationHostingResult): Promise<void>;
|
|
@@ -84,6 +98,8 @@ declare function dockerPlugin(options?: DockerPluginOptions): HostingPlugin;
|
|
|
84
98
|
declare function defaultHostingPlugin(options?: DockerPluginOptions): HostingPlugin;
|
|
85
99
|
//#endregion
|
|
86
100
|
//#region src/runtime-env.d.ts
|
|
101
|
+
/** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */
|
|
102
|
+
declare const DEV_PLATFORM_WORKER_TOKEN = "dev-platform-worker-token";
|
|
87
103
|
declare const PROJECT_DATABASE_ENV_KEYS: readonly ["POSTGRES_HOST", "POSTGRES_PORT", "POSTGRES_DB", "POSTGRES_USER", "POSTGRES_PASSWORD", "DATABASE_SEARCH_PATH"];
|
|
88
104
|
type RuntimeLaunchSpec = {
|
|
89
105
|
image: string;
|
|
@@ -101,8 +117,11 @@ declare function projectDatabaseRuntimeEnv(database: ProjectRuntimeDatabase): Re
|
|
|
101
117
|
declare function resolveRuntimeLaunch(options: HostingOptions, artifactUrl: string, database: ProjectRuntimeDatabase): RuntimeLaunchSpec;
|
|
102
118
|
/** Env vars passed into the project server container/machine. */
|
|
103
119
|
declare function buildRuntimeEnv(source: NodeJS.ProcessEnv, artifactUrl: string, database: ProjectRuntimeDatabase): Record<string, string>;
|
|
120
|
+
declare function resolvePlatformWorkerToken(source?: NodeJS.ProcessEnv): string | undefined;
|
|
121
|
+
declare function resolveWorkerPlatformUrl(source?: NodeJS.ProcessEnv): string | undefined;
|
|
104
122
|
/** Rewrite loopback hosts so containers can reach Postgres and other host services. */
|
|
105
123
|
declare function rewriteLoopbackHost(host: string): string;
|
|
124
|
+
declare function rewriteLoopbackUrl(url: string): string;
|
|
106
125
|
/** dockerode expects `KEY=value` strings. */
|
|
107
126
|
declare function formatDockerEnv(env: Record<string, string>): string[];
|
|
108
127
|
declare function resolveProjectServerImage(env?: NodeJS.ProcessEnv, override?: string): string;
|
|
@@ -137,5 +156,5 @@ declare function pingProjectTarget(target: ProjectPingTarget, options?: PingProj
|
|
|
137
156
|
plugin?: Pick<HostingPlugin, "canPingTarget" | "pingRequestHeaders">;
|
|
138
157
|
}): Promise<boolean>;
|
|
139
158
|
//#endregion
|
|
140
|
-
export { type DockerPluginOptions, type HostingOptions, type HostingPlugin, type OrganizationHostingInput, type OrganizationHostingResult, PROJECT_DATABASE_ENV_KEYS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, type PingProjectOptions, type ProjectPingTarget, type ProjectRuntime, type ProjectRuntimeDatabase, type ProjectRuntimeHosting, type ProjectRuntimeInput, type ProjectRuntimeResult, RUNTIME_PING_TIMEOUT_MS, type RuntimeLaunchSpec, type WaitForHealthOptions, buildRuntimeEnv, canPingProjectTarget, defaultHostingPlugin, dockerPlugin, formatDockerEnv, pingProject, pingProjectTarget, projectDatabaseRuntimeEnv, resolveProjectServerImage, resolveRuntimeLaunch, rewriteLoopbackHost, waitForHealth };
|
|
159
|
+
export { DEV_PLATFORM_WORKER_TOKEN, type DockerPluginOptions, type HostingOptions, type HostingPlugin, type OrganizationHostingInput, type OrganizationHostingResult, PROJECT_DATABASE_ENV_KEYS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, type PingProjectOptions, type ProjectPingTarget, type ProjectRuntime, type ProjectRuntimeDatabase, type ProjectRuntimeHosting, type ProjectRuntimeInput, type ProjectRuntimeResult, RUNTIME_PING_TIMEOUT_MS, type RuntimeLaunchSpec, type WaitForHealthOptions, type WorkerRuntimeConfig, WorkerRuntimeConfigError, buildRuntimeEnv, canPingProjectTarget, defaultHostingPlugin, dockerPlugin, formatDockerEnv, pingProject, pingProjectTarget, projectDatabaseRuntimeEnv, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, waitForHealth };
|
|
141
160
|
//# 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.ts","../src/plugin.ts","../src/docker/create-docker-runtime.ts","../src/docker/plugin.ts","../src/default-plugin.ts","../src/runtime-env.ts","../src/wait-for-health.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.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;;;KCbE,sBAAA;EACV,IAAA;EACA,IAAA;EACA,QAAA;EACA,IAAA;EACA,QAAA;EACA,UAAA;EACA,SAAA;EACA,cAAA;AAAA;AAAA,KAGU,qBAAA;EACV,OAAO;AAAA;AAAA,KAGG,mBAAA;EACV,SAAA;EACA,IAAA;EACA,WAAA;EACA,QAAA,EAAU,sBAAA;EACV,OAAA,GAAU,qBAAqB;AAAA;AAAA,KAGrB,oBAAA;EACV,SAAA;EACA,OAAO;AAAA;AAAA,KAGG,cAAA;EACV,KAAA,CAAM,KAAA,EAAO,mBAAA,GAAsB,OAAA,CAAQ,oBAAA;AAAA;AAAA,KAGjC,iBAAA;EACV,OAAA;EACA,SAAS;AAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/constants.ts","../src/runtime.ts","../src/worker-runtime-config.ts","../src/plugin.ts","../src/docker/create-docker-runtime.ts","../src/docker/plugin.ts","../src/default-plugin.ts","../src/runtime-env.ts","../src/wait-for-health.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.ts"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -44,6 +44,19 @@ type ProjectPingTarget = {
|
|
|
44
44
|
runtimeId: string | null;
|
|
45
45
|
};
|
|
46
46
|
//#endregion
|
|
47
|
+
//#region src/worker-runtime-config.d.ts
|
|
48
|
+
/** Resolved platform ↔ project-server worker auth contract. */
|
|
49
|
+
type WorkerRuntimeConfig = {
|
|
50
|
+
/** Platform API base URL reachable from the project-server runtime. */platformUrl: string; /** Bearer token for platform `/internal` routes. */
|
|
51
|
+
workerToken: string;
|
|
52
|
+
};
|
|
53
|
+
declare class WorkerRuntimeConfigError extends Error {
|
|
54
|
+
readonly missing: readonly string[];
|
|
55
|
+
constructor(missing: string[]);
|
|
56
|
+
}
|
|
57
|
+
/** Fail fast when the platform cannot start worker-mode project servers. */
|
|
58
|
+
declare function resolveWorkerRuntimeConfig(source?: NodeJS.ProcessEnv): WorkerRuntimeConfig;
|
|
59
|
+
//#endregion
|
|
47
60
|
//#region src/plugin.d.ts
|
|
48
61
|
type HostingOptions = {
|
|
49
62
|
image?: string;
|
|
@@ -60,7 +73,8 @@ type OrganizationHostingResult = {
|
|
|
60
73
|
appName: string;
|
|
61
74
|
};
|
|
62
75
|
type HostingPlugin = {
|
|
63
|
-
name: string;
|
|
76
|
+
name: string; /** Validated at plugin creation — shared by platform internal routes and project-server containers. */
|
|
77
|
+
workerRuntime: WorkerRuntimeConfig;
|
|
64
78
|
createRuntime(): ProjectRuntime;
|
|
65
79
|
provisionOrganization?(input: OrganizationHostingInput): Promise<OrganizationHostingResult>;
|
|
66
80
|
deprovisionOrganization?(result: OrganizationHostingResult): Promise<void>;
|
|
@@ -84,6 +98,8 @@ declare function dockerPlugin(options?: DockerPluginOptions): HostingPlugin;
|
|
|
84
98
|
declare function defaultHostingPlugin(options?: DockerPluginOptions): HostingPlugin;
|
|
85
99
|
//#endregion
|
|
86
100
|
//#region src/runtime-env.d.ts
|
|
101
|
+
/** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */
|
|
102
|
+
declare const DEV_PLATFORM_WORKER_TOKEN = "dev-platform-worker-token";
|
|
87
103
|
declare const PROJECT_DATABASE_ENV_KEYS: readonly ["POSTGRES_HOST", "POSTGRES_PORT", "POSTGRES_DB", "POSTGRES_USER", "POSTGRES_PASSWORD", "DATABASE_SEARCH_PATH"];
|
|
88
104
|
type RuntimeLaunchSpec = {
|
|
89
105
|
image: string;
|
|
@@ -101,8 +117,11 @@ declare function projectDatabaseRuntimeEnv(database: ProjectRuntimeDatabase): Re
|
|
|
101
117
|
declare function resolveRuntimeLaunch(options: HostingOptions, artifactUrl: string, database: ProjectRuntimeDatabase): RuntimeLaunchSpec;
|
|
102
118
|
/** Env vars passed into the project server container/machine. */
|
|
103
119
|
declare function buildRuntimeEnv(source: NodeJS.ProcessEnv, artifactUrl: string, database: ProjectRuntimeDatabase): Record<string, string>;
|
|
120
|
+
declare function resolvePlatformWorkerToken(source?: NodeJS.ProcessEnv): string | undefined;
|
|
121
|
+
declare function resolveWorkerPlatformUrl(source?: NodeJS.ProcessEnv): string | undefined;
|
|
104
122
|
/** Rewrite loopback hosts so containers can reach Postgres and other host services. */
|
|
105
123
|
declare function rewriteLoopbackHost(host: string): string;
|
|
124
|
+
declare function rewriteLoopbackUrl(url: string): string;
|
|
106
125
|
/** dockerode expects `KEY=value` strings. */
|
|
107
126
|
declare function formatDockerEnv(env: Record<string, string>): string[];
|
|
108
127
|
declare function resolveProjectServerImage(env?: NodeJS.ProcessEnv, override?: string): string;
|
|
@@ -137,5 +156,5 @@ declare function pingProjectTarget(target: ProjectPingTarget, options?: PingProj
|
|
|
137
156
|
plugin?: Pick<HostingPlugin, "canPingTarget" | "pingRequestHeaders">;
|
|
138
157
|
}): Promise<boolean>;
|
|
139
158
|
//#endregion
|
|
140
|
-
export { type DockerPluginOptions, type HostingOptions, type HostingPlugin, type OrganizationHostingInput, type OrganizationHostingResult, PROJECT_DATABASE_ENV_KEYS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, type PingProjectOptions, type ProjectPingTarget, type ProjectRuntime, type ProjectRuntimeDatabase, type ProjectRuntimeHosting, type ProjectRuntimeInput, type ProjectRuntimeResult, RUNTIME_PING_TIMEOUT_MS, type RuntimeLaunchSpec, type WaitForHealthOptions, buildRuntimeEnv, canPingProjectTarget, defaultHostingPlugin, dockerPlugin, formatDockerEnv, pingProject, pingProjectTarget, projectDatabaseRuntimeEnv, resolveProjectServerImage, resolveRuntimeLaunch, rewriteLoopbackHost, waitForHealth };
|
|
159
|
+
export { DEV_PLATFORM_WORKER_TOKEN, type DockerPluginOptions, type HostingOptions, type HostingPlugin, type OrganizationHostingInput, type OrganizationHostingResult, PROJECT_DATABASE_ENV_KEYS, PROJECT_SERVER_FRAMEWORK_NODE_MODULES, PROJECT_SERVER_FRAMEWORK_ROOT, PROJECT_SERVER_HEALTH, PROJECT_SERVER_IMAGE, PROJECT_SERVER_PORT, PROJECT_SERVER_ROOT, type PingProjectOptions, type ProjectPingTarget, type ProjectRuntime, type ProjectRuntimeDatabase, type ProjectRuntimeHosting, type ProjectRuntimeInput, type ProjectRuntimeResult, RUNTIME_PING_TIMEOUT_MS, type RuntimeLaunchSpec, type WaitForHealthOptions, type WorkerRuntimeConfig, WorkerRuntimeConfigError, buildRuntimeEnv, canPingProjectTarget, defaultHostingPlugin, dockerPlugin, formatDockerEnv, pingProject, pingProjectTarget, projectDatabaseRuntimeEnv, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, waitForHealth };
|
|
141
160
|
//# 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.ts","../src/plugin.ts","../src/docker/create-docker-runtime.ts","../src/docker/plugin.ts","../src/default-plugin.ts","../src/runtime-env.ts","../src/wait-for-health.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.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;;;KCbE,sBAAA;EACV,IAAA;EACA,IAAA;EACA,QAAA;EACA,IAAA;EACA,QAAA;EACA,UAAA;EACA,SAAA;EACA,cAAA;AAAA;AAAA,KAGU,qBAAA;EACV,OAAO;AAAA;AAAA,KAGG,mBAAA;EACV,SAAA;EACA,IAAA;EACA,WAAA;EACA,QAAA,EAAU,sBAAA;EACV,OAAA,GAAU,qBAAqB;AAAA;AAAA,KAGrB,oBAAA;EACV,SAAA;EACA,OAAO;AAAA;AAAA,KAGG,cAAA;EACV,KAAA,CAAM,KAAA,EAAO,mBAAA,GAAsB,OAAA,CAAQ,oBAAA;AAAA;AAAA,KAGjC,iBAAA;EACV,OAAA;EACA,SAAS;AAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/constants.ts","../src/runtime.ts","../src/worker-runtime-config.ts","../src/plugin.ts","../src/docker/create-docker-runtime.ts","../src/docker/plugin.ts","../src/default-plugin.ts","../src/runtime-env.ts","../src/wait-for-health.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -18,7 +18,8 @@ const RUNTIME_ENV_KEYS = [
|
|
|
18
18
|
"ANTHROPIC_API_KEY",
|
|
19
19
|
"OPENAI_API_KEY"
|
|
20
20
|
];
|
|
21
|
-
|
|
21
|
+
/** Shared dev token when `PLATFORM_WORKER_TOKEN` is unset (non-production only). */
|
|
22
|
+
const DEV_PLATFORM_WORKER_TOKEN = "dev-platform-worker-token";
|
|
22
23
|
const PROJECT_DATABASE_ENV_KEYS = [
|
|
23
24
|
"POSTGRES_HOST",
|
|
24
25
|
"POSTGRES_PORT",
|
|
@@ -75,23 +76,40 @@ function buildRuntimeEnv(source, artifactUrl, database) {
|
|
|
75
76
|
if (credentialsKey) entries.set("CREDENTIALS_ENCRYPTION_KEY", credentialsKey);
|
|
76
77
|
}
|
|
77
78
|
if (mode === "worker") {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
const platformUrl = source.PLATFORM_URL ?? source.PUBLIC_WEB_URL;
|
|
83
|
-
if (platformUrl) entries.set("PLATFORM_URL", platformUrl);
|
|
84
|
-
const workerToken = source.PLATFORM_WORKER_TOKEN ?? source.WORKER_INTERNAL_TOKEN;
|
|
85
|
-
if (workerToken) entries.set("WORKER_INTERNAL_TOKEN", workerToken);
|
|
79
|
+
const worker = resolveWorkerRuntimeConfig(source);
|
|
80
|
+
entries.set("PLATFORM_URL", worker.platformUrl);
|
|
81
|
+
entries.set("WORKER_INTERNAL_TOKEN", worker.workerToken);
|
|
86
82
|
}
|
|
87
83
|
for (const [key, value] of Object.entries(projectDatabaseRuntimeEnv(database))) entries.set(key, value);
|
|
88
84
|
return Object.fromEntries(entries);
|
|
89
85
|
}
|
|
86
|
+
function resolvePlatformWorkerToken(source = process.env) {
|
|
87
|
+
const explicit = source.PLATFORM_WORKER_TOKEN?.trim() ?? source.WORKER_INTERNAL_TOKEN?.trim();
|
|
88
|
+
if (explicit) return explicit;
|
|
89
|
+
if (source.NODE_ENV === "production") return;
|
|
90
|
+
return DEV_PLATFORM_WORKER_TOKEN;
|
|
91
|
+
}
|
|
92
|
+
/** Platform API URL reachable from a project-server container. */
|
|
93
|
+
const DEV_PLATFORM_URL = "http://localhost:3002";
|
|
94
|
+
function resolveWorkerPlatformUrl(source = process.env) {
|
|
95
|
+
const raw = source.PLATFORM_URL?.trim() ?? source.PUBLIC_PLATFORM_URL?.trim() ?? (source.NODE_ENV === "production" ? void 0 : DEV_PLATFORM_URL);
|
|
96
|
+
if (!raw) return;
|
|
97
|
+
return rewriteLoopbackUrl(raw);
|
|
98
|
+
}
|
|
90
99
|
/** Rewrite loopback hosts so containers can reach Postgres and other host services. */
|
|
91
100
|
function rewriteLoopbackHost(host) {
|
|
92
101
|
if (host === "localhost" || host === "127.0.0.1") return "host.docker.internal";
|
|
93
102
|
return host;
|
|
94
103
|
}
|
|
104
|
+
function rewriteLoopbackUrl(url) {
|
|
105
|
+
try {
|
|
106
|
+
const parsed = new URL(url);
|
|
107
|
+
parsed.hostname = rewriteLoopbackHost(parsed.hostname);
|
|
108
|
+
return parsed.toString().replace(/\/$/, "");
|
|
109
|
+
} catch {
|
|
110
|
+
return url;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
95
113
|
/** dockerode expects `KEY=value` strings. */
|
|
96
114
|
function formatDockerEnv(env) {
|
|
97
115
|
return Object.entries(env).map(([key, value]) => `${key}=${value}`);
|
|
@@ -100,6 +118,29 @@ function resolveProjectServerImage(env = process.env, override) {
|
|
|
100
118
|
return override ?? env.PROJECT_DOCKER_IMAGE ?? env.TENANT_DOCKER_IMAGE ?? "keystroke/project-server:local";
|
|
101
119
|
}
|
|
102
120
|
//#endregion
|
|
121
|
+
//#region src/worker-runtime-config.ts
|
|
122
|
+
var WorkerRuntimeConfigError = class extends Error {
|
|
123
|
+
missing;
|
|
124
|
+
constructor(missing) {
|
|
125
|
+
super(`Worker runtime config incomplete (missing: ${missing.join(", ")}). In production set PLATFORM_WORKER_TOKEN and PUBLIC_PLATFORM_URL (or PLATFORM_URL).`);
|
|
126
|
+
this.name = "WorkerRuntimeConfigError";
|
|
127
|
+
this.missing = missing;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
/** Fail fast when the platform cannot start worker-mode project servers. */
|
|
131
|
+
function resolveWorkerRuntimeConfig(source = process.env) {
|
|
132
|
+
const platformUrl = resolveWorkerPlatformUrl(source);
|
|
133
|
+
const workerToken = resolvePlatformWorkerToken(source);
|
|
134
|
+
const missing = [];
|
|
135
|
+
if (!platformUrl) missing.push("PUBLIC_PLATFORM_URL or PLATFORM_URL");
|
|
136
|
+
if (!workerToken) missing.push("PLATFORM_WORKER_TOKEN");
|
|
137
|
+
if (missing.length > 0) throw new WorkerRuntimeConfigError(missing);
|
|
138
|
+
return {
|
|
139
|
+
platformUrl,
|
|
140
|
+
workerToken
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
103
144
|
//#region src/wait-for-health.ts
|
|
104
145
|
const DEFAULT_TIMEOUT_MS = 12e4;
|
|
105
146
|
const DEFAULT_INTERVAL_MS = 500;
|
|
@@ -199,9 +240,14 @@ async function ensureImage(docker, image) {
|
|
|
199
240
|
//#endregion
|
|
200
241
|
//#region src/docker/plugin.ts
|
|
201
242
|
function dockerPlugin(options = {}) {
|
|
243
|
+
const env = options.env ?? process.env;
|
|
202
244
|
return {
|
|
203
245
|
name: "docker",
|
|
204
|
-
|
|
246
|
+
workerRuntime: resolveWorkerRuntimeConfig(env),
|
|
247
|
+
createRuntime: () => createDockerRuntime({
|
|
248
|
+
...options,
|
|
249
|
+
env
|
|
250
|
+
})
|
|
205
251
|
};
|
|
206
252
|
}
|
|
207
253
|
//#endregion
|
|
@@ -242,6 +288,6 @@ async function pingProjectTarget(target, options = {}) {
|
|
|
242
288
|
});
|
|
243
289
|
}
|
|
244
290
|
//#endregion
|
|
245
|
-
export { PROJECT_DATABASE_ENV_KEYS, 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, buildRuntimeEnv, canPingProjectTarget, defaultHostingPlugin, dockerPlugin, formatDockerEnv, pingProject, pingProjectTarget, projectDatabaseRuntimeEnv, resolveProjectServerImage, resolveRuntimeLaunch, rewriteLoopbackHost, waitForHealth };
|
|
291
|
+
export { DEV_PLATFORM_WORKER_TOKEN, PROJECT_DATABASE_ENV_KEYS, 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, defaultHostingPlugin, dockerPlugin, formatDockerEnv, pingProject, pingProjectTarget, projectDatabaseRuntimeEnv, resolvePlatformWorkerToken, resolveProjectServerImage, resolveRuntimeLaunch, resolveWorkerPlatformUrl, resolveWorkerRuntimeConfig, rewriteLoopbackHost, rewriteLoopbackUrl, waitForHealth };
|
|
246
292
|
|
|
247
293
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/constants.ts","../src/runtime-env.ts","../src/wait-for-health.ts","../src/docker/create-docker-runtime.ts","../src/docker/plugin.ts","../src/default-plugin.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.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","import type { ProjectRuntimeDatabase } 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\";\n\nconst RUNTIME_ENV_KEYS = [\n \"BETTER_AUTH_SECRET\",\n \"PUBLIC_SERVER_URL\",\n \"PUBLIC_WEB_URL\",\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n] as const;\n\nconst WORKER_RUNTIME_ENV_KEYS = [\"PLATFORM_URL\", \"PLATFORM_WORKER_TOKEN\"] as const;\n\nexport const PROJECT_DATABASE_ENV_KEYS = [\n \"POSTGRES_HOST\",\n \"POSTGRES_PORT\",\n \"POSTGRES_DB\",\n \"POSTGRES_USER\",\n \"POSTGRES_PASSWORD\",\n \"DATABASE_SEARCH_PATH\",\n] as const;\n\nexport type RuntimeLaunchSpec = {\n image: string;\n env: Record<string, string>;\n port: number;\n health: typeof PROJECT_SERVER_HEALTH;\n};\n\n/** Per-project postgres env injected into every project server container/machine. */\nexport function projectDatabaseRuntimeEnv(\n database: ProjectRuntimeDatabase,\n): Record<(typeof PROJECT_DATABASE_ENV_KEYS)[number], string> {\n return {\n POSTGRES_HOST: rewriteLoopbackHost(database.host),\n POSTGRES_PORT: String(database.port),\n POSTGRES_DB: database.database,\n POSTGRES_USER: database.user,\n POSTGRES_PASSWORD: database.password,\n DATABASE_SEARCH_PATH: database.searchPath,\n };\n}\n\n/**\n * Builds the launch spec for a single project server. `artifactUrl` is the\n * per-project presigned URL to that deploy's built `dist` — there is no base\n * image, so it is required.\n */\nexport function resolveRuntimeLaunch(\n options: HostingOptions,\n artifactUrl: string,\n database: ProjectRuntimeDatabase,\n): RuntimeLaunchSpec {\n if (!artifactUrl) {\n throw new Error(\"Cannot start a project server without an artifact URL\");\n }\n\n const env = options.env ?? process.env;\n\n return {\n image: resolveProjectServerImage(env, options.image),\n env: buildRuntimeEnv(env, artifactUrl, database),\n port: PROJECT_SERVER_PORT,\n health: PROJECT_SERVER_HEALTH,\n };\n}\n\n/** Env vars passed into the project server container/machine. */\nexport function buildRuntimeEnv(\n source: NodeJS.ProcessEnv,\n artifactUrl: string,\n database: ProjectRuntimeDatabase,\n): Record<string, string> {\n const mode = source.KEYSTROKE_MODE ?? \"worker\";\n const entries = new Map<string, string>([\n // Container bind port — not derived from PUBLIC_SERVER_URL (external URL metadata).\n [\"PORT\", String(PROJECT_SERVER_PORT)],\n [\"KEYSTROKE_ROOT\", PROJECT_SERVER_ROOT],\n [\"KEYSTROKE_RUNTIME_NODE_MODULES\", PROJECT_SERVER_FRAMEWORK_NODE_MODULES],\n [\"ARTIFACT_URL\", artifactUrl],\n [\"KEYSTROKE_MODE\", mode],\n [\"PROJECT_ID\", database.projectId],\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];\n if (value) {\n entries.set(key, value);\n }\n }\n\n if (mode !== \"worker\") {\n const credentialsKey = source.CREDENTIALS_ENCRYPTION_KEY;\n if (credentialsKey) {\n entries.set(\"CREDENTIALS_ENCRYPTION_KEY\", credentialsKey);\n }\n }\n\n if (mode === \"worker\") {\n for (const key of WORKER_RUNTIME_ENV_KEYS) {\n const value = source[key];\n if (value) {\n entries.set(key, value);\n }\n }\n\n const platformUrl = source.PLATFORM_URL ?? source.PUBLIC_WEB_URL;\n if (platformUrl) {\n entries.set(\"PLATFORM_URL\", platformUrl);\n }\n\n const workerToken = source.PLATFORM_WORKER_TOKEN ?? source.WORKER_INTERNAL_TOKEN;\n if (workerToken) {\n entries.set(\"WORKER_INTERNAL_TOKEN\", workerToken);\n }\n }\n\n for (const [key, value] of Object.entries(projectDatabaseRuntimeEnv(database))) {\n entries.set(key, value);\n }\n\n return Object.fromEntries(entries);\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\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","import Docker from \"dockerode\";\n\nimport type { ProjectRuntime } from \"../runtime\";\n\nimport type { HostingOptions } from \"../plugin\";\nimport { formatDockerEnv, resolveRuntimeLaunch } from \"../runtime-env\";\nimport { waitForHealth } from \"../wait-for-health\";\n\nexport type DockerPluginOptions = HostingOptions & {\n docker?: Docker;\n};\n\nconst MINIO_DOCKER_NETWORK = process.env.MINIO_DOCKER_NETWORK ?? \"keystroke\";\n\nexport function createDockerRuntime(options: DockerPluginOptions = {}): ProjectRuntime {\n const docker = options.docker ?? new Docker();\n\n return {\n async start(input) {\n const launch = resolveRuntimeLaunch(options, input.artifactUrl, input.database);\n await ensureImage(docker, launch.image);\n await removeExistingContainer(docker, input.projectId);\n\n const container = await docker.createContainer({\n Image: launch.image,\n name: containerName(input.projectId),\n Labels: {\n \"keystroke.project.id\": input.projectId,\n \"keystroke.project.name\": input.name,\n },\n ExposedPorts: {\n [`${launch.port}/tcp`]: {},\n },\n HostConfig: {\n ExtraHosts: [\"host.docker.internal:host-gateway\"],\n PortBindings: {\n [`${launch.port}/tcp`]: [{ HostPort: \"0\" }],\n },\n },\n NetworkingConfig: {\n EndpointsConfig: {\n [MINIO_DOCKER_NETWORK]: {},\n },\n },\n Env: formatDockerEnv(launch.env),\n });\n\n await container.start();\n\n const inspect = await container.inspect();\n const binding = inspect.NetworkSettings.Ports?.[`${launch.port}/tcp`]?.[0];\n if (!binding?.HostPort) {\n throw new Error(\"Failed to resolve project container host port\");\n }\n\n const baseUrl = `http://127.0.0.1:${binding.HostPort}`;\n await waitForHealth(baseUrl, {\n fetchImpl: options.fetchImpl,\n timeoutMs: options.healthTimeoutMs,\n });\n\n return {\n runtimeId: inspect.Id,\n baseUrl,\n };\n },\n };\n}\n\nfunction containerName(projectId: string): string {\n return `keystroke-project-${projectId}`;\n}\n\nasync function removeExistingContainer(docker: Docker, projectId: string): Promise<void> {\n try {\n const existing = docker.getContainer(containerName(projectId));\n await existing.stop({ t: 5 }).catch(() => undefined);\n await existing.remove({ force: true });\n } catch {\n // no existing container\n }\n}\n\nasync function ensureImage(docker: Docker, image: string): Promise<void> {\n try {\n await docker.getImage(image).inspect();\n return;\n } catch {\n // pull below\n }\n\n await new Promise<void>((resolvePromise, reject) => {\n docker.pull(image, (error: Error | null, stream: NodeJS.ReadableStream | undefined) => {\n if (error) {\n reject(error);\n return;\n }\n\n if (!stream) {\n reject(new Error(`Failed to pull image ${image}`));\n return;\n }\n\n docker.modem.followProgress(stream, (progressError: Error | null) => {\n if (progressError) {\n reject(progressError);\n return;\n }\n\n resolvePromise();\n });\n });\n });\n}\n","import type { HostingPlugin } from \"../plugin\";\n\nimport { createDockerRuntime } from \"./create-docker-runtime\";\nimport type { DockerPluginOptions } from \"./create-docker-runtime\";\n\nexport type { DockerPluginOptions } from \"./create-docker-runtime\";\n\nexport function dockerPlugin(options: DockerPluginOptions = {}): HostingPlugin {\n return {\n name: \"docker\",\n createRuntime: () => createDockerRuntime(options),\n };\n}\n","import type { HostingPlugin } from \"./plugin\";\nimport { dockerPlugin, type DockerPluginOptions } from \"./docker/plugin\";\n\n/** Local Docker hosting — default for platform and dev. */\nexport function defaultHostingPlugin(options: DockerPluginOptions = {}): HostingPlugin {\n return dockerPlugin(options);\n}\n","/** Timeout for a single project runtime `/health` probe. */\nexport const RUNTIME_PING_TIMEOUT_MS = 15_000;\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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/constants.ts","../src/runtime-env.ts","../src/worker-runtime-config.ts","../src/wait-for-health.ts","../src/docker/create-docker-runtime.ts","../src/docker/plugin.ts","../src/default-plugin.ts","../src/runtime-constants.ts","../src/ping-project.ts","../src/ping-project-target.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","import type { ProjectRuntimeDatabase } 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\";\n\nconst RUNTIME_ENV_KEYS = [\n \"BETTER_AUTH_SECRET\",\n \"PUBLIC_SERVER_URL\",\n \"PUBLIC_WEB_URL\",\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\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 const PROJECT_DATABASE_ENV_KEYS = [\n \"POSTGRES_HOST\",\n \"POSTGRES_PORT\",\n \"POSTGRES_DB\",\n \"POSTGRES_USER\",\n \"POSTGRES_PASSWORD\",\n \"DATABASE_SEARCH_PATH\",\n] as const;\n\nexport type RuntimeLaunchSpec = {\n image: string;\n env: Record<string, string>;\n port: number;\n health: typeof PROJECT_SERVER_HEALTH;\n};\n\n/** Per-project postgres env injected into every project server container/machine. */\nexport function projectDatabaseRuntimeEnv(\n database: ProjectRuntimeDatabase,\n): Record<(typeof PROJECT_DATABASE_ENV_KEYS)[number], string> {\n return {\n POSTGRES_HOST: rewriteLoopbackHost(database.host),\n POSTGRES_PORT: String(database.port),\n POSTGRES_DB: database.database,\n POSTGRES_USER: database.user,\n POSTGRES_PASSWORD: database.password,\n DATABASE_SEARCH_PATH: database.searchPath,\n };\n}\n\n/**\n * Builds the launch spec for a single project server. `artifactUrl` is the\n * per-project presigned URL to that deploy's built `dist` — there is no base\n * image, so it is required.\n */\nexport function resolveRuntimeLaunch(\n options: HostingOptions,\n artifactUrl: string,\n database: ProjectRuntimeDatabase,\n): RuntimeLaunchSpec {\n if (!artifactUrl) {\n throw new Error(\"Cannot start a project server without an artifact URL\");\n }\n\n const env = options.env ?? process.env;\n\n return {\n image: resolveProjectServerImage(env, options.image),\n env: buildRuntimeEnv(env, artifactUrl, database),\n port: PROJECT_SERVER_PORT,\n health: PROJECT_SERVER_HEALTH,\n };\n}\n\n/** Env vars passed into the project server container/machine. */\nexport function buildRuntimeEnv(\n source: NodeJS.ProcessEnv,\n artifactUrl: string,\n database: ProjectRuntimeDatabase,\n): Record<string, string> {\n const mode = source.KEYSTROKE_MODE ?? \"worker\";\n const entries = new Map<string, string>([\n // Container bind port — not derived from PUBLIC_SERVER_URL (external URL metadata).\n [\"PORT\", String(PROJECT_SERVER_PORT)],\n [\"KEYSTROKE_ROOT\", PROJECT_SERVER_ROOT],\n [\"KEYSTROKE_RUNTIME_NODE_MODULES\", PROJECT_SERVER_FRAMEWORK_NODE_MODULES],\n [\"ARTIFACT_URL\", artifactUrl],\n [\"KEYSTROKE_MODE\", mode],\n [\"PROJECT_ID\", database.projectId],\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];\n if (value) {\n entries.set(key, value);\n }\n }\n\n if (mode !== \"worker\") {\n const credentialsKey = source.CREDENTIALS_ENCRYPTION_KEY;\n if (credentialsKey) {\n entries.set(\"CREDENTIALS_ENCRYPTION_KEY\", credentialsKey);\n }\n }\n\n if (mode === \"worker\") {\n const worker = resolveWorkerRuntimeConfig(source);\n entries.set(\"PLATFORM_URL\", worker.platformUrl);\n entries.set(\"WORKER_INTERNAL_TOKEN\", worker.workerToken);\n }\n\n for (const [key, value] of Object.entries(projectDatabaseRuntimeEnv(database))) {\n entries.set(key, value);\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. */\nconst DEV_PLATFORM_URL = \"http://localhost:3002\";\n\nexport function resolveWorkerPlatformUrl(\n source: NodeJS.ProcessEnv = process.env,\n): string | undefined {\n const raw =\n source.PLATFORM_URL?.trim() ??\n source.PUBLIC_PLATFORM_URL?.trim() ??\n (source.NODE_ENV === \"production\" ? undefined : DEV_PLATFORM_URL);\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 { 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 { 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","import Docker from \"dockerode\";\n\nimport type { ProjectRuntime } from \"../runtime\";\n\nimport type { HostingOptions } from \"../plugin\";\nimport { formatDockerEnv, resolveRuntimeLaunch } from \"../runtime-env\";\nimport { waitForHealth } from \"../wait-for-health\";\n\nexport type DockerPluginOptions = HostingOptions & {\n docker?: Docker;\n};\n\nconst MINIO_DOCKER_NETWORK = process.env.MINIO_DOCKER_NETWORK ?? \"keystroke\";\n\nexport function createDockerRuntime(options: DockerPluginOptions = {}): ProjectRuntime {\n const docker = options.docker ?? new Docker();\n\n return {\n async start(input) {\n const launch = resolveRuntimeLaunch(options, input.artifactUrl, input.database);\n await ensureImage(docker, launch.image);\n await removeExistingContainer(docker, input.projectId);\n\n const container = await docker.createContainer({\n Image: launch.image,\n name: containerName(input.projectId),\n Labels: {\n \"keystroke.project.id\": input.projectId,\n \"keystroke.project.name\": input.name,\n },\n ExposedPorts: {\n [`${launch.port}/tcp`]: {},\n },\n HostConfig: {\n ExtraHosts: [\"host.docker.internal:host-gateway\"],\n PortBindings: {\n [`${launch.port}/tcp`]: [{ HostPort: \"0\" }],\n },\n },\n NetworkingConfig: {\n EndpointsConfig: {\n [MINIO_DOCKER_NETWORK]: {},\n },\n },\n Env: formatDockerEnv(launch.env),\n });\n\n await container.start();\n\n const inspect = await container.inspect();\n const binding = inspect.NetworkSettings.Ports?.[`${launch.port}/tcp`]?.[0];\n if (!binding?.HostPort) {\n throw new Error(\"Failed to resolve project container host port\");\n }\n\n const baseUrl = `http://127.0.0.1:${binding.HostPort}`;\n await waitForHealth(baseUrl, {\n fetchImpl: options.fetchImpl,\n timeoutMs: options.healthTimeoutMs,\n });\n\n return {\n runtimeId: inspect.Id,\n baseUrl,\n };\n },\n };\n}\n\nfunction containerName(projectId: string): string {\n return `keystroke-project-${projectId}`;\n}\n\nasync function removeExistingContainer(docker: Docker, projectId: string): Promise<void> {\n try {\n const existing = docker.getContainer(containerName(projectId));\n await existing.stop({ t: 5 }).catch(() => undefined);\n await existing.remove({ force: true });\n } catch {\n // no existing container\n }\n}\n\nasync function ensureImage(docker: Docker, image: string): Promise<void> {\n try {\n await docker.getImage(image).inspect();\n return;\n } catch {\n // pull below\n }\n\n await new Promise<void>((resolvePromise, reject) => {\n docker.pull(image, (error: Error | null, stream: NodeJS.ReadableStream | undefined) => {\n if (error) {\n reject(error);\n return;\n }\n\n if (!stream) {\n reject(new Error(`Failed to pull image ${image}`));\n return;\n }\n\n docker.modem.followProgress(stream, (progressError: Error | null) => {\n if (progressError) {\n reject(progressError);\n return;\n }\n\n resolvePromise();\n });\n });\n });\n}\n","import type { HostingPlugin } from \"../plugin\";\nimport { resolveWorkerRuntimeConfig } from \"../worker-runtime-config\";\n\nimport { createDockerRuntime } from \"./create-docker-runtime\";\nimport type { DockerPluginOptions } from \"./create-docker-runtime\";\n\nexport type { DockerPluginOptions } from \"./create-docker-runtime\";\n\nexport function dockerPlugin(options: DockerPluginOptions = {}): HostingPlugin {\n const env = options.env ?? process.env;\n\n return {\n name: \"docker\",\n workerRuntime: resolveWorkerRuntimeConfig(env),\n createRuntime: () => createDockerRuntime({ ...options, env }),\n };\n}\n","import type { HostingPlugin } from \"./plugin\";\nimport { dockerPlugin, type DockerPluginOptions } from \"./docker/plugin\";\n\n/** Local Docker hosting — default for platform and dev. */\nexport function defaultHostingPlugin(options: DockerPluginOptions = {}): HostingPlugin {\n return dockerPlugin(options);\n}\n","/** Timeout for a single project runtime `/health` probe. */\nexport const RUNTIME_PING_TIMEOUT_MS = 15_000;\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"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keystrokehq/hosting",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.75",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/dallinbentley/keystroke.git",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"typescript": "^6.0.3",
|
|
38
38
|
"vitest": "^4.1.7",
|
|
39
39
|
"@keystrokehq/oxlint-config": "0.0.3",
|
|
40
|
+
"@keystrokehq/shared": "0.0.55",
|
|
40
41
|
"@keystrokehq/tsconfig": "0.0.3",
|
|
41
|
-
"@keystrokehq/shared": "0.0.54",
|
|
42
42
|
"@keystrokehq/tsdown-config": "0.0.3",
|
|
43
43
|
"@keystrokehq/vitest-config": "0.0.3"
|
|
44
44
|
},
|