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
package/dist/db/core.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.cjs","names":["join","existsSync","readFileSync","dirname"],"sources":["../../src/db/core.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport interface MigrationStorage {\n schema: string;\n table: string;\n slug: string;\n}\n\nconst DEFAULT_MIGRATION_JOURNAL = {\n schema: \"drizzle\",\n table: \"__drizzle_migrations\",\n} as const;\n\nconst PER_PLUGIN_ISOLATION = false;\n\nexport function normalizeSlug(name: string): string {\n const basename = name.split(\"/\").pop() ?? name;\n return basename\n .replace(/^@/, \"\")\n .replace(/[^a-zA-Z0-9_-]/g, \"_\")\n .replace(/-plugin$/i, \"\")\n .replace(/-/g, \"_\")\n .toLowerCase();\n}\n\nexport function getMigrationSlug(dir?: string): string {\n if (!dir) return normalizeSlug(process.env.npm_package_name ?? \"unknown\");\n let current = dir;\n for (let i = 0; i < 10; i++) {\n const pkgPath = join(current, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { name?: string };\n return normalizeSlug(pkg.name ?? current);\n } catch {\n return normalizeSlug(current);\n }\n }\n const parent = dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return normalizeSlug(dir);\n}\n\nexport function getMigrationStorage(\n slug?: string,\n options?: { isolated?: boolean },\n): MigrationStorage {\n const s = normalizeSlug(slug ?? getMigrationSlug());\n const isolated = options?.isolated ?? PER_PLUGIN_ISOLATION;\n if (isolated) {\n return {\n schema: DEFAULT_MIGRATION_JOURNAL.schema,\n table: `__drizzle_migrations_${s}`,\n slug: s,\n };\n }\n return {\n schema: DEFAULT_MIGRATION_JOURNAL.schema,\n table: DEFAULT_MIGRATION_JOURNAL.table,\n slug: s,\n };\n}\n\n/**\n * Format a JavaScript string array as a PostgreSQL text array literal for use\n * with Drizzle's `sql` tag. Example return:\n * `'{\"h1\",\"h2\"}'::text[]`\n *\n * Usage: sql`WHERE col = ANY(${toSqlArray(values)})`\n *\n * Drizzle's default parameter binding does not handle array types correctly\n * with the pg driver (it emits `ANY(($1))` with a single string, which\n * Postgres rejects as a malformed array literal).\n */\nexport function toSqlArray(arr: string[]): string {\n if (arr.length === 0) return `'{}'::text[]`;\n const escaped = arr.map((v) => v.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"'));\n return `'{${escaped.map((v) => `\"${v}\"`).join(\",\")}}'::text[]`;\n}\n\nexport function pluginMigrationSlug(key: string): string {\n return normalizeSlug(key);\n}\n\nexport function getDatabaseUrlSecretName(slug: string): string {\n return `${slug.toUpperCase().replace(/-/g, \"_\")}_DATABASE_URL`;\n}\n\nexport const DUPLICATE_OBJECT_SQLSTATES: readonly string[] = [\"42710\", \"42701\", \"42P07\"];\n\n/**\n * Walk `error` and its `cause` chain (bounded), invoking `visit` on each link.\n * Postgres driver errors arrive wrapped by drizzle/Effect at varying depths,\n * so every error-shape predicate below shares this traversal.\n */\nexport function visitCauses(\n error: unknown,\n depth: number,\n visit: (link: object) => boolean,\n): boolean {\n let current: unknown = error;\n for (let i = 0; i < depth && current; i++) {\n if (typeof current === \"object\" && current !== null && visit(current)) return true;\n current = (current as { cause?: unknown })?.cause;\n }\n return false;\n}\n\n/**\n * pg_catalog unique indexes that can surface a concurrent-DDL race as SQLSTATE\n * 23505 instead of a duplicate-object class. When two connections run\n * `CREATE TABLE <name>` at the same time, the loser fails its insert into\n * `pg_type` (\"duplicate key value violates unique constraint\n * `pg_type_typname_nsp_index`\") rather than seeing 42P07, because the winner's\n * table is not yet committed. The same shape exists for schemas and other\n * relations.\n */\nconst CONCURRENT_DDL_CONSTRAINTS: ReadonlySet<string> = new Set([\n \"pg_type_typname_nsp_index\",\n \"pg_namespace_nspname_index\",\n \"pg_class_relname_nsp_index\",\n]);\n\n/**\n * Whether a SQLSTATE 23505 unique violation is the concurrent-DDL catalog\n * collision signature rather than a data-level constraint on a user table.\n * Data-level violations must keep failing loudly; only the pg_catalog indexes\n * above are treated as duplicate-DDL tolerance candidates.\n */\nexport function isConcurrentDdlUniqueViolation(error: unknown): boolean {\n return visitCauses(error, 6, (link) => {\n const { code, constraint, message } = link as {\n code?: unknown;\n constraint?: unknown;\n message?: unknown;\n };\n if (code !== \"23505\") return false;\n if (typeof constraint === \"string\" && CONCURRENT_DDL_CONSTRAINTS.has(constraint)) return true;\n if (typeof message !== \"string\") return false;\n for (const name of CONCURRENT_DDL_CONSTRAINTS) {\n if (message.includes(name)) return true;\n }\n return false;\n });\n}\n\nconst RETRYABLE_SQLSTATES: ReadonlySet<string> = new Set([\n \"42P06\",\n \"42710\",\n \"42701\",\n \"42P07\",\n \"23505\",\n \"40001\",\n \"40P01\",\n \"55P03\",\n]);\n\nconst RETRYABLE_DRIVER_CODES: ReadonlySet<string> = new Set([\n \"ECONNREFUSED\",\n \"ECONNRESET\",\n \"EPIPE\",\n \"ETIMEDOUT\",\n \"ENOTFOUND\",\n \"EAI_AGAIN\",\n]);\n\nfunction matchesRetryableStates(error: unknown, states: ReadonlySet<string>): boolean {\n return visitCauses(error, 6, (link) => {\n const code = (link as { code?: unknown }).code;\n if (typeof code !== \"string\") return false;\n return states.has(code) || code.startsWith(\"08\") || RETRYABLE_DRIVER_CODES.has(code);\n });\n}\n\n/**\n * Decide whether a failed migration-init statement (schema/journal creation)\n * is worth retrying. Covers the concurrent `CREATE SCHEMA IF NOT EXISTS`\n * race (unique violation on `pg_namespace`, duplicate-object errors),\n * serialization/deadlock errors, and transient connection failures.\n */\nexport function isRetryableMigrationError(error: unknown): boolean {\n return matchesRetryableStates(error, RETRYABLE_SQLSTATES);\n}\n\nconst RETRYABLE_STATEMENT_SQLSTATES: ReadonlySet<string> = new Set([\n \"40001\", // serialization_failure\n \"40P01\", // deadlock_detected\n \"55P03\", // lock_not_available\n]);\n\n/**\n * Decide whether a failed migration *statement* (inside its transaction) is\n * worth retrying. Deliberately narrower than `isRetryableMigrationError`:\n * duplicate-object classes are tolerated at the SAVEPOINT level, and a 23505\n * is either the concurrent-DDL catalog collision (also tolerated) or a\n * deterministic data-level violation (retrying is pointless) — so only\n * lock/serialization/transient-connection states justify re-running the\n * transaction.\n */\nexport function isRetryableMigrationExecutionError(error: unknown): boolean {\n return matchesRetryableStates(error, RETRYABLE_STATEMENT_SQLSTATES);\n}\n\nconst PG_QUERY_QUEUE_DEPRECATION = \"client.query() when the client is already executing a query\";\n\nlet pgWarningFilterInstalled = false;\n\n/**\n * Silence pg's query-queue deprecation warning (fires once per process from\n * pg-pool's internal dispatch under concurrent boot load — node-postgres#3612,\n * #3617). Node's default warning handler prints even when user listeners are\n * attached, so it is removed first; every other warning is re-printed here.\n */\nexport function suppressPgQueryQueueDeprecation(): void {\n if (pgWarningFilterInstalled) return;\n if (typeof process === \"undefined\" || typeof process.on !== \"function\") return;\n pgWarningFilterInstalled = true;\n process.removeAllListeners(\"warning\");\n process.on(\"warning\", (warning) => {\n if (\n warning.name === \"DeprecationWarning\" &&\n warning.message.includes(PG_QUERY_QUEUE_DEPRECATION)\n ) {\n return;\n }\n console.error(warning.stack || `${warning.name}: ${warning.message}`);\n });\n}\n\nexport function extractExpectedTables(migrations: { sql: string[] }[]): string[] {\n const tables = new Set<string>();\n const re = /CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:\"([^\"]+)\"\\.)?\"([^\"]+)\"/gi;\n for (const migration of migrations) {\n for (const stmt of migration.sql) {\n for (const match of stmt.matchAll(re)) {\n const tableName = match[2];\n if (tableName) {\n tables.add(tableName);\n }\n }\n }\n }\n return [...tables];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.cjs","names":["join","existsSync","readFileSync","dirname"],"sources":["../../src/db/core.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport interface MigrationStorage {\n schema: string;\n table: string;\n slug: string;\n}\n\nconst DEFAULT_MIGRATION_JOURNAL = {\n schema: \"drizzle\",\n table: \"__drizzle_migrations\",\n} as const;\n\nconst PER_PLUGIN_ISOLATION = false;\n\nexport function normalizeSlug(name: string): string {\n const basename = name.split(\"/\").pop() ?? name;\n return basename\n .replace(/^@/, \"\")\n .replace(/[^a-zA-Z0-9_-]/g, \"_\")\n .replace(/-plugin$/i, \"\")\n .replace(/-/g, \"_\")\n .toLowerCase();\n}\n\nexport function getMigrationSlug(dir?: string): string {\n if (!dir) return normalizeSlug(process.env.npm_package_name ?? \"unknown\");\n let current = dir;\n for (let i = 0; i < 10; i++) {\n const pkgPath = join(current, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { name?: string };\n return normalizeSlug(pkg.name ?? current);\n } catch {\n return normalizeSlug(current);\n }\n }\n const parent = dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return normalizeSlug(dir);\n}\n\nexport function getMigrationStorage(\n slug?: string,\n options?: { isolated?: boolean },\n): MigrationStorage {\n const s = normalizeSlug(slug ?? getMigrationSlug());\n const isolated = options?.isolated ?? PER_PLUGIN_ISOLATION;\n if (isolated) {\n return {\n schema: DEFAULT_MIGRATION_JOURNAL.schema,\n table: `__drizzle_migrations_${s}`,\n slug: s,\n };\n }\n return {\n schema: DEFAULT_MIGRATION_JOURNAL.schema,\n table: DEFAULT_MIGRATION_JOURNAL.table,\n slug: s,\n };\n}\n\n/**\n * Format a JavaScript string array as a PostgreSQL text array literal for use\n * with Drizzle's `sql` tag. Example return:\n * `'{\"h1\",\"h2\"}'::text[]`\n *\n * Usage: sql`WHERE col = ANY(${toSqlArray(values)})`\n *\n * Drizzle's default parameter binding does not handle array types correctly\n * with the pg driver (it emits `ANY(($1))` with a single string, which\n * Postgres rejects as a malformed array literal).\n */\nexport function toSqlArray(arr: string[]): string {\n if (arr.length === 0) return `'{}'::text[]`;\n const escaped = arr.map((v) => v.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"'));\n return `'{${escaped.map((v) => `\"${v}\"`).join(\",\")}}'::text[]`;\n}\n\nexport function pluginMigrationSlug(key: string): string {\n return normalizeSlug(key);\n}\n\nexport function getDatabaseUrlSecretName(slug: string): string {\n return `${slug.toUpperCase().replace(/-/g, \"_\")}_DATABASE_URL`;\n}\n\nexport const DUPLICATE_OBJECT_SQLSTATES: readonly string[] = [\"42710\", \"42701\", \"42P07\"];\n\n/**\n * Walk `error` and its `cause` chain (bounded), invoking `visit` on each link.\n * Postgres driver errors arrive wrapped by drizzle/Effect at varying depths,\n * so every error-shape predicate below shares this traversal.\n */\nexport function visitCauses(\n error: unknown,\n depth: number,\n visit: (link: object) => boolean,\n): boolean {\n let current: unknown = error;\n for (let i = 0; i < depth && current; i++) {\n if (typeof current === \"object\" && current !== null && visit(current)) return true;\n current = (current as { cause?: unknown })?.cause;\n }\n return false;\n}\n\n/**\n * pg_catalog unique indexes that can surface a concurrent-DDL race as SQLSTATE\n * 23505 instead of a duplicate-object class. When two connections run\n * `CREATE TABLE <name>` at the same time, the loser fails its insert into\n * `pg_type` (\"duplicate key value violates unique constraint\n * `pg_type_typname_nsp_index`\") rather than seeing 42P07, because the winner's\n * table is not yet committed. The same shape exists for schemas and other\n * relations.\n */\nconst CONCURRENT_DDL_CONSTRAINTS: ReadonlySet<string> = new Set([\n \"pg_type_typname_nsp_index\",\n \"pg_namespace_nspname_index\",\n \"pg_class_relname_nsp_index\",\n]);\n\n/**\n * Whether a SQLSTATE 23505 unique violation is the concurrent-DDL catalog\n * collision signature rather than a data-level constraint on a user table.\n * Data-level violations must keep failing loudly; only the pg_catalog indexes\n * above are treated as duplicate-DDL tolerance candidates.\n */\nexport function isConcurrentDdlUniqueViolation(error: unknown): boolean {\n return visitCauses(error, 6, (link) => {\n const { code, constraint, message } = link as {\n code?: unknown;\n constraint?: unknown;\n message?: unknown;\n };\n if (code !== \"23505\") return false;\n if (typeof constraint === \"string\" && CONCURRENT_DDL_CONSTRAINTS.has(constraint)) return true;\n if (typeof message !== \"string\") return false;\n for (const name of CONCURRENT_DDL_CONSTRAINTS) {\n if (message.includes(name)) return true;\n }\n return false;\n });\n}\n\nconst RETRYABLE_SQLSTATES: ReadonlySet<string> = new Set([\n \"42P06\",\n \"42710\",\n \"42701\",\n \"42P07\",\n \"23505\",\n \"40001\",\n \"40P01\",\n \"55P03\",\n]);\n\nconst RETRYABLE_DRIVER_CODES: ReadonlySet<string> = new Set([\n \"ECONNREFUSED\",\n \"ECONNRESET\",\n \"EPIPE\",\n \"ETIMEDOUT\",\n \"ENOTFOUND\",\n \"EAI_AGAIN\",\n]);\n\nfunction matchesRetryableStates(error: unknown, states: ReadonlySet<string>): boolean {\n return visitCauses(error, 6, (link) => {\n const code = (link as { code?: unknown }).code;\n if (typeof code !== \"string\") return false;\n return states.has(code) || code.startsWith(\"08\") || RETRYABLE_DRIVER_CODES.has(code);\n });\n}\n\n/**\n * Decide whether a failed migration-init statement (schema/journal creation)\n * is worth retrying. Covers the concurrent `CREATE SCHEMA IF NOT EXISTS`\n * race (unique violation on `pg_namespace`, duplicate-object errors),\n * serialization/deadlock errors, and transient connection failures.\n */\nexport function isRetryableMigrationError(error: unknown): boolean {\n return matchesRetryableStates(error, RETRYABLE_SQLSTATES);\n}\n\nconst RETRYABLE_STATEMENT_SQLSTATES: ReadonlySet<string> = new Set([\n \"40001\", // serialization_failure\n \"40P01\", // deadlock_detected\n \"55P03\", // lock_not_available\n]);\n\n/**\n * Decide whether a failed migration *statement* (inside its transaction) is\n * worth retrying. Deliberately narrower than `isRetryableMigrationError`:\n * duplicate-object classes are tolerated at the SAVEPOINT level, and a 23505\n * is either the concurrent-DDL catalog collision (also tolerated) or a\n * deterministic data-level violation (retrying is pointless) — so only\n * lock/serialization/transient-connection states justify re-running the\n * transaction.\n */\nexport function isRetryableMigrationExecutionError(error: unknown): boolean {\n return matchesRetryableStates(error, RETRYABLE_STATEMENT_SQLSTATES);\n}\n\nconst PG_QUERY_QUEUE_DEPRECATION = \"client.query() when the client is already executing a query\";\n\nlet pgWarningFilterInstalled = false;\n\n/**\n * Silence pg's query-queue deprecation warning (fires once per process from\n * pg-pool's internal dispatch under concurrent boot load — node-postgres#3612,\n * #3617). Node's default warning handler prints even when user listeners are\n * attached, so it is removed first; every other warning is re-printed here.\n */\nexport function suppressPgQueryQueueDeprecation(): void {\n if (pgWarningFilterInstalled) return;\n if (typeof process === \"undefined\" || typeof process.on !== \"function\") return;\n pgWarningFilterInstalled = true;\n process.removeAllListeners(\"warning\");\n process.on(\"warning\", (warning) => {\n if (\n warning.name === \"DeprecationWarning\" &&\n warning.message.includes(PG_QUERY_QUEUE_DEPRECATION)\n ) {\n return;\n }\n console.error(warning.stack || `${warning.name}: ${warning.message}`);\n });\n}\n\nexport function extractExpectedTables(migrations: { sql: string[] }[]): string[] {\n const tables = new Set<string>();\n const ident = String.raw`(?:\"([^\"]+)\"|(\\w+))`;\n const qualified = String.raw`(?:${ident}\\.)?`;\n const createRe = new RegExp(\n String.raw`CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?${qualified}${ident}`,\n \"gi\",\n );\n const dropRe = new RegExp(\n String.raw`DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?${qualified}${ident}`,\n \"gi\",\n );\n const renameRe = new RegExp(\n String.raw`ALTER\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?${qualified}${ident}${String.raw`\\s+RENAME\\s+TO\\s+`}${ident}`,\n \"gi\",\n );\n for (const migration of migrations) {\n for (const stmt of migration.sql) {\n for (const match of stmt.matchAll(createRe)) {\n const tableName = match[3] ?? match[4];\n if (tableName) {\n tables.add(tableName);\n }\n }\n for (const match of stmt.matchAll(dropRe)) {\n const tableName = match[3] ?? match[4];\n if (tableName) {\n tables.delete(tableName);\n }\n }\n for (const match of stmt.matchAll(renameRe)) {\n const from = match[3] ?? match[4];\n const to = match[5] ?? match[6];\n if (from && to) {\n tables.delete(from);\n tables.add(to);\n }\n }\n }\n }\n return [...tables];\n}\n"],"mappings":";;;;AASA,MAAM,4BAA4B;CAChC,QAAQ;CACR,OAAO;AACT;AAEA,MAAM,uBAAuB;AAE7B,SAAgB,cAAc,MAAsB;CAElD,QADiB,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,KAC3B,CACZ,QAAQ,MAAM,EAAE,CAAC,CACjB,QAAQ,mBAAmB,GAAG,CAAC,CAC/B,QAAQ,aAAa,EAAE,CAAC,CACxB,QAAQ,MAAM,GAAG,CAAC,CAClB,YAAY;AACjB;AAEA,SAAgB,iBAAiB,KAAsB;CACrD,IAAI,CAAC,KAAK,OAAO,cAAc,QAAQ,IAAI,oBAAoB,SAAS;CACxE,IAAI,UAAU;CACd,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,cAAUA,gBAAK,SAAS,cAAc;EAC5C,QAAIC,oBAAW,OAAO,GACpB,IAAI;GAEF,OAAO,cADK,KAAK,UAAMC,sBAAa,SAAS,OAAO,CAC7B,CAAC,CAAC,QAAQ,OAAO;EAC1C,QAAQ;GACN,OAAO,cAAc,OAAO;EAC9B;EAEF,MAAM,aAASC,mBAAQ,OAAO;EAC9B,IAAI,WAAW,SAAS;EACxB,UAAU;CACZ;CACA,OAAO,cAAc,GAAG;AAC1B;AAEA,SAAgB,oBACd,MACA,SACkB;CAClB,MAAM,IAAI,cAAc,QAAQ,iBAAiB,CAAC;CAElD,IADiB,SAAS,YAAY,sBAEpC,OAAO;EACL,QAAQ,0BAA0B;EAClC,OAAO,wBAAwB;EAC/B,MAAM;CACR;CAEF,OAAO;EACL,QAAQ,0BAA0B;EAClC,OAAO,0BAA0B;EACjC,MAAM;CACR;AACF;;;;;;;;;;;;AAaA,SAAgB,WAAW,KAAuB;CAChD,IAAI,IAAI,WAAW,GAAG,OAAO;CAE7B,OAAO,KADS,IAAI,KAAK,MAAM,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAK,CACzD,CAAC,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,EAAE;AACrD;AAEA,SAAgB,oBAAoB,KAAqB;CACvD,OAAO,cAAc,GAAG;AAC1B;AAEA,SAAgB,yBAAyB,MAAsB;CAC7D,OAAO,GAAG,KAAK,YAAY,CAAC,CAAC,QAAQ,MAAM,GAAG,EAAE;AAClD;AAEA,MAAa,6BAAgD;CAAC;CAAS;CAAS;AAAO;;;;;;AAOvF,SAAgB,YACd,OACA,OACA,OACS;CACT,IAAI,UAAmB;CACvB,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,SAAS,KAAK;EACzC,IAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,MAAM,OAAO,GAAG,OAAO;EAC9E,UAAW,SAAiC;CAC9C;CACA,OAAO;AACT;;;;;;;;;;AAWA,MAAM,6CAAkD,IAAI,IAAI;CAC9D;CACA;CACA;AACF,CAAC;;;;;;;AAQD,SAAgB,+BAA+B,OAAyB;CACtE,OAAO,YAAY,OAAO,IAAI,SAAS;EACrC,MAAM,EAAE,MAAM,YAAY,YAAY;EAKtC,IAAI,SAAS,SAAS,OAAO;EAC7B,IAAI,OAAO,eAAe,YAAY,2BAA2B,IAAI,UAAU,GAAG,OAAO;EACzF,IAAI,OAAO,YAAY,UAAU,OAAO;EACxC,KAAK,MAAM,QAAQ,4BACjB,IAAI,QAAQ,SAAS,IAAI,GAAG,OAAO;EAErC,OAAO;CACT,CAAC;AACH;AAEA,MAAM,sCAA2C,IAAI,IAAI;CACvD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,yCAA8C,IAAI,IAAI;CAC1D;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,uBAAuB,OAAgB,QAAsC;CACpF,OAAO,YAAY,OAAO,IAAI,SAAS;EACrC,MAAM,OAAQ,KAA4B;EAC1C,IAAI,OAAO,SAAS,UAAU,OAAO;EACrC,OAAO,OAAO,IAAI,IAAI,KAAK,KAAK,WAAW,IAAI,KAAK,uBAAuB,IAAI,IAAI;CACrF,CAAC;AACH;;;;;;;AAQA,SAAgB,0BAA0B,OAAyB;CACjE,OAAO,uBAAuB,OAAO,mBAAmB;AAC1D;AAEA,MAAM,gDAAqD,IAAI,IAAI;CACjE;CACA;CACA;AACF,CAAC;;;;;;;;;;AAWD,SAAgB,mCAAmC,OAAyB;CAC1E,OAAO,uBAAuB,OAAO,6BAA6B;AACpE;AAEA,MAAM,6BAA6B;AAEnC,IAAI,2BAA2B;;;;;;;AAQ/B,SAAgB,kCAAwC;CACtD,IAAI,0BAA0B;CAC9B,IAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,OAAO,YAAY;CACxE,2BAA2B;CAC3B,QAAQ,mBAAmB,SAAS;CACpC,QAAQ,GAAG,YAAY,YAAY;EACjC,IACE,QAAQ,SAAS,wBACjB,QAAQ,QAAQ,SAAS,0BAA0B,GAEnD;EAEF,QAAQ,MAAM,QAAQ,SAAS,GAAG,QAAQ,KAAK,IAAI,QAAQ,SAAS;CACtE,CAAC;AACH;AAEA,SAAgB,sBAAsB,YAA2C;CAC/E,MAAM,yBAAS,IAAI,IAAY;CAC/B,MAAM,QAAQ,OAAO,GAAG;CACxB,MAAM,YAAY,OAAO,GAAG,MAAM,MAAM;CACxC,MAAM,WAAW,IAAI,OACnB,OAAO,GAAG,6CAA6C,YAAY,SACnE,IACF;CACA,MAAM,SAAS,IAAI,OACjB,OAAO,GAAG,qCAAqC,YAAY,SAC3D,IACF;CACA,MAAM,WAAW,IAAI,OACnB,OAAO,GAAG,sCAAsC,YAAY,QAAQ,OAAO,GAAG,sBAAsB,SACpG,IACF;CACA,KAAK,MAAM,aAAa,YACtB,KAAK,MAAM,QAAQ,UAAU,KAAK;EAChC,KAAK,MAAM,SAAS,KAAK,SAAS,QAAQ,GAAG;GAC3C,MAAM,YAAY,MAAM,MAAM,MAAM;GACpC,IAAI,WACF,OAAO,IAAI,SAAS;EAExB;EACA,KAAK,MAAM,SAAS,KAAK,SAAS,MAAM,GAAG;GACzC,MAAM,YAAY,MAAM,MAAM,MAAM;GACpC,IAAI,WACF,OAAO,OAAO,SAAS;EAE3B;EACA,KAAK,MAAM,SAAS,KAAK,SAAS,QAAQ,GAAG;GAC3C,MAAM,OAAO,MAAM,MAAM,MAAM;GAC/B,MAAM,KAAK,MAAM,MAAM,MAAM;GAC7B,IAAI,QAAQ,IAAI;IACd,OAAO,OAAO,IAAI;IAClB,OAAO,IAAI,EAAE;GACf;EACF;CACF;CAEF,OAAO,CAAC,GAAG,MAAM;AACnB"}
|
package/dist/db/core.mjs
CHANGED
|
@@ -179,10 +179,28 @@ function suppressPgQueryQueueDeprecation() {
|
|
|
179
179
|
}
|
|
180
180
|
function extractExpectedTables(migrations) {
|
|
181
181
|
const tables = /* @__PURE__ */ new Set();
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
const ident = String.raw`(?:"([^"]+)"|(\w+))`;
|
|
183
|
+
const qualified = String.raw`(?:${ident}\.)?`;
|
|
184
|
+
const createRe = new RegExp(String.raw`CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?${qualified}${ident}`, "gi");
|
|
185
|
+
const dropRe = new RegExp(String.raw`DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?${qualified}${ident}`, "gi");
|
|
186
|
+
const renameRe = new RegExp(String.raw`ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?${qualified}${ident}${String.raw`\s+RENAME\s+TO\s+`}${ident}`, "gi");
|
|
187
|
+
for (const migration of migrations) for (const stmt of migration.sql) {
|
|
188
|
+
for (const match of stmt.matchAll(createRe)) {
|
|
189
|
+
const tableName = match[3] ?? match[4];
|
|
190
|
+
if (tableName) tables.add(tableName);
|
|
191
|
+
}
|
|
192
|
+
for (const match of stmt.matchAll(dropRe)) {
|
|
193
|
+
const tableName = match[3] ?? match[4];
|
|
194
|
+
if (tableName) tables.delete(tableName);
|
|
195
|
+
}
|
|
196
|
+
for (const match of stmt.matchAll(renameRe)) {
|
|
197
|
+
const from = match[3] ?? match[4];
|
|
198
|
+
const to = match[5] ?? match[6];
|
|
199
|
+
if (from && to) {
|
|
200
|
+
tables.delete(from);
|
|
201
|
+
tables.add(to);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
186
204
|
}
|
|
187
205
|
return [...tables];
|
|
188
206
|
}
|
package/dist/db/core.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.mjs","names":[],"sources":["../../src/db/core.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport interface MigrationStorage {\n schema: string;\n table: string;\n slug: string;\n}\n\nconst DEFAULT_MIGRATION_JOURNAL = {\n schema: \"drizzle\",\n table: \"__drizzle_migrations\",\n} as const;\n\nconst PER_PLUGIN_ISOLATION = false;\n\nexport function normalizeSlug(name: string): string {\n const basename = name.split(\"/\").pop() ?? name;\n return basename\n .replace(/^@/, \"\")\n .replace(/[^a-zA-Z0-9_-]/g, \"_\")\n .replace(/-plugin$/i, \"\")\n .replace(/-/g, \"_\")\n .toLowerCase();\n}\n\nexport function getMigrationSlug(dir?: string): string {\n if (!dir) return normalizeSlug(process.env.npm_package_name ?? \"unknown\");\n let current = dir;\n for (let i = 0; i < 10; i++) {\n const pkgPath = join(current, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { name?: string };\n return normalizeSlug(pkg.name ?? current);\n } catch {\n return normalizeSlug(current);\n }\n }\n const parent = dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return normalizeSlug(dir);\n}\n\nexport function getMigrationStorage(\n slug?: string,\n options?: { isolated?: boolean },\n): MigrationStorage {\n const s = normalizeSlug(slug ?? getMigrationSlug());\n const isolated = options?.isolated ?? PER_PLUGIN_ISOLATION;\n if (isolated) {\n return {\n schema: DEFAULT_MIGRATION_JOURNAL.schema,\n table: `__drizzle_migrations_${s}`,\n slug: s,\n };\n }\n return {\n schema: DEFAULT_MIGRATION_JOURNAL.schema,\n table: DEFAULT_MIGRATION_JOURNAL.table,\n slug: s,\n };\n}\n\n/**\n * Format a JavaScript string array as a PostgreSQL text array literal for use\n * with Drizzle's `sql` tag. Example return:\n * `'{\"h1\",\"h2\"}'::text[]`\n *\n * Usage: sql`WHERE col = ANY(${toSqlArray(values)})`\n *\n * Drizzle's default parameter binding does not handle array types correctly\n * with the pg driver (it emits `ANY(($1))` with a single string, which\n * Postgres rejects as a malformed array literal).\n */\nexport function toSqlArray(arr: string[]): string {\n if (arr.length === 0) return `'{}'::text[]`;\n const escaped = arr.map((v) => v.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"'));\n return `'{${escaped.map((v) => `\"${v}\"`).join(\",\")}}'::text[]`;\n}\n\nexport function pluginMigrationSlug(key: string): string {\n return normalizeSlug(key);\n}\n\nexport function getDatabaseUrlSecretName(slug: string): string {\n return `${slug.toUpperCase().replace(/-/g, \"_\")}_DATABASE_URL`;\n}\n\nexport const DUPLICATE_OBJECT_SQLSTATES: readonly string[] = [\"42710\", \"42701\", \"42P07\"];\n\n/**\n * Walk `error` and its `cause` chain (bounded), invoking `visit` on each link.\n * Postgres driver errors arrive wrapped by drizzle/Effect at varying depths,\n * so every error-shape predicate below shares this traversal.\n */\nexport function visitCauses(\n error: unknown,\n depth: number,\n visit: (link: object) => boolean,\n): boolean {\n let current: unknown = error;\n for (let i = 0; i < depth && current; i++) {\n if (typeof current === \"object\" && current !== null && visit(current)) return true;\n current = (current as { cause?: unknown })?.cause;\n }\n return false;\n}\n\n/**\n * pg_catalog unique indexes that can surface a concurrent-DDL race as SQLSTATE\n * 23505 instead of a duplicate-object class. When two connections run\n * `CREATE TABLE <name>` at the same time, the loser fails its insert into\n * `pg_type` (\"duplicate key value violates unique constraint\n * `pg_type_typname_nsp_index`\") rather than seeing 42P07, because the winner's\n * table is not yet committed. The same shape exists for schemas and other\n * relations.\n */\nconst CONCURRENT_DDL_CONSTRAINTS: ReadonlySet<string> = new Set([\n \"pg_type_typname_nsp_index\",\n \"pg_namespace_nspname_index\",\n \"pg_class_relname_nsp_index\",\n]);\n\n/**\n * Whether a SQLSTATE 23505 unique violation is the concurrent-DDL catalog\n * collision signature rather than a data-level constraint on a user table.\n * Data-level violations must keep failing loudly; only the pg_catalog indexes\n * above are treated as duplicate-DDL tolerance candidates.\n */\nexport function isConcurrentDdlUniqueViolation(error: unknown): boolean {\n return visitCauses(error, 6, (link) => {\n const { code, constraint, message } = link as {\n code?: unknown;\n constraint?: unknown;\n message?: unknown;\n };\n if (code !== \"23505\") return false;\n if (typeof constraint === \"string\" && CONCURRENT_DDL_CONSTRAINTS.has(constraint)) return true;\n if (typeof message !== \"string\") return false;\n for (const name of CONCURRENT_DDL_CONSTRAINTS) {\n if (message.includes(name)) return true;\n }\n return false;\n });\n}\n\nconst RETRYABLE_SQLSTATES: ReadonlySet<string> = new Set([\n \"42P06\",\n \"42710\",\n \"42701\",\n \"42P07\",\n \"23505\",\n \"40001\",\n \"40P01\",\n \"55P03\",\n]);\n\nconst RETRYABLE_DRIVER_CODES: ReadonlySet<string> = new Set([\n \"ECONNREFUSED\",\n \"ECONNRESET\",\n \"EPIPE\",\n \"ETIMEDOUT\",\n \"ENOTFOUND\",\n \"EAI_AGAIN\",\n]);\n\nfunction matchesRetryableStates(error: unknown, states: ReadonlySet<string>): boolean {\n return visitCauses(error, 6, (link) => {\n const code = (link as { code?: unknown }).code;\n if (typeof code !== \"string\") return false;\n return states.has(code) || code.startsWith(\"08\") || RETRYABLE_DRIVER_CODES.has(code);\n });\n}\n\n/**\n * Decide whether a failed migration-init statement (schema/journal creation)\n * is worth retrying. Covers the concurrent `CREATE SCHEMA IF NOT EXISTS`\n * race (unique violation on `pg_namespace`, duplicate-object errors),\n * serialization/deadlock errors, and transient connection failures.\n */\nexport function isRetryableMigrationError(error: unknown): boolean {\n return matchesRetryableStates(error, RETRYABLE_SQLSTATES);\n}\n\nconst RETRYABLE_STATEMENT_SQLSTATES: ReadonlySet<string> = new Set([\n \"40001\", // serialization_failure\n \"40P01\", // deadlock_detected\n \"55P03\", // lock_not_available\n]);\n\n/**\n * Decide whether a failed migration *statement* (inside its transaction) is\n * worth retrying. Deliberately narrower than `isRetryableMigrationError`:\n * duplicate-object classes are tolerated at the SAVEPOINT level, and a 23505\n * is either the concurrent-DDL catalog collision (also tolerated) or a\n * deterministic data-level violation (retrying is pointless) — so only\n * lock/serialization/transient-connection states justify re-running the\n * transaction.\n */\nexport function isRetryableMigrationExecutionError(error: unknown): boolean {\n return matchesRetryableStates(error, RETRYABLE_STATEMENT_SQLSTATES);\n}\n\nconst PG_QUERY_QUEUE_DEPRECATION = \"client.query() when the client is already executing a query\";\n\nlet pgWarningFilterInstalled = false;\n\n/**\n * Silence pg's query-queue deprecation warning (fires once per process from\n * pg-pool's internal dispatch under concurrent boot load — node-postgres#3612,\n * #3617). Node's default warning handler prints even when user listeners are\n * attached, so it is removed first; every other warning is re-printed here.\n */\nexport function suppressPgQueryQueueDeprecation(): void {\n if (pgWarningFilterInstalled) return;\n if (typeof process === \"undefined\" || typeof process.on !== \"function\") return;\n pgWarningFilterInstalled = true;\n process.removeAllListeners(\"warning\");\n process.on(\"warning\", (warning) => {\n if (\n warning.name === \"DeprecationWarning\" &&\n warning.message.includes(PG_QUERY_QUEUE_DEPRECATION)\n ) {\n return;\n }\n console.error(warning.stack || `${warning.name}: ${warning.message}`);\n });\n}\n\nexport function extractExpectedTables(migrations: { sql: string[] }[]): string[] {\n const tables = new Set<string>();\n const re = /CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:\"([^\"]+)\"\\.)?\"([^\"]+)\"/gi;\n for (const migration of migrations) {\n for (const stmt of migration.sql) {\n for (const match of stmt.matchAll(re)) {\n const tableName = match[2];\n if (tableName) {\n tables.add(tableName);\n }\n }\n }\n }\n return [...tables];\n}\n"],"mappings":";;;;AASA,MAAM,4BAA4B;CAChC,QAAQ;CACR,OAAO;AACT;AAEA,MAAM,uBAAuB;AAE7B,SAAgB,cAAc,MAAsB;CAElD,QADiB,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,KAC3B,CACZ,QAAQ,MAAM,EAAE,CAAC,CACjB,QAAQ,mBAAmB,GAAG,CAAC,CAC/B,QAAQ,aAAa,EAAE,CAAC,CACxB,QAAQ,MAAM,GAAG,CAAC,CAClB,YAAY;AACjB;AAEA,SAAgB,iBAAiB,KAAsB;CACrD,IAAI,CAAC,KAAK,OAAO,cAAc,QAAQ,IAAI,oBAAoB,SAAS;CACxE,IAAI,UAAU;CACd,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,UAAU,KAAK,SAAS,cAAc;EAC5C,IAAI,WAAW,OAAO,GACpB,IAAI;GAEF,OAAO,cADK,KAAK,MAAM,aAAa,SAAS,OAAO,CAC7B,CAAC,CAAC,QAAQ,OAAO;EAC1C,QAAQ;GACN,OAAO,cAAc,OAAO;EAC9B;EAEF,MAAM,SAAS,QAAQ,OAAO;EAC9B,IAAI,WAAW,SAAS;EACxB,UAAU;CACZ;CACA,OAAO,cAAc,GAAG;AAC1B;AAEA,SAAgB,oBACd,MACA,SACkB;CAClB,MAAM,IAAI,cAAc,QAAQ,iBAAiB,CAAC;CAElD,IADiB,SAAS,YAAY,sBAEpC,OAAO;EACL,QAAQ,0BAA0B;EAClC,OAAO,wBAAwB;EAC/B,MAAM;CACR;CAEF,OAAO;EACL,QAAQ,0BAA0B;EAClC,OAAO,0BAA0B;EACjC,MAAM;CACR;AACF;;;;;;;;;;;;AAaA,SAAgB,WAAW,KAAuB;CAChD,IAAI,IAAI,WAAW,GAAG,OAAO;CAE7B,OAAO,KADS,IAAI,KAAK,MAAM,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAK,CACzD,CAAC,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,EAAE;AACrD;AAEA,SAAgB,oBAAoB,KAAqB;CACvD,OAAO,cAAc,GAAG;AAC1B;AAEA,SAAgB,yBAAyB,MAAsB;CAC7D,OAAO,GAAG,KAAK,YAAY,CAAC,CAAC,QAAQ,MAAM,GAAG,EAAE;AAClD;AAEA,MAAa,6BAAgD;CAAC;CAAS;CAAS;AAAO;;;;;;AAOvF,SAAgB,YACd,OACA,OACA,OACS;CACT,IAAI,UAAmB;CACvB,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,SAAS,KAAK;EACzC,IAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,MAAM,OAAO,GAAG,OAAO;EAC9E,UAAW,SAAiC;CAC9C;CACA,OAAO;AACT;;;;;;;;;;AAWA,MAAM,6CAAkD,IAAI,IAAI;CAC9D;CACA;CACA;AACF,CAAC;;;;;;;AAQD,SAAgB,+BAA+B,OAAyB;CACtE,OAAO,YAAY,OAAO,IAAI,SAAS;EACrC,MAAM,EAAE,MAAM,YAAY,YAAY;EAKtC,IAAI,SAAS,SAAS,OAAO;EAC7B,IAAI,OAAO,eAAe,YAAY,2BAA2B,IAAI,UAAU,GAAG,OAAO;EACzF,IAAI,OAAO,YAAY,UAAU,OAAO;EACxC,KAAK,MAAM,QAAQ,4BACjB,IAAI,QAAQ,SAAS,IAAI,GAAG,OAAO;EAErC,OAAO;CACT,CAAC;AACH;AAEA,MAAM,sCAA2C,IAAI,IAAI;CACvD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,yCAA8C,IAAI,IAAI;CAC1D;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,uBAAuB,OAAgB,QAAsC;CACpF,OAAO,YAAY,OAAO,IAAI,SAAS;EACrC,MAAM,OAAQ,KAA4B;EAC1C,IAAI,OAAO,SAAS,UAAU,OAAO;EACrC,OAAO,OAAO,IAAI,IAAI,KAAK,KAAK,WAAW,IAAI,KAAK,uBAAuB,IAAI,IAAI;CACrF,CAAC;AACH;;;;;;;AAQA,SAAgB,0BAA0B,OAAyB;CACjE,OAAO,uBAAuB,OAAO,mBAAmB;AAC1D;AAEA,MAAM,gDAAqD,IAAI,IAAI;CACjE;CACA;CACA;AACF,CAAC;;;;;;;;;;AAWD,SAAgB,mCAAmC,OAAyB;CAC1E,OAAO,uBAAuB,OAAO,6BAA6B;AACpE;AAEA,MAAM,6BAA6B;AAEnC,IAAI,2BAA2B;;;;;;;AAQ/B,SAAgB,kCAAwC;CACtD,IAAI,0BAA0B;CAC9B,IAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,OAAO,YAAY;CACxE,2BAA2B;CAC3B,QAAQ,mBAAmB,SAAS;CACpC,QAAQ,GAAG,YAAY,YAAY;EACjC,IACE,QAAQ,SAAS,wBACjB,QAAQ,QAAQ,SAAS,0BAA0B,GAEnD;EAEF,QAAQ,MAAM,QAAQ,SAAS,GAAG,QAAQ,KAAK,IAAI,QAAQ,SAAS;CACtE,CAAC;AACH;AAEA,SAAgB,sBAAsB,YAA2C;CAC/E,MAAM,yBAAS,IAAI,IAAY;CAC/B,MAAM,KAAK;CACX,KAAK,MAAM,aAAa,YACtB,KAAK,MAAM,QAAQ,UAAU,KAC3B,KAAK,MAAM,SAAS,KAAK,SAAS,EAAE,GAAG;EACrC,MAAM,YAAY,MAAM;EACxB,IAAI,WACF,OAAO,IAAI,SAAS;CAExB;CAGJ,OAAO,CAAC,GAAG,MAAM;AACnB"}
|
|
1
|
+
{"version":3,"file":"core.mjs","names":[],"sources":["../../src/db/core.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport interface MigrationStorage {\n schema: string;\n table: string;\n slug: string;\n}\n\nconst DEFAULT_MIGRATION_JOURNAL = {\n schema: \"drizzle\",\n table: \"__drizzle_migrations\",\n} as const;\n\nconst PER_PLUGIN_ISOLATION = false;\n\nexport function normalizeSlug(name: string): string {\n const basename = name.split(\"/\").pop() ?? name;\n return basename\n .replace(/^@/, \"\")\n .replace(/[^a-zA-Z0-9_-]/g, \"_\")\n .replace(/-plugin$/i, \"\")\n .replace(/-/g, \"_\")\n .toLowerCase();\n}\n\nexport function getMigrationSlug(dir?: string): string {\n if (!dir) return normalizeSlug(process.env.npm_package_name ?? \"unknown\");\n let current = dir;\n for (let i = 0; i < 10; i++) {\n const pkgPath = join(current, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { name?: string };\n return normalizeSlug(pkg.name ?? current);\n } catch {\n return normalizeSlug(current);\n }\n }\n const parent = dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return normalizeSlug(dir);\n}\n\nexport function getMigrationStorage(\n slug?: string,\n options?: { isolated?: boolean },\n): MigrationStorage {\n const s = normalizeSlug(slug ?? getMigrationSlug());\n const isolated = options?.isolated ?? PER_PLUGIN_ISOLATION;\n if (isolated) {\n return {\n schema: DEFAULT_MIGRATION_JOURNAL.schema,\n table: `__drizzle_migrations_${s}`,\n slug: s,\n };\n }\n return {\n schema: DEFAULT_MIGRATION_JOURNAL.schema,\n table: DEFAULT_MIGRATION_JOURNAL.table,\n slug: s,\n };\n}\n\n/**\n * Format a JavaScript string array as a PostgreSQL text array literal for use\n * with Drizzle's `sql` tag. Example return:\n * `'{\"h1\",\"h2\"}'::text[]`\n *\n * Usage: sql`WHERE col = ANY(${toSqlArray(values)})`\n *\n * Drizzle's default parameter binding does not handle array types correctly\n * with the pg driver (it emits `ANY(($1))` with a single string, which\n * Postgres rejects as a malformed array literal).\n */\nexport function toSqlArray(arr: string[]): string {\n if (arr.length === 0) return `'{}'::text[]`;\n const escaped = arr.map((v) => v.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"'));\n return `'{${escaped.map((v) => `\"${v}\"`).join(\",\")}}'::text[]`;\n}\n\nexport function pluginMigrationSlug(key: string): string {\n return normalizeSlug(key);\n}\n\nexport function getDatabaseUrlSecretName(slug: string): string {\n return `${slug.toUpperCase().replace(/-/g, \"_\")}_DATABASE_URL`;\n}\n\nexport const DUPLICATE_OBJECT_SQLSTATES: readonly string[] = [\"42710\", \"42701\", \"42P07\"];\n\n/**\n * Walk `error` and its `cause` chain (bounded), invoking `visit` on each link.\n * Postgres driver errors arrive wrapped by drizzle/Effect at varying depths,\n * so every error-shape predicate below shares this traversal.\n */\nexport function visitCauses(\n error: unknown,\n depth: number,\n visit: (link: object) => boolean,\n): boolean {\n let current: unknown = error;\n for (let i = 0; i < depth && current; i++) {\n if (typeof current === \"object\" && current !== null && visit(current)) return true;\n current = (current as { cause?: unknown })?.cause;\n }\n return false;\n}\n\n/**\n * pg_catalog unique indexes that can surface a concurrent-DDL race as SQLSTATE\n * 23505 instead of a duplicate-object class. When two connections run\n * `CREATE TABLE <name>` at the same time, the loser fails its insert into\n * `pg_type` (\"duplicate key value violates unique constraint\n * `pg_type_typname_nsp_index`\") rather than seeing 42P07, because the winner's\n * table is not yet committed. The same shape exists for schemas and other\n * relations.\n */\nconst CONCURRENT_DDL_CONSTRAINTS: ReadonlySet<string> = new Set([\n \"pg_type_typname_nsp_index\",\n \"pg_namespace_nspname_index\",\n \"pg_class_relname_nsp_index\",\n]);\n\n/**\n * Whether a SQLSTATE 23505 unique violation is the concurrent-DDL catalog\n * collision signature rather than a data-level constraint on a user table.\n * Data-level violations must keep failing loudly; only the pg_catalog indexes\n * above are treated as duplicate-DDL tolerance candidates.\n */\nexport function isConcurrentDdlUniqueViolation(error: unknown): boolean {\n return visitCauses(error, 6, (link) => {\n const { code, constraint, message } = link as {\n code?: unknown;\n constraint?: unknown;\n message?: unknown;\n };\n if (code !== \"23505\") return false;\n if (typeof constraint === \"string\" && CONCURRENT_DDL_CONSTRAINTS.has(constraint)) return true;\n if (typeof message !== \"string\") return false;\n for (const name of CONCURRENT_DDL_CONSTRAINTS) {\n if (message.includes(name)) return true;\n }\n return false;\n });\n}\n\nconst RETRYABLE_SQLSTATES: ReadonlySet<string> = new Set([\n \"42P06\",\n \"42710\",\n \"42701\",\n \"42P07\",\n \"23505\",\n \"40001\",\n \"40P01\",\n \"55P03\",\n]);\n\nconst RETRYABLE_DRIVER_CODES: ReadonlySet<string> = new Set([\n \"ECONNREFUSED\",\n \"ECONNRESET\",\n \"EPIPE\",\n \"ETIMEDOUT\",\n \"ENOTFOUND\",\n \"EAI_AGAIN\",\n]);\n\nfunction matchesRetryableStates(error: unknown, states: ReadonlySet<string>): boolean {\n return visitCauses(error, 6, (link) => {\n const code = (link as { code?: unknown }).code;\n if (typeof code !== \"string\") return false;\n return states.has(code) || code.startsWith(\"08\") || RETRYABLE_DRIVER_CODES.has(code);\n });\n}\n\n/**\n * Decide whether a failed migration-init statement (schema/journal creation)\n * is worth retrying. Covers the concurrent `CREATE SCHEMA IF NOT EXISTS`\n * race (unique violation on `pg_namespace`, duplicate-object errors),\n * serialization/deadlock errors, and transient connection failures.\n */\nexport function isRetryableMigrationError(error: unknown): boolean {\n return matchesRetryableStates(error, RETRYABLE_SQLSTATES);\n}\n\nconst RETRYABLE_STATEMENT_SQLSTATES: ReadonlySet<string> = new Set([\n \"40001\", // serialization_failure\n \"40P01\", // deadlock_detected\n \"55P03\", // lock_not_available\n]);\n\n/**\n * Decide whether a failed migration *statement* (inside its transaction) is\n * worth retrying. Deliberately narrower than `isRetryableMigrationError`:\n * duplicate-object classes are tolerated at the SAVEPOINT level, and a 23505\n * is either the concurrent-DDL catalog collision (also tolerated) or a\n * deterministic data-level violation (retrying is pointless) — so only\n * lock/serialization/transient-connection states justify re-running the\n * transaction.\n */\nexport function isRetryableMigrationExecutionError(error: unknown): boolean {\n return matchesRetryableStates(error, RETRYABLE_STATEMENT_SQLSTATES);\n}\n\nconst PG_QUERY_QUEUE_DEPRECATION = \"client.query() when the client is already executing a query\";\n\nlet pgWarningFilterInstalled = false;\n\n/**\n * Silence pg's query-queue deprecation warning (fires once per process from\n * pg-pool's internal dispatch under concurrent boot load — node-postgres#3612,\n * #3617). Node's default warning handler prints even when user listeners are\n * attached, so it is removed first; every other warning is re-printed here.\n */\nexport function suppressPgQueryQueueDeprecation(): void {\n if (pgWarningFilterInstalled) return;\n if (typeof process === \"undefined\" || typeof process.on !== \"function\") return;\n pgWarningFilterInstalled = true;\n process.removeAllListeners(\"warning\");\n process.on(\"warning\", (warning) => {\n if (\n warning.name === \"DeprecationWarning\" &&\n warning.message.includes(PG_QUERY_QUEUE_DEPRECATION)\n ) {\n return;\n }\n console.error(warning.stack || `${warning.name}: ${warning.message}`);\n });\n}\n\nexport function extractExpectedTables(migrations: { sql: string[] }[]): string[] {\n const tables = new Set<string>();\n const ident = String.raw`(?:\"([^\"]+)\"|(\\w+))`;\n const qualified = String.raw`(?:${ident}\\.)?`;\n const createRe = new RegExp(\n String.raw`CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?${qualified}${ident}`,\n \"gi\",\n );\n const dropRe = new RegExp(\n String.raw`DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?${qualified}${ident}`,\n \"gi\",\n );\n const renameRe = new RegExp(\n String.raw`ALTER\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?${qualified}${ident}${String.raw`\\s+RENAME\\s+TO\\s+`}${ident}`,\n \"gi\",\n );\n for (const migration of migrations) {\n for (const stmt of migration.sql) {\n for (const match of stmt.matchAll(createRe)) {\n const tableName = match[3] ?? match[4];\n if (tableName) {\n tables.add(tableName);\n }\n }\n for (const match of stmt.matchAll(dropRe)) {\n const tableName = match[3] ?? match[4];\n if (tableName) {\n tables.delete(tableName);\n }\n }\n for (const match of stmt.matchAll(renameRe)) {\n const from = match[3] ?? match[4];\n const to = match[5] ?? match[6];\n if (from && to) {\n tables.delete(from);\n tables.add(to);\n }\n }\n }\n }\n return [...tables];\n}\n"],"mappings":"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"}
|
|
@@ -253,6 +253,12 @@ function createLogPipeline(options) {
|
|
|
253
253
|
});
|
|
254
254
|
if (completed !== null) emit(completed.meta, completed.text);
|
|
255
255
|
},
|
|
256
|
+
flushSource: (source) => {
|
|
257
|
+
const state = normalizers.get(source);
|
|
258
|
+
if (!state) return;
|
|
259
|
+
const completed = drainState(state);
|
|
260
|
+
if (completed !== null) emit(completed.meta, completed.text);
|
|
261
|
+
},
|
|
256
262
|
flush: () => {
|
|
257
263
|
for (const state of normalizers.values()) {
|
|
258
264
|
const completed = drainState(state);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-log-pipeline.cjs","names":[],"sources":["../src/dev-log-pipeline.ts"],"sourcesContent":["const ESC = \"\\x1b\";\nconst BEL = \"\\x07\";\nconst ANSI_RE = new RegExp(`${ESC}\\\\[[0-?]*[ -/]*[@-~]|${ESC}\\\\][^${BEL}]*${BEL}`, \"g\");\n\nexport const stripAnsi = (input: string): string => input.replace(ANSI_RE, \"\");\n\nexport type LogLevel = \"error\" | \"warn\" | \"info\" | \"debug\";\n\nexport type LogCategory = \"banner\" | \"build\" | \"db\" | \"mf\" | \"lifecycle\" | \"shutdown\" | \"other\";\n\nexport interface RawLogLine {\n source: string;\n line: string;\n isError?: boolean;\n timestamp?: number;\n}\n\nexport interface LogEvent {\n timestamp: number;\n source: string;\n line: string;\n isError: boolean;\n level: LogLevel;\n category: LogCategory;\n}\n\nconst LEVEL_RANK: Record<LogLevel, number> = { error: 0, warn: 1, info: 2, debug: 3 };\n\nconst LOG_LEVELS: readonly LogLevel[] = [\"error\", \"warn\", \"info\", \"debug\"];\n\nexport interface LogLevelEnv {\n BOS_LOG_LEVEL?: string;\n DEBUG?: string;\n}\n\nexport function isDebug(value: string | undefined): boolean {\n return value === \"true\" || value === \"1\";\n}\n\nexport function resolveLogLevel(\n env: LogLevelEnv = process.env as LogLevelEnv,\n flag?: string,\n): LogLevel {\n if (flag && (LOG_LEVELS as readonly string[]).includes(flag)) return flag as LogLevel;\n if (env.BOS_LOG_LEVEL && (LOG_LEVELS as readonly string[]).includes(env.BOS_LOG_LEVEL)) {\n return env.BOS_LOG_LEVEL as LogLevel;\n }\n if (isDebug(env.DEBUG)) return \"debug\";\n return \"warn\";\n}\n\nexport type EffectLogLevel = \"Error\" | \"Warn\" | \"Info\" | \"Debug\";\n\nexport function toEffectLogLevel(level: LogLevel): EffectLogLevel {\n switch (level) {\n case \"error\":\n return \"Error\";\n case \"warn\":\n return \"Warn\";\n case \"info\":\n return \"Info\";\n case \"debug\":\n return \"Debug\";\n }\n}\n\nconst STACK_FRAME_RE = /^\\s+at\\s/;\n\nconst countBraces = (line: string): number => {\n let count = 0;\n for (const ch of line) {\n if (ch === \"{\") count += 1;\n else if (ch === \"}\") count -= 1;\n }\n return count;\n};\n\ninterface PendingMeta {\n source: string;\n isError?: boolean;\n timestamp?: number;\n}\n\ninterface NormalizerState {\n pending: string[];\n openBraces: number;\n meta?: PendingMeta;\n}\n\nconst makeNormalizerState = (): NormalizerState => ({ pending: [], openBraces: 0 });\n\nconst pushLine = (state: NormalizerState, line: string) => {\n state.pending.push(line);\n state.openBraces = Math.max(0, state.openBraces + countBraces(line));\n};\n\nconst resetState = (state: NormalizerState) => {\n state.pending = [];\n state.openBraces = 0;\n};\n\ninterface CompletedEvent {\n text: string;\n meta: PendingMeta;\n}\n\nconst feedLine = (\n state: NormalizerState,\n line: string,\n meta: PendingMeta,\n): CompletedEvent | null => {\n if (state.pending.length === 0) {\n state.meta = meta;\n pushLine(state, line);\n return null;\n }\n\n const isContinuation = state.openBraces > 0 || STACK_FRAME_RE.test(line) || /^\\s*\\{/.test(line);\n\n if (isContinuation) {\n const closeOnBalance = state.openBraces > 0;\n pushLine(state, line);\n if (closeOnBalance && state.openBraces === 0) {\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n return completed;\n }\n return null;\n }\n\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n state.meta = meta;\n pushLine(state, line);\n return completed;\n};\n\nconst drainState = (state: NormalizerState): CompletedEvent | null => {\n if (state.pending.length === 0) return null;\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n return completed;\n};\n\nexport function normalizeLines(lines: string[]): string[] {\n const state = makeNormalizerState();\n const events: string[] = [];\n for (const line of lines) {\n const completed = feedLine(state, line, { source: \"\" });\n if (completed !== null) events.push(completed.text);\n }\n const last = drainState(state);\n if (last !== null) events.push(last.text);\n return events;\n}\n\nconst WARN_RE = /(?:^|\\s)WARN\\b|\\[WARN\\]|(?:^|\\s)\\w*Warning:/i;\nconst DEBUG_RE = /(?:^|\\s)DEBUG\\b|\\[DEBUG\\]/i;\n\n// rspack/rsbuild write the \"Build error:\" title to stderr with an empty\n// message and the actual diagnostics (`File: …`, `× …`) to stdout. Promote\n// those diagnostic lines so they pass the default warn display filter.\nconst BUILD_DIAGNOSTIC_RE = /^(?:File: |\\s*[×✖]\\s)/;\n\nconst EXIT_LINE_RE =\n /^Process exited (?:after|before) ready \\((?:exit code: (\\d+)|signal: ([A-Z]+))\\)/;\n\nconst CLEAN_SIGNALS = new Set([\"SIGTERM\", \"SIGINT\"]);\n\nconst CATEGORY_PATTERNS: Array<{ category: LogCategory; patterns: RegExp[] }> = [\n {\n category: \"shutdown\",\n patterns: [EXIT_LINE_RE, /\\[SIGTERM\\]/i, /shutting down/i, /graceful shutdown/i],\n },\n {\n category: \"mf\",\n patterns: [\n /\\[ ?Federation Runtime ?\\]/,\n /\\[MF\\]/,\n /Module Federation/i,\n /Executing an Effect versioned/,\n /you may want to dedupe the effect dependencies/,\n /\\[IntegrityMonitor\\]/,\n /\\[Plugins\\]/,\n ],\n },\n {\n category: \"db\",\n patterns: [/\\[Database\\]/i, /\\bpostgres\\b/i, /\\bdrizzle\\b/i, /\\bpglite\\b/i],\n },\n {\n category: \"banner\",\n patterns: [/🚀|📡|📖|💚/, /➜/, /^[┌┐└┘│─┬┴├┤╔╗╚╝║═]/],\n },\n {\n category: \"build\",\n patterns: [\n /rspack\\.config\\.js not found/,\n /rspack|rsbuild/i,\n /compiled (?:success|with|in)/i,\n /built in \\d+/i,\n /webpack/i,\n /\\bHMR\\b/,\n /building for production/i,\n BUILD_DIAGNOSTIC_RE,\n ],\n },\n {\n category: \"lifecycle\",\n patterns: [/\\bready in\\b/i, /listening (?:on|at)/i, /server (?:is )?running/i],\n },\n];\n\nconst classifyCategory = (text: string): LogCategory => {\n for (const { category, patterns } of CATEGORY_PATTERNS) {\n if (patterns.some((pattern) => pattern.test(text))) return category;\n }\n return \"other\";\n};\n\nexport function classifyEvent(raw: RawLogLine): LogEvent {\n const text = stripAnsi(raw.line);\n const exitMatch = text.match(EXIT_LINE_RE);\n const category = classifyCategory(text);\n\n let level: LogLevel;\n let isError = raw.isError === true;\n\n if (exitMatch) {\n if (exitMatch[2]) {\n level = CLEAN_SIGNALS.has(exitMatch[2]) ? \"info\" : \"error\";\n } else {\n level = exitMatch[1] === \"0\" ? \"info\" : \"error\";\n }\n isError = level === \"error\";\n } else if (BUILD_DIAGNOSTIC_RE.test(text)) {\n level = \"error\";\n isError = true;\n } else if (WARN_RE.test(text)) {\n level = \"warn\";\n isError = false;\n } else if (DEBUG_RE.test(text)) {\n level = \"debug\";\n isError = false;\n } else if (isError) {\n level = \"error\";\n } else {\n level = \"info\";\n }\n\n return {\n timestamp: raw.timestamp ?? Date.now(),\n source: raw.source,\n line: text,\n isError,\n level,\n category,\n };\n}\n\nexport function passesLevel(event: LogEvent, level: LogLevel): boolean {\n return LEVEL_RANK[event.level] <= LEVEL_RANK[level];\n}\n\nexport interface CollapsedDbEvent extends LogEvent {\n collapsed: boolean;\n}\n\nclass DbCollapser {\n private runs = new Set<string>();\n\n feed(event: LogEvent): CollapsedDbEvent | null {\n if (event.category === \"db\" && event.level !== \"error\") {\n if (!this.runs.has(event.source)) {\n this.runs.add(event.source);\n return { ...event, line: \"db ready\", isError: false, level: \"info\", collapsed: true };\n }\n return null;\n }\n this.runs.delete(event.source);\n return { ...event, collapsed: false };\n }\n}\n\nexport interface LogPipelineSinks {\n display: (event: LogEvent) => void;\n file: (event: LogEvent) => void;\n export: (event: LogEvent) => void;\n}\n\nexport interface LogPipeline {\n ingest: (raw: RawLogLine) => void;\n flush: () => void;\n}\n\nexport function createLogPipeline(options: {\n level?: LogLevel;\n sinks: LogPipelineSinks;\n}): LogPipeline {\n const level = options.level ?? resolveLogLevel();\n const sinks = options.sinks;\n const normalizers = new Map<string, NormalizerState>();\n const collapser = new DbCollapser();\n\n const stateFor = (source: string): NormalizerState => {\n let state = normalizers.get(source);\n if (!state) {\n state = makeNormalizerState();\n normalizers.set(source, state);\n }\n return state;\n };\n\n const emit = (meta: PendingMeta, text: string) => {\n const event = classifyEvent({\n source: meta.source,\n line: text,\n isError: meta.isError,\n timestamp: meta.timestamp,\n });\n sinks.file(event);\n if (!passesLevel(event, level)) return;\n const collapsed = collapser.feed(event);\n if (!collapsed) return;\n sinks.export(collapsed);\n sinks.display(collapsed);\n };\n\n return {\n ingest: (raw) => {\n const clean = stripAnsi(raw.line);\n if (!clean.trim()) return;\n const state = stateFor(raw.source);\n const completed = feedLine(state, clean, {\n source: raw.source,\n isError: raw.isError,\n timestamp: raw.timestamp,\n });\n if (completed !== null) emit(completed.meta, completed.text);\n },\n flush: () => {\n for (const state of normalizers.values()) {\n const completed = drainState(state);\n if (completed !== null) emit(completed.meta, completed.text);\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dev-log-pipeline.cjs","names":[],"sources":["../src/dev-log-pipeline.ts"],"sourcesContent":["const ESC = \"\\x1b\";\nconst BEL = \"\\x07\";\nconst ANSI_RE = new RegExp(`${ESC}\\\\[[0-?]*[ -/]*[@-~]|${ESC}\\\\][^${BEL}]*${BEL}`, \"g\");\n\nexport const stripAnsi = (input: string): string => input.replace(ANSI_RE, \"\");\n\nexport type LogLevel = \"error\" | \"warn\" | \"info\" | \"debug\";\n\nexport type LogCategory = \"banner\" | \"build\" | \"db\" | \"mf\" | \"lifecycle\" | \"shutdown\" | \"other\";\n\nexport interface RawLogLine {\n source: string;\n line: string;\n isError?: boolean;\n timestamp?: number;\n}\n\nexport interface LogEvent {\n timestamp: number;\n source: string;\n line: string;\n isError: boolean;\n level: LogLevel;\n category: LogCategory;\n}\n\nconst LEVEL_RANK: Record<LogLevel, number> = { error: 0, warn: 1, info: 2, debug: 3 };\n\nconst LOG_LEVELS: readonly LogLevel[] = [\"error\", \"warn\", \"info\", \"debug\"];\n\nexport interface LogLevelEnv {\n BOS_LOG_LEVEL?: string;\n DEBUG?: string;\n}\n\nexport function isDebug(value: string | undefined): boolean {\n return value === \"true\" || value === \"1\";\n}\n\nexport function resolveLogLevel(\n env: LogLevelEnv = process.env as LogLevelEnv,\n flag?: string,\n): LogLevel {\n if (flag && (LOG_LEVELS as readonly string[]).includes(flag)) return flag as LogLevel;\n if (env.BOS_LOG_LEVEL && (LOG_LEVELS as readonly string[]).includes(env.BOS_LOG_LEVEL)) {\n return env.BOS_LOG_LEVEL as LogLevel;\n }\n if (isDebug(env.DEBUG)) return \"debug\";\n return \"warn\";\n}\n\nexport type EffectLogLevel = \"Error\" | \"Warn\" | \"Info\" | \"Debug\";\n\nexport function toEffectLogLevel(level: LogLevel): EffectLogLevel {\n switch (level) {\n case \"error\":\n return \"Error\";\n case \"warn\":\n return \"Warn\";\n case \"info\":\n return \"Info\";\n case \"debug\":\n return \"Debug\";\n }\n}\n\nconst STACK_FRAME_RE = /^\\s+at\\s/;\n\nconst countBraces = (line: string): number => {\n let count = 0;\n for (const ch of line) {\n if (ch === \"{\") count += 1;\n else if (ch === \"}\") count -= 1;\n }\n return count;\n};\n\ninterface PendingMeta {\n source: string;\n isError?: boolean;\n timestamp?: number;\n}\n\ninterface NormalizerState {\n pending: string[];\n openBraces: number;\n meta?: PendingMeta;\n}\n\nconst makeNormalizerState = (): NormalizerState => ({ pending: [], openBraces: 0 });\n\nconst pushLine = (state: NormalizerState, line: string) => {\n state.pending.push(line);\n state.openBraces = Math.max(0, state.openBraces + countBraces(line));\n};\n\nconst resetState = (state: NormalizerState) => {\n state.pending = [];\n state.openBraces = 0;\n};\n\ninterface CompletedEvent {\n text: string;\n meta: PendingMeta;\n}\n\nconst feedLine = (\n state: NormalizerState,\n line: string,\n meta: PendingMeta,\n): CompletedEvent | null => {\n if (state.pending.length === 0) {\n state.meta = meta;\n pushLine(state, line);\n return null;\n }\n\n const isContinuation = state.openBraces > 0 || STACK_FRAME_RE.test(line) || /^\\s*\\{/.test(line);\n\n if (isContinuation) {\n const closeOnBalance = state.openBraces > 0;\n pushLine(state, line);\n if (closeOnBalance && state.openBraces === 0) {\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n return completed;\n }\n return null;\n }\n\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n state.meta = meta;\n pushLine(state, line);\n return completed;\n};\n\nconst drainState = (state: NormalizerState): CompletedEvent | null => {\n if (state.pending.length === 0) return null;\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n return completed;\n};\n\nexport function normalizeLines(lines: string[]): string[] {\n const state = makeNormalizerState();\n const events: string[] = [];\n for (const line of lines) {\n const completed = feedLine(state, line, { source: \"\" });\n if (completed !== null) events.push(completed.text);\n }\n const last = drainState(state);\n if (last !== null) events.push(last.text);\n return events;\n}\n\nconst WARN_RE = /(?:^|\\s)WARN\\b|\\[WARN\\]|(?:^|\\s)\\w*Warning:/i;\nconst DEBUG_RE = /(?:^|\\s)DEBUG\\b|\\[DEBUG\\]/i;\n\n// rspack/rsbuild write the \"Build error:\" title to stderr with an empty\n// message and the actual diagnostics (`File: …`, `× …`) to stdout. Promote\n// those diagnostic lines so they pass the default warn display filter.\nconst BUILD_DIAGNOSTIC_RE = /^(?:File: |\\s*[×✖]\\s)/;\n\nconst EXIT_LINE_RE =\n /^Process exited (?:after|before) ready \\((?:exit code: (\\d+)|signal: ([A-Z]+))\\)/;\n\nconst CLEAN_SIGNALS = new Set([\"SIGTERM\", \"SIGINT\"]);\n\nconst CATEGORY_PATTERNS: Array<{ category: LogCategory; patterns: RegExp[] }> = [\n {\n category: \"shutdown\",\n patterns: [EXIT_LINE_RE, /\\[SIGTERM\\]/i, /shutting down/i, /graceful shutdown/i],\n },\n {\n category: \"mf\",\n patterns: [\n /\\[ ?Federation Runtime ?\\]/,\n /\\[MF\\]/,\n /Module Federation/i,\n /Executing an Effect versioned/,\n /you may want to dedupe the effect dependencies/,\n /\\[IntegrityMonitor\\]/,\n /\\[Plugins\\]/,\n ],\n },\n {\n category: \"db\",\n patterns: [/\\[Database\\]/i, /\\bpostgres\\b/i, /\\bdrizzle\\b/i, /\\bpglite\\b/i],\n },\n {\n category: \"banner\",\n patterns: [/🚀|📡|📖|💚/, /➜/, /^[┌┐└┘│─┬┴├┤╔╗╚╝║═]/],\n },\n {\n category: \"build\",\n patterns: [\n /rspack\\.config\\.js not found/,\n /rspack|rsbuild/i,\n /compiled (?:success|with|in)/i,\n /built in \\d+/i,\n /webpack/i,\n /\\bHMR\\b/,\n /building for production/i,\n BUILD_DIAGNOSTIC_RE,\n ],\n },\n {\n category: \"lifecycle\",\n patterns: [/\\bready in\\b/i, /listening (?:on|at)/i, /server (?:is )?running/i],\n },\n];\n\nconst classifyCategory = (text: string): LogCategory => {\n for (const { category, patterns } of CATEGORY_PATTERNS) {\n if (patterns.some((pattern) => pattern.test(text))) return category;\n }\n return \"other\";\n};\n\nexport function classifyEvent(raw: RawLogLine): LogEvent {\n const text = stripAnsi(raw.line);\n const exitMatch = text.match(EXIT_LINE_RE);\n const category = classifyCategory(text);\n\n let level: LogLevel;\n let isError = raw.isError === true;\n\n if (exitMatch) {\n if (exitMatch[2]) {\n level = CLEAN_SIGNALS.has(exitMatch[2]) ? \"info\" : \"error\";\n } else {\n level = exitMatch[1] === \"0\" ? \"info\" : \"error\";\n }\n isError = level === \"error\";\n } else if (BUILD_DIAGNOSTIC_RE.test(text)) {\n level = \"error\";\n isError = true;\n } else if (WARN_RE.test(text)) {\n level = \"warn\";\n isError = false;\n } else if (DEBUG_RE.test(text)) {\n level = \"debug\";\n isError = false;\n } else if (isError) {\n level = \"error\";\n } else {\n level = \"info\";\n }\n\n return {\n timestamp: raw.timestamp ?? Date.now(),\n source: raw.source,\n line: text,\n isError,\n level,\n category,\n };\n}\n\nexport function passesLevel(event: LogEvent, level: LogLevel): boolean {\n return LEVEL_RANK[event.level] <= LEVEL_RANK[level];\n}\n\nexport interface CollapsedDbEvent extends LogEvent {\n collapsed: boolean;\n}\n\nclass DbCollapser {\n private runs = new Set<string>();\n\n feed(event: LogEvent): CollapsedDbEvent | null {\n if (event.category === \"db\" && event.level !== \"error\") {\n if (!this.runs.has(event.source)) {\n this.runs.add(event.source);\n return { ...event, line: \"db ready\", isError: false, level: \"info\", collapsed: true };\n }\n return null;\n }\n this.runs.delete(event.source);\n return { ...event, collapsed: false };\n }\n}\n\nexport interface LogPipelineSinks {\n display: (event: LogEvent) => void;\n file: (event: LogEvent) => void;\n export: (event: LogEvent) => void;\n}\n\nexport interface LogPipeline {\n ingest: (raw: RawLogLine) => void;\n /** Drain one source's pending multi-line buffer immediately — the last\n * event before a failure must never be lost to the one-line delay. */\n flushSource: (source: string) => void;\n flush: () => void;\n}\n\nexport function createLogPipeline(options: {\n level?: LogLevel;\n sinks: LogPipelineSinks;\n}): LogPipeline {\n const level = options.level ?? resolveLogLevel();\n const sinks = options.sinks;\n const normalizers = new Map<string, NormalizerState>();\n const collapser = new DbCollapser();\n\n const stateFor = (source: string): NormalizerState => {\n let state = normalizers.get(source);\n if (!state) {\n state = makeNormalizerState();\n normalizers.set(source, state);\n }\n return state;\n };\n\n const emit = (meta: PendingMeta, text: string) => {\n const event = classifyEvent({\n source: meta.source,\n line: text,\n isError: meta.isError,\n timestamp: meta.timestamp,\n });\n sinks.file(event);\n if (!passesLevel(event, level)) return;\n const collapsed = collapser.feed(event);\n if (!collapsed) return;\n sinks.export(collapsed);\n sinks.display(collapsed);\n };\n\n return {\n ingest: (raw) => {\n const clean = stripAnsi(raw.line);\n if (!clean.trim()) return;\n const state = stateFor(raw.source);\n const completed = feedLine(state, clean, {\n source: raw.source,\n isError: raw.isError,\n timestamp: raw.timestamp,\n });\n if (completed !== null) emit(completed.meta, completed.text);\n },\n flushSource: (source) => {\n const state = normalizers.get(source);\n if (!state) return;\n const completed = drainState(state);\n if (completed !== null) emit(completed.meta, completed.text);\n },\n flush: () => {\n for (const state of normalizers.values()) {\n const completed = drainState(state);\n if (completed !== null) emit(completed.meta, completed.text);\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -253,6 +253,12 @@ function createLogPipeline(options) {
|
|
|
253
253
|
});
|
|
254
254
|
if (completed !== null) emit(completed.meta, completed.text);
|
|
255
255
|
},
|
|
256
|
+
flushSource: (source) => {
|
|
257
|
+
const state = normalizers.get(source);
|
|
258
|
+
if (!state) return;
|
|
259
|
+
const completed = drainState(state);
|
|
260
|
+
if (completed !== null) emit(completed.meta, completed.text);
|
|
261
|
+
},
|
|
256
262
|
flush: () => {
|
|
257
263
|
for (const state of normalizers.values()) {
|
|
258
264
|
const completed = drainState(state);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-log-pipeline.mjs","names":[],"sources":["../src/dev-log-pipeline.ts"],"sourcesContent":["const ESC = \"\\x1b\";\nconst BEL = \"\\x07\";\nconst ANSI_RE = new RegExp(`${ESC}\\\\[[0-?]*[ -/]*[@-~]|${ESC}\\\\][^${BEL}]*${BEL}`, \"g\");\n\nexport const stripAnsi = (input: string): string => input.replace(ANSI_RE, \"\");\n\nexport type LogLevel = \"error\" | \"warn\" | \"info\" | \"debug\";\n\nexport type LogCategory = \"banner\" | \"build\" | \"db\" | \"mf\" | \"lifecycle\" | \"shutdown\" | \"other\";\n\nexport interface RawLogLine {\n source: string;\n line: string;\n isError?: boolean;\n timestamp?: number;\n}\n\nexport interface LogEvent {\n timestamp: number;\n source: string;\n line: string;\n isError: boolean;\n level: LogLevel;\n category: LogCategory;\n}\n\nconst LEVEL_RANK: Record<LogLevel, number> = { error: 0, warn: 1, info: 2, debug: 3 };\n\nconst LOG_LEVELS: readonly LogLevel[] = [\"error\", \"warn\", \"info\", \"debug\"];\n\nexport interface LogLevelEnv {\n BOS_LOG_LEVEL?: string;\n DEBUG?: string;\n}\n\nexport function isDebug(value: string | undefined): boolean {\n return value === \"true\" || value === \"1\";\n}\n\nexport function resolveLogLevel(\n env: LogLevelEnv = process.env as LogLevelEnv,\n flag?: string,\n): LogLevel {\n if (flag && (LOG_LEVELS as readonly string[]).includes(flag)) return flag as LogLevel;\n if (env.BOS_LOG_LEVEL && (LOG_LEVELS as readonly string[]).includes(env.BOS_LOG_LEVEL)) {\n return env.BOS_LOG_LEVEL as LogLevel;\n }\n if (isDebug(env.DEBUG)) return \"debug\";\n return \"warn\";\n}\n\nexport type EffectLogLevel = \"Error\" | \"Warn\" | \"Info\" | \"Debug\";\n\nexport function toEffectLogLevel(level: LogLevel): EffectLogLevel {\n switch (level) {\n case \"error\":\n return \"Error\";\n case \"warn\":\n return \"Warn\";\n case \"info\":\n return \"Info\";\n case \"debug\":\n return \"Debug\";\n }\n}\n\nconst STACK_FRAME_RE = /^\\s+at\\s/;\n\nconst countBraces = (line: string): number => {\n let count = 0;\n for (const ch of line) {\n if (ch === \"{\") count += 1;\n else if (ch === \"}\") count -= 1;\n }\n return count;\n};\n\ninterface PendingMeta {\n source: string;\n isError?: boolean;\n timestamp?: number;\n}\n\ninterface NormalizerState {\n pending: string[];\n openBraces: number;\n meta?: PendingMeta;\n}\n\nconst makeNormalizerState = (): NormalizerState => ({ pending: [], openBraces: 0 });\n\nconst pushLine = (state: NormalizerState, line: string) => {\n state.pending.push(line);\n state.openBraces = Math.max(0, state.openBraces + countBraces(line));\n};\n\nconst resetState = (state: NormalizerState) => {\n state.pending = [];\n state.openBraces = 0;\n};\n\ninterface CompletedEvent {\n text: string;\n meta: PendingMeta;\n}\n\nconst feedLine = (\n state: NormalizerState,\n line: string,\n meta: PendingMeta,\n): CompletedEvent | null => {\n if (state.pending.length === 0) {\n state.meta = meta;\n pushLine(state, line);\n return null;\n }\n\n const isContinuation = state.openBraces > 0 || STACK_FRAME_RE.test(line) || /^\\s*\\{/.test(line);\n\n if (isContinuation) {\n const closeOnBalance = state.openBraces > 0;\n pushLine(state, line);\n if (closeOnBalance && state.openBraces === 0) {\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n return completed;\n }\n return null;\n }\n\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n state.meta = meta;\n pushLine(state, line);\n return completed;\n};\n\nconst drainState = (state: NormalizerState): CompletedEvent | null => {\n if (state.pending.length === 0) return null;\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n return completed;\n};\n\nexport function normalizeLines(lines: string[]): string[] {\n const state = makeNormalizerState();\n const events: string[] = [];\n for (const line of lines) {\n const completed = feedLine(state, line, { source: \"\" });\n if (completed !== null) events.push(completed.text);\n }\n const last = drainState(state);\n if (last !== null) events.push(last.text);\n return events;\n}\n\nconst WARN_RE = /(?:^|\\s)WARN\\b|\\[WARN\\]|(?:^|\\s)\\w*Warning:/i;\nconst DEBUG_RE = /(?:^|\\s)DEBUG\\b|\\[DEBUG\\]/i;\n\n// rspack/rsbuild write the \"Build error:\" title to stderr with an empty\n// message and the actual diagnostics (`File: …`, `× …`) to stdout. Promote\n// those diagnostic lines so they pass the default warn display filter.\nconst BUILD_DIAGNOSTIC_RE = /^(?:File: |\\s*[×✖]\\s)/;\n\nconst EXIT_LINE_RE =\n /^Process exited (?:after|before) ready \\((?:exit code: (\\d+)|signal: ([A-Z]+))\\)/;\n\nconst CLEAN_SIGNALS = new Set([\"SIGTERM\", \"SIGINT\"]);\n\nconst CATEGORY_PATTERNS: Array<{ category: LogCategory; patterns: RegExp[] }> = [\n {\n category: \"shutdown\",\n patterns: [EXIT_LINE_RE, /\\[SIGTERM\\]/i, /shutting down/i, /graceful shutdown/i],\n },\n {\n category: \"mf\",\n patterns: [\n /\\[ ?Federation Runtime ?\\]/,\n /\\[MF\\]/,\n /Module Federation/i,\n /Executing an Effect versioned/,\n /you may want to dedupe the effect dependencies/,\n /\\[IntegrityMonitor\\]/,\n /\\[Plugins\\]/,\n ],\n },\n {\n category: \"db\",\n patterns: [/\\[Database\\]/i, /\\bpostgres\\b/i, /\\bdrizzle\\b/i, /\\bpglite\\b/i],\n },\n {\n category: \"banner\",\n patterns: [/🚀|📡|📖|💚/, /➜/, /^[┌┐└┘│─┬┴├┤╔╗╚╝║═]/],\n },\n {\n category: \"build\",\n patterns: [\n /rspack\\.config\\.js not found/,\n /rspack|rsbuild/i,\n /compiled (?:success|with|in)/i,\n /built in \\d+/i,\n /webpack/i,\n /\\bHMR\\b/,\n /building for production/i,\n BUILD_DIAGNOSTIC_RE,\n ],\n },\n {\n category: \"lifecycle\",\n patterns: [/\\bready in\\b/i, /listening (?:on|at)/i, /server (?:is )?running/i],\n },\n];\n\nconst classifyCategory = (text: string): LogCategory => {\n for (const { category, patterns } of CATEGORY_PATTERNS) {\n if (patterns.some((pattern) => pattern.test(text))) return category;\n }\n return \"other\";\n};\n\nexport function classifyEvent(raw: RawLogLine): LogEvent {\n const text = stripAnsi(raw.line);\n const exitMatch = text.match(EXIT_LINE_RE);\n const category = classifyCategory(text);\n\n let level: LogLevel;\n let isError = raw.isError === true;\n\n if (exitMatch) {\n if (exitMatch[2]) {\n level = CLEAN_SIGNALS.has(exitMatch[2]) ? \"info\" : \"error\";\n } else {\n level = exitMatch[1] === \"0\" ? \"info\" : \"error\";\n }\n isError = level === \"error\";\n } else if (BUILD_DIAGNOSTIC_RE.test(text)) {\n level = \"error\";\n isError = true;\n } else if (WARN_RE.test(text)) {\n level = \"warn\";\n isError = false;\n } else if (DEBUG_RE.test(text)) {\n level = \"debug\";\n isError = false;\n } else if (isError) {\n level = \"error\";\n } else {\n level = \"info\";\n }\n\n return {\n timestamp: raw.timestamp ?? Date.now(),\n source: raw.source,\n line: text,\n isError,\n level,\n category,\n };\n}\n\nexport function passesLevel(event: LogEvent, level: LogLevel): boolean {\n return LEVEL_RANK[event.level] <= LEVEL_RANK[level];\n}\n\nexport interface CollapsedDbEvent extends LogEvent {\n collapsed: boolean;\n}\n\nclass DbCollapser {\n private runs = new Set<string>();\n\n feed(event: LogEvent): CollapsedDbEvent | null {\n if (event.category === \"db\" && event.level !== \"error\") {\n if (!this.runs.has(event.source)) {\n this.runs.add(event.source);\n return { ...event, line: \"db ready\", isError: false, level: \"info\", collapsed: true };\n }\n return null;\n }\n this.runs.delete(event.source);\n return { ...event, collapsed: false };\n }\n}\n\nexport interface LogPipelineSinks {\n display: (event: LogEvent) => void;\n file: (event: LogEvent) => void;\n export: (event: LogEvent) => void;\n}\n\nexport interface LogPipeline {\n ingest: (raw: RawLogLine) => void;\n flush: () => void;\n}\n\nexport function createLogPipeline(options: {\n level?: LogLevel;\n sinks: LogPipelineSinks;\n}): LogPipeline {\n const level = options.level ?? resolveLogLevel();\n const sinks = options.sinks;\n const normalizers = new Map<string, NormalizerState>();\n const collapser = new DbCollapser();\n\n const stateFor = (source: string): NormalizerState => {\n let state = normalizers.get(source);\n if (!state) {\n state = makeNormalizerState();\n normalizers.set(source, state);\n }\n return state;\n };\n\n const emit = (meta: PendingMeta, text: string) => {\n const event = classifyEvent({\n source: meta.source,\n line: text,\n isError: meta.isError,\n timestamp: meta.timestamp,\n });\n sinks.file(event);\n if (!passesLevel(event, level)) return;\n const collapsed = collapser.feed(event);\n if (!collapsed) return;\n sinks.export(collapsed);\n sinks.display(collapsed);\n };\n\n return {\n ingest: (raw) => {\n const clean = stripAnsi(raw.line);\n if (!clean.trim()) return;\n const state = stateFor(raw.source);\n const completed = feedLine(state, clean, {\n source: raw.source,\n isError: raw.isError,\n timestamp: raw.timestamp,\n });\n if (completed !== null) emit(completed.meta, completed.text);\n },\n flush: () => {\n for (const state of normalizers.values()) {\n const completed = drainState(state);\n if (completed !== null) emit(completed.meta, completed.text);\n }\n },\n };\n}\n"],"mappings":";AAAA,MAAM,MAAM;AACZ,MAAM,MAAM;AACZ,MAAM,UAAU,IAAI,OAAO,GAAG,IAAI,uBAAuB,IAAI,OAAO,IAAI,IAAI,OAAO,GAAG;AAEtF,MAAa,aAAa,UAA0B,MAAM,QAAQ,SAAS,EAAE;AAsB7E,MAAM,aAAuC;CAAE,OAAO;CAAG,MAAM;CAAG,MAAM;CAAG,OAAO;AAAE;AAEpF,MAAM,aAAkC;CAAC;CAAS;CAAQ;CAAQ;AAAO;AAOzE,SAAgB,QAAQ,OAAoC;CAC1D,OAAO,UAAU,UAAU,UAAU;AACvC;AAEA,SAAgB,gBACd,MAAmB,QAAQ,KAC3B,MACU;CACV,IAAI,QAAS,WAAiC,SAAS,IAAI,GAAG,OAAO;CACrE,IAAI,IAAI,iBAAkB,WAAiC,SAAS,IAAI,aAAa,GACnF,OAAO,IAAI;CAEb,IAAI,QAAQ,IAAI,KAAK,GAAG,OAAO;CAC/B,OAAO;AACT;AAIA,SAAgB,iBAAiB,OAAiC;CAChE,QAAQ,OAAR;EACE,KAAK,SACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,SACH,OAAO;CACX;AACF;AAEA,MAAM,iBAAiB;AAEvB,MAAM,eAAe,SAAyB;CAC5C,IAAI,QAAQ;CACZ,KAAK,MAAM,MAAM,MACf,IAAI,OAAO,KAAK,SAAS;MACpB,IAAI,OAAO,KAAK,SAAS;CAEhC,OAAO;AACT;AAcA,MAAM,6BAA8C;CAAE,SAAS,CAAC;CAAG,YAAY;AAAE;AAEjF,MAAM,YAAY,OAAwB,SAAiB;CACzD,MAAM,QAAQ,KAAK,IAAI;CACvB,MAAM,aAAa,KAAK,IAAI,GAAG,MAAM,aAAa,YAAY,IAAI,CAAC;AACrE;AAEA,MAAM,cAAc,UAA2B;CAC7C,MAAM,UAAU,CAAC;CACjB,MAAM,aAAa;AACrB;AAOA,MAAM,YACJ,OACA,MACA,SAC0B;CAC1B,IAAI,MAAM,QAAQ,WAAW,GAAG;EAC9B,MAAM,OAAO;EACb,SAAS,OAAO,IAAI;EACpB,OAAO;CACT;CAIA,IAFuB,MAAM,aAAa,KAAK,eAAe,KAAK,IAAI,KAAK,SAAS,KAAK,IAAI,GAE1E;EAClB,MAAM,iBAAiB,MAAM,aAAa;EAC1C,SAAS,OAAO,IAAI;EACpB,IAAI,kBAAkB,MAAM,eAAe,GAAG;GAC5C,MAAM,YAAY;IAAE,MAAM,MAAM,QAAQ,KAAK,IAAI;IAAG,MAAM,MAAM;GAAM;GACtE,WAAW,KAAK;GAChB,OAAO;EACT;EACA,OAAO;CACT;CAEA,MAAM,YAAY;EAAE,MAAM,MAAM,QAAQ,KAAK,IAAI;EAAG,MAAM,MAAM;CAAM;CACtE,WAAW,KAAK;CAChB,MAAM,OAAO;CACb,SAAS,OAAO,IAAI;CACpB,OAAO;AACT;AAEA,MAAM,cAAc,UAAkD;CACpE,IAAI,MAAM,QAAQ,WAAW,GAAG,OAAO;CACvC,MAAM,YAAY;EAAE,MAAM,MAAM,QAAQ,KAAK,IAAI;EAAG,MAAM,MAAM;CAAM;CACtE,WAAW,KAAK;CAChB,OAAO;AACT;AAcA,MAAM,UAAU;AAChB,MAAM,WAAW;AAKjB,MAAM,sBAAsB;AAE5B,MAAM,eACJ;AAEF,MAAM,gCAAgB,IAAI,IAAI,CAAC,WAAW,QAAQ,CAAC;AAEnD,MAAM,oBAA0E;CAC9E;EACE,UAAU;EACV,UAAU;GAAC;GAAc;GAAgB;GAAkB;EAAoB;CACjF;CACA;EACE,UAAU;EACV,UAAU;GACR;GACA;GACA;GACA;GACA;GACA;GACA;EACF;CACF;CACA;EACE,UAAU;EACV,UAAU;GAAC;GAAiB;GAAiB;GAAgB;EAAa;CAC5E;CACA;EACE,UAAU;EACV,UAAU;GAAC;GAAe;GAAK;EAAqB;CACtD;CACA;EACE,UAAU;EACV,UAAU;GACR;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;CACF;CACA;EACE,UAAU;EACV,UAAU;GAAC;GAAiB;GAAwB;EAAyB;CAC/E;AACF;AAEA,MAAM,oBAAoB,SAA8B;CACtD,KAAK,MAAM,EAAE,UAAU,cAAc,mBACnC,IAAI,SAAS,MAAM,YAAY,QAAQ,KAAK,IAAI,CAAC,GAAG,OAAO;CAE7D,OAAO;AACT;AAEA,SAAgB,cAAc,KAA2B;CACvD,MAAM,OAAO,UAAU,IAAI,IAAI;CAC/B,MAAM,YAAY,KAAK,MAAM,YAAY;CACzC,MAAM,WAAW,iBAAiB,IAAI;CAEtC,IAAI;CACJ,IAAI,UAAU,IAAI,YAAY;CAE9B,IAAI,WAAW;EACb,IAAI,UAAU,IACZ,QAAQ,cAAc,IAAI,UAAU,EAAE,IAAI,SAAS;OAEnD,QAAQ,UAAU,OAAO,MAAM,SAAS;EAE1C,UAAU,UAAU;CACtB,OAAO,IAAI,oBAAoB,KAAK,IAAI,GAAG;EACzC,QAAQ;EACR,UAAU;CACZ,OAAO,IAAI,QAAQ,KAAK,IAAI,GAAG;EAC7B,QAAQ;EACR,UAAU;CACZ,OAAO,IAAI,SAAS,KAAK,IAAI,GAAG;EAC9B,QAAQ;EACR,UAAU;CACZ,OAAO,IAAI,SACT,QAAQ;MAER,QAAQ;CAGV,OAAO;EACL,WAAW,IAAI,aAAa,KAAK,IAAI;EACrC,QAAQ,IAAI;EACZ,MAAM;EACN;EACA;EACA;CACF;AACF;AAEA,SAAgB,YAAY,OAAiB,OAA0B;CACrE,OAAO,WAAW,MAAM,UAAU,WAAW;AAC/C;AAMA,IAAM,cAAN,MAAkB;CAChB,AAAQ,uBAAO,IAAI,IAAY;CAE/B,KAAK,OAA0C;EAC7C,IAAI,MAAM,aAAa,QAAQ,MAAM,UAAU,SAAS;GACtD,IAAI,CAAC,KAAK,KAAK,IAAI,MAAM,MAAM,GAAG;IAChC,KAAK,KAAK,IAAI,MAAM,MAAM;IAC1B,OAAO;KAAE,GAAG;KAAO,MAAM;KAAY,SAAS;KAAO,OAAO;KAAQ,WAAW;IAAK;GACtF;GACA,OAAO;EACT;EACA,KAAK,KAAK,OAAO,MAAM,MAAM;EAC7B,OAAO;GAAE,GAAG;GAAO,WAAW;EAAM;CACtC;AACF;AAaA,SAAgB,kBAAkB,SAGlB;CACd,MAAM,QAAQ,QAAQ,SAAS,gBAAgB;CAC/C,MAAM,QAAQ,QAAQ;CACtB,MAAM,8BAAc,IAAI,IAA6B;CACrD,MAAM,YAAY,IAAI,YAAY;CAElC,MAAM,YAAY,WAAoC;EACpD,IAAI,QAAQ,YAAY,IAAI,MAAM;EAClC,IAAI,CAAC,OAAO;GACV,QAAQ,oBAAoB;GAC5B,YAAY,IAAI,QAAQ,KAAK;EAC/B;EACA,OAAO;CACT;CAEA,MAAM,QAAQ,MAAmB,SAAiB;EAChD,MAAM,QAAQ,cAAc;GAC1B,QAAQ,KAAK;GACb,MAAM;GACN,SAAS,KAAK;GACd,WAAW,KAAK;EAClB,CAAC;EACD,MAAM,KAAK,KAAK;EAChB,IAAI,CAAC,YAAY,OAAO,KAAK,GAAG;EAChC,MAAM,YAAY,UAAU,KAAK,KAAK;EACtC,IAAI,CAAC,WAAW;EAChB,MAAM,OAAO,SAAS;EACtB,MAAM,QAAQ,SAAS;CACzB;CAEA,OAAO;EACL,SAAS,QAAQ;GACf,MAAM,QAAQ,UAAU,IAAI,IAAI;GAChC,IAAI,CAAC,MAAM,KAAK,GAAG;GACnB,MAAM,QAAQ,SAAS,IAAI,MAAM;GACjC,MAAM,YAAY,SAAS,OAAO,OAAO;IACvC,QAAQ,IAAI;IACZ,SAAS,IAAI;IACb,WAAW,IAAI;GACjB,CAAC;GACD,IAAI,cAAc,MAAM,KAAK,UAAU,MAAM,UAAU,IAAI;EAC7D;EACA,aAAa;GACX,KAAK,MAAM,SAAS,YAAY,OAAO,GAAG;IACxC,MAAM,YAAY,WAAW,KAAK;IAClC,IAAI,cAAc,MAAM,KAAK,UAAU,MAAM,UAAU,IAAI;GAC7D;EACF;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"dev-log-pipeline.mjs","names":[],"sources":["../src/dev-log-pipeline.ts"],"sourcesContent":["const ESC = \"\\x1b\";\nconst BEL = \"\\x07\";\nconst ANSI_RE = new RegExp(`${ESC}\\\\[[0-?]*[ -/]*[@-~]|${ESC}\\\\][^${BEL}]*${BEL}`, \"g\");\n\nexport const stripAnsi = (input: string): string => input.replace(ANSI_RE, \"\");\n\nexport type LogLevel = \"error\" | \"warn\" | \"info\" | \"debug\";\n\nexport type LogCategory = \"banner\" | \"build\" | \"db\" | \"mf\" | \"lifecycle\" | \"shutdown\" | \"other\";\n\nexport interface RawLogLine {\n source: string;\n line: string;\n isError?: boolean;\n timestamp?: number;\n}\n\nexport interface LogEvent {\n timestamp: number;\n source: string;\n line: string;\n isError: boolean;\n level: LogLevel;\n category: LogCategory;\n}\n\nconst LEVEL_RANK: Record<LogLevel, number> = { error: 0, warn: 1, info: 2, debug: 3 };\n\nconst LOG_LEVELS: readonly LogLevel[] = [\"error\", \"warn\", \"info\", \"debug\"];\n\nexport interface LogLevelEnv {\n BOS_LOG_LEVEL?: string;\n DEBUG?: string;\n}\n\nexport function isDebug(value: string | undefined): boolean {\n return value === \"true\" || value === \"1\";\n}\n\nexport function resolveLogLevel(\n env: LogLevelEnv = process.env as LogLevelEnv,\n flag?: string,\n): LogLevel {\n if (flag && (LOG_LEVELS as readonly string[]).includes(flag)) return flag as LogLevel;\n if (env.BOS_LOG_LEVEL && (LOG_LEVELS as readonly string[]).includes(env.BOS_LOG_LEVEL)) {\n return env.BOS_LOG_LEVEL as LogLevel;\n }\n if (isDebug(env.DEBUG)) return \"debug\";\n return \"warn\";\n}\n\nexport type EffectLogLevel = \"Error\" | \"Warn\" | \"Info\" | \"Debug\";\n\nexport function toEffectLogLevel(level: LogLevel): EffectLogLevel {\n switch (level) {\n case \"error\":\n return \"Error\";\n case \"warn\":\n return \"Warn\";\n case \"info\":\n return \"Info\";\n case \"debug\":\n return \"Debug\";\n }\n}\n\nconst STACK_FRAME_RE = /^\\s+at\\s/;\n\nconst countBraces = (line: string): number => {\n let count = 0;\n for (const ch of line) {\n if (ch === \"{\") count += 1;\n else if (ch === \"}\") count -= 1;\n }\n return count;\n};\n\ninterface PendingMeta {\n source: string;\n isError?: boolean;\n timestamp?: number;\n}\n\ninterface NormalizerState {\n pending: string[];\n openBraces: number;\n meta?: PendingMeta;\n}\n\nconst makeNormalizerState = (): NormalizerState => ({ pending: [], openBraces: 0 });\n\nconst pushLine = (state: NormalizerState, line: string) => {\n state.pending.push(line);\n state.openBraces = Math.max(0, state.openBraces + countBraces(line));\n};\n\nconst resetState = (state: NormalizerState) => {\n state.pending = [];\n state.openBraces = 0;\n};\n\ninterface CompletedEvent {\n text: string;\n meta: PendingMeta;\n}\n\nconst feedLine = (\n state: NormalizerState,\n line: string,\n meta: PendingMeta,\n): CompletedEvent | null => {\n if (state.pending.length === 0) {\n state.meta = meta;\n pushLine(state, line);\n return null;\n }\n\n const isContinuation = state.openBraces > 0 || STACK_FRAME_RE.test(line) || /^\\s*\\{/.test(line);\n\n if (isContinuation) {\n const closeOnBalance = state.openBraces > 0;\n pushLine(state, line);\n if (closeOnBalance && state.openBraces === 0) {\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n return completed;\n }\n return null;\n }\n\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n state.meta = meta;\n pushLine(state, line);\n return completed;\n};\n\nconst drainState = (state: NormalizerState): CompletedEvent | null => {\n if (state.pending.length === 0) return null;\n const completed = { text: state.pending.join(\"\\n\"), meta: state.meta! };\n resetState(state);\n return completed;\n};\n\nexport function normalizeLines(lines: string[]): string[] {\n const state = makeNormalizerState();\n const events: string[] = [];\n for (const line of lines) {\n const completed = feedLine(state, line, { source: \"\" });\n if (completed !== null) events.push(completed.text);\n }\n const last = drainState(state);\n if (last !== null) events.push(last.text);\n return events;\n}\n\nconst WARN_RE = /(?:^|\\s)WARN\\b|\\[WARN\\]|(?:^|\\s)\\w*Warning:/i;\nconst DEBUG_RE = /(?:^|\\s)DEBUG\\b|\\[DEBUG\\]/i;\n\n// rspack/rsbuild write the \"Build error:\" title to stderr with an empty\n// message and the actual diagnostics (`File: …`, `× …`) to stdout. Promote\n// those diagnostic lines so they pass the default warn display filter.\nconst BUILD_DIAGNOSTIC_RE = /^(?:File: |\\s*[×✖]\\s)/;\n\nconst EXIT_LINE_RE =\n /^Process exited (?:after|before) ready \\((?:exit code: (\\d+)|signal: ([A-Z]+))\\)/;\n\nconst CLEAN_SIGNALS = new Set([\"SIGTERM\", \"SIGINT\"]);\n\nconst CATEGORY_PATTERNS: Array<{ category: LogCategory; patterns: RegExp[] }> = [\n {\n category: \"shutdown\",\n patterns: [EXIT_LINE_RE, /\\[SIGTERM\\]/i, /shutting down/i, /graceful shutdown/i],\n },\n {\n category: \"mf\",\n patterns: [\n /\\[ ?Federation Runtime ?\\]/,\n /\\[MF\\]/,\n /Module Federation/i,\n /Executing an Effect versioned/,\n /you may want to dedupe the effect dependencies/,\n /\\[IntegrityMonitor\\]/,\n /\\[Plugins\\]/,\n ],\n },\n {\n category: \"db\",\n patterns: [/\\[Database\\]/i, /\\bpostgres\\b/i, /\\bdrizzle\\b/i, /\\bpglite\\b/i],\n },\n {\n category: \"banner\",\n patterns: [/🚀|📡|📖|💚/, /➜/, /^[┌┐└┘│─┬┴├┤╔╗╚╝║═]/],\n },\n {\n category: \"build\",\n patterns: [\n /rspack\\.config\\.js not found/,\n /rspack|rsbuild/i,\n /compiled (?:success|with|in)/i,\n /built in \\d+/i,\n /webpack/i,\n /\\bHMR\\b/,\n /building for production/i,\n BUILD_DIAGNOSTIC_RE,\n ],\n },\n {\n category: \"lifecycle\",\n patterns: [/\\bready in\\b/i, /listening (?:on|at)/i, /server (?:is )?running/i],\n },\n];\n\nconst classifyCategory = (text: string): LogCategory => {\n for (const { category, patterns } of CATEGORY_PATTERNS) {\n if (patterns.some((pattern) => pattern.test(text))) return category;\n }\n return \"other\";\n};\n\nexport function classifyEvent(raw: RawLogLine): LogEvent {\n const text = stripAnsi(raw.line);\n const exitMatch = text.match(EXIT_LINE_RE);\n const category = classifyCategory(text);\n\n let level: LogLevel;\n let isError = raw.isError === true;\n\n if (exitMatch) {\n if (exitMatch[2]) {\n level = CLEAN_SIGNALS.has(exitMatch[2]) ? \"info\" : \"error\";\n } else {\n level = exitMatch[1] === \"0\" ? \"info\" : \"error\";\n }\n isError = level === \"error\";\n } else if (BUILD_DIAGNOSTIC_RE.test(text)) {\n level = \"error\";\n isError = true;\n } else if (WARN_RE.test(text)) {\n level = \"warn\";\n isError = false;\n } else if (DEBUG_RE.test(text)) {\n level = \"debug\";\n isError = false;\n } else if (isError) {\n level = \"error\";\n } else {\n level = \"info\";\n }\n\n return {\n timestamp: raw.timestamp ?? Date.now(),\n source: raw.source,\n line: text,\n isError,\n level,\n category,\n };\n}\n\nexport function passesLevel(event: LogEvent, level: LogLevel): boolean {\n return LEVEL_RANK[event.level] <= LEVEL_RANK[level];\n}\n\nexport interface CollapsedDbEvent extends LogEvent {\n collapsed: boolean;\n}\n\nclass DbCollapser {\n private runs = new Set<string>();\n\n feed(event: LogEvent): CollapsedDbEvent | null {\n if (event.category === \"db\" && event.level !== \"error\") {\n if (!this.runs.has(event.source)) {\n this.runs.add(event.source);\n return { ...event, line: \"db ready\", isError: false, level: \"info\", collapsed: true };\n }\n return null;\n }\n this.runs.delete(event.source);\n return { ...event, collapsed: false };\n }\n}\n\nexport interface LogPipelineSinks {\n display: (event: LogEvent) => void;\n file: (event: LogEvent) => void;\n export: (event: LogEvent) => void;\n}\n\nexport interface LogPipeline {\n ingest: (raw: RawLogLine) => void;\n /** Drain one source's pending multi-line buffer immediately — the last\n * event before a failure must never be lost to the one-line delay. */\n flushSource: (source: string) => void;\n flush: () => void;\n}\n\nexport function createLogPipeline(options: {\n level?: LogLevel;\n sinks: LogPipelineSinks;\n}): LogPipeline {\n const level = options.level ?? resolveLogLevel();\n const sinks = options.sinks;\n const normalizers = new Map<string, NormalizerState>();\n const collapser = new DbCollapser();\n\n const stateFor = (source: string): NormalizerState => {\n let state = normalizers.get(source);\n if (!state) {\n state = makeNormalizerState();\n normalizers.set(source, state);\n }\n return state;\n };\n\n const emit = (meta: PendingMeta, text: string) => {\n const event = classifyEvent({\n source: meta.source,\n line: text,\n isError: meta.isError,\n timestamp: meta.timestamp,\n });\n sinks.file(event);\n if (!passesLevel(event, level)) return;\n const collapsed = collapser.feed(event);\n if (!collapsed) return;\n sinks.export(collapsed);\n sinks.display(collapsed);\n };\n\n return {\n ingest: (raw) => {\n const clean = stripAnsi(raw.line);\n if (!clean.trim()) return;\n const state = stateFor(raw.source);\n const completed = feedLine(state, clean, {\n source: raw.source,\n isError: raw.isError,\n timestamp: raw.timestamp,\n });\n if (completed !== null) emit(completed.meta, completed.text);\n },\n flushSource: (source) => {\n const state = normalizers.get(source);\n if (!state) return;\n const completed = drainState(state);\n if (completed !== null) emit(completed.meta, completed.text);\n },\n flush: () => {\n for (const state of normalizers.values()) {\n const completed = drainState(state);\n if (completed !== null) emit(completed.meta, completed.text);\n }\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/dev-program.cjs
CHANGED
|
@@ -33,6 +33,20 @@ function parseSourceMode(value, defaultValue) {
|
|
|
33
33
|
if (value === "local" || value === "remote") return value;
|
|
34
34
|
return defaultValue;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* A production start booting from an explicit config has declared that config
|
|
38
|
+
* as its truth — the host's SnapshotWatch must not override it with the
|
|
39
|
+
* registry pointer mid-run (a fixture-booted stack carrying a live identity
|
|
40
|
+
* would otherwise adopt a foreign generation 30 seconds in, and a
|
|
41
|
+
* config-path production boot is the operator's declared truth). The watch
|
|
42
|
+
* stays on for identity-driven boots — adopting published config changes is
|
|
43
|
+
* its feature. An operator-set interval always wins.
|
|
44
|
+
*/
|
|
45
|
+
function setSnapshotWatchIntervalForBoot(source, env, processEnv = process.env) {
|
|
46
|
+
if (processEnv.BOS_SNAPSHOT_WATCH_INTERVAL_MS !== void 0) return;
|
|
47
|
+
if (env !== "production" || !source.configPath) return;
|
|
48
|
+
processEnv.BOS_SNAPSHOT_WATCH_INTERVAL_MS = "0";
|
|
49
|
+
}
|
|
36
50
|
async function resolvePublishedConfig(account, gateway, registry) {
|
|
37
51
|
try {
|
|
38
52
|
const { config: merged } = await require_resolution_session.walkExtendsChain(`bos://${account}/${gateway}`, {
|
|
@@ -235,14 +249,16 @@ const startBootstrap = (deps, input) => effect.Effect.gen(function* () {
|
|
|
235
249
|
BOS_ACCOUNT: require_process_env.getProcessEnv("BOS_ACCOUNT"),
|
|
236
250
|
BOS_GATEWAY: require_process_env.getProcessEnv("BOS_GATEWAY")
|
|
237
251
|
});
|
|
252
|
+
const registry = input.registry ?? require_process_env.getProcessEnv("BOS_REGISTRY");
|
|
253
|
+
setSnapshotWatchIntervalForBoot(explicitConfig, bosEnv);
|
|
238
254
|
let config = null;
|
|
239
255
|
let remoteConfig = null;
|
|
240
256
|
if (explicitConfig.configPath) config = deps.session?.config ?? null;
|
|
241
257
|
else if (explicitConfig.registry) {
|
|
242
258
|
const { account, domain } = explicitConfig.registry;
|
|
243
|
-
const expectedUrl = require_fastkv.buildRegistryConfigUrl(account, domain,
|
|
259
|
+
const expectedUrl = require_fastkv.buildRegistryConfigUrl(account, domain, registry);
|
|
244
260
|
remoteConfig = yield* effect.Effect.tryPromise({
|
|
245
|
-
try: () => resolvePublishedConfig(account, domain,
|
|
261
|
+
try: () => resolvePublishedConfig(account, domain, registry),
|
|
246
262
|
catch: (error) => new StartFetchFailed({ message: `Failed to fetch config for bos://${account}/${domain}: ${error instanceof Error ? error.message : "Unknown error"}\nExpected URL: ${expectedUrl}` })
|
|
247
263
|
});
|
|
248
264
|
if (remoteConfig) config = remoteConfig;
|
|
@@ -356,7 +372,7 @@ const startBootstrap = (deps, input) => effect.Effect.gen(function* () {
|
|
|
356
372
|
const services = require_service_descriptor.buildServiceDescriptorMap(plan.runtimeConfig);
|
|
357
373
|
const summary = {
|
|
358
374
|
configSource: explicitConfig.configPath ? explicitConfig.configPath : remoteConfig ? `bos://${explicitConfig.registry?.account}/${explicitConfig.registry?.domain}` : require_config.findConfigPath() ?? "bos.config.json",
|
|
359
|
-
configSourceHttp: remoteConfig && explicitConfig.registry ? require_fastkv.buildRegistryConfigUrl(explicitConfig.registry.account, explicitConfig.registry.domain,
|
|
375
|
+
configSourceHttp: remoteConfig && explicitConfig.registry ? require_fastkv.buildRegistryConfigUrl(explicitConfig.registry.account, explicitConfig.registry.domain, registry) : void 0,
|
|
360
376
|
account: baseConfig.account,
|
|
361
377
|
domain: baseConfig.domain ?? void 0,
|
|
362
378
|
modules: {
|
|
@@ -409,5 +425,6 @@ exports.bootstrapLayers = bootstrapLayers;
|
|
|
409
425
|
exports.devBootstrap = devBootstrap;
|
|
410
426
|
exports.resolveProxyUrl = resolveProxyUrl;
|
|
411
427
|
exports.resolvePublishedConfig = resolvePublishedConfig;
|
|
428
|
+
exports.setSnapshotWatchIntervalForBoot = setSnapshotWatchIntervalForBoot;
|
|
412
429
|
exports.startBootstrap = startBootstrap;
|
|
413
430
|
//# sourceMappingURL=dev-program.cjs.map
|
package/dist/dev-program.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-program.cjs","names":["Data","walkExtendsChain","resolveConfigComposableEntries","BosConfigSchema","timedPhase","Effect","captureShellEnv","ProjectEnv","detectLocalPackages","syncResolvedSharedDeps","run","findWorkspaceRoot","ensureFreshDeps","openResolution","planInfra","materializeViaLayer","mergeGeneratedOverFileEnv","processEnvRecord","preflightLocalInfra","shouldAutoStartDocker","detectAutoStartContext","isDockerAvailable","runDockerComposeUp","buildServiceDescriptorMapFromPlan","isDebug","getProcessEnv","generateCodeArtifacts","buildDescription","emitProgress","resolveStartConfigSource","buildRegistryConfigUrl","getHostDevelopmentPort","buildRuntimePluginsForConfig","buildRuntimeConfig","isRegistryStart","isRailwayPublicProxyUrl","buildServiceDescriptorMap","findConfigPath","Layer","ProjectEnvLive","PortAllocatorLive"],"sources":["../src/dev-program.ts"],"sourcesContent":["import { Data, Effect, Layer } from \"effect\";\nimport { detectLocalPackages, PortAllocatorLive } from \"./app\";\nimport { generateCodeArtifacts } from \"./code-artifacts\";\nimport {\n buildRuntimeConfig,\n buildRuntimePluginsForConfig,\n findConfigPath,\n getHostDevelopmentPort,\n resolveConfigComposableEntries,\n} from \"./config\";\nimport type { DevOptions, PhaseTiming, StartOptions } from \"./contract\";\nimport { isRailwayPublicProxyUrl } from \"./db/driver\";\nimport { isDebug } from \"./dev-log-pipeline\";\nimport type { DevSessionData, StartSummary } from \"./dev-session-data\";\nimport {\n deleteProcessEnv,\n getProcessEnv,\n processEnvRecord,\n setProcessEnv,\n} from \"./env/process-env\";\nimport {\n captureShellEnv,\n type EnvEnsureError,\n type EnvLoadError,\n ProjectEnv,\n ProjectEnvLive,\n type ProjectEnvService,\n} from \"./env/project-env\";\nimport { buildRegistryConfigUrl } from \"./fastkv\";\nimport {\n detectAutoStartContext,\n isDockerAvailable,\n runDockerComposeUp,\n shouldAutoStartDocker,\n} from \"./infra/docker\";\nimport { materializeViaLayer } from \"./infra/materializer\";\nimport { planInfra } from \"./infra/planner\";\nimport { preflightLocalInfra } from \"./infra/preflight\";\nimport type { InfraPlan } from \"./infra/types\";\nimport { mergeGeneratedOverFileEnv } from \"./orchestrator\";\nimport { emitProgress, timedPhase } from \"./progress\";\nimport { openResolution, type ResolutionSession, walkExtendsChain } from \"./resolution/session\";\nimport {\n type AppOrchestrator,\n buildDescription,\n buildServiceDescriptorMap,\n buildServiceDescriptorMapFromPlan,\n} from \"./service-descriptor\";\nimport { syncResolvedSharedDeps } from \"./shared-deps\";\nimport { isRegistryStart, resolveStartConfigSource } from \"./start-config-source\";\nimport type { BosConfig, SourceMode } from \"./types\";\nimport { BosConfigSchema } from \"./types\";\nimport { run } from \"./utils/run\";\nimport { ensureFreshDeps, findWorkspaceRoot } from \"./workspace\";\n\nexport type { DevSessionData, StartSummary } from \"./dev-session-data\";\n\nexport interface BootstrapDeps {\n readonly session: ResolutionSession | null;\n}\n\nexport class DevStepError extends Data.TaggedError(\"DevStepError\")<{\n phase: string;\n cause: unknown;\n}> {}\n\nexport class DevConfigMissing extends Data.TaggedError(\"DevConfigMissing\")<Record<string, never>> {}\n\nexport class DevProxyMissing extends Data.TaggedError(\"DevProxyMissing\")<Record<string, never>> {}\n\nexport class DevPreflightFailed extends Data.TaggedError(\"DevPreflightFailed\")<{\n messages: string[];\n}> {}\n\nexport class StartFetchFailed extends Data.TaggedError(\"StartFetchFailed\")<{ message: string }> {}\n\nexport class StartRemoteConfigMissing extends Data.TaggedError(\"StartRemoteConfigMissing\")<{\n message: string;\n}> {}\n\nexport class StartConfigMissing extends Data.TaggedError(\"StartConfigMissing\")<\n Record<string, never>\n> {}\n\nfunction parseSourceMode(value: string | undefined, defaultValue: SourceMode): SourceMode {\n if (value === \"local\" || value === \"remote\") return value;\n return defaultValue;\n}\n\nexport async function resolvePublishedConfig(\n account: string,\n gateway: string,\n registry?: string,\n): Promise<BosConfig | null> {\n try {\n const { config: merged } = await walkExtendsChain(`bos://${account}/${gateway}`, {\n env: \"production\",\n registry,\n visit: async () => {},\n });\n return resolveConfigComposableEntries(\n BosConfigSchema.parse(merged),\n process.cwd(),\n \"production\",\n );\n } catch (error) {\n if (error instanceof Error && error.message.startsWith(\"No config found\")) {\n return null;\n }\n throw error;\n }\n}\n\nfunction isValidProxyUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === \"http:\" || parsed.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nexport function resolveProxyUrl(bosConfig: BosConfig | null): string | null {\n if (!bosConfig) return null;\n const apiConfig = bosConfig.app.api;\n if (!apiConfig) return null;\n if (apiConfig.proxy && isValidProxyUrl(apiConfig.proxy)) return apiConfig.proxy;\n if (apiConfig.production && isValidProxyUrl(apiConfig.production)) return apiConfig.production;\n return null;\n}\n\nconst step = <A>(timings: PhaseTiming[], name: string, fn: () => Promise<A>) =>\n timedPhase(\n timings,\n name,\n Effect.tryPromise({\n try: fn,\n catch: (cause) => new DevStepError({ phase: name, cause }),\n }),\n );\n\nconst ensureEnvStep = (projectEnv: ProjectEnvService, configDir: string) =>\n projectEnv\n .ensureFile(configDir)\n .pipe(\n Effect.mapError((cause: EnvEnsureError) => new DevStepError({ phase: \"ensure env\", cause })),\n );\n\nconst loadEnvStep = (projectEnv: ProjectEnvService, configDir: string) =>\n projectEnv\n .load(configDir)\n .pipe(Effect.mapError((cause: EnvLoadError) => new DevStepError({ phase: \"load env\", cause })));\n\nexport const devBootstrap = (deps: BootstrapDeps, input: DevOptions, timings: PhaseTiming[]) =>\n Effect.gen(function* () {\n const shell = yield* captureShellEnv;\n const projectEnv = yield* ProjectEnv;\n\n if (!deps.session) {\n return yield* new DevConfigMissing({});\n }\n let session: ResolutionSession = deps.session;\n\n yield* ensureEnvStep(projectEnv, session.root);\n yield* loadEnvStep(projectEnv, session.root);\n\n const localPackages = detectLocalPackages(\n session.config ?? undefined,\n session.runtime ?? undefined,\n session.root,\n );\n const localPackageNames = new Set(localPackages.map((entry) => entry.name));\n const localDirs = localPackages.map((entry) => entry.dir);\n\n const hostSource: SourceMode = localPackageNames.has(\"host\")\n ? parseSourceMode(input.host, \"local\")\n : \"remote\";\n const uiSource: SourceMode = localPackageNames.has(\"ui\")\n ? parseSourceMode(input.ui, \"local\")\n : \"remote\";\n const apiSource: SourceMode = localPackageNames.has(\"api\")\n ? parseSourceMode(input.api, \"local\")\n : \"remote\";\n const authSource: SourceMode = localPackageNames.has(\"auth\")\n ? parseSourceMode(input.auth, \"local\")\n : \"remote\";\n const ssr = input.ssr ?? false;\n const proxy = input.proxy ?? false;\n\n if (input.logLevel) {\n yield* Effect.sync(() => {\n setProcessEnv(\"BOS_LOG_LEVEL\", input.logLevel!);\n });\n }\n\n if (ssr) {\n yield* Effect.sync(() => {\n setProcessEnv(\"BOS_SSR\", \"1\");\n });\n }\n\n const sharedSync = yield* step(timings, \"shared deps\", () =>\n syncResolvedSharedDeps({\n configDir: session.root,\n hostMode: hostSource,\n bosConfig: session.config ?? undefined,\n extendsChain: [],\n }),\n );\n let configMayHaveChanged = false;\n if (sharedSync.catalogChanged) {\n yield* step(timings, \"install\", () =>\n run(\"pnpm\", [\"install\"], { cwd: findWorkspaceRoot(session.root)?.dir ?? session.root }),\n );\n configMayHaveChanged = true;\n }\n\n yield* step(timings, \"build\", async () => {\n const report = await ensureFreshDeps(session.root, localDirs);\n if (report.rebuilt.some((member) => member.name === \"everything-dev\")) {\n // Only the bos process itself runs the everything-dev dist (plugin\n // children spawn after this step and load the fresh build). A source\n // run (node --import tsx src/cli.ts) never imported dist, so nothing\n // is stale for it — warn only where the previously imported build\n // matters.\n const runningFromDist = import.meta.url.includes(\"/dist/\");\n if (runningFromDist) {\n console.log(\n \"[dev] everything-dev was rebuilt — this session still runs the previous \" +\n \"orchestrator build. Restart `bos dev` once to pick it up.\",\n );\n }\n }\n });\n\n let devExtendsChain: string[] | undefined;\n if (configMayHaveChanged || input.remotePlugins !== undefined) {\n yield* step(timings, \"resolve config\", async () => {\n const opened = await openResolution({\n cwd: session.root,\n remotePlugins: input.remotePlugins,\n });\n if (opened) {\n session = opened;\n devExtendsChain = [...opened.chain];\n }\n });\n }\n\n if (!session.config) {\n return yield* new DevConfigMissing({});\n }\n const bosConfig: BosConfig = session.config;\n\n if (proxy && !resolveProxyUrl(bosConfig)) {\n return yield* new DevProxyMissing({});\n }\n\n const developmentRuntime = yield* Effect.tryPromise({\n try: async () => {\n return session.buildRuntime({\n uiSource,\n apiSource,\n authSource,\n hostSource,\n env: \"development\",\n plugins: session.runtime?.plugins,\n });\n },\n catch: (cause) => new DevStepError({ phase: \"build runtime config\", cause }),\n });\n for (const message of session.warnings) {\n yield* Effect.logWarning(message);\n }\n\n const plan: InfraPlan = yield* timedPhase(\n timings,\n \"ports\",\n planInfra({\n configDir: session.root,\n bosConfig: developmentRuntime,\n cli: {\n port: input.port,\n apiPort: input.apiPort,\n authPort: input.authPort,\n uiPort: input.uiPort,\n pluginPortStart: input.pluginPortStart,\n ssr,\n proxy,\n hostSource,\n uiSource,\n apiSource,\n authSource,\n interactive: input.interactive,\n },\n }),\n );\n\n yield* Effect.tryPromise({\n try: () => materializeViaLayer(session.root, plan.runtimeConfig),\n catch: (cause) => new DevStepError({ phase: \"materialize infra\", cause }),\n });\n yield* ensureEnvStep(projectEnv, session.root);\n yield* loadEnvStep(projectEnv, session.root);\n\n yield* projectEnv\n .sync(session.root, plan.envGenerated, shell)\n .pipe(\n Effect.catchTag(\"EnvSyncError\", (error) =>\n Effect.logWarning(\n `[env] failed to refresh .env from resolved ports: ${String(error.cause)}`,\n ),\n ),\n );\n\n const mergedEnv = yield* Effect.sync(() =>\n mergeGeneratedOverFileEnv(\n plan.envGenerated,\n processEnvRecord() as Record<string, string>,\n shell,\n ),\n );\n yield* Effect.sync(() => {\n for (const [key, value] of Object.entries(mergedEnv)) {\n if (key === \"BASE_URL\" || key === \"CORS_ORIGIN\") setProcessEnv(key, value);\n }\n });\n let preflightFailures = yield* preflightLocalInfra(plan.envGenerated, mergedEnv);\n if (\n preflightFailures.length > 0 &&\n shouldAutoStartDocker(preflightFailures, {\n ...detectAutoStartContext(session.root),\n dockerAvailable: yield* Effect.promise(isDockerAvailable),\n })\n ) {\n const compose = yield* step(timings, \"docker compose up\", () =>\n runDockerComposeUp(session.root),\n );\n if (compose.ok) {\n preflightFailures = yield* preflightLocalInfra(plan.envGenerated, mergedEnv);\n } else {\n preflightFailures = [\n ...preflightFailures,\n {\n secret: \"docker-compose\",\n host: \"localhost\",\n port: 0,\n error: `docker compose up -d --wait failed${compose.tail ? `:\\n${compose.tail}` : \"\"}`,\n tcpReachable: false,\n },\n ];\n }\n }\n if (preflightFailures.length > 0) {\n return yield* new DevPreflightFailed({ messages: preflightFailures.map((f) => f.error) });\n }\n\n const services = buildServiceDescriptorMapFromPlan(plan, { ssr, proxy });\n\n const packages = [...plan.serviceDescriptors.keys()];\n if (isDebug(getProcessEnv(\"DEBUG\"))) {\n yield* Effect.logError(`[DEBUG dev] services keys: ${packages.join(\", \")}`);\n }\n const apiSvc = services.get(\"api\");\n if (apiSvc?.proxy) {\n const proxyUrl = resolveProxyUrl(bosConfig);\n if (proxyUrl) plan.orchestrator.env.API_PROXY = proxyUrl;\n }\n\n yield* step(timings, \"generate artifacts\", () =>\n generateCodeArtifacts(session.root, bosConfig, {\n env: \"development\",\n extendsChain: devExtendsChain,\n runtimeConfig: plan.runtimeConfig,\n }),\n );\n\n return {\n session: {\n orchestrator: plan.orchestrator,\n services,\n runtimeConfig: plan.runtimeConfig,\n envGenerated: plan.envGenerated,\n shellEnv: shell,\n } satisfies DevSessionData,\n description: buildDescription(services) || plan.description,\n processes: packages,\n };\n });\n\nexport const startBootstrap = (deps: BootstrapDeps, input: StartOptions) =>\n Effect.gen(function* () {\n const shell = yield* captureShellEnv;\n const projectEnv = yield* ProjectEnv;\n\n const sessionRoot = deps.session?.root ?? process.cwd();\n\n yield* loadEnvStep(projectEnv, sessionRoot);\n\n yield* emitProgress({ phase: \"config\", status: \"running\" });\n\n const bosEnv = input.env ?? (getProcessEnv(\"BOS_ENV\") === \"staging\" ? \"staging\" : \"production\");\n const explicitConfig = resolveStartConfigSource(input, {\n BOS_ACCOUNT: getProcessEnv(\"BOS_ACCOUNT\"),\n BOS_GATEWAY: getProcessEnv(\"BOS_GATEWAY\"),\n });\n\n let config: BosConfig | null = null;\n let remoteConfig: BosConfig | null = null;\n\n if (explicitConfig.configPath) {\n config = deps.session?.config ?? null;\n } else if (explicitConfig.registry) {\n const { account, domain } = explicitConfig.registry;\n const expectedUrl = buildRegistryConfigUrl(account, domain, input.registry);\n remoteConfig = yield* Effect.tryPromise({\n try: () => resolvePublishedConfig(account, domain, input.registry),\n catch: (error) =>\n new StartFetchFailed({\n message: `Failed to fetch config for bos://${account}/${domain}: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }\\nExpected URL: ${expectedUrl}`,\n }),\n });\n if (remoteConfig) {\n config = remoteConfig;\n } else {\n return yield* new StartRemoteConfigMissing({\n message: `No config found at bos://${account}/${domain}. Verify the account and gateway are correct and the config has been published.\\nExpected URL: ${expectedUrl}`,\n });\n }\n } else {\n config = deps.session?.config ?? null;\n }\n\n if (!config) {\n return yield* new StartConfigMissing({});\n }\n\n if (!explicitConfig.configPath) {\n if (explicitConfig.registry?.account) {\n config = { ...config, account: explicitConfig.registry.account };\n }\n if (explicitConfig.registry?.domain) {\n config = { ...config, domain: explicitConfig.registry.domain };\n }\n }\n const baseConfig: BosConfig = config;\n\n const port = input.port ?? getHostDevelopmentPort(baseConfig.app.host.development);\n const isStaging = bosEnv === \"staging\";\n const runtimePlugins = yield* Effect.tryPromise({\n try: () => buildRuntimePluginsForConfig(baseConfig, sessionRoot, \"production\"),\n catch: (cause) => new DevStepError({ phase: \"resolve runtime plugins\", cause }),\n });\n const runtimeConfig = yield* Effect.tryPromise({\n try: () =>\n buildRuntimeConfig(baseConfig, sessionRoot, \"production\", {\n uiSource: \"remote\",\n apiSource: \"remote\",\n authSource: \"remote\",\n hostSource: \"remote\",\n plugins: runtimePlugins,\n }),\n catch: (cause) => new DevStepError({ phase: \"build runtime config\", cause }),\n });\n\n if (isStaging && baseConfig.staging?.domain) {\n runtimeConfig.domain = baseConfig.staging.domain;\n }\n\n if (isStaging) {\n runtimeConfig.env = \"staging\";\n }\n\n yield* emitProgress({ phase: \"generate artifacts\", status: \"running\" });\n yield* Effect.tryPromise({\n try: () =>\n generateCodeArtifacts(sessionRoot, baseConfig, {\n env: \"production\",\n runtimeConfig,\n }),\n catch: (cause) => new DevStepError({ phase: \"generate artifacts\", cause }),\n });\n yield* emitProgress({ phase: \"generate artifacts\", status: \"done\" });\n\n const productionEnv: Record<string, string> = {};\n const warnings: string[] = [];\n\n const localhostOrigin = /^https?:\\/\\/(localhost|127\\.0\\.0\\.1)(:\\d+)?$/i;\n const corsOrigin = getProcessEnv(\"CORS_ORIGIN\");\n const isLocalhostProductionOrigin =\n corsOrigin !== undefined && localhostOrigin.test(corsOrigin);\n if (isLocalhostProductionOrigin && isRegistryStart(explicitConfig)) {\n warnings.push(\n `CORS_ORIGIN is a localhost origin (${corsOrigin}) in a registry production start — overriding with the configured domain`,\n );\n deleteProcessEnv(\"CORS_ORIGIN\");\n deleteProcessEnv(\"BASE_URL\");\n }\n\n if (!getProcessEnv(\"CORS_ORIGIN\") && baseConfig.domain) {\n const effectiveDomain = isStaging\n ? (baseConfig.staging?.domain ?? baseConfig.domain)\n : baseConfig.domain;\n const defaultOrigin = `https://${effectiveDomain}`;\n productionEnv.CORS_ORIGIN = defaultOrigin;\n productionEnv.BASE_URL = defaultOrigin;\n warnings.push(`CORS_ORIGIN defaulting to ${defaultOrigin}`);\n }\n\n const requiredSecrets = new Set<string>();\n const missingSecrets: string[] = [];\n\n if (runtimeConfig.host.secrets) {\n for (const s of runtimeConfig.host.secrets) requiredSecrets.add(s);\n }\n if (runtimeConfig.auth?.secrets) {\n for (const s of runtimeConfig.auth.secrets) requiredSecrets.add(s);\n }\n if (runtimeConfig.api?.secrets) {\n for (const s of runtimeConfig.api.secrets) requiredSecrets.add(s);\n }\n for (const plugin of Object.values(runtimeConfig.plugins ?? {})) {\n if (plugin.secrets) {\n for (const s of plugin.secrets) {\n if (s.endsWith(\"_DATABASE_URL\")) continue;\n requiredSecrets.add(s);\n }\n }\n }\n\n for (const secret of requiredSecrets) {\n const value = getProcessEnv(secret);\n if (!value || value.length === 0) {\n missingSecrets.push(secret);\n }\n }\n\n if (missingSecrets.length > 0) {\n warnings.push(`Missing ${missingSecrets.length} secret(s): ${missingSecrets.join(\", \")}`);\n }\n\n for (const [secret, value] of Object.entries(processEnvRecord())) {\n if (!value || !secret.endsWith(\"_DATABASE_URL\")) continue;\n if (isRailwayPublicProxyUrl(value)) {\n const host = new URL(value).hostname;\n warnings.push(\n `${secret} points at Railway's public proxy (${host}) — its TLS certificate is self-signed, ` +\n `so connections use unverified TLS. Prefer the private *.railway.internal URL when the ` +\n `database runs in the same Railway project.`,\n );\n }\n }\n\n const stagingEnvVars: Record<string, string> = isStaging\n ? { BOS_GATEWAY: baseConfig.staging?.domain ?? baseConfig.domain ?? \"\" }\n : {};\n\n const plan: InfraPlan = yield* planInfra({\n configDir: sessionRoot,\n bosConfig: runtimeConfig,\n cli: {\n port: input.port,\n ssr: false,\n proxy: false,\n hostSource: \"remote\",\n uiSource: \"remote\",\n apiSource: \"remote\",\n authSource: \"remote\",\n interactive: input.interactive,\n },\n });\n\n const services = buildServiceDescriptorMap(plan.runtimeConfig);\n\n const configSource = explicitConfig.configPath\n ? explicitConfig.configPath\n : remoteConfig\n ? `bos://${explicitConfig.registry?.account}/${explicitConfig.registry?.domain}`\n : (findConfigPath() ?? \"bos.config.json\");\n\n const configSourceHttp =\n remoteConfig && explicitConfig.registry\n ? buildRegistryConfigUrl(\n explicitConfig.registry.account,\n explicitConfig.registry.domain,\n input.registry,\n )\n : undefined;\n\n const summary: StartSummary = {\n configSource,\n configSourceHttp,\n account: baseConfig.account,\n domain: baseConfig.domain ?? undefined,\n modules: {\n host: plan.runtimeConfig.host.remoteUrl ?? plan.runtimeConfig.host.url ?? \"local\",\n ui: plan.runtimeConfig.ui.url ?? \"local\",\n api: plan.runtimeConfig.api.url ?? \"local\",\n auth: plan.runtimeConfig.auth?.url ?? undefined,\n },\n warnings,\n };\n\n const orchestrator: AppOrchestrator = {\n packages: [\"host\"],\n env: {\n NODE_ENV: \"production\",\n ...productionEnv,\n ...stagingEnvVars,\n ...plan.launch.env,\n },\n description: `${isStaging ? \"Staging\" : \"Production\"} Mode (${baseConfig.account})`,\n port: plan.resolvedPorts.host ?? port,\n interactive: input.interactive,\n // Log persistence stays off for start stacks: the SSR host emits ~80\n // log events per page render (i18n uncompiled-catalog warnings), and\n // the file sink writes every event twice through a serialized\n // appendFile chain regardless of level or dedup — on a loaded machine\n // that chain starves the event loop and degrades SSR/hydration\n // mid-suite. Boot failures are diagnosed from stdout (the renderer\n // prints error-level lines; the smoke captures 400 lines of it).\n };\n\n yield* emitProgress({ phase: \"config\", status: \"done\" });\n\n return {\n session: {\n orchestrator,\n services,\n runtimeConfig: plan.runtimeConfig,\n envGenerated: plan.envGenerated,\n shellEnv: shell,\n } satisfies DevSessionData,\n summary,\n url: plan.launch.hostUrl ?? `http://localhost:${plan.resolvedPorts.host ?? port}`,\n };\n });\n\nexport const bootstrapLayers = Layer.mergeAll(ProjectEnvLive, PortAllocatorLive);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6DA,IAAa,eAAb,cAAkCA,YAAK,YAAY,cAAc,CAAC,CAG/D,CAAC;AAEJ,IAAa,mBAAb,cAAsCA,YAAK,YAAY,kBAAkB,CAAC,CAAwB,CAAC;AAEnG,IAAa,kBAAb,cAAqCA,YAAK,YAAY,iBAAiB,CAAC,CAAwB,CAAC;AAEjG,IAAa,qBAAb,cAAwCA,YAAK,YAAY,oBAAoB,CAAC,CAE3E,CAAC;AAEJ,IAAa,mBAAb,cAAsCA,YAAK,YAAY,kBAAkB,CAAC,CAAsB,CAAC;AAEjG,IAAa,2BAAb,cAA8CA,YAAK,YAAY,0BAA0B,CAAC,CAEvF,CAAC;AAEJ,IAAa,qBAAb,cAAwCA,YAAK,YAAY,oBAAoB,CAAC,CAE5E,CAAC;AAEH,SAAS,gBAAgB,OAA2B,cAAsC;CACxF,IAAI,UAAU,WAAW,UAAU,UAAU,OAAO;CACpD,OAAO;AACT;AAEA,eAAsB,uBACpB,SACA,SACA,UAC2B;CAC3B,IAAI;EACF,MAAM,EAAE,QAAQ,WAAW,MAAMC,4CAAiB,SAAS,QAAQ,GAAG,WAAW;GAC/E,KAAK;GACL;GACA,OAAO,YAAY,CAAC;EACtB,CAAC;EACD,OAAOC,8CACLC,8BAAgB,MAAM,MAAM,GAC5B,QAAQ,IAAI,GACZ,YACF;CACF,SAAS,OAAO;EACd,IAAI,iBAAiB,SAAS,MAAM,QAAQ,WAAW,iBAAiB,GACtE,OAAO;EAET,MAAM;CACR;AACF;AAEA,SAAS,gBAAgB,KAAsB;CAC7C,IAAI;EACF,MAAM,SAAS,IAAI,IAAI,GAAG;EAC1B,OAAO,OAAO,aAAa,WAAW,OAAO,aAAa;CAC5D,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,gBAAgB,WAA4C;CAC1E,IAAI,CAAC,WAAW,OAAO;CACvB,MAAM,YAAY,UAAU,IAAI;CAChC,IAAI,CAAC,WAAW,OAAO;CACvB,IAAI,UAAU,SAAS,gBAAgB,UAAU,KAAK,GAAG,OAAO,UAAU;CAC1E,IAAI,UAAU,cAAc,gBAAgB,UAAU,UAAU,GAAG,OAAO,UAAU;CACpF,OAAO;AACT;AAEA,MAAM,QAAW,SAAwB,MAAc,OACrDC,4BACE,SACA,MACAC,cAAO,WAAW;CAChB,KAAK;CACL,QAAQ,UAAU,IAAI,aAAa;EAAE,OAAO;EAAM;CAAM,CAAC;AAC3D,CAAC,CACH;AAEF,MAAM,iBAAiB,YAA+B,cACpD,WACG,WAAW,SAAS,CAAC,CACrB,KACCA,cAAO,UAAU,UAA0B,IAAI,aAAa;CAAE,OAAO;CAAc;AAAM,CAAC,CAAC,CAC7F;AAEJ,MAAM,eAAe,YAA+B,cAClD,WACG,KAAK,SAAS,CAAC,CACf,KAAKA,cAAO,UAAU,UAAwB,IAAI,aAAa;CAAE,OAAO;CAAY;AAAM,CAAC,CAAC,CAAC;AAElG,MAAa,gBAAgB,MAAqB,OAAmB,YACnEA,cAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAOC;CACrB,MAAM,aAAa,OAAOC;CAE1B,IAAI,CAAC,KAAK,SACR,OAAO,OAAO,IAAI,iBAAiB,CAAC,CAAC;CAEvC,IAAI,UAA6B,KAAK;CAEtC,OAAO,cAAc,YAAY,QAAQ,IAAI;CAC7C,OAAO,YAAY,YAAY,QAAQ,IAAI;CAE3C,MAAM,gBAAgBC,gCACpB,QAAQ,UAAU,QAClB,QAAQ,WAAW,QACnB,QAAQ,IACV;CACA,MAAM,oBAAoB,IAAI,IAAI,cAAc,KAAK,UAAU,MAAM,IAAI,CAAC;CAC1E,MAAM,YAAY,cAAc,KAAK,UAAU,MAAM,GAAG;CAExD,MAAM,aAAyB,kBAAkB,IAAI,MAAM,IACvD,gBAAgB,MAAM,MAAM,OAAO,IACnC;CACJ,MAAM,WAAuB,kBAAkB,IAAI,IAAI,IACnD,gBAAgB,MAAM,IAAI,OAAO,IACjC;CACJ,MAAM,YAAwB,kBAAkB,IAAI,KAAK,IACrD,gBAAgB,MAAM,KAAK,OAAO,IAClC;CACJ,MAAM,aAAyB,kBAAkB,IAAI,MAAM,IACvD,gBAAgB,MAAM,MAAM,OAAO,IACnC;CACJ,MAAM,MAAM,MAAM,OAAO;CACzB,MAAM,QAAQ,MAAM,SAAS;CAE7B,IAAI,MAAM,UACR,OAAOH,cAAO,WAAW;EACvB,kCAAc,iBAAiB,MAAM,QAAS;CAChD,CAAC;CAGH,IAAI,KACF,OAAOA,cAAO,WAAW;EACvB,kCAAc,WAAW,GAAG;CAC9B,CAAC;CAGH,MAAM,aAAa,OAAO,KAAK,SAAS,qBACtCI,2CAAuB;EACrB,WAAW,QAAQ;EACnB,UAAU;EACV,WAAW,QAAQ,UAAU;EAC7B,cAAc,CAAC;CACjB,CAAC,CACH;CACA,IAAI,uBAAuB;CAC3B,IAAI,WAAW,gBAAgB;EAC7B,OAAO,KAAK,SAAS,iBACnBC,gBAAI,QAAQ,CAAC,SAAS,GAAG,EAAE,KAAKC,oCAAkB,QAAQ,IAAI,CAAC,EAAE,OAAO,QAAQ,KAAK,CAAC,CACxF;EACA,uBAAuB;CACzB;CAEA,OAAO,KAAK,SAAS,SAAS,YAAY;EAExC,KAAI,MADiBC,kCAAgB,QAAQ,MAAM,SAAS,EAClD,CAAC,QAAQ,MAAM,WAAW,OAAO,SAAS,gBAAgB,GAOlE;qDADwC,SAAS,QAC/B,GAChB,QAAQ,IACN,mIAEF;EACF;CAEJ,CAAC;CAED,IAAI;CACJ,IAAI,wBAAwB,MAAM,kBAAkB,QAClD,OAAO,KAAK,SAAS,kBAAkB,YAAY;EACjD,MAAM,SAAS,MAAMC,0CAAe;GAClC,KAAK,QAAQ;GACb,eAAe,MAAM;EACvB,CAAC;EACD,IAAI,QAAQ;GACV,UAAU;GACV,kBAAkB,CAAC,GAAG,OAAO,KAAK;EACpC;CACF,CAAC;CAGH,IAAI,CAAC,QAAQ,QACX,OAAO,OAAO,IAAI,iBAAiB,CAAC,CAAC;CAEvC,MAAM,YAAuB,QAAQ;CAErC,IAAI,SAAS,CAAC,gBAAgB,SAAS,GACrC,OAAO,OAAO,IAAI,gBAAgB,CAAC,CAAC;CAGtC,MAAM,qBAAqB,OAAOR,cAAO,WAAW;EAClD,KAAK,YAAY;GACf,OAAO,QAAQ,aAAa;IAC1B;IACA;IACA;IACA;IACA,KAAK;IACL,SAAS,QAAQ,SAAS;GAC5B,CAAC;EACH;EACA,QAAQ,UAAU,IAAI,aAAa;GAAE,OAAO;GAAwB;EAAM,CAAC;CAC7E,CAAC;CACD,KAAK,MAAM,WAAW,QAAQ,UAC5B,OAAOA,cAAO,WAAW,OAAO;CAGlC,MAAM,OAAkB,OAAOD,4BAC7B,SACA,SACAU,0BAAU;EACR,WAAW,QAAQ;EACnB,WAAW;EACX,KAAK;GACH,MAAM,MAAM;GACZ,SAAS,MAAM;GACf,UAAU,MAAM;GAChB,QAAQ,MAAM;GACd,iBAAiB,MAAM;GACvB;GACA;GACA;GACA;GACA;GACA;GACA,aAAa,MAAM;EACrB;CACF,CAAC,CACH;CAEA,OAAOT,cAAO,WAAW;EACvB,WAAWU,yCAAoB,QAAQ,MAAM,KAAK,aAAa;EAC/D,QAAQ,UAAU,IAAI,aAAa;GAAE,OAAO;GAAqB;EAAM,CAAC;CAC1E,CAAC;CACD,OAAO,cAAc,YAAY,QAAQ,IAAI;CAC7C,OAAO,YAAY,YAAY,QAAQ,IAAI;CAE3C,OAAO,WACJ,KAAK,QAAQ,MAAM,KAAK,cAAc,KAAK,CAAC,CAC5C,KACCV,cAAO,SAAS,iBAAiB,UAC/BA,cAAO,WACL,qDAAqD,OAAO,MAAM,KAAK,GACzE,CACF,CACF;CAEF,MAAM,YAAY,OAAOA,cAAO,WAC9BW,+CACE,KAAK,cACLC,qCAAiB,GACjB,KACF,CACF;CACA,OAAOZ,cAAO,WAAW;EACvB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,GACjD,IAAI,QAAQ,cAAc,QAAQ,eAAe,kCAAc,KAAK,KAAK;CAE7E,CAAC;CACD,IAAI,oBAAoB,OAAOa,sCAAoB,KAAK,cAAc,SAAS;CAC/E,IACE,kBAAkB,SAAS,KAC3BC,qCAAsB,mBAAmB;EACvC,GAAGC,sCAAuB,QAAQ,IAAI;EACtC,iBAAiB,OAAOf,cAAO,QAAQgB,gCAAiB;CAC1D,CAAC,GACD;EACA,MAAM,UAAU,OAAO,KAAK,SAAS,2BACnCC,kCAAmB,QAAQ,IAAI,CACjC;EACA,IAAI,QAAQ,IACV,oBAAoB,OAAOJ,sCAAoB,KAAK,cAAc,SAAS;OAE3E,oBAAoB,CAClB,GAAG,mBACH;GACE,QAAQ;GACR,MAAM;GACN,MAAM;GACN,OAAO,qCAAqC,QAAQ,OAAO,MAAM,QAAQ,SAAS;GAClF,cAAc;EAChB,CACF;CAEJ;CACA,IAAI,kBAAkB,SAAS,GAC7B,OAAO,OAAO,IAAI,mBAAmB,EAAE,UAAU,kBAAkB,KAAK,MAAM,EAAE,KAAK,EAAE,CAAC;CAG1F,MAAM,WAAWK,6DAAkC,MAAM;EAAE;EAAK;CAAM,CAAC;CAEvE,MAAM,WAAW,CAAC,GAAG,KAAK,mBAAmB,KAAK,CAAC;CACnD,IAAIC,iCAAQC,kCAAc,OAAO,CAAC,GAChC,OAAOpB,cAAO,SAAS,8BAA8B,SAAS,KAAK,IAAI,GAAG;CAG5E,IADe,SAAS,IAAI,KACnB,CAAC,EAAE,OAAO;EACjB,MAAM,WAAW,gBAAgB,SAAS;EAC1C,IAAI,UAAU,KAAK,aAAa,IAAI,YAAY;CAClD;CAEA,OAAO,KAAK,SAAS,4BACnBqB,6CAAsB,QAAQ,MAAM,WAAW;EAC7C,KAAK;EACL,cAAc;EACd,eAAe,KAAK;CACtB,CAAC,CACH;CAEA,OAAO;EACL,SAAS;GACP,cAAc,KAAK;GACnB;GACA,eAAe,KAAK;GACpB,cAAc,KAAK;GACnB,UAAU;EACZ;EACA,aAAaC,4CAAiB,QAAQ,KAAK,KAAK;EAChD,WAAW;CACb;AACF,CAAC;AAEH,MAAa,kBAAkB,MAAqB,UAClDtB,cAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAOC;CACrB,MAAM,aAAa,OAAOC;CAE1B,MAAM,cAAc,KAAK,SAAS,QAAQ,QAAQ,IAAI;CAEtD,OAAO,YAAY,YAAY,WAAW;CAE1C,OAAOqB,8BAAa;EAAE,OAAO;EAAU,QAAQ;CAAU,CAAC;CAE1D,MAAM,SAAS,MAAM,QAAQH,kCAAc,SAAS,MAAM,YAAY,YAAY;CAClF,MAAM,iBAAiBI,qDAAyB,OAAO;EACrD,aAAaJ,kCAAc,aAAa;EACxC,aAAaA,kCAAc,aAAa;CAC1C,CAAC;CAED,IAAI,SAA2B;CAC/B,IAAI,eAAiC;CAErC,IAAI,eAAe,YACjB,SAAS,KAAK,SAAS,UAAU;MAC5B,IAAI,eAAe,UAAU;EAClC,MAAM,EAAE,SAAS,WAAW,eAAe;EAC3C,MAAM,cAAcK,sCAAuB,SAAS,QAAQ,MAAM,QAAQ;EAC1E,eAAe,OAAOzB,cAAO,WAAW;GACtC,WAAW,uBAAuB,SAAS,QAAQ,MAAM,QAAQ;GACjE,QAAQ,UACN,IAAI,iBAAiB,EACnB,SAAS,oCAAoC,QAAQ,GAAG,OAAO,IAC7D,iBAAiB,QAAQ,MAAM,UAAU,gBAC1C,kBAAkB,cACrB,CAAC;EACL,CAAC;EACD,IAAI,cACF,SAAS;OAET,OAAO,OAAO,IAAI,yBAAyB,EACzC,SAAS,4BAA4B,QAAQ,GAAG,OAAO,iGAAiG,cAC1J,CAAC;CAEL,OACE,SAAS,KAAK,SAAS,UAAU;CAGnC,IAAI,CAAC,QACH,OAAO,OAAO,IAAI,mBAAmB,CAAC,CAAC;CAGzC,IAAI,CAAC,eAAe,YAAY;EAC9B,IAAI,eAAe,UAAU,SAC3B,SAAS;GAAE,GAAG;GAAQ,SAAS,eAAe,SAAS;EAAQ;EAEjE,IAAI,eAAe,UAAU,QAC3B,SAAS;GAAE,GAAG;GAAQ,QAAQ,eAAe,SAAS;EAAO;CAEjE;CACA,MAAM,aAAwB;CAE9B,MAAM,OAAO,MAAM,QAAQ0B,sCAAuB,WAAW,IAAI,KAAK,WAAW;CACjF,MAAM,YAAY,WAAW;CAC7B,MAAM,iBAAiB,OAAO1B,cAAO,WAAW;EAC9C,WAAW2B,4CAA6B,YAAY,aAAa,YAAY;EAC7E,QAAQ,UAAU,IAAI,aAAa;GAAE,OAAO;GAA2B;EAAM,CAAC;CAChF,CAAC;CACD,MAAM,gBAAgB,OAAO3B,cAAO,WAAW;EAC7C,WACE4B,kCAAmB,YAAY,aAAa,cAAc;GACxD,UAAU;GACV,WAAW;GACX,YAAY;GACZ,YAAY;GACZ,SAAS;EACX,CAAC;EACH,QAAQ,UAAU,IAAI,aAAa;GAAE,OAAO;GAAwB;EAAM,CAAC;CAC7E,CAAC;CAED,IAAI,aAAa,WAAW,SAAS,QACnC,cAAc,SAAS,WAAW,QAAQ;CAG5C,IAAI,WACF,cAAc,MAAM;CAGtB,OAAOL,8BAAa;EAAE,OAAO;EAAsB,QAAQ;CAAU,CAAC;CACtE,OAAOvB,cAAO,WAAW;EACvB,WACEqB,6CAAsB,aAAa,YAAY;GAC7C,KAAK;GACL;EACF,CAAC;EACH,QAAQ,UAAU,IAAI,aAAa;GAAE,OAAO;GAAsB;EAAM,CAAC;CAC3E,CAAC;CACD,OAAOE,8BAAa;EAAE,OAAO;EAAsB,QAAQ;CAAO,CAAC;CAEnE,MAAM,gBAAwC,CAAC;CAC/C,MAAM,WAAqB,CAAC;CAE5B,MAAM,kBAAkB;CACxB,MAAM,aAAaH,kCAAc,aAAa;CAG9C,IADE,eAAe,UAAa,gBAAgB,KAAK,UAAU,KAC1BS,4CAAgB,cAAc,GAAG;EAClE,SAAS,KACP,sCAAsC,WAAW,yEACnD;EACA,qCAAiB,aAAa;EAC9B,qCAAiB,UAAU;CAC7B;CAEA,IAAI,CAACT,kCAAc,aAAa,KAAK,WAAW,QAAQ;EAItD,MAAM,gBAAgB,WAHE,YACnB,WAAW,SAAS,UAAU,WAAW,SAC1C,WAAW;EAEf,cAAc,cAAc;EAC5B,cAAc,WAAW;EACzB,SAAS,KAAK,6BAA6B,eAAe;CAC5D;CAEA,MAAM,kCAAkB,IAAI,IAAY;CACxC,MAAM,iBAA2B,CAAC;CAElC,IAAI,cAAc,KAAK,SACrB,KAAK,MAAM,KAAK,cAAc,KAAK,SAAS,gBAAgB,IAAI,CAAC;CAEnE,IAAI,cAAc,MAAM,SACtB,KAAK,MAAM,KAAK,cAAc,KAAK,SAAS,gBAAgB,IAAI,CAAC;CAEnE,IAAI,cAAc,KAAK,SACrB,KAAK,MAAM,KAAK,cAAc,IAAI,SAAS,gBAAgB,IAAI,CAAC;CAElE,KAAK,MAAM,UAAU,OAAO,OAAO,cAAc,WAAW,CAAC,CAAC,GAC5D,IAAI,OAAO,SACT,KAAK,MAAM,KAAK,OAAO,SAAS;EAC9B,IAAI,EAAE,SAAS,eAAe,GAAG;EACjC,gBAAgB,IAAI,CAAC;CACvB;CAIJ,KAAK,MAAM,UAAU,iBAAiB;EACpC,MAAM,QAAQA,kCAAc,MAAM;EAClC,IAAI,CAAC,SAAS,MAAM,WAAW,GAC7B,eAAe,KAAK,MAAM;CAE9B;CAEA,IAAI,eAAe,SAAS,GAC1B,SAAS,KAAK,WAAW,eAAe,OAAO,cAAc,eAAe,KAAK,IAAI,GAAG;CAG1F,KAAK,MAAM,CAAC,QAAQ,UAAU,OAAO,QAAQR,qCAAiB,CAAC,GAAG;EAChE,IAAI,CAAC,SAAS,CAAC,OAAO,SAAS,eAAe,GAAG;EACjD,IAAIkB,uCAAwB,KAAK,GAAG;GAClC,MAAM,OAAO,IAAI,IAAI,KAAK,CAAC,CAAC;GAC5B,SAAS,KACP,GAAG,OAAO,qCAAqC,KAAK,yKAGtD;EACF;CACF;CAEA,MAAM,iBAAyC,YAC3C,EAAE,aAAa,WAAW,SAAS,UAAU,WAAW,UAAU,GAAG,IACrE,CAAC;CAEL,MAAM,OAAkB,OAAOrB,0BAAU;EACvC,WAAW;EACX,WAAW;EACX,KAAK;GACH,MAAM,MAAM;GACZ,KAAK;GACL,OAAO;GACP,YAAY;GACZ,UAAU;GACV,WAAW;GACX,YAAY;GACZ,aAAa,MAAM;EACrB;CACF,CAAC;CAED,MAAM,WAAWsB,qDAA0B,KAAK,aAAa;CAiB7D,MAAM,UAAwB;EAC5B,cAhBmB,eAAe,aAChC,eAAe,aACf,eACE,SAAS,eAAe,UAAU,QAAQ,GAAG,eAAe,UAAU,WACrEC,8BAAe,KAAK;EAazB,kBAVA,gBAAgB,eAAe,WAC3BP,sCACE,eAAe,SAAS,SACxB,eAAe,SAAS,QACxB,MAAM,QACR,IACA;EAKJ,SAAS,WAAW;EACpB,QAAQ,WAAW,UAAU;EAC7B,SAAS;GACP,MAAM,KAAK,cAAc,KAAK,aAAa,KAAK,cAAc,KAAK,OAAO;GAC1E,IAAI,KAAK,cAAc,GAAG,OAAO;GACjC,KAAK,KAAK,cAAc,IAAI,OAAO;GACnC,MAAM,KAAK,cAAc,MAAM,OAAO;EACxC;EACA;CACF;CAEA,MAAM,eAAgC;EACpC,UAAU,CAAC,MAAM;EACjB,KAAK;GACH,UAAU;GACV,GAAG;GACH,GAAG;GACH,GAAG,KAAK,OAAO;EACjB;EACA,aAAa,GAAG,YAAY,YAAY,aAAa,SAAS,WAAW,QAAQ;EACjF,MAAM,KAAK,cAAc,QAAQ;EACjC,aAAa,MAAM;CAQrB;CAEA,OAAOF,8BAAa;EAAE,OAAO;EAAU,QAAQ;CAAO,CAAC;CAEvD,OAAO;EACL,SAAS;GACP;GACA;GACA,eAAe,KAAK;GACpB,cAAc,KAAK;GACnB,UAAU;EACZ;EACA;EACA,KAAK,KAAK,OAAO,WAAW,oBAAoB,KAAK,cAAc,QAAQ;CAC7E;AACF,CAAC;AAEH,MAAa,kBAAkBU,aAAM,SAASC,oCAAgBC,6BAAiB"}
|
|
1
|
+
{"version":3,"file":"dev-program.cjs","names":["Data","walkExtendsChain","resolveConfigComposableEntries","BosConfigSchema","timedPhase","Effect","captureShellEnv","ProjectEnv","detectLocalPackages","syncResolvedSharedDeps","run","findWorkspaceRoot","ensureFreshDeps","openResolution","planInfra","materializeViaLayer","mergeGeneratedOverFileEnv","processEnvRecord","preflightLocalInfra","shouldAutoStartDocker","detectAutoStartContext","isDockerAvailable","runDockerComposeUp","buildServiceDescriptorMapFromPlan","isDebug","getProcessEnv","generateCodeArtifacts","buildDescription","emitProgress","resolveStartConfigSource","buildRegistryConfigUrl","getHostDevelopmentPort","buildRuntimePluginsForConfig","buildRuntimeConfig","isRegistryStart","isRailwayPublicProxyUrl","buildServiceDescriptorMap","findConfigPath","Layer","ProjectEnvLive","PortAllocatorLive"],"sources":["../src/dev-program.ts"],"sourcesContent":["import { Data, Effect, Layer } from \"effect\";\nimport { detectLocalPackages, PortAllocatorLive } from \"./app\";\nimport { generateCodeArtifacts } from \"./code-artifacts\";\nimport {\n buildRuntimeConfig,\n buildRuntimePluginsForConfig,\n findConfigPath,\n getHostDevelopmentPort,\n resolveConfigComposableEntries,\n} from \"./config\";\nimport type { DevOptions, PhaseTiming, StartOptions } from \"./contract\";\nimport { isRailwayPublicProxyUrl } from \"./db/driver\";\nimport { isDebug } from \"./dev-log-pipeline\";\nimport type { DevSessionData, StartSummary } from \"./dev-session-data\";\nimport {\n deleteProcessEnv,\n getProcessEnv,\n processEnvRecord,\n setProcessEnv,\n} from \"./env/process-env\";\nimport {\n captureShellEnv,\n type EnvEnsureError,\n type EnvLoadError,\n ProjectEnv,\n ProjectEnvLive,\n type ProjectEnvService,\n} from \"./env/project-env\";\nimport { buildRegistryConfigUrl } from \"./fastkv\";\nimport {\n detectAutoStartContext,\n isDockerAvailable,\n runDockerComposeUp,\n shouldAutoStartDocker,\n} from \"./infra/docker\";\nimport { materializeViaLayer } from \"./infra/materializer\";\nimport { planInfra } from \"./infra/planner\";\nimport { preflightLocalInfra } from \"./infra/preflight\";\nimport type { InfraPlan } from \"./infra/types\";\nimport { mergeGeneratedOverFileEnv } from \"./orchestrator\";\nimport { emitProgress, timedPhase } from \"./progress\";\nimport { openResolution, type ResolutionSession, walkExtendsChain } from \"./resolution/session\";\nimport {\n type AppOrchestrator,\n buildDescription,\n buildServiceDescriptorMap,\n buildServiceDescriptorMapFromPlan,\n} from \"./service-descriptor\";\nimport { syncResolvedSharedDeps } from \"./shared-deps\";\nimport {\n isRegistryStart,\n resolveStartConfigSource,\n type StartConfigSource,\n} from \"./start-config-source\";\nimport type { BosConfig, SourceMode } from \"./types\";\nimport { BosConfigSchema } from \"./types\";\nimport { run } from \"./utils/run\";\nimport { ensureFreshDeps, findWorkspaceRoot } from \"./workspace\";\n\nexport type { DevSessionData, StartSummary } from \"./dev-session-data\";\n\nexport interface BootstrapDeps {\n readonly session: ResolutionSession | null;\n}\n\nexport class DevStepError extends Data.TaggedError(\"DevStepError\")<{\n phase: string;\n cause: unknown;\n}> {}\n\nexport class DevConfigMissing extends Data.TaggedError(\"DevConfigMissing\")<Record<string, never>> {}\n\nexport class DevProxyMissing extends Data.TaggedError(\"DevProxyMissing\")<Record<string, never>> {}\n\nexport class DevPreflightFailed extends Data.TaggedError(\"DevPreflightFailed\")<{\n messages: string[];\n}> {}\n\nexport class StartFetchFailed extends Data.TaggedError(\"StartFetchFailed\")<{ message: string }> {}\n\nexport class StartRemoteConfigMissing extends Data.TaggedError(\"StartRemoteConfigMissing\")<{\n message: string;\n}> {}\n\nexport class StartConfigMissing extends Data.TaggedError(\"StartConfigMissing\")<\n Record<string, never>\n> {}\n\nfunction parseSourceMode(value: string | undefined, defaultValue: SourceMode): SourceMode {\n if (value === \"local\" || value === \"remote\") return value;\n return defaultValue;\n}\n\n/**\n * A production start booting from an explicit config has declared that config\n * as its truth — the host's SnapshotWatch must not override it with the\n * registry pointer mid-run (a fixture-booted stack carrying a live identity\n * would otherwise adopt a foreign generation 30 seconds in, and a\n * config-path production boot is the operator's declared truth). The watch\n * stays on for identity-driven boots — adopting published config changes is\n * its feature. An operator-set interval always wins.\n */\nexport function setSnapshotWatchIntervalForBoot(\n source: StartConfigSource,\n env: \"production\" | \"staging\",\n processEnv: { BOS_SNAPSHOT_WATCH_INTERVAL_MS?: string } = process.env,\n): void {\n if (processEnv.BOS_SNAPSHOT_WATCH_INTERVAL_MS !== undefined) return;\n if (env !== \"production\" || !source.configPath) return;\n processEnv.BOS_SNAPSHOT_WATCH_INTERVAL_MS = \"0\";\n}\n\nexport async function resolvePublishedConfig(\n account: string,\n gateway: string,\n registry?: string,\n): Promise<BosConfig | null> {\n try {\n const { config: merged } = await walkExtendsChain(`bos://${account}/${gateway}`, {\n env: \"production\",\n registry,\n visit: async () => {},\n });\n return resolveConfigComposableEntries(\n BosConfigSchema.parse(merged),\n process.cwd(),\n \"production\",\n );\n } catch (error) {\n if (error instanceof Error && error.message.startsWith(\"No config found\")) {\n return null;\n }\n throw error;\n }\n}\n\nfunction isValidProxyUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === \"http:\" || parsed.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nexport function resolveProxyUrl(bosConfig: BosConfig | null): string | null {\n if (!bosConfig) return null;\n const apiConfig = bosConfig.app.api;\n if (!apiConfig) return null;\n if (apiConfig.proxy && isValidProxyUrl(apiConfig.proxy)) return apiConfig.proxy;\n if (apiConfig.production && isValidProxyUrl(apiConfig.production)) return apiConfig.production;\n return null;\n}\n\nconst step = <A>(timings: PhaseTiming[], name: string, fn: () => Promise<A>) =>\n timedPhase(\n timings,\n name,\n Effect.tryPromise({\n try: fn,\n catch: (cause) => new DevStepError({ phase: name, cause }),\n }),\n );\n\nconst ensureEnvStep = (projectEnv: ProjectEnvService, configDir: string) =>\n projectEnv\n .ensureFile(configDir)\n .pipe(\n Effect.mapError((cause: EnvEnsureError) => new DevStepError({ phase: \"ensure env\", cause })),\n );\n\nconst loadEnvStep = (projectEnv: ProjectEnvService, configDir: string) =>\n projectEnv\n .load(configDir)\n .pipe(Effect.mapError((cause: EnvLoadError) => new DevStepError({ phase: \"load env\", cause })));\n\nexport const devBootstrap = (deps: BootstrapDeps, input: DevOptions, timings: PhaseTiming[]) =>\n Effect.gen(function* () {\n const shell = yield* captureShellEnv;\n const projectEnv = yield* ProjectEnv;\n\n if (!deps.session) {\n return yield* new DevConfigMissing({});\n }\n let session: ResolutionSession = deps.session;\n\n yield* ensureEnvStep(projectEnv, session.root);\n yield* loadEnvStep(projectEnv, session.root);\n\n const localPackages = detectLocalPackages(\n session.config ?? undefined,\n session.runtime ?? undefined,\n session.root,\n );\n const localPackageNames = new Set(localPackages.map((entry) => entry.name));\n const localDirs = localPackages.map((entry) => entry.dir);\n\n const hostSource: SourceMode = localPackageNames.has(\"host\")\n ? parseSourceMode(input.host, \"local\")\n : \"remote\";\n const uiSource: SourceMode = localPackageNames.has(\"ui\")\n ? parseSourceMode(input.ui, \"local\")\n : \"remote\";\n const apiSource: SourceMode = localPackageNames.has(\"api\")\n ? parseSourceMode(input.api, \"local\")\n : \"remote\";\n const authSource: SourceMode = localPackageNames.has(\"auth\")\n ? parseSourceMode(input.auth, \"local\")\n : \"remote\";\n const ssr = input.ssr ?? false;\n const proxy = input.proxy ?? false;\n\n if (input.logLevel) {\n yield* Effect.sync(() => {\n setProcessEnv(\"BOS_LOG_LEVEL\", input.logLevel!);\n });\n }\n\n if (ssr) {\n yield* Effect.sync(() => {\n setProcessEnv(\"BOS_SSR\", \"1\");\n });\n }\n\n const sharedSync = yield* step(timings, \"shared deps\", () =>\n syncResolvedSharedDeps({\n configDir: session.root,\n hostMode: hostSource,\n bosConfig: session.config ?? undefined,\n extendsChain: [],\n }),\n );\n let configMayHaveChanged = false;\n if (sharedSync.catalogChanged) {\n yield* step(timings, \"install\", () =>\n run(\"pnpm\", [\"install\"], { cwd: findWorkspaceRoot(session.root)?.dir ?? session.root }),\n );\n configMayHaveChanged = true;\n }\n\n yield* step(timings, \"build\", async () => {\n const report = await ensureFreshDeps(session.root, localDirs);\n if (report.rebuilt.some((member) => member.name === \"everything-dev\")) {\n // Only the bos process itself runs the everything-dev dist (plugin\n // children spawn after this step and load the fresh build). A source\n // run (node --import tsx src/cli.ts) never imported dist, so nothing\n // is stale for it — warn only where the previously imported build\n // matters.\n const runningFromDist = import.meta.url.includes(\"/dist/\");\n if (runningFromDist) {\n console.log(\n \"[dev] everything-dev was rebuilt — this session still runs the previous \" +\n \"orchestrator build. Restart `bos dev` once to pick it up.\",\n );\n }\n }\n });\n\n let devExtendsChain: string[] | undefined;\n if (configMayHaveChanged || input.remotePlugins !== undefined) {\n yield* step(timings, \"resolve config\", async () => {\n const opened = await openResolution({\n cwd: session.root,\n remotePlugins: input.remotePlugins,\n });\n if (opened) {\n session = opened;\n devExtendsChain = [...opened.chain];\n }\n });\n }\n\n if (!session.config) {\n return yield* new DevConfigMissing({});\n }\n const bosConfig: BosConfig = session.config;\n\n if (proxy && !resolveProxyUrl(bosConfig)) {\n return yield* new DevProxyMissing({});\n }\n\n const developmentRuntime = yield* Effect.tryPromise({\n try: async () => {\n return session.buildRuntime({\n uiSource,\n apiSource,\n authSource,\n hostSource,\n env: \"development\",\n plugins: session.runtime?.plugins,\n });\n },\n catch: (cause) => new DevStepError({ phase: \"build runtime config\", cause }),\n });\n for (const message of session.warnings) {\n yield* Effect.logWarning(message);\n }\n\n const plan: InfraPlan = yield* timedPhase(\n timings,\n \"ports\",\n planInfra({\n configDir: session.root,\n bosConfig: developmentRuntime,\n cli: {\n port: input.port,\n apiPort: input.apiPort,\n authPort: input.authPort,\n uiPort: input.uiPort,\n pluginPortStart: input.pluginPortStart,\n ssr,\n proxy,\n hostSource,\n uiSource,\n apiSource,\n authSource,\n interactive: input.interactive,\n },\n }),\n );\n\n yield* Effect.tryPromise({\n try: () => materializeViaLayer(session.root, plan.runtimeConfig),\n catch: (cause) => new DevStepError({ phase: \"materialize infra\", cause }),\n });\n yield* ensureEnvStep(projectEnv, session.root);\n yield* loadEnvStep(projectEnv, session.root);\n\n yield* projectEnv\n .sync(session.root, plan.envGenerated, shell)\n .pipe(\n Effect.catchTag(\"EnvSyncError\", (error) =>\n Effect.logWarning(\n `[env] failed to refresh .env from resolved ports: ${String(error.cause)}`,\n ),\n ),\n );\n\n const mergedEnv = yield* Effect.sync(() =>\n mergeGeneratedOverFileEnv(\n plan.envGenerated,\n processEnvRecord() as Record<string, string>,\n shell,\n ),\n );\n yield* Effect.sync(() => {\n for (const [key, value] of Object.entries(mergedEnv)) {\n if (key === \"BASE_URL\" || key === \"CORS_ORIGIN\") setProcessEnv(key, value);\n }\n });\n let preflightFailures = yield* preflightLocalInfra(plan.envGenerated, mergedEnv);\n if (\n preflightFailures.length > 0 &&\n shouldAutoStartDocker(preflightFailures, {\n ...detectAutoStartContext(session.root),\n dockerAvailable: yield* Effect.promise(isDockerAvailable),\n })\n ) {\n const compose = yield* step(timings, \"docker compose up\", () =>\n runDockerComposeUp(session.root),\n );\n if (compose.ok) {\n preflightFailures = yield* preflightLocalInfra(plan.envGenerated, mergedEnv);\n } else {\n preflightFailures = [\n ...preflightFailures,\n {\n secret: \"docker-compose\",\n host: \"localhost\",\n port: 0,\n error: `docker compose up -d --wait failed${compose.tail ? `:\\n${compose.tail}` : \"\"}`,\n tcpReachable: false,\n },\n ];\n }\n }\n if (preflightFailures.length > 0) {\n return yield* new DevPreflightFailed({ messages: preflightFailures.map((f) => f.error) });\n }\n\n const services = buildServiceDescriptorMapFromPlan(plan, { ssr, proxy });\n\n const packages = [...plan.serviceDescriptors.keys()];\n if (isDebug(getProcessEnv(\"DEBUG\"))) {\n yield* Effect.logError(`[DEBUG dev] services keys: ${packages.join(\", \")}`);\n }\n const apiSvc = services.get(\"api\");\n if (apiSvc?.proxy) {\n const proxyUrl = resolveProxyUrl(bosConfig);\n if (proxyUrl) plan.orchestrator.env.API_PROXY = proxyUrl;\n }\n\n yield* step(timings, \"generate artifacts\", () =>\n generateCodeArtifacts(session.root, bosConfig, {\n env: \"development\",\n extendsChain: devExtendsChain,\n runtimeConfig: plan.runtimeConfig,\n }),\n );\n\n return {\n session: {\n orchestrator: plan.orchestrator,\n services,\n runtimeConfig: plan.runtimeConfig,\n envGenerated: plan.envGenerated,\n shellEnv: shell,\n } satisfies DevSessionData,\n description: buildDescription(services) || plan.description,\n processes: packages,\n };\n });\n\nexport const startBootstrap = (deps: BootstrapDeps, input: StartOptions) =>\n Effect.gen(function* () {\n const shell = yield* captureShellEnv;\n const projectEnv = yield* ProjectEnv;\n\n const sessionRoot = deps.session?.root ?? process.cwd();\n\n yield* loadEnvStep(projectEnv, sessionRoot);\n\n yield* emitProgress({ phase: \"config\", status: \"running\" });\n\n const bosEnv = input.env ?? (getProcessEnv(\"BOS_ENV\") === \"staging\" ? \"staging\" : \"production\");\n const explicitConfig = resolveStartConfigSource(input, {\n BOS_ACCOUNT: getProcessEnv(\"BOS_ACCOUNT\"),\n BOS_GATEWAY: getProcessEnv(\"BOS_GATEWAY\"),\n });\n const registry = input.registry ?? getProcessEnv(\"BOS_REGISTRY\");\n setSnapshotWatchIntervalForBoot(explicitConfig, bosEnv);\n\n let config: BosConfig | null = null;\n let remoteConfig: BosConfig | null = null;\n\n if (explicitConfig.configPath) {\n config = deps.session?.config ?? null;\n } else if (explicitConfig.registry) {\n const { account, domain } = explicitConfig.registry;\n const expectedUrl = buildRegistryConfigUrl(account, domain, registry);\n remoteConfig = yield* Effect.tryPromise({\n try: () => resolvePublishedConfig(account, domain, registry),\n catch: (error) =>\n new StartFetchFailed({\n message: `Failed to fetch config for bos://${account}/${domain}: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }\\nExpected URL: ${expectedUrl}`,\n }),\n });\n if (remoteConfig) {\n config = remoteConfig;\n } else {\n return yield* new StartRemoteConfigMissing({\n message: `No config found at bos://${account}/${domain}. Verify the account and gateway are correct and the config has been published.\\nExpected URL: ${expectedUrl}`,\n });\n }\n } else {\n config = deps.session?.config ?? null;\n }\n\n if (!config) {\n return yield* new StartConfigMissing({});\n }\n\n if (!explicitConfig.configPath) {\n if (explicitConfig.registry?.account) {\n config = { ...config, account: explicitConfig.registry.account };\n }\n if (explicitConfig.registry?.domain) {\n config = { ...config, domain: explicitConfig.registry.domain };\n }\n }\n const baseConfig: BosConfig = config;\n\n const port = input.port ?? getHostDevelopmentPort(baseConfig.app.host.development);\n const isStaging = bosEnv === \"staging\";\n const runtimePlugins = yield* Effect.tryPromise({\n try: () => buildRuntimePluginsForConfig(baseConfig, sessionRoot, \"production\"),\n catch: (cause) => new DevStepError({ phase: \"resolve runtime plugins\", cause }),\n });\n const runtimeConfig = yield* Effect.tryPromise({\n try: () =>\n buildRuntimeConfig(baseConfig, sessionRoot, \"production\", {\n uiSource: \"remote\",\n apiSource: \"remote\",\n authSource: \"remote\",\n hostSource: \"remote\",\n plugins: runtimePlugins,\n }),\n catch: (cause) => new DevStepError({ phase: \"build runtime config\", cause }),\n });\n\n if (isStaging && baseConfig.staging?.domain) {\n runtimeConfig.domain = baseConfig.staging.domain;\n }\n\n if (isStaging) {\n runtimeConfig.env = \"staging\";\n }\n\n yield* emitProgress({ phase: \"generate artifacts\", status: \"running\" });\n yield* Effect.tryPromise({\n try: () =>\n generateCodeArtifacts(sessionRoot, baseConfig, {\n env: \"production\",\n runtimeConfig,\n }),\n catch: (cause) => new DevStepError({ phase: \"generate artifacts\", cause }),\n });\n yield* emitProgress({ phase: \"generate artifacts\", status: \"done\" });\n\n const productionEnv: Record<string, string> = {};\n const warnings: string[] = [];\n\n const localhostOrigin = /^https?:\\/\\/(localhost|127\\.0\\.0\\.1)(:\\d+)?$/i;\n const corsOrigin = getProcessEnv(\"CORS_ORIGIN\");\n const isLocalhostProductionOrigin =\n corsOrigin !== undefined && localhostOrigin.test(corsOrigin);\n if (isLocalhostProductionOrigin && isRegistryStart(explicitConfig)) {\n warnings.push(\n `CORS_ORIGIN is a localhost origin (${corsOrigin}) in a registry production start — overriding with the configured domain`,\n );\n deleteProcessEnv(\"CORS_ORIGIN\");\n deleteProcessEnv(\"BASE_URL\");\n }\n\n if (!getProcessEnv(\"CORS_ORIGIN\") && baseConfig.domain) {\n const effectiveDomain = isStaging\n ? (baseConfig.staging?.domain ?? baseConfig.domain)\n : baseConfig.domain;\n const defaultOrigin = `https://${effectiveDomain}`;\n productionEnv.CORS_ORIGIN = defaultOrigin;\n productionEnv.BASE_URL = defaultOrigin;\n warnings.push(`CORS_ORIGIN defaulting to ${defaultOrigin}`);\n }\n\n const requiredSecrets = new Set<string>();\n const missingSecrets: string[] = [];\n\n if (runtimeConfig.host.secrets) {\n for (const s of runtimeConfig.host.secrets) requiredSecrets.add(s);\n }\n if (runtimeConfig.auth?.secrets) {\n for (const s of runtimeConfig.auth.secrets) requiredSecrets.add(s);\n }\n if (runtimeConfig.api?.secrets) {\n for (const s of runtimeConfig.api.secrets) requiredSecrets.add(s);\n }\n for (const plugin of Object.values(runtimeConfig.plugins ?? {})) {\n if (plugin.secrets) {\n for (const s of plugin.secrets) {\n if (s.endsWith(\"_DATABASE_URL\")) continue;\n requiredSecrets.add(s);\n }\n }\n }\n\n for (const secret of requiredSecrets) {\n const value = getProcessEnv(secret);\n if (!value || value.length === 0) {\n missingSecrets.push(secret);\n }\n }\n\n if (missingSecrets.length > 0) {\n warnings.push(`Missing ${missingSecrets.length} secret(s): ${missingSecrets.join(\", \")}`);\n }\n\n for (const [secret, value] of Object.entries(processEnvRecord())) {\n if (!value || !secret.endsWith(\"_DATABASE_URL\")) continue;\n if (isRailwayPublicProxyUrl(value)) {\n const host = new URL(value).hostname;\n warnings.push(\n `${secret} points at Railway's public proxy (${host}) — its TLS certificate is self-signed, ` +\n `so connections use unverified TLS. Prefer the private *.railway.internal URL when the ` +\n `database runs in the same Railway project.`,\n );\n }\n }\n\n const stagingEnvVars: Record<string, string> = isStaging\n ? { BOS_GATEWAY: baseConfig.staging?.domain ?? baseConfig.domain ?? \"\" }\n : {};\n\n const plan: InfraPlan = yield* planInfra({\n configDir: sessionRoot,\n bosConfig: runtimeConfig,\n cli: {\n port: input.port,\n ssr: false,\n proxy: false,\n hostSource: \"remote\",\n uiSource: \"remote\",\n apiSource: \"remote\",\n authSource: \"remote\",\n interactive: input.interactive,\n },\n });\n\n const services = buildServiceDescriptorMap(plan.runtimeConfig);\n\n const configSource = explicitConfig.configPath\n ? explicitConfig.configPath\n : remoteConfig\n ? `bos://${explicitConfig.registry?.account}/${explicitConfig.registry?.domain}`\n : (findConfigPath() ?? \"bos.config.json\");\n\n const configSourceHttp =\n remoteConfig && explicitConfig.registry\n ? buildRegistryConfigUrl(\n explicitConfig.registry.account,\n explicitConfig.registry.domain,\n registry,\n )\n : undefined;\n\n const summary: StartSummary = {\n configSource,\n configSourceHttp,\n account: baseConfig.account,\n domain: baseConfig.domain ?? undefined,\n modules: {\n host: plan.runtimeConfig.host.remoteUrl ?? plan.runtimeConfig.host.url ?? \"local\",\n ui: plan.runtimeConfig.ui.url ?? \"local\",\n api: plan.runtimeConfig.api.url ?? \"local\",\n auth: plan.runtimeConfig.auth?.url ?? undefined,\n },\n warnings,\n };\n\n const orchestrator: AppOrchestrator = {\n packages: [\"host\"],\n env: {\n NODE_ENV: \"production\",\n ...productionEnv,\n ...stagingEnvVars,\n ...plan.launch.env,\n },\n description: `${isStaging ? \"Staging\" : \"Production\"} Mode (${baseConfig.account})`,\n port: plan.resolvedPorts.host ?? port,\n interactive: input.interactive,\n // Log persistence stays off for start stacks: the SSR host emits ~80\n // log events per page render (i18n uncompiled-catalog warnings), and\n // the file sink writes every event twice through a serialized\n // appendFile chain regardless of level or dedup — on a loaded machine\n // that chain starves the event loop and degrades SSR/hydration\n // mid-suite. Boot failures are diagnosed from stdout (the renderer\n // prints error-level lines; the smoke captures 400 lines of it).\n };\n\n yield* emitProgress({ phase: \"config\", status: \"done\" });\n\n return {\n session: {\n orchestrator,\n services,\n runtimeConfig: plan.runtimeConfig,\n envGenerated: plan.envGenerated,\n shellEnv: shell,\n } satisfies DevSessionData,\n summary,\n url: plan.launch.hostUrl ?? `http://localhost:${plan.resolvedPorts.host ?? port}`,\n };\n });\n\nexport const bootstrapLayers = Layer.mergeAll(ProjectEnvLive, PortAllocatorLive);\n"],"mappings":"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"}
|