everything-dev 2.0.0-rc.6 → 2.0.0-rc.8
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/README.md +2 -2
- package/dist/api/auth-middleware.cjs +14 -1
- package/dist/api/auth-middleware.cjs.map +1 -1
- package/dist/api/auth-middleware.d.cts +9 -0
- package/dist/api/auth-middleware.d.mts +9 -0
- package/dist/api/auth-middleware.mjs +14 -1
- package/dist/api/auth-middleware.mjs.map +1 -1
- package/dist/build.cjs +1 -1
- package/dist/build.mjs +1 -1
- package/dist/bundle-cache.cjs +1 -1
- package/dist/bundle-cache.cjs.map +1 -1
- package/dist/bundle-cache.mjs +1 -1
- package/dist/bundle-cache.mjs.map +1 -1
- package/dist/cli/init.cjs +22 -10
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.mjs +22 -10
- package/dist/cli/init.mjs.map +1 -1
- package/dist/cli.cjs +6 -5
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +5 -4
- package/dist/cli.mjs.map +1 -1
- package/dist/commands/deploy.cjs +111 -1
- package/dist/commands/deploy.cjs.map +1 -1
- package/dist/commands/deploy.mjs +112 -2
- package/dist/commands/deploy.mjs.map +1 -1
- package/dist/commands/keys.cjs +1 -1
- package/dist/commands/keys.cjs.map +1 -1
- package/dist/commands/keys.mjs +1 -1
- package/dist/commands/keys.mjs.map +1 -1
- package/dist/commands/smoke.cjs +41 -0
- package/dist/commands/smoke.cjs.map +1 -0
- package/dist/commands/smoke.mjs +41 -0
- package/dist/commands/smoke.mjs.map +1 -0
- package/dist/commands/upgrade.cjs +2 -2
- package/dist/commands/upgrade.cjs.map +1 -1
- package/dist/commands/upgrade.mjs +1 -1
- package/dist/commands/upgrade.mjs.map +1 -1
- package/dist/contract.cjs +27 -1
- package/dist/contract.cjs.map +1 -1
- package/dist/contract.d.cts +65 -1
- package/dist/contract.d.mts +65 -1
- package/dist/contract.meta.cjs +14 -2
- package/dist/contract.meta.cjs.map +1 -1
- package/dist/contract.meta.d.cts +24 -2
- package/dist/contract.meta.d.mts +24 -2
- package/dist/contract.meta.mjs +14 -2
- package/dist/contract.meta.mjs.map +1 -1
- package/dist/contract.mjs +26 -2
- package/dist/contract.mjs.map +1 -1
- package/dist/db/core.cjs +22 -4
- package/dist/db/core.cjs.map +1 -1
- package/dist/db/core.mjs +22 -4
- package/dist/db/core.mjs.map +1 -1
- package/dist/dev-log-pipeline.cjs +6 -0
- package/dist/dev-log-pipeline.cjs.map +1 -1
- package/dist/dev-log-pipeline.mjs +6 -0
- package/dist/dev-log-pipeline.mjs.map +1 -1
- package/dist/dev-program.cjs +20 -3
- package/dist/dev-program.cjs.map +1 -1
- package/dist/dev-program.mjs +20 -4
- package/dist/dev-program.mjs.map +1 -1
- package/dist/dev-session.cjs +1 -0
- package/dist/dev-session.cjs.map +1 -1
- package/dist/dev-session.mjs +1 -0
- package/dist/dev-session.mjs.map +1 -1
- package/dist/fastkv.cjs +21 -3
- package/dist/fastkv.cjs.map +1 -1
- package/dist/fastkv.d.cts +14 -1
- package/dist/fastkv.d.mts +14 -1
- package/dist/fastkv.mjs +21 -5
- package/dist/fastkv.mjs.map +1 -1
- package/dist/{mf.cjs → federation.cjs} +6 -13
- package/dist/federation.cjs.map +1 -0
- package/dist/{mf.d.cts → federation.d.cts} +2 -2
- package/dist/{mf.d.mts → federation.d.mts} +2 -2
- package/dist/{mf.mjs → federation.mjs} +6 -13
- package/dist/federation.mjs.map +1 -0
- package/dist/http-client.cjs +84 -57
- package/dist/http-client.cjs.map +1 -1
- package/dist/http-client.mjs +84 -58
- package/dist/http-client.mjs.map +1 -1
- package/dist/image-deploy.cjs +9 -0
- package/dist/image-deploy.cjs.map +1 -1
- package/dist/image-deploy.mjs +9 -1
- package/dist/image-deploy.mjs.map +1 -1
- package/dist/index.cjs +4 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -3
- package/dist/infra/planner.cjs +6 -2
- package/dist/infra/planner.cjs.map +1 -1
- package/dist/infra/planner.mjs +6 -2
- package/dist/infra/planner.mjs.map +1 -1
- package/dist/orchestrator.cjs +39 -35
- package/dist/orchestrator.cjs.map +1 -1
- package/dist/orchestrator.mjs +39 -35
- package/dist/orchestrator.mjs.map +1 -1
- package/dist/plugin.cjs +2 -0
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +24 -0
- package/dist/plugin.d.mts +24 -0
- package/dist/plugin.mjs +2 -0
- package/dist/plugin.mjs.map +1 -1
- package/dist/process-registry.cjs +1 -1
- package/dist/process-registry.mjs +1 -1
- package/dist/publish.cjs +3 -3
- package/dist/publish.cjs.map +1 -1
- package/dist/publish.mjs +4 -4
- package/dist/publish.mjs.map +1 -1
- package/dist/resolver.cjs +293 -0
- package/dist/resolver.cjs.map +1 -0
- package/dist/resolver.d.cts +99 -0
- package/dist/resolver.d.mts +99 -0
- package/dist/resolver.mjs +284 -0
- package/dist/resolver.mjs.map +1 -0
- package/dist/smoke.cjs +262 -0
- package/dist/smoke.cjs.map +1 -0
- package/dist/smoke.mjs +260 -0
- package/dist/smoke.mjs.map +1 -0
- package/dist/ui/auth.d.cts +217 -123
- package/dist/ui/auth.d.mts +217 -123
- package/dist/ui/router-client.cjs +2 -1
- package/dist/ui/router-client.cjs.map +1 -1
- package/dist/ui/router-client.mjs +2 -1
- package/dist/ui/router-client.mjs.map +1 -1
- package/dist/version-manifest-resolve.cjs +3 -3
- package/dist/version-manifest-resolve.cjs.map +1 -1
- package/dist/version-manifest-resolve.mjs +1 -1
- package/dist/version-manifest-resolve.mjs.map +1 -1
- package/dist/workspace.cjs +1 -1
- package/dist/workspace.mjs +1 -1
- package/package.json +18 -18
- package/skills/api-and-auth/SKILL.md +12 -9
- package/skills/api-and-auth/references/middleware.md +38 -0
- package/skills/cli-reference/SKILL.md +22 -6
- package/skills/talk-to-the-app/SKILL.md +32 -5
- package/dist/bundle-fs-resolve.cjs +0 -235
- package/dist/bundle-fs-resolve.cjs.map +0 -1
- package/dist/bundle-fs-resolve.d.cts +0 -82
- package/dist/bundle-fs-resolve.d.mts +0 -82
- package/dist/bundle-fs-resolve.mjs +0 -228
- package/dist/bundle-fs-resolve.mjs.map +0 -1
- package/dist/bundle-path.cjs +0 -48
- package/dist/bundle-path.cjs.map +0 -1
- package/dist/bundle-path.mjs +0 -45
- package/dist/bundle-path.mjs.map +0 -1
- package/dist/mf.cjs.map +0 -1
- package/dist/mf.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.cjs","names":["Data","Schema","Effect","stripAnsi","DevRuntimeConfig","Deferred","Ref","DevGeneratedEnv","ShellEnv","spawn","Schedule","Readable","Stream","Option","ServiceDescriptorMap"],"sources":["../src/orchestrator.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { Readable } from \"node:stream\";\nimport { Data, Deferred, Effect, Option, Ref, Schedule, Schema, Stream } from \"effect\";\nimport { stripAnsi } from \"./dev-log-pipeline\";\nimport { ShellEnv } from \"./env/project-env\";\nimport { patchManifestFetchForSsrPublicPath } from \"./mf\";\nimport {\n DevGeneratedEnv,\n DevRuntimeConfig,\n type ServiceDescriptor,\n ServiceDescriptorMap,\n} from \"./service-descriptor\";\nimport type { RuntimeConfig } from \"./types\";\n\nconst runFetch = (url: string, init?: RequestInit): Promise<Response> => fetch(url, init);\n\nprocess.on(\"unhandledRejection\", (reason) => {\n console.error(\"[Orchestrator] Unhandled rejection:\", reason);\n});\n\nprocess.on(\"uncaughtException\", (err) => {\n console.error(\"[Orchestrator] Uncaught exception:\", err);\n});\n\nexport interface ProcessCallbacks {\n onStatus: (name: string, status: ProcessStatus, message?: string) => void;\n onLog: (name: string, line: string, isError?: boolean) => void;\n}\n\nexport interface ProcessHandle {\n name: string;\n pid: number | undefined;\n kill: Effect.Effect<void>;\n waitForReady: Effect.Effect<void, OrchestratorError>;\n waitForExit: Effect.Effect<number, OrchestratorError>;\n}\n\nexport class OrchestratorError extends Data.TaggedError(\"OrchestratorError\")<{\n readonly operation: string;\n readonly detail: string;\n readonly cause?: unknown;\n}> {\n override get message() {\n return `${this.operation}: ${this.detail}`;\n }\n}\n\nconst omitUndefined = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((item) => (item === undefined ? null : omitUndefined(item)));\n }\n if (value !== null && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value)\n .filter(([, item]) => item !== undefined)\n .map(([key, item]) => [key, omitUndefined(item)]),\n );\n }\n return value;\n};\n\nexport const encodeRuntimeConfig = (runtimeConfig: unknown) =>\n Schema.encodeUnknownEffect(Schema.fromJsonString(Schema.Json))(omitUndefined(runtimeConfig)).pipe(\n Effect.mapError(\n (cause) =>\n new OrchestratorError({\n operation: \"serialize runtime config\",\n detail: cause.message,\n cause,\n }),\n ),\n );\n\nexport type ProcessStatus = \"pending\" | \"starting\" | \"ready\" | \"error\";\n\nexport interface ProcessState {\n name: string;\n status: ProcessStatus;\n port: number;\n message?: string;\n source?: \"local\" | \"remote\";\n uiPort?: number;\n}\n\nconst probeHttpOk = (url: string, timeoutMs = 400) =>\n Effect.tryPromise({\n try: async () => {\n try {\n const res = await runFetch(url, { signal: AbortSignal.timeout(timeoutMs) });\n return res.ok;\n } catch {\n return false;\n }\n },\n catch: () => false,\n });\n\nconst LOCAL_PROBE_DEADLINE_MS = 90_000;\nconst LOCAL_PROBE_INTERVAL_MS = 200;\n\nconst cleanExitSignals: Record<string, true> = { SIGTERM: true, SIGINT: true };\n\nconst REMOTE_PROBE_TIMEOUT_MS = 5000;\nconst REMOTE_PROBE_DEADLINE_MS = 60_000;\nconst REMOTE_PROBE_BACKOFF_INITIAL_MS = 1000;\nconst REMOTE_PROBE_BACKOFF_MAX_MS = 15_000;\n\nexport const detectStatus = (\n line: string,\n descriptor: ServiceDescriptor,\n): { status: ProcessStatus; isError: boolean } | null => {\n const cleanLine = stripAnsi(line);\n const errorPatterns = descriptor.errorPatterns ?? [];\n const readyPatterns = descriptor.readyPatterns ?? [];\n for (const pattern of readyPatterns) {\n if (pattern.test(cleanLine)) {\n return { status: \"ready\", isError: false };\n }\n }\n for (const pattern of errorPatterns) {\n if (pattern.test(cleanLine)) {\n return { status: \"error\", isError: true };\n }\n }\n return null;\n};\n\ninterface ServerHandle {\n ready: Promise<void>;\n shutdown: () => Promise<void>;\n}\n\ninterface ServerInput {\n config: RuntimeConfig;\n port?: number;\n env?: Record<string, string>;\n}\n\nconst patchConsole = (name: string, callbacks: ProcessCallbacks): (() => void) => {\n const originalLog = console.log;\n const originalError = console.error;\n const originalWarn = console.warn;\n const originalInfo = console.info;\n\n const formatArgs = (args: unknown[], isError = false): string => {\n return args\n .map((arg) => {\n if (arg instanceof Error) {\n const parts = [`${arg.name}: ${arg.message}`];\n if (arg.cause instanceof Error)\n parts.push(`(cause: ${arg.cause.name}: ${arg.cause.message})`);\n else if (arg.cause) {\n const cause = arg.cause;\n parts.push(\n `(cause: ${cause instanceof Error ? cause.message : typeof cause === \"string\" ? cause : (JSON.stringify(cause) ?? \"[Unserializable cause]\")})`,\n );\n }\n if (isError && arg.stack) parts.push(arg.stack);\n return parts.join(\"\\n\");\n }\n if (arg === null) return \"null\";\n if (typeof arg === \"string\") return arg;\n if (typeof arg === \"number\" || typeof arg === \"bigint\" || typeof arg === \"boolean\")\n return `${arg}`;\n if (typeof arg === \"symbol\") return arg.description ?? \"\";\n if (typeof arg === \"undefined\") return \"undefined\";\n return JSON.stringify(arg, null, 2) ?? \"[Unserializable value]\";\n })\n .join(\" \");\n };\n\n console.log = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n console.error = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args, true), true);\n };\n console.warn = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n console.info = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n\n return () => {\n console.log = originalLog;\n console.error = originalError;\n console.warn = originalWarn;\n console.info = originalInfo;\n };\n};\n\nexport class HostRemoteUrlMissing extends Data.TaggedError(\"HostRemoteUrlMissing\")<\n Record<never, never>\n> {\n override get message() {\n return \"remoteUrl not provided on host descriptor\";\n }\n}\n\nexport class HostModuleInvalid extends Data.TaggedError(\"HostModuleInvalid\")<Record<never, never>> {\n override get message() {\n return \"Host module does not export runServer function\";\n }\n}\n\nexport class LocalPathMissing extends Data.TaggedError(\"LocalPathMissing\")<{ key: string }> {\n get message() {\n return `No localPath for local service: ${this.key}`;\n }\n}\n\nconst spawnRemoteHost = (descriptor: ServiceDescriptor, callbacks: ProcessCallbacks) =>\n Effect.gen(function* () {\n const runtimeConfig = yield* DevRuntimeConfig;\n const remoteUrl = descriptor.remoteUrl;\n if (!remoteUrl) {\n return yield* new HostRemoteUrlMissing();\n }\n\n callbacks.onStatus(descriptor.key, \"starting\");\n callbacks.onLog(descriptor.key, `Remote: ${remoteUrl}`);\n const restoreConsole = patchConsole(descriptor.key, callbacks);\n callbacks.onLog(descriptor.key, \"Loading Module Federation runtime...\");\n\n const mfRuntime = yield* Effect.tryPromise({\n try: () => import(\"@module-federation/enhanced/runtime\"),\n catch: (cause) =>\n new OrchestratorError({\n operation: \"load module federation runtime\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n\n const mfCore = yield* Effect.tryPromise({\n try: () => import(\"@module-federation/runtime-core\"),\n catch: (cause) =>\n new OrchestratorError({\n operation: \"load module federation core\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n\n let mf = mfRuntime.getInstance();\n if (!mf) {\n mf = mfRuntime.createInstance({ name: \"cli-host\", remotes: [] });\n mfCore.setGlobalFederationInstance(mf);\n }\n patchManifestFetchForSsrPublicPath(mf as any);\n\n const baseUrl = remoteUrl\n .replace(/\\/remoteEntry\\.js$/, \"\")\n .replace(/\\/mf-manifest\\.json$/, \"\")\n .replace(/\\/$/, \"\");\n const manifestUrl = `${baseUrl}/mf-manifest.json`;\n\n // The manifest IS the entry contract (ADR 0020 amendment: hashed\n // entrypoints, fixed-name `remoteEntry.js` retired — it 404s on the CDN).\n // A failed manifest fetch must fail loud with the URL and status: the old\n // silent fallback to remoteEntry.js turned any transient hiccup (a CDN\n // 403 challenge, a timeout) into a guaranteed loadRemote failure with no\n // named cause.\n const entryUrl = yield* Effect.tryPromise({\n try: async () => {\n let res: Response;\n try {\n res = await runFetch(manifestUrl, { signal: AbortSignal.timeout(10_000) });\n } catch (e) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — ${e instanceof Error ? e.message : String(e)}`,\n cause: e,\n });\n }\n if (!res.ok) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — HTTP ${res.status}${res.statusText ? ` ${res.statusText}` : \"\"}`,\n });\n }\n const json = (await res.json()) as Record<string, unknown>;\n if (\n !json ||\n typeof json !== \"object\" ||\n !(\"metaData\" in json) ||\n !(\"exposes\" in json) ||\n !(\"shared\" in json)\n ) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — not a Module Federation manifest (missing metaData/exposes/shared)`,\n });\n }\n return manifestUrl;\n },\n catch: (cause) =>\n cause instanceof OrchestratorError\n ? cause\n : new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — ${String(cause)}`,\n }),\n });\n\n (mf as any).registerRemotes([{ name: \"host\", entry: entryUrl }]);\n callbacks.onLog(descriptor.key, `Loading host from ${entryUrl}...`);\n\n const hostModule = yield* Effect.tryPromise({\n try: () =>\n (mf as any).loadRemote(\"host/Server\") as Promise<{\n runServer: (input: ServerInput) => ServerHandle;\n }>,\n catch: (cause) =>\n new OrchestratorError({\n operation: \"load host module\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n\n if (!hostModule?.runServer) {\n return yield* new HostModuleInvalid();\n }\n\n callbacks.onLog(descriptor.key, \"Starting server...\");\n const hostPort = runtimeConfig.host?.port;\n const hostEnv: Record<string, string> | undefined = hostPort\n ? { PORT: String(hostPort) }\n : undefined;\n const serverHandle = hostModule.runServer({\n config: runtimeConfig,\n port: hostPort,\n env: hostEnv,\n });\n yield* Effect.tryPromise({\n try: () => serverHandle.ready,\n catch: (cause) =>\n new OrchestratorError({\n operation: \"start server\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n\n callbacks.onStatus(descriptor.key, \"ready\");\n\n return {\n name: descriptor.key,\n pid: undefined,\n kill: Effect.gen(function* () {\n callbacks.onLog(descriptor.key, \"Shutting down remote host...\");\n restoreConsole();\n yield* Effect.tryPromise({\n try: () => serverHandle.shutdown(),\n catch: () => {},\n }).pipe(Effect.ignore);\n }),\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n });\n\n/**\n * Spawn env precedence, three tiers: values explicitly exported by the\n * caller (shell / CI / regression harness — captured by the bootstrap\n * program into the `ShellEnv` service before any `.env` loading) outrank the\n * generated infra env, which outranks `.env`-file values inherited through\n * `processEnv`. The service's resolved port is always authoritative.\n */\nexport function composeSpawnEnv(\n processEnv: Record<string, string>,\n generatedEnv: Record<string, string>,\n port: number,\n shellEnv: Record<string, string> = {},\n): Record<string, string> {\n return {\n ...processEnv,\n ...mergeGeneratedOverFileEnv(generatedEnv, processEnv, shellEnv),\n FORCE_COLOR: \"1\",\n ...(port > 0 ? { PORT: String(port) } : {}),\n };\n}\n\n/**\n * Overlay the generated infra env (ports drift, so stale `.env` values must\n * lose) while keeping every explicitly exported key from `shellEnv` intact.\n * Keys absent from both are untouched.\n *\n * Exception (ADR 0012 / plan 038): the origin keys BASE_URL and CORS_ORIGIN\n * are always generated-owned — a wrapper that sourced a stale `.env` must not\n * win over the resolved host port, in the child env or on disk.\n */\nconst GENERATED_OWNED_KEYS = new Set([\"BASE_URL\", \"CORS_ORIGIN\"]);\n\nexport function mergeGeneratedOverFileEnv(\n generatedEnv: Record<string, string>,\n processEnv: Record<string, string>,\n shellEnv: Record<string, string> = {},\n): Record<string, string> {\n const result: Record<string, string> = { ...processEnv };\n for (const [key, value] of Object.entries(generatedEnv)) {\n if (!GENERATED_OWNED_KEYS.has(key) && key in shellEnv) {\n result[key] = shellEnv[key]!;\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\nconst spawnDevProcess = (descriptor: ServiceDescriptor, callbacks: ProcessCallbacks) =>\n Effect.gen(function* () {\n const runtimeConfig = yield* DevRuntimeConfig;\n\n if (!descriptor.localPath) {\n return yield* new LocalPathMissing({ key: descriptor.key });\n }\n\n const fullCwd = descriptor.localPath;\n const command = descriptor.command ?? \"pnpm\";\n const args = descriptor.args ?? [\"run\", \"dev\"];\n const port = descriptor.port ?? descriptor.defaultPort;\n const name = descriptor.key;\n\n const readyDeferred = yield* Deferred.make<void, OrchestratorError>();\n const statusRef = yield* Ref.make<ProcessStatus>(\"starting\");\n\n callbacks.onStatus(name, \"starting\");\n\n const generatedEnv = yield* DevGeneratedEnv;\n const shellTier = yield* ShellEnv;\n // The descriptor's env joins the generated tier — folding it in before\n // composeSpawnEnv keeps the documented precedence (shell > generated >\n // .env-file); assigning after would let it outrank the shell tier (and\n // the generated-owned keys) silently.\n const envVars = composeSpawnEnv(\n process.env as Record<string, string>,\n { ...generatedEnv, ...descriptor.env },\n port,\n shellTier,\n );\n\n envVars.BOS_RUNTIME_CONFIG = yield* encodeRuntimeConfig(runtimeConfig);\n\n const cmd = spawn(command, args, {\n cwd: fullCwd,\n env: envVars,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n });\n\n let lastExit: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n const exitCode = Effect.callback<number, OrchestratorError>((resume) => {\n const onExit = (code: number | null, signal: NodeJS.Signals | null) => {\n lastExit = { code, signal };\n resume(Effect.succeed(code ?? (signal ? 1 : 0)));\n };\n const onError = (err: Error) => {\n callbacks.onLog(name, `Spawn failed: ${err.message}`, true);\n callbacks.onStatus(name, \"error\", `spawn failed: ${err.message}`);\n resume(\n Effect.fail(\n new OrchestratorError({\n operation: \"spawn process\",\n detail: err.message,\n cause: err,\n }),\n ),\n );\n };\n cmd.once(\"exit\", onExit);\n cmd.once(\"error\", onError);\n return Effect.sync(() => {\n cmd.off(\"exit\", onExit);\n cmd.off(\"error\", onError);\n });\n });\n\n const describeExit = (exitCodeValue: number): string => {\n if (lastExit?.code === null && lastExit.signal) return `signal: ${lastExit.signal}`;\n return `exit code: ${exitCodeValue}`;\n };\n const isCleanSignalExit = (): boolean =>\n lastExit?.code === null && lastExit.signal != null && lastExit.signal in cleanExitSignals;\n\n const markReady = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"ready\");\n callbacks.onStatus(name, \"ready\");\n yield* Deferred.succeed(readyDeferred, undefined).pipe(Effect.ignore);\n });\n\n const markError = (message: string) =>\n Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"error\");\n callbacks.onStatus(name, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({ operation: \"wait for process readiness\", detail: message }),\n ).pipe(Effect.ignore);\n });\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const readinessPath = descriptor.readinessPath;\n const url = `http://127.0.0.1:${port}${readinessPath}`;\n const readinessCheck = Effect.gen(function* () {\n const status = yield* Ref.get(statusRef);\n if (status === \"ready\" || status === \"error\") return true;\n if (port <= 0) return false;\n const ok = yield* probeHttpOk(url);\n if (ok) yield* markReady;\n return ok;\n });\n const ready = yield* Effect.repeat(readinessCheck, {\n schedule: Schedule.spaced(`${port > 0 ? LOCAL_PROBE_INTERVAL_MS : 500} millis`),\n until: (done) => done,\n }).pipe(\n Effect.timeout(`${LOCAL_PROBE_DEADLINE_MS} millis`),\n Effect.catchTag(\"TimeoutError\", () => Effect.succeed(false)),\n );\n if (ready) return;\n\n const status = yield* Ref.get(statusRef);\n if (status !== \"ready\" && status !== \"error\") {\n callbacks.onLog(name, \"Probe deadline exceeded after 90s\", true);\n yield* markError(`Probe deadline exceeded: ${name}`);\n }\n }),\n );\n\n const pid = cmd.pid ?? undefined;\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const exitCodeValue = yield* exitCode;\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") {\n // Post-ready exits must stay visible — a silently dead child (OOM\n // kill included) used to leave the stack answering with nothing.\n // A SIGTERM/SIGINT-signalled exit is the polite-quit path, not a\n // crash, so it logs as a plain shutdown line.\n if (currentStatus === \"ready\") {\n const detail = describeExit(exitCodeValue);\n callbacks.onLog(name, `Process exited after ready (${detail})`, !isCleanSignalExit());\n if (!isCleanSignalExit()) {\n callbacks.onStatus(name, \"error\", `exited after ready (${detail})`);\n }\n yield* markError(`Process exited after ready: ${name}`);\n }\n return;\n }\n callbacks.onLog(\n name,\n `Process exited before ready (${describeExit(exitCodeValue)})`,\n !isCleanSignalExit(),\n );\n yield* markError(`Process exited before ready: ${name}`);\n }),\n );\n\n const handleLine = (line: string, isStderr: boolean) =>\n Effect.gen(function* () {\n if (!line.trim()) return;\n\n const cleanLine = stripAnsi(line);\n const looksLikeError =\n isStderr &&\n /^(error|fail|fatal|exception|unhandled|reject)/i.test(cleanLine) &&\n !cleanLine.startsWith(\"$\");\n callbacks.onLog(name, line, looksLikeError);\n\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\") return;\n\n const detected = detectStatus(line, descriptor);\n if (detected) {\n if (detected.status === \"ready\") {\n yield* markReady;\n } else if (currentStatus !== \"error\") {\n yield* markError(`Process failed: ${name}`);\n }\n }\n });\n\n const stdoutStream = cmd.stdout\n ? (Readable.toWeb(cmd.stdout) as unknown as ReadableStream<Uint8Array>)\n : null;\n const stderrStream = cmd.stderr\n ? (Readable.toWeb(cmd.stderr) as unknown as ReadableStream<Uint8Array>)\n : null;\n\n if (stdoutStream) {\n yield* Effect.forkScoped(\n Stream.runForEach((line: string) => handleLine(line, false))(\n Stream.splitLines(\n Stream.decodeText(\n Stream.fromReadableStream({\n evaluate: () => stdoutStream,\n onError: (cause) =>\n new OrchestratorError({\n operation: \"read process stdout\",\n detail: String(cause),\n cause,\n }),\n }),\n ),\n ),\n ),\n );\n }\n\n if (stderrStream) {\n yield* Effect.forkScoped(\n Stream.runForEach((line: string) => handleLine(line, true))(\n Stream.splitLines(\n Stream.decodeText(\n Stream.fromReadableStream({\n evaluate: () => stderrStream,\n onError: (cause) =>\n new OrchestratorError({\n operation: \"read process stderr\",\n detail: String(cause),\n cause,\n }),\n }),\n ),\n ),\n ),\n );\n }\n\n return {\n name,\n pid,\n kill: Effect.gen(function* () {\n const groupPid = pid;\n const groupSignal = (signal: NodeJS.Signals) =>\n Effect.try(() => {\n if (groupPid !== undefined) process.kill(-groupPid, signal);\n }).pipe(Effect.ignore);\n yield* groupSignal(\"SIGTERM\");\n const exited = yield* exitCode.pipe(Effect.timeout(\"3 seconds\"), Effect.option);\n if (Option.isNone(exited)) {\n yield* groupSignal(\"SIGKILL\");\n yield* Effect.sleep(\"250 millis\");\n }\n }).pipe(Effect.ignore),\n waitForReady: Deferred.await(readyDeferred),\n waitForExit: exitCode,\n } satisfies ProcessHandle;\n });\n\nconst spawnRemoteProbe = (\n pkg: string,\n descriptor: ServiceDescriptor,\n callbacks: ProcessCallbacks,\n) =>\n Effect.gen(function* () {\n callbacks.onStatus(pkg, \"starting\");\n const readyDeferred = yield* Deferred.make<void, OrchestratorError>();\n const statusRef = yield* Ref.make<ProcessStatus>(\"starting\");\n\n const markReady = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"ready\");\n yield* Deferred.succeed(readyDeferred, undefined).pipe(Effect.ignore);\n callbacks.onStatus(pkg, \"ready\", \"loaded\");\n });\n\n const markError = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({\n operation: \"probe remote process\",\n detail: `Remote ${pkg} unreachable`,\n }),\n ).pipe(Effect.ignore);\n callbacks.onStatus(pkg, \"error\", \"unreachable\");\n });\n\n const baseUrl = descriptor.url.replace(/\\/$/, \"\");\n const manifestUrl = `${baseUrl}/mf-manifest.json`;\n const entryUrl = `${baseUrl}${descriptor.readinessPath}`;\n const probeUrl = descriptor.readinessPath === \"/health\" ? `${baseUrl}/health` : manifestUrl;\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const readinessCheck = Effect.gen(function* () {\n const status = yield* Ref.get(statusRef);\n if (status === \"ready\" || status === \"error\") return true;\n\n const ok = yield* probeHttpOk(probeUrl, REMOTE_PROBE_TIMEOUT_MS);\n if (ok) {\n yield* markReady;\n return true;\n }\n\n const fallbackOk = yield* probeHttpOk(entryUrl, REMOTE_PROBE_TIMEOUT_MS);\n if (fallbackOk) {\n yield* markReady;\n return true;\n }\n return false;\n });\n const ready = yield* Effect.repeat(readinessCheck, {\n schedule: Schedule.min([\n Schedule.exponential(`${REMOTE_PROBE_BACKOFF_INITIAL_MS} millis`, 1.5),\n Schedule.spaced(`${REMOTE_PROBE_BACKOFF_MAX_MS} millis`),\n ]),\n until: (done) => done,\n }).pipe(\n Effect.timeout(`${REMOTE_PROBE_DEADLINE_MS} millis`),\n Effect.catchTag(\"TimeoutError\", () => Effect.succeed(false)),\n );\n if (ready) return;\n\n const status = yield* Ref.get(statusRef);\n if (status !== \"ready\") {\n yield* markError;\n }\n }),\n );\n\n return {\n name: pkg,\n pid: undefined,\n kill: Effect.gen(function* () {\n yield* Ref.set(statusRef, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({ operation: \"stop remote process\", detail: \"Killed\" }),\n ).pipe(Effect.ignore);\n }),\n waitForReady: Deferred.await(readyDeferred),\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n });\n\nexport const makeDevProcess = (pkg: string, callbacks: ProcessCallbacks, portOverride?: number) =>\n Effect.gen(function* () {\n const services = yield* ServiceDescriptorMap;\n const descriptor = services.get(pkg);\n\n if (!descriptor) {\n callbacks.onStatus(pkg, \"ready\", \"Remote\");\n return {\n name: pkg,\n pid: undefined,\n kill: Effect.void,\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n }\n\n if (pkg === \"host\" && descriptor.source === \"remote\") {\n return yield* spawnRemoteHost(descriptor, callbacks);\n }\n\n if (descriptor.source === \"remote\" || !descriptor.localPath) {\n return yield* spawnRemoteProbe(pkg, descriptor, callbacks);\n }\n\n const resolvedDescriptor = portOverride ? { ...descriptor, port: portOverride } : descriptor;\n\n return yield* spawnDevProcess(resolvedDescriptor, callbacks);\n });\n\nexport function getProcessStates(\n packages: string[],\n services: Map<string, ServiceDescriptor>,\n portOverride?: number,\n): ProcessState[] {\n return packages.map((pkg) => {\n const descriptor = services.get(pkg);\n return {\n name: pkg,\n status: \"pending\" as const,\n port:\n portOverride && pkg === \"host\"\n ? portOverride\n : (descriptor?.port ?? descriptor?.defaultPort ?? 0),\n source: descriptor?.source,\n uiPort: descriptor?.uiPort,\n };\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"orchestrator.cjs","names":["Data","Schema","Effect","stripAnsi","DevRuntimeConfig","fetchRaw","registerRemote","loadRemoteModule","Deferred","Ref","DevGeneratedEnv","ShellEnv","spawn","Schedule","Readable","Stream","Option","ServiceDescriptorMap"],"sources":["../src/orchestrator.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { Readable } from \"node:stream\";\nimport { Data, Deferred, Effect, Option, Ref, Schedule, Schema, Stream } from \"effect\";\nimport { stripAnsi } from \"./dev-log-pipeline\";\nimport { ShellEnv } from \"./env/project-env\";\nimport { loadRemoteModule, registerRemote } from \"./federation\";\nimport { fetchRaw } from \"./http-client\";\nimport {\n DevGeneratedEnv,\n DevRuntimeConfig,\n type ServiceDescriptor,\n ServiceDescriptorMap,\n} from \"./service-descriptor\";\nimport type { RuntimeConfig } from \"./types\";\n\nprocess.on(\"unhandledRejection\", (reason) => {\n console.error(\"[Orchestrator] Unhandled rejection:\", reason);\n});\n\nprocess.on(\"uncaughtException\", (err) => {\n console.error(\"[Orchestrator] Uncaught exception:\", err);\n});\n\nexport interface ProcessCallbacks {\n onStatus: (name: string, status: ProcessStatus, message?: string) => void;\n onLog: (name: string, line: string, isError?: boolean) => void;\n}\n\nexport interface ProcessHandle {\n name: string;\n pid: number | undefined;\n kill: Effect.Effect<void>;\n waitForReady: Effect.Effect<void, OrchestratorError>;\n waitForExit: Effect.Effect<number, OrchestratorError>;\n}\n\nexport class OrchestratorError extends Data.TaggedError(\"OrchestratorError\")<{\n readonly operation: string;\n readonly detail: string;\n readonly cause?: unknown;\n}> {\n override get message() {\n return `${this.operation}: ${this.detail}`;\n }\n}\n\nconst omitUndefined = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((item) => (item === undefined ? null : omitUndefined(item)));\n }\n if (value !== null && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value)\n .filter(([, item]) => item !== undefined)\n .map(([key, item]) => [key, omitUndefined(item)]),\n );\n }\n return value;\n};\n\nexport const encodeRuntimeConfig = (runtimeConfig: unknown) =>\n Schema.encodeUnknownEffect(Schema.fromJsonString(Schema.Json))(omitUndefined(runtimeConfig)).pipe(\n Effect.mapError(\n (cause) =>\n new OrchestratorError({\n operation: \"serialize runtime config\",\n detail: cause.message,\n cause,\n }),\n ),\n );\n\nexport type ProcessStatus = \"pending\" | \"starting\" | \"ready\" | \"error\";\n\nexport interface ProcessState {\n name: string;\n status: ProcessStatus;\n port: number;\n message?: string;\n source?: \"local\" | \"remote\";\n uiPort?: number;\n}\n\nconst probeHttpOk = (url: string, timeoutMs = 400) =>\n Effect.tryPromise({\n try: async () => {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });\n return res.ok;\n } catch {\n return false;\n }\n },\n catch: () => false,\n });\n\nconst LOCAL_PROBE_DEADLINE_MS = 90_000;\n\n/** Remote-host boot budgets: every stage of the CDN-only boot is deadline-\n * bounded so a hung connection or a wedged module load fails loud with the\n * URL and stage — long before the smoke's 240s probe deadline turns the\n * silence into a mystery. */\nconst MANIFEST_FETCH_DEADLINE = \"10 seconds\";\nconst LOAD_REMOTE_DEADLINE = \"60 seconds\";\nconst SERVER_READY_DEADLINE = \"120 seconds\";\nconst REMOTE_HOST_BOOT_DEADLINE = \"180 seconds\";\nconst LOCAL_PROBE_INTERVAL_MS = 200;\n\nconst cleanExitSignals: Record<string, true> = { SIGTERM: true, SIGINT: true };\n\nconst REMOTE_PROBE_TIMEOUT_MS = 5000;\nconst REMOTE_PROBE_DEADLINE_MS = 60_000;\nconst REMOTE_PROBE_BACKOFF_INITIAL_MS = 1000;\nconst REMOTE_PROBE_BACKOFF_MAX_MS = 15_000;\n\nexport const detectStatus = (\n line: string,\n descriptor: ServiceDescriptor,\n): { status: ProcessStatus; isError: boolean } | null => {\n const cleanLine = stripAnsi(line);\n const errorPatterns = descriptor.errorPatterns ?? [];\n const readyPatterns = descriptor.readyPatterns ?? [];\n for (const pattern of readyPatterns) {\n if (pattern.test(cleanLine)) {\n return { status: \"ready\", isError: false };\n }\n }\n for (const pattern of errorPatterns) {\n if (pattern.test(cleanLine)) {\n return { status: \"error\", isError: true };\n }\n }\n return null;\n};\n\ninterface ServerHandle {\n ready: Promise<void>;\n shutdown: () => Promise<void>;\n}\n\ninterface ServerInput {\n config: RuntimeConfig;\n port?: number;\n env?: Record<string, string>;\n}\n\nconst patchConsole = (name: string, callbacks: ProcessCallbacks): (() => void) => {\n const originalLog = console.log;\n const originalError = console.error;\n const originalWarn = console.warn;\n const originalInfo = console.info;\n\n const formatArgs = (args: unknown[], isError = false): string => {\n return args\n .map((arg) => {\n if (arg instanceof Error) {\n const parts = [`${arg.name}: ${arg.message}`];\n if (arg.cause instanceof Error)\n parts.push(`(cause: ${arg.cause.name}: ${arg.cause.message})`);\n else if (arg.cause) {\n const cause = arg.cause;\n parts.push(\n `(cause: ${cause instanceof Error ? cause.message : typeof cause === \"string\" ? cause : (JSON.stringify(cause) ?? \"[Unserializable cause]\")})`,\n );\n }\n if (isError && arg.stack) parts.push(arg.stack);\n return parts.join(\"\\n\");\n }\n if (arg === null) return \"null\";\n if (typeof arg === \"string\") return arg;\n if (typeof arg === \"number\" || typeof arg === \"bigint\" || typeof arg === \"boolean\")\n return `${arg}`;\n if (typeof arg === \"symbol\") return arg.description ?? \"\";\n if (typeof arg === \"undefined\") return \"undefined\";\n return JSON.stringify(arg, null, 2) ?? \"[Unserializable value]\";\n })\n .join(\" \");\n };\n\n console.log = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n console.error = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args, true), true);\n };\n console.warn = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n console.info = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n\n return () => {\n console.log = originalLog;\n console.error = originalError;\n console.warn = originalWarn;\n console.info = originalInfo;\n };\n};\n\nexport class HostRemoteUrlMissing extends Data.TaggedError(\"HostRemoteUrlMissing\")<\n Record<never, never>\n> {\n override get message() {\n return \"remoteUrl not provided on host descriptor\";\n }\n}\n\nexport class HostModuleInvalid extends Data.TaggedError(\"HostModuleInvalid\")<Record<never, never>> {\n override get message() {\n return \"Host module does not export runServer function\";\n }\n}\n\nexport class LocalPathMissing extends Data.TaggedError(\"LocalPathMissing\")<{ key: string }> {\n get message() {\n return `No localPath for local service: ${this.key}`;\n }\n}\n\nconst spawnRemoteHost = (descriptor: ServiceDescriptor, callbacks: ProcessCallbacks) =>\n Effect.gen(function* () {\n const runtimeConfig = yield* DevRuntimeConfig;\n const remoteUrl = descriptor.remoteUrl;\n if (!remoteUrl) {\n return yield* new HostRemoteUrlMissing();\n }\n\n callbacks.onStatus(descriptor.key, \"starting\");\n callbacks.onLog(descriptor.key, `Remote: ${remoteUrl}`);\n const restoreConsole = patchConsole(descriptor.key, callbacks);\n callbacks.onLog(descriptor.key, \"Loading Module Federation runtime...\");\n\n const baseUrl = remoteUrl\n .replace(/\\/remoteEntry\\.js$/, \"\")\n .replace(/\\/mf-manifest\\.json$/, \"\")\n .replace(/\\/$/, \"\");\n const manifestUrl = `${baseUrl}/mf-manifest.json`;\n\n // The manifest IS the entry contract (ADR 0020 amendment: hashed\n // entrypoints, fixed-name `remoteEntry.js` retired — it 404s on the CDN).\n // A failed manifest fetch must fail loud with the URL and status: the old\n // silent fallback to remoteEntry.js turned any transient hiccup (a CDN\n // 403 challenge, a timeout) into a guaranteed loadRemote failure with no\n // named cause.\n const entryUrl = yield* Effect.tryPromise({\n try: async () => {\n let res: Response;\n try {\n res = await fetchRaw(manifestUrl, undefined, MANIFEST_FETCH_DEADLINE);\n } catch (e) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — ${e instanceof Error ? e.message : String(e)}`,\n cause: e,\n });\n }\n if (!res.ok) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — HTTP ${res.status}${res.statusText ? ` ${res.statusText}` : \"\"}`,\n });\n }\n const json = (await res.json()) as Record<string, unknown>;\n if (\n !json ||\n typeof json !== \"object\" ||\n !(\"metaData\" in json) ||\n !(\"exposes\" in json) ||\n !(\"shared\" in json)\n ) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — not a Module Federation manifest (missing metaData/exposes/shared)`,\n });\n }\n return manifestUrl;\n },\n catch: (cause) =>\n cause instanceof OrchestratorError\n ? cause\n : new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — ${String(cause)}`,\n }),\n });\n\n yield* Effect.promise(() => registerRemote({ name: \"host\", entry: entryUrl }));\n callbacks.onLog(descriptor.key, `Loading host from ${entryUrl}...`);\n\n const hostModule = yield* Effect.tryPromise({\n try: () =>\n loadRemoteModule<{\n runServer: (input: ServerInput) => ServerHandle;\n }>(\"host/Server\"),\n catch: (cause) =>\n new OrchestratorError({\n operation: \"load host module\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n }).pipe(\n Effect.timeoutOrElse({\n duration: LOAD_REMOTE_DEADLINE,\n orElse: () =>\n Effect.fail(\n new OrchestratorError({\n operation: \"load host module\",\n detail: `timed out after ${LOAD_REMOTE_DEADLINE} — the module (or its shared dependencies) did not finish loading from ${entryUrl}`,\n }),\n ),\n }),\n );\n\n if (!hostModule?.runServer) {\n return yield* new HostModuleInvalid();\n }\n\n callbacks.onLog(descriptor.key, \"Starting server...\");\n const hostPort = runtimeConfig.host?.port;\n const hostEnv: Record<string, string> | undefined = hostPort\n ? { PORT: String(hostPort) }\n : undefined;\n const serverHandle = hostModule.runServer({\n config: runtimeConfig,\n port: hostPort,\n env: hostEnv,\n });\n yield* Effect.tryPromise({\n try: () => serverHandle.ready,\n catch: (cause) =>\n new OrchestratorError({\n operation: \"start server\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n }).pipe(\n Effect.timeoutOrElse({\n duration: SERVER_READY_DEADLINE,\n // A half-started server must not leak its port on the deadline path —\n // the success path hands shutdown to the process handle instead.\n orElse: () =>\n Effect.gen(function* () {\n yield* Effect.exit(Effect.promise(() => serverHandle.shutdown()));\n return yield* new OrchestratorError({\n operation: \"start server\",\n detail: `server did not become ready within ${SERVER_READY_DEADLINE}`,\n });\n }),\n }),\n );\n\n callbacks.onStatus(descriptor.key, \"ready\");\n\n return {\n name: descriptor.key,\n pid: undefined,\n kill: Effect.gen(function* () {\n callbacks.onLog(descriptor.key, \"Shutting down remote host...\");\n restoreConsole();\n yield* Effect.tryPromise({\n try: () => serverHandle.shutdown(),\n catch: () => {},\n }).pipe(Effect.ignore);\n }),\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n });\n\n/**\n * Spawn env precedence, three tiers: values explicitly exported by the\n * caller (shell / CI / regression harness — captured by the bootstrap\n * program into the `ShellEnv` service before any `.env` loading) outrank the\n * generated infra env, which outranks `.env`-file values inherited through\n * `processEnv`. The service's resolved port is always authoritative.\n */\nexport function composeSpawnEnv(\n processEnv: Record<string, string>,\n generatedEnv: Record<string, string>,\n port: number,\n shellEnv: Record<string, string> = {},\n): Record<string, string> {\n return {\n ...processEnv,\n ...mergeGeneratedOverFileEnv(generatedEnv, processEnv, shellEnv),\n FORCE_COLOR: \"1\",\n ...(port > 0 ? { PORT: String(port) } : {}),\n };\n}\n\n/**\n * Overlay the generated infra env (ports drift, so stale `.env` values must\n * lose) while keeping every explicitly exported key from `shellEnv` intact.\n * Keys absent from both are untouched.\n *\n * Exception (ADR 0012 / plan 038): the origin keys BASE_URL and CORS_ORIGIN\n * are always generated-owned — a wrapper that sourced a stale `.env` must not\n * win over the resolved host port, in the child env or on disk.\n */\nconst GENERATED_OWNED_KEYS = new Set([\"BASE_URL\", \"CORS_ORIGIN\"]);\n\nexport function mergeGeneratedOverFileEnv(\n generatedEnv: Record<string, string>,\n processEnv: Record<string, string>,\n shellEnv: Record<string, string> = {},\n): Record<string, string> {\n const result: Record<string, string> = { ...processEnv };\n for (const [key, value] of Object.entries(generatedEnv)) {\n if (!GENERATED_OWNED_KEYS.has(key) && key in shellEnv) {\n result[key] = shellEnv[key]!;\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\nconst spawnDevProcess = (descriptor: ServiceDescriptor, callbacks: ProcessCallbacks) =>\n Effect.gen(function* () {\n const runtimeConfig = yield* DevRuntimeConfig;\n\n if (!descriptor.localPath) {\n return yield* new LocalPathMissing({ key: descriptor.key });\n }\n\n const fullCwd = descriptor.localPath;\n const command = descriptor.command ?? \"pnpm\";\n const args = descriptor.args ?? [\"run\", \"dev\"];\n const port = descriptor.port ?? descriptor.defaultPort;\n const name = descriptor.key;\n\n const readyDeferred = yield* Deferred.make<void, OrchestratorError>();\n const statusRef = yield* Ref.make<ProcessStatus>(\"starting\");\n\n callbacks.onStatus(name, \"starting\");\n\n const generatedEnv = yield* DevGeneratedEnv;\n const shellTier = yield* ShellEnv;\n // The descriptor's env joins the generated tier — folding it in before\n // composeSpawnEnv keeps the documented precedence (shell > generated >\n // .env-file); assigning after would let it outrank the shell tier (and\n // the generated-owned keys) silently.\n const envVars = composeSpawnEnv(\n process.env as Record<string, string>,\n { ...generatedEnv, ...descriptor.env },\n port,\n shellTier,\n );\n\n envVars.BOS_RUNTIME_CONFIG = yield* encodeRuntimeConfig(runtimeConfig);\n\n const cmd = spawn(command, args, {\n cwd: fullCwd,\n env: envVars,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n });\n\n let lastExit: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n const exitCode = Effect.callback<number, OrchestratorError>((resume) => {\n const onExit = (code: number | null, signal: NodeJS.Signals | null) => {\n lastExit = { code, signal };\n resume(Effect.succeed(code ?? (signal ? 1 : 0)));\n };\n const onError = (err: Error) => {\n callbacks.onLog(name, `Spawn failed: ${err.message}`, true);\n callbacks.onStatus(name, \"error\", `spawn failed: ${err.message}`);\n resume(\n Effect.fail(\n new OrchestratorError({\n operation: \"spawn process\",\n detail: err.message,\n cause: err,\n }),\n ),\n );\n };\n cmd.once(\"exit\", onExit);\n cmd.once(\"error\", onError);\n return Effect.sync(() => {\n cmd.off(\"exit\", onExit);\n cmd.off(\"error\", onError);\n });\n });\n\n const describeExit = (exitCodeValue: number): string => {\n if (lastExit?.code === null && lastExit.signal) return `signal: ${lastExit.signal}`;\n return `exit code: ${exitCodeValue}`;\n };\n const isCleanSignalExit = (): boolean =>\n lastExit?.code === null && lastExit.signal != null && lastExit.signal in cleanExitSignals;\n\n const markReady = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"ready\");\n callbacks.onStatus(name, \"ready\");\n yield* Deferred.succeed(readyDeferred, undefined).pipe(Effect.ignore);\n });\n\n const markError = (message: string) =>\n Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"error\");\n callbacks.onStatus(name, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({ operation: \"wait for process readiness\", detail: message }),\n ).pipe(Effect.ignore);\n });\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const readinessPath = descriptor.readinessPath;\n const url = `http://127.0.0.1:${port}${readinessPath}`;\n const readinessCheck = Effect.gen(function* () {\n const status = yield* Ref.get(statusRef);\n if (status === \"ready\" || status === \"error\") return true;\n if (port <= 0) return false;\n const ok = yield* probeHttpOk(url);\n if (ok) yield* markReady;\n return ok;\n });\n const ready = yield* Effect.repeat(readinessCheck, {\n schedule: Schedule.spaced(`${port > 0 ? LOCAL_PROBE_INTERVAL_MS : 500} millis`),\n until: (done) => done,\n }).pipe(\n Effect.timeout(`${LOCAL_PROBE_DEADLINE_MS} millis`),\n Effect.catchTag(\"TimeoutError\", () => Effect.succeed(false)),\n );\n if (ready) return;\n\n const status = yield* Ref.get(statusRef);\n if (status !== \"ready\" && status !== \"error\") {\n callbacks.onLog(name, \"Probe deadline exceeded after 90s\", true);\n yield* markError(`Probe deadline exceeded: ${name}`);\n }\n }),\n );\n\n const pid = cmd.pid ?? undefined;\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const exitCodeValue = yield* exitCode;\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") {\n // Post-ready exits must stay visible — a silently dead child (OOM\n // kill included) used to leave the stack answering with nothing.\n // A SIGTERM/SIGINT-signalled exit is the polite-quit path, not a\n // crash, so it logs as a plain shutdown line.\n if (currentStatus === \"ready\") {\n const detail = describeExit(exitCodeValue);\n callbacks.onLog(name, `Process exited after ready (${detail})`, !isCleanSignalExit());\n if (!isCleanSignalExit()) {\n callbacks.onStatus(name, \"error\", `exited after ready (${detail})`);\n }\n yield* markError(`Process exited after ready: ${name}`);\n }\n return;\n }\n callbacks.onLog(\n name,\n `Process exited before ready (${describeExit(exitCodeValue)})`,\n !isCleanSignalExit(),\n );\n yield* markError(`Process exited before ready: ${name}`);\n }),\n );\n\n const handleLine = (line: string, isStderr: boolean) =>\n Effect.gen(function* () {\n if (!line.trim()) return;\n\n const cleanLine = stripAnsi(line);\n const looksLikeError =\n isStderr &&\n /^(error|fail|fatal|exception|unhandled|reject)/i.test(cleanLine) &&\n !cleanLine.startsWith(\"$\");\n callbacks.onLog(name, line, looksLikeError);\n\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\") return;\n\n const detected = detectStatus(line, descriptor);\n if (detected) {\n if (detected.status === \"ready\") {\n yield* markReady;\n } else if (currentStatus !== \"error\") {\n yield* markError(`Process failed: ${name}`);\n }\n }\n });\n\n const stdoutStream = cmd.stdout\n ? (Readable.toWeb(cmd.stdout) as unknown as ReadableStream<Uint8Array>)\n : null;\n const stderrStream = cmd.stderr\n ? (Readable.toWeb(cmd.stderr) as unknown as ReadableStream<Uint8Array>)\n : null;\n\n if (stdoutStream) {\n yield* Effect.forkScoped(\n Stream.runForEach((line: string) => handleLine(line, false))(\n Stream.splitLines(\n Stream.decodeText(\n Stream.fromReadableStream({\n evaluate: () => stdoutStream,\n onError: (cause) =>\n new OrchestratorError({\n operation: \"read process stdout\",\n detail: String(cause),\n cause,\n }),\n }),\n ),\n ),\n ),\n );\n }\n\n if (stderrStream) {\n yield* Effect.forkScoped(\n Stream.runForEach((line: string) => handleLine(line, true))(\n Stream.splitLines(\n Stream.decodeText(\n Stream.fromReadableStream({\n evaluate: () => stderrStream,\n onError: (cause) =>\n new OrchestratorError({\n operation: \"read process stderr\",\n detail: String(cause),\n cause,\n }),\n }),\n ),\n ),\n ),\n );\n }\n\n return {\n name,\n pid,\n kill: Effect.gen(function* () {\n const groupPid = pid;\n const groupSignal = (signal: NodeJS.Signals) =>\n Effect.try(() => {\n if (groupPid !== undefined) process.kill(-groupPid, signal);\n }).pipe(Effect.ignore);\n yield* groupSignal(\"SIGTERM\");\n const exited = yield* exitCode.pipe(Effect.timeout(\"3 seconds\"), Effect.option);\n if (Option.isNone(exited)) {\n yield* groupSignal(\"SIGKILL\");\n yield* Effect.sleep(\"250 millis\");\n }\n }).pipe(Effect.ignore),\n waitForReady: Deferred.await(readyDeferred),\n waitForExit: exitCode,\n } satisfies ProcessHandle;\n });\n\nconst spawnRemoteProbe = (\n pkg: string,\n descriptor: ServiceDescriptor,\n callbacks: ProcessCallbacks,\n) =>\n Effect.gen(function* () {\n callbacks.onStatus(pkg, \"starting\");\n const readyDeferred = yield* Deferred.make<void, OrchestratorError>();\n const statusRef = yield* Ref.make<ProcessStatus>(\"starting\");\n\n const markReady = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"ready\");\n yield* Deferred.succeed(readyDeferred, undefined).pipe(Effect.ignore);\n callbacks.onStatus(pkg, \"ready\", \"loaded\");\n });\n\n const markError = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({\n operation: \"probe remote process\",\n detail: `Remote ${pkg} unreachable`,\n }),\n ).pipe(Effect.ignore);\n callbacks.onStatus(pkg, \"error\", \"unreachable\");\n });\n\n const baseUrl = descriptor.url.replace(/\\/$/, \"\");\n const manifestUrl = `${baseUrl}/mf-manifest.json`;\n const entryUrl = `${baseUrl}${descriptor.readinessPath}`;\n const probeUrl = descriptor.readinessPath === \"/health\" ? `${baseUrl}/health` : manifestUrl;\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const readinessCheck = Effect.gen(function* () {\n const status = yield* Ref.get(statusRef);\n if (status === \"ready\" || status === \"error\") return true;\n\n const ok = yield* probeHttpOk(probeUrl, REMOTE_PROBE_TIMEOUT_MS);\n if (ok) {\n yield* markReady;\n return true;\n }\n\n const fallbackOk = yield* probeHttpOk(entryUrl, REMOTE_PROBE_TIMEOUT_MS);\n if (fallbackOk) {\n yield* markReady;\n return true;\n }\n return false;\n });\n const ready = yield* Effect.repeat(readinessCheck, {\n schedule: Schedule.min([\n Schedule.exponential(`${REMOTE_PROBE_BACKOFF_INITIAL_MS} millis`, 1.5),\n Schedule.spaced(`${REMOTE_PROBE_BACKOFF_MAX_MS} millis`),\n ]),\n until: (done) => done,\n }).pipe(\n Effect.timeout(`${REMOTE_PROBE_DEADLINE_MS} millis`),\n Effect.catchTag(\"TimeoutError\", () => Effect.succeed(false)),\n );\n if (ready) return;\n\n const status = yield* Ref.get(statusRef);\n if (status !== \"ready\") {\n yield* markError;\n }\n }),\n );\n\n return {\n name: pkg,\n pid: undefined,\n kill: Effect.gen(function* () {\n yield* Ref.set(statusRef, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({ operation: \"stop remote process\", detail: \"Killed\" }),\n ).pipe(Effect.ignore);\n }),\n waitForReady: Deferred.await(readyDeferred),\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n });\n\nexport const makeDevProcess = (pkg: string, callbacks: ProcessCallbacks, portOverride?: number) =>\n Effect.gen(function* () {\n const services = yield* ServiceDescriptorMap;\n const descriptor = services.get(pkg);\n\n if (!descriptor) {\n callbacks.onStatus(pkg, \"ready\", \"Remote\");\n return {\n name: pkg,\n pid: undefined,\n kill: Effect.void,\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n }\n\n if (pkg === \"host\" && descriptor.source === \"remote\") {\n return yield* spawnRemoteHost(descriptor, callbacks).pipe(\n // Overall boot budget: with per-stage deadlines inside, this is the\n // backstop for anything the stage deadlines don't cover (a config\n // fetch, a slow MF internal) — the boot either comes up named-and-\n // ready or fails named-and-loud.\n Effect.timeoutOrElse({\n duration: REMOTE_HOST_BOOT_DEADLINE,\n orElse: () =>\n Effect.fail(\n new OrchestratorError({\n operation: \"boot remote host\",\n detail: `remote host boot exceeded the ${REMOTE_HOST_BOOT_DEADLINE} overall deadline`,\n }),\n ),\n }),\n );\n }\n\n if (descriptor.source === \"remote\" || !descriptor.localPath) {\n return yield* spawnRemoteProbe(pkg, descriptor, callbacks);\n }\n\n const resolvedDescriptor = portOverride ? { ...descriptor, port: portOverride } : descriptor;\n\n return yield* spawnDevProcess(resolvedDescriptor, callbacks);\n });\n\nexport function getProcessStates(\n packages: string[],\n services: Map<string, ServiceDescriptor>,\n portOverride?: number,\n): ProcessState[] {\n return packages.map((pkg) => {\n const descriptor = services.get(pkg);\n return {\n name: pkg,\n status: \"pending\" as const,\n port:\n portOverride && pkg === \"host\"\n ? portOverride\n : (descriptor?.port ?? descriptor?.defaultPort ?? 0),\n source: descriptor?.source,\n uiPort: descriptor?.uiPort,\n };\n });\n}\n"],"mappings":"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"}
|
package/dist/orchestrator.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import { fetchRaw } from "./http-client.mjs";
|
|
1
2
|
import { DevGeneratedEnv, DevRuntimeConfig, ServiceDescriptorMap } from "./service-descriptor.mjs";
|
|
2
3
|
import { stripAnsi } from "./dev-log-pipeline.mjs";
|
|
3
|
-
import {
|
|
4
|
+
import { loadRemoteModule, registerRemote } from "./federation.mjs";
|
|
4
5
|
import { ShellEnv } from "./env/project-env.mjs";
|
|
5
6
|
import { Data, Deferred, Effect, Option, Ref, Schedule, Schema, Stream } from "effect";
|
|
6
7
|
import { spawn } from "node:child_process";
|
|
7
8
|
import { Readable } from "node:stream";
|
|
8
9
|
|
|
9
10
|
//#region src/orchestrator.ts
|
|
10
|
-
const runFetch = (url, init) => fetch(url, init);
|
|
11
11
|
process.on("unhandledRejection", (reason) => {
|
|
12
12
|
console.error("[Orchestrator] Unhandled rejection:", reason);
|
|
13
13
|
});
|
|
@@ -32,7 +32,7 @@ const encodeRuntimeConfig = (runtimeConfig) => Schema.encodeUnknownEffect(Schema
|
|
|
32
32
|
const probeHttpOk = (url, timeoutMs = 400) => Effect.tryPromise({
|
|
33
33
|
try: async () => {
|
|
34
34
|
try {
|
|
35
|
-
return (await
|
|
35
|
+
return (await fetch(url, { signal: AbortSignal.timeout(timeoutMs) })).ok;
|
|
36
36
|
} catch {
|
|
37
37
|
return false;
|
|
38
38
|
}
|
|
@@ -40,6 +40,14 @@ const probeHttpOk = (url, timeoutMs = 400) => Effect.tryPromise({
|
|
|
40
40
|
catch: () => false
|
|
41
41
|
});
|
|
42
42
|
const LOCAL_PROBE_DEADLINE_MS = 9e4;
|
|
43
|
+
/** Remote-host boot budgets: every stage of the CDN-only boot is deadline-
|
|
44
|
+
* bounded so a hung connection or a wedged module load fails loud with the
|
|
45
|
+
* URL and stage — long before the smoke's 240s probe deadline turns the
|
|
46
|
+
* silence into a mystery. */
|
|
47
|
+
const MANIFEST_FETCH_DEADLINE = "10 seconds";
|
|
48
|
+
const LOAD_REMOTE_DEADLINE = "60 seconds";
|
|
49
|
+
const SERVER_READY_DEADLINE = "120 seconds";
|
|
50
|
+
const REMOTE_HOST_BOOT_DEADLINE = "180 seconds";
|
|
43
51
|
const LOCAL_PROBE_INTERVAL_MS = 200;
|
|
44
52
|
const cleanExitSignals = {
|
|
45
53
|
SIGTERM: true,
|
|
@@ -130,37 +138,12 @@ const spawnRemoteHost = (descriptor, callbacks) => Effect.gen(function* () {
|
|
|
130
138
|
callbacks.onLog(descriptor.key, `Remote: ${remoteUrl}`);
|
|
131
139
|
const restoreConsole = patchConsole(descriptor.key, callbacks);
|
|
132
140
|
callbacks.onLog(descriptor.key, "Loading Module Federation runtime...");
|
|
133
|
-
const mfRuntime = yield* Effect.tryPromise({
|
|
134
|
-
try: () => import("@module-federation/enhanced/runtime"),
|
|
135
|
-
catch: (cause) => new OrchestratorError({
|
|
136
|
-
operation: "load module federation runtime",
|
|
137
|
-
detail: cause instanceof Error ? cause.message : String(cause),
|
|
138
|
-
cause
|
|
139
|
-
})
|
|
140
|
-
});
|
|
141
|
-
const mfCore = yield* Effect.tryPromise({
|
|
142
|
-
try: () => import("@module-federation/runtime-core"),
|
|
143
|
-
catch: (cause) => new OrchestratorError({
|
|
144
|
-
operation: "load module federation core",
|
|
145
|
-
detail: cause instanceof Error ? cause.message : String(cause),
|
|
146
|
-
cause
|
|
147
|
-
})
|
|
148
|
-
});
|
|
149
|
-
let mf = mfRuntime.getInstance();
|
|
150
|
-
if (!mf) {
|
|
151
|
-
mf = mfRuntime.createInstance({
|
|
152
|
-
name: "cli-host",
|
|
153
|
-
remotes: []
|
|
154
|
-
});
|
|
155
|
-
mfCore.setGlobalFederationInstance(mf);
|
|
156
|
-
}
|
|
157
|
-
patchManifestFetchForSsrPublicPath(mf);
|
|
158
141
|
const manifestUrl = `${remoteUrl.replace(/\/remoteEntry\.js$/, "").replace(/\/mf-manifest\.json$/, "").replace(/\/$/, "")}/mf-manifest.json`;
|
|
159
142
|
const entryUrl = yield* Effect.tryPromise({
|
|
160
143
|
try: async () => {
|
|
161
144
|
let res;
|
|
162
145
|
try {
|
|
163
|
-
res = await
|
|
146
|
+
res = await fetchRaw(manifestUrl, void 0, MANIFEST_FETCH_DEADLINE);
|
|
164
147
|
} catch (e) {
|
|
165
148
|
throw new OrchestratorError({
|
|
166
149
|
operation: "fetch host manifest",
|
|
@@ -184,19 +167,25 @@ const spawnRemoteHost = (descriptor, callbacks) => Effect.gen(function* () {
|
|
|
184
167
|
detail: `${manifestUrl} — ${String(cause)}`
|
|
185
168
|
})
|
|
186
169
|
});
|
|
187
|
-
|
|
170
|
+
yield* Effect.promise(() => registerRemote({
|
|
188
171
|
name: "host",
|
|
189
172
|
entry: entryUrl
|
|
190
|
-
}
|
|
173
|
+
}));
|
|
191
174
|
callbacks.onLog(descriptor.key, `Loading host from ${entryUrl}...`);
|
|
192
175
|
const hostModule = yield* Effect.tryPromise({
|
|
193
|
-
try: () =>
|
|
176
|
+
try: () => loadRemoteModule("host/Server"),
|
|
194
177
|
catch: (cause) => new OrchestratorError({
|
|
195
178
|
operation: "load host module",
|
|
196
179
|
detail: cause instanceof Error ? cause.message : String(cause),
|
|
197
180
|
cause
|
|
198
181
|
})
|
|
199
|
-
})
|
|
182
|
+
}).pipe(Effect.timeoutOrElse({
|
|
183
|
+
duration: LOAD_REMOTE_DEADLINE,
|
|
184
|
+
orElse: () => Effect.fail(new OrchestratorError({
|
|
185
|
+
operation: "load host module",
|
|
186
|
+
detail: `timed out after ${LOAD_REMOTE_DEADLINE} — the module (or its shared dependencies) did not finish loading from ${entryUrl}`
|
|
187
|
+
}))
|
|
188
|
+
}));
|
|
200
189
|
if (!hostModule?.runServer) return yield* new HostModuleInvalid();
|
|
201
190
|
callbacks.onLog(descriptor.key, "Starting server...");
|
|
202
191
|
const hostPort = runtimeConfig.host?.port;
|
|
@@ -213,7 +202,16 @@ const spawnRemoteHost = (descriptor, callbacks) => Effect.gen(function* () {
|
|
|
213
202
|
detail: cause instanceof Error ? cause.message : String(cause),
|
|
214
203
|
cause
|
|
215
204
|
})
|
|
216
|
-
})
|
|
205
|
+
}).pipe(Effect.timeoutOrElse({
|
|
206
|
+
duration: SERVER_READY_DEADLINE,
|
|
207
|
+
orElse: () => Effect.gen(function* () {
|
|
208
|
+
yield* Effect.exit(Effect.promise(() => serverHandle.shutdown()));
|
|
209
|
+
return yield* new OrchestratorError({
|
|
210
|
+
operation: "start server",
|
|
211
|
+
detail: `server did not become ready within ${SERVER_READY_DEADLINE}`
|
|
212
|
+
});
|
|
213
|
+
})
|
|
214
|
+
}));
|
|
217
215
|
callbacks.onStatus(descriptor.key, "ready");
|
|
218
216
|
return {
|
|
219
217
|
name: descriptor.key,
|
|
@@ -494,7 +492,13 @@ const makeDevProcess = (pkg, callbacks, portOverride) => Effect.gen(function* ()
|
|
|
494
492
|
waitForExit: Effect.never
|
|
495
493
|
};
|
|
496
494
|
}
|
|
497
|
-
if (pkg === "host" && descriptor.source === "remote") return yield* spawnRemoteHost(descriptor, callbacks)
|
|
495
|
+
if (pkg === "host" && descriptor.source === "remote") return yield* spawnRemoteHost(descriptor, callbacks).pipe(Effect.timeoutOrElse({
|
|
496
|
+
duration: REMOTE_HOST_BOOT_DEADLINE,
|
|
497
|
+
orElse: () => Effect.fail(new OrchestratorError({
|
|
498
|
+
operation: "boot remote host",
|
|
499
|
+
detail: `remote host boot exceeded the ${REMOTE_HOST_BOOT_DEADLINE} overall deadline`
|
|
500
|
+
}))
|
|
501
|
+
}));
|
|
498
502
|
if (descriptor.source === "remote" || !descriptor.localPath) return yield* spawnRemoteProbe(pkg, descriptor, callbacks);
|
|
499
503
|
const resolvedDescriptor = portOverride ? {
|
|
500
504
|
...descriptor,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.mjs","names":[],"sources":["../src/orchestrator.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { Readable } from \"node:stream\";\nimport { Data, Deferred, Effect, Option, Ref, Schedule, Schema, Stream } from \"effect\";\nimport { stripAnsi } from \"./dev-log-pipeline\";\nimport { ShellEnv } from \"./env/project-env\";\nimport { patchManifestFetchForSsrPublicPath } from \"./mf\";\nimport {\n DevGeneratedEnv,\n DevRuntimeConfig,\n type ServiceDescriptor,\n ServiceDescriptorMap,\n} from \"./service-descriptor\";\nimport type { RuntimeConfig } from \"./types\";\n\nconst runFetch = (url: string, init?: RequestInit): Promise<Response> => fetch(url, init);\n\nprocess.on(\"unhandledRejection\", (reason) => {\n console.error(\"[Orchestrator] Unhandled rejection:\", reason);\n});\n\nprocess.on(\"uncaughtException\", (err) => {\n console.error(\"[Orchestrator] Uncaught exception:\", err);\n});\n\nexport interface ProcessCallbacks {\n onStatus: (name: string, status: ProcessStatus, message?: string) => void;\n onLog: (name: string, line: string, isError?: boolean) => void;\n}\n\nexport interface ProcessHandle {\n name: string;\n pid: number | undefined;\n kill: Effect.Effect<void>;\n waitForReady: Effect.Effect<void, OrchestratorError>;\n waitForExit: Effect.Effect<number, OrchestratorError>;\n}\n\nexport class OrchestratorError extends Data.TaggedError(\"OrchestratorError\")<{\n readonly operation: string;\n readonly detail: string;\n readonly cause?: unknown;\n}> {\n override get message() {\n return `${this.operation}: ${this.detail}`;\n }\n}\n\nconst omitUndefined = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((item) => (item === undefined ? null : omitUndefined(item)));\n }\n if (value !== null && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value)\n .filter(([, item]) => item !== undefined)\n .map(([key, item]) => [key, omitUndefined(item)]),\n );\n }\n return value;\n};\n\nexport const encodeRuntimeConfig = (runtimeConfig: unknown) =>\n Schema.encodeUnknownEffect(Schema.fromJsonString(Schema.Json))(omitUndefined(runtimeConfig)).pipe(\n Effect.mapError(\n (cause) =>\n new OrchestratorError({\n operation: \"serialize runtime config\",\n detail: cause.message,\n cause,\n }),\n ),\n );\n\nexport type ProcessStatus = \"pending\" | \"starting\" | \"ready\" | \"error\";\n\nexport interface ProcessState {\n name: string;\n status: ProcessStatus;\n port: number;\n message?: string;\n source?: \"local\" | \"remote\";\n uiPort?: number;\n}\n\nconst probeHttpOk = (url: string, timeoutMs = 400) =>\n Effect.tryPromise({\n try: async () => {\n try {\n const res = await runFetch(url, { signal: AbortSignal.timeout(timeoutMs) });\n return res.ok;\n } catch {\n return false;\n }\n },\n catch: () => false,\n });\n\nconst LOCAL_PROBE_DEADLINE_MS = 90_000;\nconst LOCAL_PROBE_INTERVAL_MS = 200;\n\nconst cleanExitSignals: Record<string, true> = { SIGTERM: true, SIGINT: true };\n\nconst REMOTE_PROBE_TIMEOUT_MS = 5000;\nconst REMOTE_PROBE_DEADLINE_MS = 60_000;\nconst REMOTE_PROBE_BACKOFF_INITIAL_MS = 1000;\nconst REMOTE_PROBE_BACKOFF_MAX_MS = 15_000;\n\nexport const detectStatus = (\n line: string,\n descriptor: ServiceDescriptor,\n): { status: ProcessStatus; isError: boolean } | null => {\n const cleanLine = stripAnsi(line);\n const errorPatterns = descriptor.errorPatterns ?? [];\n const readyPatterns = descriptor.readyPatterns ?? [];\n for (const pattern of readyPatterns) {\n if (pattern.test(cleanLine)) {\n return { status: \"ready\", isError: false };\n }\n }\n for (const pattern of errorPatterns) {\n if (pattern.test(cleanLine)) {\n return { status: \"error\", isError: true };\n }\n }\n return null;\n};\n\ninterface ServerHandle {\n ready: Promise<void>;\n shutdown: () => Promise<void>;\n}\n\ninterface ServerInput {\n config: RuntimeConfig;\n port?: number;\n env?: Record<string, string>;\n}\n\nconst patchConsole = (name: string, callbacks: ProcessCallbacks): (() => void) => {\n const originalLog = console.log;\n const originalError = console.error;\n const originalWarn = console.warn;\n const originalInfo = console.info;\n\n const formatArgs = (args: unknown[], isError = false): string => {\n return args\n .map((arg) => {\n if (arg instanceof Error) {\n const parts = [`${arg.name}: ${arg.message}`];\n if (arg.cause instanceof Error)\n parts.push(`(cause: ${arg.cause.name}: ${arg.cause.message})`);\n else if (arg.cause) {\n const cause = arg.cause;\n parts.push(\n `(cause: ${cause instanceof Error ? cause.message : typeof cause === \"string\" ? cause : (JSON.stringify(cause) ?? \"[Unserializable cause]\")})`,\n );\n }\n if (isError && arg.stack) parts.push(arg.stack);\n return parts.join(\"\\n\");\n }\n if (arg === null) return \"null\";\n if (typeof arg === \"string\") return arg;\n if (typeof arg === \"number\" || typeof arg === \"bigint\" || typeof arg === \"boolean\")\n return `${arg}`;\n if (typeof arg === \"symbol\") return arg.description ?? \"\";\n if (typeof arg === \"undefined\") return \"undefined\";\n return JSON.stringify(arg, null, 2) ?? \"[Unserializable value]\";\n })\n .join(\" \");\n };\n\n console.log = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n console.error = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args, true), true);\n };\n console.warn = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n console.info = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n\n return () => {\n console.log = originalLog;\n console.error = originalError;\n console.warn = originalWarn;\n console.info = originalInfo;\n };\n};\n\nexport class HostRemoteUrlMissing extends Data.TaggedError(\"HostRemoteUrlMissing\")<\n Record<never, never>\n> {\n override get message() {\n return \"remoteUrl not provided on host descriptor\";\n }\n}\n\nexport class HostModuleInvalid extends Data.TaggedError(\"HostModuleInvalid\")<Record<never, never>> {\n override get message() {\n return \"Host module does not export runServer function\";\n }\n}\n\nexport class LocalPathMissing extends Data.TaggedError(\"LocalPathMissing\")<{ key: string }> {\n get message() {\n return `No localPath for local service: ${this.key}`;\n }\n}\n\nconst spawnRemoteHost = (descriptor: ServiceDescriptor, callbacks: ProcessCallbacks) =>\n Effect.gen(function* () {\n const runtimeConfig = yield* DevRuntimeConfig;\n const remoteUrl = descriptor.remoteUrl;\n if (!remoteUrl) {\n return yield* new HostRemoteUrlMissing();\n }\n\n callbacks.onStatus(descriptor.key, \"starting\");\n callbacks.onLog(descriptor.key, `Remote: ${remoteUrl}`);\n const restoreConsole = patchConsole(descriptor.key, callbacks);\n callbacks.onLog(descriptor.key, \"Loading Module Federation runtime...\");\n\n const mfRuntime = yield* Effect.tryPromise({\n try: () => import(\"@module-federation/enhanced/runtime\"),\n catch: (cause) =>\n new OrchestratorError({\n operation: \"load module federation runtime\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n\n const mfCore = yield* Effect.tryPromise({\n try: () => import(\"@module-federation/runtime-core\"),\n catch: (cause) =>\n new OrchestratorError({\n operation: \"load module federation core\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n\n let mf = mfRuntime.getInstance();\n if (!mf) {\n mf = mfRuntime.createInstance({ name: \"cli-host\", remotes: [] });\n mfCore.setGlobalFederationInstance(mf);\n }\n patchManifestFetchForSsrPublicPath(mf as any);\n\n const baseUrl = remoteUrl\n .replace(/\\/remoteEntry\\.js$/, \"\")\n .replace(/\\/mf-manifest\\.json$/, \"\")\n .replace(/\\/$/, \"\");\n const manifestUrl = `${baseUrl}/mf-manifest.json`;\n\n // The manifest IS the entry contract (ADR 0020 amendment: hashed\n // entrypoints, fixed-name `remoteEntry.js` retired — it 404s on the CDN).\n // A failed manifest fetch must fail loud with the URL and status: the old\n // silent fallback to remoteEntry.js turned any transient hiccup (a CDN\n // 403 challenge, a timeout) into a guaranteed loadRemote failure with no\n // named cause.\n const entryUrl = yield* Effect.tryPromise({\n try: async () => {\n let res: Response;\n try {\n res = await runFetch(manifestUrl, { signal: AbortSignal.timeout(10_000) });\n } catch (e) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — ${e instanceof Error ? e.message : String(e)}`,\n cause: e,\n });\n }\n if (!res.ok) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — HTTP ${res.status}${res.statusText ? ` ${res.statusText}` : \"\"}`,\n });\n }\n const json = (await res.json()) as Record<string, unknown>;\n if (\n !json ||\n typeof json !== \"object\" ||\n !(\"metaData\" in json) ||\n !(\"exposes\" in json) ||\n !(\"shared\" in json)\n ) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — not a Module Federation manifest (missing metaData/exposes/shared)`,\n });\n }\n return manifestUrl;\n },\n catch: (cause) =>\n cause instanceof OrchestratorError\n ? cause\n : new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — ${String(cause)}`,\n }),\n });\n\n (mf as any).registerRemotes([{ name: \"host\", entry: entryUrl }]);\n callbacks.onLog(descriptor.key, `Loading host from ${entryUrl}...`);\n\n const hostModule = yield* Effect.tryPromise({\n try: () =>\n (mf as any).loadRemote(\"host/Server\") as Promise<{\n runServer: (input: ServerInput) => ServerHandle;\n }>,\n catch: (cause) =>\n new OrchestratorError({\n operation: \"load host module\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n\n if (!hostModule?.runServer) {\n return yield* new HostModuleInvalid();\n }\n\n callbacks.onLog(descriptor.key, \"Starting server...\");\n const hostPort = runtimeConfig.host?.port;\n const hostEnv: Record<string, string> | undefined = hostPort\n ? { PORT: String(hostPort) }\n : undefined;\n const serverHandle = hostModule.runServer({\n config: runtimeConfig,\n port: hostPort,\n env: hostEnv,\n });\n yield* Effect.tryPromise({\n try: () => serverHandle.ready,\n catch: (cause) =>\n new OrchestratorError({\n operation: \"start server\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n\n callbacks.onStatus(descriptor.key, \"ready\");\n\n return {\n name: descriptor.key,\n pid: undefined,\n kill: Effect.gen(function* () {\n callbacks.onLog(descriptor.key, \"Shutting down remote host...\");\n restoreConsole();\n yield* Effect.tryPromise({\n try: () => serverHandle.shutdown(),\n catch: () => {},\n }).pipe(Effect.ignore);\n }),\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n });\n\n/**\n * Spawn env precedence, three tiers: values explicitly exported by the\n * caller (shell / CI / regression harness — captured by the bootstrap\n * program into the `ShellEnv` service before any `.env` loading) outrank the\n * generated infra env, which outranks `.env`-file values inherited through\n * `processEnv`. The service's resolved port is always authoritative.\n */\nexport function composeSpawnEnv(\n processEnv: Record<string, string>,\n generatedEnv: Record<string, string>,\n port: number,\n shellEnv: Record<string, string> = {},\n): Record<string, string> {\n return {\n ...processEnv,\n ...mergeGeneratedOverFileEnv(generatedEnv, processEnv, shellEnv),\n FORCE_COLOR: \"1\",\n ...(port > 0 ? { PORT: String(port) } : {}),\n };\n}\n\n/**\n * Overlay the generated infra env (ports drift, so stale `.env` values must\n * lose) while keeping every explicitly exported key from `shellEnv` intact.\n * Keys absent from both are untouched.\n *\n * Exception (ADR 0012 / plan 038): the origin keys BASE_URL and CORS_ORIGIN\n * are always generated-owned — a wrapper that sourced a stale `.env` must not\n * win over the resolved host port, in the child env or on disk.\n */\nconst GENERATED_OWNED_KEYS = new Set([\"BASE_URL\", \"CORS_ORIGIN\"]);\n\nexport function mergeGeneratedOverFileEnv(\n generatedEnv: Record<string, string>,\n processEnv: Record<string, string>,\n shellEnv: Record<string, string> = {},\n): Record<string, string> {\n const result: Record<string, string> = { ...processEnv };\n for (const [key, value] of Object.entries(generatedEnv)) {\n if (!GENERATED_OWNED_KEYS.has(key) && key in shellEnv) {\n result[key] = shellEnv[key]!;\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\nconst spawnDevProcess = (descriptor: ServiceDescriptor, callbacks: ProcessCallbacks) =>\n Effect.gen(function* () {\n const runtimeConfig = yield* DevRuntimeConfig;\n\n if (!descriptor.localPath) {\n return yield* new LocalPathMissing({ key: descriptor.key });\n }\n\n const fullCwd = descriptor.localPath;\n const command = descriptor.command ?? \"pnpm\";\n const args = descriptor.args ?? [\"run\", \"dev\"];\n const port = descriptor.port ?? descriptor.defaultPort;\n const name = descriptor.key;\n\n const readyDeferred = yield* Deferred.make<void, OrchestratorError>();\n const statusRef = yield* Ref.make<ProcessStatus>(\"starting\");\n\n callbacks.onStatus(name, \"starting\");\n\n const generatedEnv = yield* DevGeneratedEnv;\n const shellTier = yield* ShellEnv;\n // The descriptor's env joins the generated tier — folding it in before\n // composeSpawnEnv keeps the documented precedence (shell > generated >\n // .env-file); assigning after would let it outrank the shell tier (and\n // the generated-owned keys) silently.\n const envVars = composeSpawnEnv(\n process.env as Record<string, string>,\n { ...generatedEnv, ...descriptor.env },\n port,\n shellTier,\n );\n\n envVars.BOS_RUNTIME_CONFIG = yield* encodeRuntimeConfig(runtimeConfig);\n\n const cmd = spawn(command, args, {\n cwd: fullCwd,\n env: envVars,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n });\n\n let lastExit: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n const exitCode = Effect.callback<number, OrchestratorError>((resume) => {\n const onExit = (code: number | null, signal: NodeJS.Signals | null) => {\n lastExit = { code, signal };\n resume(Effect.succeed(code ?? (signal ? 1 : 0)));\n };\n const onError = (err: Error) => {\n callbacks.onLog(name, `Spawn failed: ${err.message}`, true);\n callbacks.onStatus(name, \"error\", `spawn failed: ${err.message}`);\n resume(\n Effect.fail(\n new OrchestratorError({\n operation: \"spawn process\",\n detail: err.message,\n cause: err,\n }),\n ),\n );\n };\n cmd.once(\"exit\", onExit);\n cmd.once(\"error\", onError);\n return Effect.sync(() => {\n cmd.off(\"exit\", onExit);\n cmd.off(\"error\", onError);\n });\n });\n\n const describeExit = (exitCodeValue: number): string => {\n if (lastExit?.code === null && lastExit.signal) return `signal: ${lastExit.signal}`;\n return `exit code: ${exitCodeValue}`;\n };\n const isCleanSignalExit = (): boolean =>\n lastExit?.code === null && lastExit.signal != null && lastExit.signal in cleanExitSignals;\n\n const markReady = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"ready\");\n callbacks.onStatus(name, \"ready\");\n yield* Deferred.succeed(readyDeferred, undefined).pipe(Effect.ignore);\n });\n\n const markError = (message: string) =>\n Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"error\");\n callbacks.onStatus(name, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({ operation: \"wait for process readiness\", detail: message }),\n ).pipe(Effect.ignore);\n });\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const readinessPath = descriptor.readinessPath;\n const url = `http://127.0.0.1:${port}${readinessPath}`;\n const readinessCheck = Effect.gen(function* () {\n const status = yield* Ref.get(statusRef);\n if (status === \"ready\" || status === \"error\") return true;\n if (port <= 0) return false;\n const ok = yield* probeHttpOk(url);\n if (ok) yield* markReady;\n return ok;\n });\n const ready = yield* Effect.repeat(readinessCheck, {\n schedule: Schedule.spaced(`${port > 0 ? LOCAL_PROBE_INTERVAL_MS : 500} millis`),\n until: (done) => done,\n }).pipe(\n Effect.timeout(`${LOCAL_PROBE_DEADLINE_MS} millis`),\n Effect.catchTag(\"TimeoutError\", () => Effect.succeed(false)),\n );\n if (ready) return;\n\n const status = yield* Ref.get(statusRef);\n if (status !== \"ready\" && status !== \"error\") {\n callbacks.onLog(name, \"Probe deadline exceeded after 90s\", true);\n yield* markError(`Probe deadline exceeded: ${name}`);\n }\n }),\n );\n\n const pid = cmd.pid ?? undefined;\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const exitCodeValue = yield* exitCode;\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") {\n // Post-ready exits must stay visible — a silently dead child (OOM\n // kill included) used to leave the stack answering with nothing.\n // A SIGTERM/SIGINT-signalled exit is the polite-quit path, not a\n // crash, so it logs as a plain shutdown line.\n if (currentStatus === \"ready\") {\n const detail = describeExit(exitCodeValue);\n callbacks.onLog(name, `Process exited after ready (${detail})`, !isCleanSignalExit());\n if (!isCleanSignalExit()) {\n callbacks.onStatus(name, \"error\", `exited after ready (${detail})`);\n }\n yield* markError(`Process exited after ready: ${name}`);\n }\n return;\n }\n callbacks.onLog(\n name,\n `Process exited before ready (${describeExit(exitCodeValue)})`,\n !isCleanSignalExit(),\n );\n yield* markError(`Process exited before ready: ${name}`);\n }),\n );\n\n const handleLine = (line: string, isStderr: boolean) =>\n Effect.gen(function* () {\n if (!line.trim()) return;\n\n const cleanLine = stripAnsi(line);\n const looksLikeError =\n isStderr &&\n /^(error|fail|fatal|exception|unhandled|reject)/i.test(cleanLine) &&\n !cleanLine.startsWith(\"$\");\n callbacks.onLog(name, line, looksLikeError);\n\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\") return;\n\n const detected = detectStatus(line, descriptor);\n if (detected) {\n if (detected.status === \"ready\") {\n yield* markReady;\n } else if (currentStatus !== \"error\") {\n yield* markError(`Process failed: ${name}`);\n }\n }\n });\n\n const stdoutStream = cmd.stdout\n ? (Readable.toWeb(cmd.stdout) as unknown as ReadableStream<Uint8Array>)\n : null;\n const stderrStream = cmd.stderr\n ? (Readable.toWeb(cmd.stderr) as unknown as ReadableStream<Uint8Array>)\n : null;\n\n if (stdoutStream) {\n yield* Effect.forkScoped(\n Stream.runForEach((line: string) => handleLine(line, false))(\n Stream.splitLines(\n Stream.decodeText(\n Stream.fromReadableStream({\n evaluate: () => stdoutStream,\n onError: (cause) =>\n new OrchestratorError({\n operation: \"read process stdout\",\n detail: String(cause),\n cause,\n }),\n }),\n ),\n ),\n ),\n );\n }\n\n if (stderrStream) {\n yield* Effect.forkScoped(\n Stream.runForEach((line: string) => handleLine(line, true))(\n Stream.splitLines(\n Stream.decodeText(\n Stream.fromReadableStream({\n evaluate: () => stderrStream,\n onError: (cause) =>\n new OrchestratorError({\n operation: \"read process stderr\",\n detail: String(cause),\n cause,\n }),\n }),\n ),\n ),\n ),\n );\n }\n\n return {\n name,\n pid,\n kill: Effect.gen(function* () {\n const groupPid = pid;\n const groupSignal = (signal: NodeJS.Signals) =>\n Effect.try(() => {\n if (groupPid !== undefined) process.kill(-groupPid, signal);\n }).pipe(Effect.ignore);\n yield* groupSignal(\"SIGTERM\");\n const exited = yield* exitCode.pipe(Effect.timeout(\"3 seconds\"), Effect.option);\n if (Option.isNone(exited)) {\n yield* groupSignal(\"SIGKILL\");\n yield* Effect.sleep(\"250 millis\");\n }\n }).pipe(Effect.ignore),\n waitForReady: Deferred.await(readyDeferred),\n waitForExit: exitCode,\n } satisfies ProcessHandle;\n });\n\nconst spawnRemoteProbe = (\n pkg: string,\n descriptor: ServiceDescriptor,\n callbacks: ProcessCallbacks,\n) =>\n Effect.gen(function* () {\n callbacks.onStatus(pkg, \"starting\");\n const readyDeferred = yield* Deferred.make<void, OrchestratorError>();\n const statusRef = yield* Ref.make<ProcessStatus>(\"starting\");\n\n const markReady = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"ready\");\n yield* Deferred.succeed(readyDeferred, undefined).pipe(Effect.ignore);\n callbacks.onStatus(pkg, \"ready\", \"loaded\");\n });\n\n const markError = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({\n operation: \"probe remote process\",\n detail: `Remote ${pkg} unreachable`,\n }),\n ).pipe(Effect.ignore);\n callbacks.onStatus(pkg, \"error\", \"unreachable\");\n });\n\n const baseUrl = descriptor.url.replace(/\\/$/, \"\");\n const manifestUrl = `${baseUrl}/mf-manifest.json`;\n const entryUrl = `${baseUrl}${descriptor.readinessPath}`;\n const probeUrl = descriptor.readinessPath === \"/health\" ? `${baseUrl}/health` : manifestUrl;\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const readinessCheck = Effect.gen(function* () {\n const status = yield* Ref.get(statusRef);\n if (status === \"ready\" || status === \"error\") return true;\n\n const ok = yield* probeHttpOk(probeUrl, REMOTE_PROBE_TIMEOUT_MS);\n if (ok) {\n yield* markReady;\n return true;\n }\n\n const fallbackOk = yield* probeHttpOk(entryUrl, REMOTE_PROBE_TIMEOUT_MS);\n if (fallbackOk) {\n yield* markReady;\n return true;\n }\n return false;\n });\n const ready = yield* Effect.repeat(readinessCheck, {\n schedule: Schedule.min([\n Schedule.exponential(`${REMOTE_PROBE_BACKOFF_INITIAL_MS} millis`, 1.5),\n Schedule.spaced(`${REMOTE_PROBE_BACKOFF_MAX_MS} millis`),\n ]),\n until: (done) => done,\n }).pipe(\n Effect.timeout(`${REMOTE_PROBE_DEADLINE_MS} millis`),\n Effect.catchTag(\"TimeoutError\", () => Effect.succeed(false)),\n );\n if (ready) return;\n\n const status = yield* Ref.get(statusRef);\n if (status !== \"ready\") {\n yield* markError;\n }\n }),\n );\n\n return {\n name: pkg,\n pid: undefined,\n kill: Effect.gen(function* () {\n yield* Ref.set(statusRef, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({ operation: \"stop remote process\", detail: \"Killed\" }),\n ).pipe(Effect.ignore);\n }),\n waitForReady: Deferred.await(readyDeferred),\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n });\n\nexport const makeDevProcess = (pkg: string, callbacks: ProcessCallbacks, portOverride?: number) =>\n Effect.gen(function* () {\n const services = yield* ServiceDescriptorMap;\n const descriptor = services.get(pkg);\n\n if (!descriptor) {\n callbacks.onStatus(pkg, \"ready\", \"Remote\");\n return {\n name: pkg,\n pid: undefined,\n kill: Effect.void,\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n }\n\n if (pkg === \"host\" && descriptor.source === \"remote\") {\n return yield* spawnRemoteHost(descriptor, callbacks);\n }\n\n if (descriptor.source === \"remote\" || !descriptor.localPath) {\n return yield* spawnRemoteProbe(pkg, descriptor, callbacks);\n }\n\n const resolvedDescriptor = portOverride ? { ...descriptor, port: portOverride } : descriptor;\n\n return yield* spawnDevProcess(resolvedDescriptor, callbacks);\n });\n\nexport function getProcessStates(\n packages: string[],\n services: Map<string, ServiceDescriptor>,\n portOverride?: number,\n): ProcessState[] {\n return packages.map((pkg) => {\n const descriptor = services.get(pkg);\n return {\n name: pkg,\n status: \"pending\" as const,\n port:\n portOverride && pkg === \"host\"\n ? portOverride\n : (descriptor?.port ?? descriptor?.defaultPort ?? 0),\n source: descriptor?.source,\n uiPort: descriptor?.uiPort,\n };\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"orchestrator.mjs","names":[],"sources":["../src/orchestrator.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { Readable } from \"node:stream\";\nimport { Data, Deferred, Effect, Option, Ref, Schedule, Schema, Stream } from \"effect\";\nimport { stripAnsi } from \"./dev-log-pipeline\";\nimport { ShellEnv } from \"./env/project-env\";\nimport { loadRemoteModule, registerRemote } from \"./federation\";\nimport { fetchRaw } from \"./http-client\";\nimport {\n DevGeneratedEnv,\n DevRuntimeConfig,\n type ServiceDescriptor,\n ServiceDescriptorMap,\n} from \"./service-descriptor\";\nimport type { RuntimeConfig } from \"./types\";\n\nprocess.on(\"unhandledRejection\", (reason) => {\n console.error(\"[Orchestrator] Unhandled rejection:\", reason);\n});\n\nprocess.on(\"uncaughtException\", (err) => {\n console.error(\"[Orchestrator] Uncaught exception:\", err);\n});\n\nexport interface ProcessCallbacks {\n onStatus: (name: string, status: ProcessStatus, message?: string) => void;\n onLog: (name: string, line: string, isError?: boolean) => void;\n}\n\nexport interface ProcessHandle {\n name: string;\n pid: number | undefined;\n kill: Effect.Effect<void>;\n waitForReady: Effect.Effect<void, OrchestratorError>;\n waitForExit: Effect.Effect<number, OrchestratorError>;\n}\n\nexport class OrchestratorError extends Data.TaggedError(\"OrchestratorError\")<{\n readonly operation: string;\n readonly detail: string;\n readonly cause?: unknown;\n}> {\n override get message() {\n return `${this.operation}: ${this.detail}`;\n }\n}\n\nconst omitUndefined = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((item) => (item === undefined ? null : omitUndefined(item)));\n }\n if (value !== null && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value)\n .filter(([, item]) => item !== undefined)\n .map(([key, item]) => [key, omitUndefined(item)]),\n );\n }\n return value;\n};\n\nexport const encodeRuntimeConfig = (runtimeConfig: unknown) =>\n Schema.encodeUnknownEffect(Schema.fromJsonString(Schema.Json))(omitUndefined(runtimeConfig)).pipe(\n Effect.mapError(\n (cause) =>\n new OrchestratorError({\n operation: \"serialize runtime config\",\n detail: cause.message,\n cause,\n }),\n ),\n );\n\nexport type ProcessStatus = \"pending\" | \"starting\" | \"ready\" | \"error\";\n\nexport interface ProcessState {\n name: string;\n status: ProcessStatus;\n port: number;\n message?: string;\n source?: \"local\" | \"remote\";\n uiPort?: number;\n}\n\nconst probeHttpOk = (url: string, timeoutMs = 400) =>\n Effect.tryPromise({\n try: async () => {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });\n return res.ok;\n } catch {\n return false;\n }\n },\n catch: () => false,\n });\n\nconst LOCAL_PROBE_DEADLINE_MS = 90_000;\n\n/** Remote-host boot budgets: every stage of the CDN-only boot is deadline-\n * bounded so a hung connection or a wedged module load fails loud with the\n * URL and stage — long before the smoke's 240s probe deadline turns the\n * silence into a mystery. */\nconst MANIFEST_FETCH_DEADLINE = \"10 seconds\";\nconst LOAD_REMOTE_DEADLINE = \"60 seconds\";\nconst SERVER_READY_DEADLINE = \"120 seconds\";\nconst REMOTE_HOST_BOOT_DEADLINE = \"180 seconds\";\nconst LOCAL_PROBE_INTERVAL_MS = 200;\n\nconst cleanExitSignals: Record<string, true> = { SIGTERM: true, SIGINT: true };\n\nconst REMOTE_PROBE_TIMEOUT_MS = 5000;\nconst REMOTE_PROBE_DEADLINE_MS = 60_000;\nconst REMOTE_PROBE_BACKOFF_INITIAL_MS = 1000;\nconst REMOTE_PROBE_BACKOFF_MAX_MS = 15_000;\n\nexport const detectStatus = (\n line: string,\n descriptor: ServiceDescriptor,\n): { status: ProcessStatus; isError: boolean } | null => {\n const cleanLine = stripAnsi(line);\n const errorPatterns = descriptor.errorPatterns ?? [];\n const readyPatterns = descriptor.readyPatterns ?? [];\n for (const pattern of readyPatterns) {\n if (pattern.test(cleanLine)) {\n return { status: \"ready\", isError: false };\n }\n }\n for (const pattern of errorPatterns) {\n if (pattern.test(cleanLine)) {\n return { status: \"error\", isError: true };\n }\n }\n return null;\n};\n\ninterface ServerHandle {\n ready: Promise<void>;\n shutdown: () => Promise<void>;\n}\n\ninterface ServerInput {\n config: RuntimeConfig;\n port?: number;\n env?: Record<string, string>;\n}\n\nconst patchConsole = (name: string, callbacks: ProcessCallbacks): (() => void) => {\n const originalLog = console.log;\n const originalError = console.error;\n const originalWarn = console.warn;\n const originalInfo = console.info;\n\n const formatArgs = (args: unknown[], isError = false): string => {\n return args\n .map((arg) => {\n if (arg instanceof Error) {\n const parts = [`${arg.name}: ${arg.message}`];\n if (arg.cause instanceof Error)\n parts.push(`(cause: ${arg.cause.name}: ${arg.cause.message})`);\n else if (arg.cause) {\n const cause = arg.cause;\n parts.push(\n `(cause: ${cause instanceof Error ? cause.message : typeof cause === \"string\" ? cause : (JSON.stringify(cause) ?? \"[Unserializable cause]\")})`,\n );\n }\n if (isError && arg.stack) parts.push(arg.stack);\n return parts.join(\"\\n\");\n }\n if (arg === null) return \"null\";\n if (typeof arg === \"string\") return arg;\n if (typeof arg === \"number\" || typeof arg === \"bigint\" || typeof arg === \"boolean\")\n return `${arg}`;\n if (typeof arg === \"symbol\") return arg.description ?? \"\";\n if (typeof arg === \"undefined\") return \"undefined\";\n return JSON.stringify(arg, null, 2) ?? \"[Unserializable value]\";\n })\n .join(\" \");\n };\n\n console.log = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n console.error = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args, true), true);\n };\n console.warn = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n console.info = (...args: unknown[]) => {\n callbacks.onLog(name, formatArgs(args), false);\n };\n\n return () => {\n console.log = originalLog;\n console.error = originalError;\n console.warn = originalWarn;\n console.info = originalInfo;\n };\n};\n\nexport class HostRemoteUrlMissing extends Data.TaggedError(\"HostRemoteUrlMissing\")<\n Record<never, never>\n> {\n override get message() {\n return \"remoteUrl not provided on host descriptor\";\n }\n}\n\nexport class HostModuleInvalid extends Data.TaggedError(\"HostModuleInvalid\")<Record<never, never>> {\n override get message() {\n return \"Host module does not export runServer function\";\n }\n}\n\nexport class LocalPathMissing extends Data.TaggedError(\"LocalPathMissing\")<{ key: string }> {\n get message() {\n return `No localPath for local service: ${this.key}`;\n }\n}\n\nconst spawnRemoteHost = (descriptor: ServiceDescriptor, callbacks: ProcessCallbacks) =>\n Effect.gen(function* () {\n const runtimeConfig = yield* DevRuntimeConfig;\n const remoteUrl = descriptor.remoteUrl;\n if (!remoteUrl) {\n return yield* new HostRemoteUrlMissing();\n }\n\n callbacks.onStatus(descriptor.key, \"starting\");\n callbacks.onLog(descriptor.key, `Remote: ${remoteUrl}`);\n const restoreConsole = patchConsole(descriptor.key, callbacks);\n callbacks.onLog(descriptor.key, \"Loading Module Federation runtime...\");\n\n const baseUrl = remoteUrl\n .replace(/\\/remoteEntry\\.js$/, \"\")\n .replace(/\\/mf-manifest\\.json$/, \"\")\n .replace(/\\/$/, \"\");\n const manifestUrl = `${baseUrl}/mf-manifest.json`;\n\n // The manifest IS the entry contract (ADR 0020 amendment: hashed\n // entrypoints, fixed-name `remoteEntry.js` retired — it 404s on the CDN).\n // A failed manifest fetch must fail loud with the URL and status: the old\n // silent fallback to remoteEntry.js turned any transient hiccup (a CDN\n // 403 challenge, a timeout) into a guaranteed loadRemote failure with no\n // named cause.\n const entryUrl = yield* Effect.tryPromise({\n try: async () => {\n let res: Response;\n try {\n res = await fetchRaw(manifestUrl, undefined, MANIFEST_FETCH_DEADLINE);\n } catch (e) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — ${e instanceof Error ? e.message : String(e)}`,\n cause: e,\n });\n }\n if (!res.ok) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — HTTP ${res.status}${res.statusText ? ` ${res.statusText}` : \"\"}`,\n });\n }\n const json = (await res.json()) as Record<string, unknown>;\n if (\n !json ||\n typeof json !== \"object\" ||\n !(\"metaData\" in json) ||\n !(\"exposes\" in json) ||\n !(\"shared\" in json)\n ) {\n throw new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — not a Module Federation manifest (missing metaData/exposes/shared)`,\n });\n }\n return manifestUrl;\n },\n catch: (cause) =>\n cause instanceof OrchestratorError\n ? cause\n : new OrchestratorError({\n operation: \"fetch host manifest\",\n detail: `${manifestUrl} — ${String(cause)}`,\n }),\n });\n\n yield* Effect.promise(() => registerRemote({ name: \"host\", entry: entryUrl }));\n callbacks.onLog(descriptor.key, `Loading host from ${entryUrl}...`);\n\n const hostModule = yield* Effect.tryPromise({\n try: () =>\n loadRemoteModule<{\n runServer: (input: ServerInput) => ServerHandle;\n }>(\"host/Server\"),\n catch: (cause) =>\n new OrchestratorError({\n operation: \"load host module\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n }).pipe(\n Effect.timeoutOrElse({\n duration: LOAD_REMOTE_DEADLINE,\n orElse: () =>\n Effect.fail(\n new OrchestratorError({\n operation: \"load host module\",\n detail: `timed out after ${LOAD_REMOTE_DEADLINE} — the module (or its shared dependencies) did not finish loading from ${entryUrl}`,\n }),\n ),\n }),\n );\n\n if (!hostModule?.runServer) {\n return yield* new HostModuleInvalid();\n }\n\n callbacks.onLog(descriptor.key, \"Starting server...\");\n const hostPort = runtimeConfig.host?.port;\n const hostEnv: Record<string, string> | undefined = hostPort\n ? { PORT: String(hostPort) }\n : undefined;\n const serverHandle = hostModule.runServer({\n config: runtimeConfig,\n port: hostPort,\n env: hostEnv,\n });\n yield* Effect.tryPromise({\n try: () => serverHandle.ready,\n catch: (cause) =>\n new OrchestratorError({\n operation: \"start server\",\n detail: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n }).pipe(\n Effect.timeoutOrElse({\n duration: SERVER_READY_DEADLINE,\n // A half-started server must not leak its port on the deadline path —\n // the success path hands shutdown to the process handle instead.\n orElse: () =>\n Effect.gen(function* () {\n yield* Effect.exit(Effect.promise(() => serverHandle.shutdown()));\n return yield* new OrchestratorError({\n operation: \"start server\",\n detail: `server did not become ready within ${SERVER_READY_DEADLINE}`,\n });\n }),\n }),\n );\n\n callbacks.onStatus(descriptor.key, \"ready\");\n\n return {\n name: descriptor.key,\n pid: undefined,\n kill: Effect.gen(function* () {\n callbacks.onLog(descriptor.key, \"Shutting down remote host...\");\n restoreConsole();\n yield* Effect.tryPromise({\n try: () => serverHandle.shutdown(),\n catch: () => {},\n }).pipe(Effect.ignore);\n }),\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n });\n\n/**\n * Spawn env precedence, three tiers: values explicitly exported by the\n * caller (shell / CI / regression harness — captured by the bootstrap\n * program into the `ShellEnv` service before any `.env` loading) outrank the\n * generated infra env, which outranks `.env`-file values inherited through\n * `processEnv`. The service's resolved port is always authoritative.\n */\nexport function composeSpawnEnv(\n processEnv: Record<string, string>,\n generatedEnv: Record<string, string>,\n port: number,\n shellEnv: Record<string, string> = {},\n): Record<string, string> {\n return {\n ...processEnv,\n ...mergeGeneratedOverFileEnv(generatedEnv, processEnv, shellEnv),\n FORCE_COLOR: \"1\",\n ...(port > 0 ? { PORT: String(port) } : {}),\n };\n}\n\n/**\n * Overlay the generated infra env (ports drift, so stale `.env` values must\n * lose) while keeping every explicitly exported key from `shellEnv` intact.\n * Keys absent from both are untouched.\n *\n * Exception (ADR 0012 / plan 038): the origin keys BASE_URL and CORS_ORIGIN\n * are always generated-owned — a wrapper that sourced a stale `.env` must not\n * win over the resolved host port, in the child env or on disk.\n */\nconst GENERATED_OWNED_KEYS = new Set([\"BASE_URL\", \"CORS_ORIGIN\"]);\n\nexport function mergeGeneratedOverFileEnv(\n generatedEnv: Record<string, string>,\n processEnv: Record<string, string>,\n shellEnv: Record<string, string> = {},\n): Record<string, string> {\n const result: Record<string, string> = { ...processEnv };\n for (const [key, value] of Object.entries(generatedEnv)) {\n if (!GENERATED_OWNED_KEYS.has(key) && key in shellEnv) {\n result[key] = shellEnv[key]!;\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\nconst spawnDevProcess = (descriptor: ServiceDescriptor, callbacks: ProcessCallbacks) =>\n Effect.gen(function* () {\n const runtimeConfig = yield* DevRuntimeConfig;\n\n if (!descriptor.localPath) {\n return yield* new LocalPathMissing({ key: descriptor.key });\n }\n\n const fullCwd = descriptor.localPath;\n const command = descriptor.command ?? \"pnpm\";\n const args = descriptor.args ?? [\"run\", \"dev\"];\n const port = descriptor.port ?? descriptor.defaultPort;\n const name = descriptor.key;\n\n const readyDeferred = yield* Deferred.make<void, OrchestratorError>();\n const statusRef = yield* Ref.make<ProcessStatus>(\"starting\");\n\n callbacks.onStatus(name, \"starting\");\n\n const generatedEnv = yield* DevGeneratedEnv;\n const shellTier = yield* ShellEnv;\n // The descriptor's env joins the generated tier — folding it in before\n // composeSpawnEnv keeps the documented precedence (shell > generated >\n // .env-file); assigning after would let it outrank the shell tier (and\n // the generated-owned keys) silently.\n const envVars = composeSpawnEnv(\n process.env as Record<string, string>,\n { ...generatedEnv, ...descriptor.env },\n port,\n shellTier,\n );\n\n envVars.BOS_RUNTIME_CONFIG = yield* encodeRuntimeConfig(runtimeConfig);\n\n const cmd = spawn(command, args, {\n cwd: fullCwd,\n env: envVars,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n });\n\n let lastExit: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n const exitCode = Effect.callback<number, OrchestratorError>((resume) => {\n const onExit = (code: number | null, signal: NodeJS.Signals | null) => {\n lastExit = { code, signal };\n resume(Effect.succeed(code ?? (signal ? 1 : 0)));\n };\n const onError = (err: Error) => {\n callbacks.onLog(name, `Spawn failed: ${err.message}`, true);\n callbacks.onStatus(name, \"error\", `spawn failed: ${err.message}`);\n resume(\n Effect.fail(\n new OrchestratorError({\n operation: \"spawn process\",\n detail: err.message,\n cause: err,\n }),\n ),\n );\n };\n cmd.once(\"exit\", onExit);\n cmd.once(\"error\", onError);\n return Effect.sync(() => {\n cmd.off(\"exit\", onExit);\n cmd.off(\"error\", onError);\n });\n });\n\n const describeExit = (exitCodeValue: number): string => {\n if (lastExit?.code === null && lastExit.signal) return `signal: ${lastExit.signal}`;\n return `exit code: ${exitCodeValue}`;\n };\n const isCleanSignalExit = (): boolean =>\n lastExit?.code === null && lastExit.signal != null && lastExit.signal in cleanExitSignals;\n\n const markReady = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"ready\");\n callbacks.onStatus(name, \"ready\");\n yield* Deferred.succeed(readyDeferred, undefined).pipe(Effect.ignore);\n });\n\n const markError = (message: string) =>\n Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"error\");\n callbacks.onStatus(name, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({ operation: \"wait for process readiness\", detail: message }),\n ).pipe(Effect.ignore);\n });\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const readinessPath = descriptor.readinessPath;\n const url = `http://127.0.0.1:${port}${readinessPath}`;\n const readinessCheck = Effect.gen(function* () {\n const status = yield* Ref.get(statusRef);\n if (status === \"ready\" || status === \"error\") return true;\n if (port <= 0) return false;\n const ok = yield* probeHttpOk(url);\n if (ok) yield* markReady;\n return ok;\n });\n const ready = yield* Effect.repeat(readinessCheck, {\n schedule: Schedule.spaced(`${port > 0 ? LOCAL_PROBE_INTERVAL_MS : 500} millis`),\n until: (done) => done,\n }).pipe(\n Effect.timeout(`${LOCAL_PROBE_DEADLINE_MS} millis`),\n Effect.catchTag(\"TimeoutError\", () => Effect.succeed(false)),\n );\n if (ready) return;\n\n const status = yield* Ref.get(statusRef);\n if (status !== \"ready\" && status !== \"error\") {\n callbacks.onLog(name, \"Probe deadline exceeded after 90s\", true);\n yield* markError(`Probe deadline exceeded: ${name}`);\n }\n }),\n );\n\n const pid = cmd.pid ?? undefined;\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const exitCodeValue = yield* exitCode;\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") {\n // Post-ready exits must stay visible — a silently dead child (OOM\n // kill included) used to leave the stack answering with nothing.\n // A SIGTERM/SIGINT-signalled exit is the polite-quit path, not a\n // crash, so it logs as a plain shutdown line.\n if (currentStatus === \"ready\") {\n const detail = describeExit(exitCodeValue);\n callbacks.onLog(name, `Process exited after ready (${detail})`, !isCleanSignalExit());\n if (!isCleanSignalExit()) {\n callbacks.onStatus(name, \"error\", `exited after ready (${detail})`);\n }\n yield* markError(`Process exited after ready: ${name}`);\n }\n return;\n }\n callbacks.onLog(\n name,\n `Process exited before ready (${describeExit(exitCodeValue)})`,\n !isCleanSignalExit(),\n );\n yield* markError(`Process exited before ready: ${name}`);\n }),\n );\n\n const handleLine = (line: string, isStderr: boolean) =>\n Effect.gen(function* () {\n if (!line.trim()) return;\n\n const cleanLine = stripAnsi(line);\n const looksLikeError =\n isStderr &&\n /^(error|fail|fatal|exception|unhandled|reject)/i.test(cleanLine) &&\n !cleanLine.startsWith(\"$\");\n callbacks.onLog(name, line, looksLikeError);\n\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\") return;\n\n const detected = detectStatus(line, descriptor);\n if (detected) {\n if (detected.status === \"ready\") {\n yield* markReady;\n } else if (currentStatus !== \"error\") {\n yield* markError(`Process failed: ${name}`);\n }\n }\n });\n\n const stdoutStream = cmd.stdout\n ? (Readable.toWeb(cmd.stdout) as unknown as ReadableStream<Uint8Array>)\n : null;\n const stderrStream = cmd.stderr\n ? (Readable.toWeb(cmd.stderr) as unknown as ReadableStream<Uint8Array>)\n : null;\n\n if (stdoutStream) {\n yield* Effect.forkScoped(\n Stream.runForEach((line: string) => handleLine(line, false))(\n Stream.splitLines(\n Stream.decodeText(\n Stream.fromReadableStream({\n evaluate: () => stdoutStream,\n onError: (cause) =>\n new OrchestratorError({\n operation: \"read process stdout\",\n detail: String(cause),\n cause,\n }),\n }),\n ),\n ),\n ),\n );\n }\n\n if (stderrStream) {\n yield* Effect.forkScoped(\n Stream.runForEach((line: string) => handleLine(line, true))(\n Stream.splitLines(\n Stream.decodeText(\n Stream.fromReadableStream({\n evaluate: () => stderrStream,\n onError: (cause) =>\n new OrchestratorError({\n operation: \"read process stderr\",\n detail: String(cause),\n cause,\n }),\n }),\n ),\n ),\n ),\n );\n }\n\n return {\n name,\n pid,\n kill: Effect.gen(function* () {\n const groupPid = pid;\n const groupSignal = (signal: NodeJS.Signals) =>\n Effect.try(() => {\n if (groupPid !== undefined) process.kill(-groupPid, signal);\n }).pipe(Effect.ignore);\n yield* groupSignal(\"SIGTERM\");\n const exited = yield* exitCode.pipe(Effect.timeout(\"3 seconds\"), Effect.option);\n if (Option.isNone(exited)) {\n yield* groupSignal(\"SIGKILL\");\n yield* Effect.sleep(\"250 millis\");\n }\n }).pipe(Effect.ignore),\n waitForReady: Deferred.await(readyDeferred),\n waitForExit: exitCode,\n } satisfies ProcessHandle;\n });\n\nconst spawnRemoteProbe = (\n pkg: string,\n descriptor: ServiceDescriptor,\n callbacks: ProcessCallbacks,\n) =>\n Effect.gen(function* () {\n callbacks.onStatus(pkg, \"starting\");\n const readyDeferred = yield* Deferred.make<void, OrchestratorError>();\n const statusRef = yield* Ref.make<ProcessStatus>(\"starting\");\n\n const markReady = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"ready\");\n yield* Deferred.succeed(readyDeferred, undefined).pipe(Effect.ignore);\n callbacks.onStatus(pkg, \"ready\", \"loaded\");\n });\n\n const markError = Effect.gen(function* () {\n const currentStatus = yield* Ref.get(statusRef);\n if (currentStatus === \"ready\" || currentStatus === \"error\") return;\n yield* Ref.set(statusRef, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({\n operation: \"probe remote process\",\n detail: `Remote ${pkg} unreachable`,\n }),\n ).pipe(Effect.ignore);\n callbacks.onStatus(pkg, \"error\", \"unreachable\");\n });\n\n const baseUrl = descriptor.url.replace(/\\/$/, \"\");\n const manifestUrl = `${baseUrl}/mf-manifest.json`;\n const entryUrl = `${baseUrl}${descriptor.readinessPath}`;\n const probeUrl = descriptor.readinessPath === \"/health\" ? `${baseUrl}/health` : manifestUrl;\n\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const readinessCheck = Effect.gen(function* () {\n const status = yield* Ref.get(statusRef);\n if (status === \"ready\" || status === \"error\") return true;\n\n const ok = yield* probeHttpOk(probeUrl, REMOTE_PROBE_TIMEOUT_MS);\n if (ok) {\n yield* markReady;\n return true;\n }\n\n const fallbackOk = yield* probeHttpOk(entryUrl, REMOTE_PROBE_TIMEOUT_MS);\n if (fallbackOk) {\n yield* markReady;\n return true;\n }\n return false;\n });\n const ready = yield* Effect.repeat(readinessCheck, {\n schedule: Schedule.min([\n Schedule.exponential(`${REMOTE_PROBE_BACKOFF_INITIAL_MS} millis`, 1.5),\n Schedule.spaced(`${REMOTE_PROBE_BACKOFF_MAX_MS} millis`),\n ]),\n until: (done) => done,\n }).pipe(\n Effect.timeout(`${REMOTE_PROBE_DEADLINE_MS} millis`),\n Effect.catchTag(\"TimeoutError\", () => Effect.succeed(false)),\n );\n if (ready) return;\n\n const status = yield* Ref.get(statusRef);\n if (status !== \"ready\") {\n yield* markError;\n }\n }),\n );\n\n return {\n name: pkg,\n pid: undefined,\n kill: Effect.gen(function* () {\n yield* Ref.set(statusRef, \"error\");\n yield* Deferred.fail(\n readyDeferred,\n new OrchestratorError({ operation: \"stop remote process\", detail: \"Killed\" }),\n ).pipe(Effect.ignore);\n }),\n waitForReady: Deferred.await(readyDeferred),\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n });\n\nexport const makeDevProcess = (pkg: string, callbacks: ProcessCallbacks, portOverride?: number) =>\n Effect.gen(function* () {\n const services = yield* ServiceDescriptorMap;\n const descriptor = services.get(pkg);\n\n if (!descriptor) {\n callbacks.onStatus(pkg, \"ready\", \"Remote\");\n return {\n name: pkg,\n pid: undefined,\n kill: Effect.void,\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle;\n }\n\n if (pkg === \"host\" && descriptor.source === \"remote\") {\n return yield* spawnRemoteHost(descriptor, callbacks).pipe(\n // Overall boot budget: with per-stage deadlines inside, this is the\n // backstop for anything the stage deadlines don't cover (a config\n // fetch, a slow MF internal) — the boot either comes up named-and-\n // ready or fails named-and-loud.\n Effect.timeoutOrElse({\n duration: REMOTE_HOST_BOOT_DEADLINE,\n orElse: () =>\n Effect.fail(\n new OrchestratorError({\n operation: \"boot remote host\",\n detail: `remote host boot exceeded the ${REMOTE_HOST_BOOT_DEADLINE} overall deadline`,\n }),\n ),\n }),\n );\n }\n\n if (descriptor.source === \"remote\" || !descriptor.localPath) {\n return yield* spawnRemoteProbe(pkg, descriptor, callbacks);\n }\n\n const resolvedDescriptor = portOverride ? { ...descriptor, port: portOverride } : descriptor;\n\n return yield* spawnDevProcess(resolvedDescriptor, callbacks);\n });\n\nexport function getProcessStates(\n packages: string[],\n services: Map<string, ServiceDescriptor>,\n portOverride?: number,\n): ProcessState[] {\n return packages.map((pkg) => {\n const descriptor = services.get(pkg);\n return {\n name: pkg,\n status: \"pending\" as const,\n port:\n portOverride && pkg === \"host\"\n ? portOverride\n : (descriptor?.port ?? descriptor?.defaultPort ?? 0),\n source: descriptor?.source,\n uiPort: descriptor?.uiPort,\n };\n });\n}\n"],"mappings":"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"}
|
package/dist/plugin.cjs
CHANGED
|
@@ -16,6 +16,7 @@ const require_init = require('./commands/init.cjs');
|
|
|
16
16
|
const require_keys = require('./commands/keys.cjs');
|
|
17
17
|
const require_ops = require('./commands/ops.cjs');
|
|
18
18
|
const require_plugins = require('./commands/plugins.cjs');
|
|
19
|
+
const require_smoke = require('./commands/smoke.cjs');
|
|
19
20
|
const require_upgrade = require('./commands/upgrade.cjs');
|
|
20
21
|
let effect = require("effect");
|
|
21
22
|
let every_plugin = require("every-plugin");
|
|
@@ -58,6 +59,7 @@ var plugin_default = (0, every_plugin.createPlugin)({
|
|
|
58
59
|
...require_dev.registerDev(builder),
|
|
59
60
|
...require_build.registerBuild(builder),
|
|
60
61
|
...require_deploy.registerDeploy(builder),
|
|
62
|
+
...require_smoke.registerSmoke(builder),
|
|
61
63
|
...require_keys.registerKeys(builder),
|
|
62
64
|
...require_init.registerInit(builder),
|
|
63
65
|
...require_upgrade.registerUpgrade(builder),
|
package/dist/plugin.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs","names":["createPlugin","z","bosContract","Effect","openResolution","buildScoped","ProjectEnv","ProjectEnvLive","process","buildScopedContext","Layer","makeDatabaseBindings","makeDrizzleKitLive","p","BosDepsTag","Context","DatabaseBindings","DrizzleKit","registerConfig","registerPlugins","registerDev","registerBuild","registerDeploy","registerKeys","registerInit","registerUpgrade","registerDb","registerOps"],"sources":["../src/plugin.ts"],"sourcesContent":["import process from \"node:process\";\nimport * as p from \"@clack/prompts\";\nimport { Context, Effect, Layer } from \"effect\";\nimport { buildScoped, buildScopedContext } from \"every-plugin\";\nimport { registerBuild } from \"./commands/build\";\nimport { registerConfig } from \"./commands/config\";\nimport { registerDb } from \"./commands/db\";\nimport { registerDeploy } from \"./commands/deploy\";\nimport { registerDev } from \"./commands/dev\";\nimport { registerInit } from \"./commands/init\";\nimport { registerKeys } from \"./commands/keys\";\nimport { registerOps } from \"./commands/ops\";\nimport { registerPlugins } from \"./commands/plugins\";\nimport { type BosDeps, BosDepsTag } from \"./commands/shared\";\nimport { registerUpgrade } from \"./commands/upgrade\";\nimport { bosContract } from \"./contract\";\nimport { DatabaseBindings, DrizzleKit, makeDatabaseBindings, makeDrizzleKitLive } from \"./db\";\nimport { ProjectEnv, ProjectEnvLive } from \"./env/project-env\";\nimport { openResolution } from \"./resolution/session\";\nimport { createPlugin, z } from \"./sdk\";\n\nexport { resolveRemoteConfigChain } from \"./commands/config\";\nexport type { DevSessionData, StartSummary } from \"./dev-program\";\nexport { type ProgressEvent, pluginEvents } from \"./progress\";\n\nexport default createPlugin({\n variables: z.object({\n configPath: z.string().optional(),\n // The artifact root (cwd-derived) — decoupled from configPath so an\n // explicit boot config (--config-path fixture) validates and loads\n // without redirecting where the CLI writes generated artifacts.\n configDir: z.string().optional(),\n }),\n secrets: z.object({}),\n contract: bosContract,\n initialize: (config, _plugins) =>\n Effect.gen(function* () {\n const session = yield* Effect.promise(() =>\n openResolution({ path: config.variables.configPath }),\n );\n\n const projectEnv = yield* buildScoped(ProjectEnv, ProjectEnvLive);\n const effectContext = yield* Effect.context();\n\n const configDir = config.variables.configDir ?? session?.root ?? process.cwd();\n\n const services = yield* buildScopedContext(\n Layer.mergeAll(\n makeDatabaseBindings({\n projectDir: configDir,\n loadRuntimeConfig: async () => (await session?.buildRuntime()) ?? null,\n loadEnv: () => Effect.runPromiseWith(effectContext)(projectEnv.load(configDir)),\n }),\n makeDrizzleKitLive({\n projectDir: configDir,\n onLog: (message) => p.log.info(message),\n }),\n ),\n );\n\n return Layer.succeed(BosDepsTag, {\n session,\n databaseBindings: Context.get(services, DatabaseBindings),\n drizzleKit: Context.get(services, DrizzleKit),\n } satisfies BosDeps);\n }),\n createRouter: (builder) => ({\n ...registerConfig(builder),\n ...registerPlugins(builder),\n ...registerDev(builder),\n ...registerBuild(builder),\n ...registerDeploy(builder),\n ...registerKeys(builder),\n ...registerInit(builder),\n ...registerUpgrade(builder),\n ...registerDb(builder),\n ...registerOps(builder),\n }),\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.cjs","names":["createPlugin","z","bosContract","Effect","openResolution","buildScoped","ProjectEnv","ProjectEnvLive","process","buildScopedContext","Layer","makeDatabaseBindings","makeDrizzleKitLive","p","BosDepsTag","Context","DatabaseBindings","DrizzleKit","registerConfig","registerPlugins","registerDev","registerBuild","registerDeploy","registerSmoke","registerKeys","registerInit","registerUpgrade","registerDb","registerOps"],"sources":["../src/plugin.ts"],"sourcesContent":["import process from \"node:process\";\nimport * as p from \"@clack/prompts\";\nimport { Context, Effect, Layer } from \"effect\";\nimport { buildScoped, buildScopedContext } from \"every-plugin\";\nimport { registerBuild } from \"./commands/build\";\nimport { registerConfig } from \"./commands/config\";\nimport { registerDb } from \"./commands/db\";\nimport { registerDeploy } from \"./commands/deploy\";\nimport { registerDev } from \"./commands/dev\";\nimport { registerInit } from \"./commands/init\";\nimport { registerKeys } from \"./commands/keys\";\nimport { registerOps } from \"./commands/ops\";\nimport { registerPlugins } from \"./commands/plugins\";\nimport { type BosDeps, BosDepsTag } from \"./commands/shared\";\nimport { registerSmoke } from \"./commands/smoke\";\nimport { registerUpgrade } from \"./commands/upgrade\";\nimport { bosContract } from \"./contract\";\nimport { DatabaseBindings, DrizzleKit, makeDatabaseBindings, makeDrizzleKitLive } from \"./db\";\nimport { ProjectEnv, ProjectEnvLive } from \"./env/project-env\";\nimport { openResolution } from \"./resolution/session\";\nimport { createPlugin, z } from \"./sdk\";\n\nexport { resolveRemoteConfigChain } from \"./commands/config\";\nexport type { DevSessionData, StartSummary } from \"./dev-program\";\nexport { type ProgressEvent, pluginEvents } from \"./progress\";\n\nexport default createPlugin({\n variables: z.object({\n configPath: z.string().optional(),\n // The artifact root (cwd-derived) — decoupled from configPath so an\n // explicit boot config (--config-path fixture) validates and loads\n // without redirecting where the CLI writes generated artifacts.\n configDir: z.string().optional(),\n }),\n secrets: z.object({}),\n contract: bosContract,\n initialize: (config, _plugins) =>\n Effect.gen(function* () {\n const session = yield* Effect.promise(() =>\n openResolution({ path: config.variables.configPath }),\n );\n\n const projectEnv = yield* buildScoped(ProjectEnv, ProjectEnvLive);\n const effectContext = yield* Effect.context();\n\n const configDir = config.variables.configDir ?? session?.root ?? process.cwd();\n\n const services = yield* buildScopedContext(\n Layer.mergeAll(\n makeDatabaseBindings({\n projectDir: configDir,\n loadRuntimeConfig: async () => (await session?.buildRuntime()) ?? null,\n loadEnv: () => Effect.runPromiseWith(effectContext)(projectEnv.load(configDir)),\n }),\n makeDrizzleKitLive({\n projectDir: configDir,\n onLog: (message) => p.log.info(message),\n }),\n ),\n );\n\n return Layer.succeed(BosDepsTag, {\n session,\n databaseBindings: Context.get(services, DatabaseBindings),\n drizzleKit: Context.get(services, DrizzleKit),\n } satisfies BosDeps);\n }),\n createRouter: (builder) => ({\n ...registerConfig(builder),\n ...registerPlugins(builder),\n ...registerDev(builder),\n ...registerBuild(builder),\n ...registerDeploy(builder),\n ...registerSmoke(builder),\n ...registerKeys(builder),\n ...registerInit(builder),\n ...registerUpgrade(builder),\n ...registerDb(builder),\n ...registerOps(builder),\n }),\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,yBAAeA,2BAAa;CAC1B,WAAWC,MAAE,OAAO;EAClB,YAAYA,MAAE,OAAO,CAAC,CAAC,SAAS;EAIhC,WAAWA,MAAE,OAAO,CAAC,CAAC,SAAS;CACjC,CAAC;CACD,SAASA,MAAE,OAAO,CAAC,CAAC;CACpB,UAAUC;CACV,aAAa,QAAQ,aACnBC,cAAO,IAAI,aAAa;EACtB,MAAM,UAAU,OAAOA,cAAO,cAC5BC,0CAAe,EAAE,MAAM,OAAO,UAAU,WAAW,CAAC,CACtD;EAEA,MAAM,aAAa,WAAOC,0BAAYC,gCAAYC,kCAAc;EAChE,MAAM,gBAAgB,OAAOJ,cAAO,QAAQ;EAE5C,MAAM,YAAY,OAAO,UAAU,aAAa,SAAS,QAAQK,qBAAQ,IAAI;EAE7E,MAAM,WAAW,WAAOC,iCACtBC,aAAM,SACJC,sCAAqB;GACnB,YAAY;GACZ,mBAAmB,YAAa,MAAM,SAAS,aAAa,KAAM;GAClE,eAAeR,cAAO,eAAe,aAAa,CAAC,CAAC,WAAW,KAAK,SAAS,CAAC;EAChF,CAAC,GACDS,uCAAmB;GACjB,YAAY;GACZ,QAAQ,YAAYC,eAAE,IAAI,KAAK,OAAO;EACxC,CAAC,CACH,CACF;EAEA,OAAOH,aAAM,QAAQI,2BAAY;GAC/B;GACA,kBAAkBC,eAAQ,IAAI,UAAUC,iCAAgB;GACxD,YAAYD,eAAQ,IAAI,UAAUE,8BAAU;EAC9C,CAAmB;CACrB,CAAC;CACH,eAAe,aAAa;EAC1B,GAAGC,8BAAe,OAAO;EACzB,GAAGC,gCAAgB,OAAO;EAC1B,GAAGC,wBAAY,OAAO;EACtB,GAAGC,4BAAc,OAAO;EACxB,GAAGC,8BAAe,OAAO;EACzB,GAAGC,4BAAc,OAAO;EACxB,GAAGC,0BAAa,OAAO;EACvB,GAAGC,0BAAa,OAAO;EACvB,GAAGC,gCAAgB,OAAO;EAC1B,GAAGC,sBAAW,OAAO;EACrB,GAAGC,wBAAY,OAAO;CACxB;AACF,CAAC"}
|