everything-dev 1.48.0 → 1.50.0

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.
Files changed (142) hide show
  1. package/dist/app.cjs +66 -86
  2. package/dist/app.cjs.map +1 -1
  3. package/dist/app.mjs +66 -87
  4. package/dist/app.mjs.map +1 -1
  5. package/dist/cli/db-doctor.cjs +6 -23
  6. package/dist/cli/db-doctor.cjs.map +1 -1
  7. package/dist/cli/db-doctor.mjs +7 -24
  8. package/dist/cli/db-doctor.mjs.map +1 -1
  9. package/dist/cli/db-repair.cjs +25 -20
  10. package/dist/cli/db-repair.cjs.map +1 -1
  11. package/dist/cli/db-repair.mjs +25 -20
  12. package/dist/cli/db-repair.mjs.map +1 -1
  13. package/dist/cli/db-studio.cjs +4 -2
  14. package/dist/cli/db-studio.cjs.map +1 -1
  15. package/dist/cli/db-studio.mjs +5 -3
  16. package/dist/cli/db-studio.mjs.map +1 -1
  17. package/dist/cli/framework-version.cjs +45 -9
  18. package/dist/cli/framework-version.cjs.map +1 -1
  19. package/dist/cli/framework-version.mjs +45 -10
  20. package/dist/cli/framework-version.mjs.map +1 -1
  21. package/dist/cli/infra.cjs +89 -3
  22. package/dist/cli/infra.cjs.map +1 -1
  23. package/dist/cli/infra.mjs +83 -4
  24. package/dist/cli/infra.mjs.map +1 -1
  25. package/dist/cli/init.cjs +39 -15
  26. package/dist/cli/init.cjs.map +1 -1
  27. package/dist/cli/init.d.cts +8 -3
  28. package/dist/cli/init.d.cts.map +1 -1
  29. package/dist/cli/init.d.mts +8 -3
  30. package/dist/cli/init.d.mts.map +1 -1
  31. package/dist/cli/init.mjs +39 -16
  32. package/dist/cli/init.mjs.map +1 -1
  33. package/dist/cli/status.cjs +6 -2
  34. package/dist/cli/status.cjs.map +1 -1
  35. package/dist/cli/status.mjs +7 -3
  36. package/dist/cli/status.mjs.map +1 -1
  37. package/dist/cli/sync.cjs +1 -3
  38. package/dist/cli/sync.cjs.map +1 -1
  39. package/dist/cli/sync.mjs +1 -3
  40. package/dist/cli/sync.mjs.map +1 -1
  41. package/dist/cli/upgrade.cjs +8 -4
  42. package/dist/cli/upgrade.cjs.map +1 -1
  43. package/dist/cli/upgrade.mjs +8 -4
  44. package/dist/cli/upgrade.mjs.map +1 -1
  45. package/dist/cli.cjs +73 -9
  46. package/dist/cli.cjs.map +1 -1
  47. package/dist/cli.mjs +74 -10
  48. package/dist/cli.mjs.map +1 -1
  49. package/dist/config.cjs +7 -3
  50. package/dist/config.cjs.map +1 -1
  51. package/dist/config.d.cts.map +1 -1
  52. package/dist/config.d.mts.map +1 -1
  53. package/dist/config.mjs +7 -3
  54. package/dist/config.mjs.map +1 -1
  55. package/dist/contract.cjs +76 -4
  56. package/dist/contract.cjs.map +1 -1
  57. package/dist/contract.d.cts +164 -19
  58. package/dist/contract.d.cts.map +1 -1
  59. package/dist/contract.d.mts +164 -19
  60. package/dist/contract.d.mts.map +1 -1
  61. package/dist/contract.meta.cjs +17 -2
  62. package/dist/contract.meta.cjs.map +1 -1
  63. package/dist/contract.meta.d.cts +23 -2
  64. package/dist/contract.meta.d.mts +23 -2
  65. package/dist/contract.meta.mjs +17 -2
  66. package/dist/contract.meta.mjs.map +1 -1
  67. package/dist/contract.mjs +72 -5
  68. package/dist/contract.mjs.map +1 -1
  69. package/dist/db.cjs +33 -25
  70. package/dist/db.cjs.map +1 -1
  71. package/dist/db.d.cts +16 -9
  72. package/dist/db.d.cts.map +1 -1
  73. package/dist/db.d.mts +16 -9
  74. package/dist/db.d.mts.map +1 -1
  75. package/dist/db.mjs +33 -24
  76. package/dist/db.mjs.map +1 -1
  77. package/dist/dev-session.cjs +28 -0
  78. package/dist/dev-session.cjs.map +1 -1
  79. package/dist/dev-session.mjs +29 -1
  80. package/dist/dev-session.mjs.map +1 -1
  81. package/dist/index.cjs +5 -0
  82. package/dist/index.d.cts +2 -2
  83. package/dist/index.d.mts +2 -2
  84. package/dist/index.mjs +2 -2
  85. package/dist/infra/planner.cjs +337 -0
  86. package/dist/infra/planner.cjs.map +1 -0
  87. package/dist/infra/planner.mjs +336 -0
  88. package/dist/infra/planner.mjs.map +1 -0
  89. package/dist/infra/preflight.cjs +131 -0
  90. package/dist/infra/preflight.cjs.map +1 -0
  91. package/dist/infra/preflight.mjs +130 -0
  92. package/dist/infra/preflight.mjs.map +1 -0
  93. package/dist/infra/types.cjs +9 -0
  94. package/dist/infra/types.cjs.map +1 -0
  95. package/dist/infra/types.mjs +8 -0
  96. package/dist/infra/types.mjs.map +1 -0
  97. package/dist/near-cli.cjs +37 -0
  98. package/dist/near-cli.cjs.map +1 -1
  99. package/dist/near-cli.mjs +36 -1
  100. package/dist/near-cli.mjs.map +1 -1
  101. package/dist/orchestrator.cjs +10 -2
  102. package/dist/orchestrator.cjs.map +1 -1
  103. package/dist/orchestrator.mjs +10 -2
  104. package/dist/orchestrator.mjs.map +1 -1
  105. package/dist/plugin.cjs +160 -43
  106. package/dist/plugin.cjs.map +1 -1
  107. package/dist/plugin.d.cts +64 -8
  108. package/dist/plugin.d.cts.map +1 -1
  109. package/dist/plugin.d.mts +64 -8
  110. package/dist/plugin.d.mts.map +1 -1
  111. package/dist/plugin.mjs +164 -47
  112. package/dist/plugin.mjs.map +1 -1
  113. package/dist/process-registry.cjs +88 -0
  114. package/dist/process-registry.cjs.map +1 -0
  115. package/dist/process-registry.mjs +83 -0
  116. package/dist/process-registry.mjs.map +1 -0
  117. package/dist/publish.cjs +4 -0
  118. package/dist/publish.cjs.map +1 -1
  119. package/dist/publish.mjs +4 -0
  120. package/dist/publish.mjs.map +1 -1
  121. package/dist/service-descriptor.cjs +4 -0
  122. package/dist/service-descriptor.cjs.map +1 -1
  123. package/dist/service-descriptor.mjs +4 -1
  124. package/dist/service-descriptor.mjs.map +1 -1
  125. package/dist/types.d.cts +2 -2
  126. package/dist/types.d.mts +2 -2
  127. package/dist/ui/index.cjs +2 -1
  128. package/dist/ui/index.d.cts +2 -2
  129. package/dist/ui/index.d.mts +2 -2
  130. package/dist/ui/index.mjs +2 -2
  131. package/dist/ui/router.cjs +40 -0
  132. package/dist/ui/router.cjs.map +1 -1
  133. package/dist/ui/router.d.cts +6 -1
  134. package/dist/ui/router.d.cts.map +1 -1
  135. package/dist/ui/router.d.mts +6 -1
  136. package/dist/ui/router.d.mts.map +1 -1
  137. package/dist/ui/router.mjs +40 -1
  138. package/dist/ui/router.mjs.map +1 -1
  139. package/package.json +4 -1
  140. package/skills/cli-reference/SKILL.md +5 -4
  141. package/skills/dev-workflow/SKILL.md +40 -11
  142. package/skills/plugin-development/SKILL.md +9 -2
package/dist/db.cjs CHANGED
@@ -4,12 +4,17 @@ let node_fs = require("node:fs");
4
4
  let node_path = require("node:path");
5
5
 
6
6
  //#region src/db.ts
7
+ const DEFAULT_MIGRATION_JOURNAL = {
8
+ schema: "drizzle",
9
+ table: "__drizzle_migrations"
10
+ };
11
+ const PER_PLUGIN_ISOLATION = false;
7
12
  function normalizeSlug(name) {
8
13
  return (name.split("/").pop() ?? name).replace(/^@/, "").replace(/[^a-zA-Z0-9_-]/g, "_").replace(/-plugin$/i, "").replace(/-/g, "_").toLowerCase();
9
14
  }
10
15
  function getMigrationSlug(dir) {
11
16
  if (!dir) return normalizeSlug(process.env.npm_package_name ?? "unknown");
12
- let current = (0, node_path.dirname)(dir);
17
+ let current = dir;
13
18
  for (let i = 0; i < 10; i++) {
14
19
  const pkgPath = (0, node_path.join)(current, "package.json");
15
20
  if ((0, node_fs.existsSync)(pkgPath)) try {
@@ -23,30 +28,36 @@ function getMigrationSlug(dir) {
23
28
  }
24
29
  return normalizeSlug(dir);
25
30
  }
26
- function getMigrationStorage(dir) {
27
- return {
28
- schema: "drizzle",
29
- table: `__drizzle_migrations_${getMigrationSlug(dir)}`,
30
- slug: getMigrationSlug(dir)
31
+ function getMigrationStorage(slug, options) {
32
+ const s = normalizeSlug(slug ?? getMigrationSlug());
33
+ if (options?.isolated ?? PER_PLUGIN_ISOLATION) return {
34
+ schema: DEFAULT_MIGRATION_JOURNAL.schema,
35
+ table: `__drizzle_migrations_${s}`,
36
+ slug: s
31
37
  };
32
- }
33
- function getLegacyCandidates() {
34
- return [{
35
- schema: "drizzle",
36
- table: "__drizzle_migrations"
37
- }, {
38
- schema: "public",
39
- table: "drizzle_migrations"
40
- }];
41
- }
42
- function migrateSql(storage) {
43
38
  return {
44
- ...storage,
45
- qualified: `"${storage.schema}"."${storage.table}"`
39
+ schema: DEFAULT_MIGRATION_JOURNAL.schema,
40
+ table: DEFAULT_MIGRATION_JOURNAL.table,
41
+ slug: s
46
42
  };
47
43
  }
44
+ /**
45
+ * Format a JavaScript string array as a PostgreSQL text array literal for use
46
+ * with Drizzle's `sql` tag. Example return:
47
+ * `'{"h1","h2"}'::text[]`
48
+ *
49
+ * Usage: sql`WHERE col = ANY(${toSqlArray(values)})`
50
+ *
51
+ * Drizzle's default parameter binding does not handle array types correctly
52
+ * with the pg driver (it emits `ANY(($1))` with a single string, which
53
+ * Postgres rejects as a malformed array literal).
54
+ */
55
+ function toSqlArray(arr) {
56
+ if (arr.length === 0) return `'{}'::text[]`;
57
+ return `'{${arr.map((v) => v.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")).map((v) => `"${v}"`).join(",")}}'::text[]`;
58
+ }
48
59
  function pluginMigrationSlug(key) {
49
- return (key.split("/").pop() ?? key).replace(/^@/, "").replace(/[^a-zA-Z0-9_-]/g, "_").replace(/-plugin$/i, "").replace(/-/g, "_").toLowerCase();
60
+ return normalizeSlug(key);
50
61
  }
51
62
  function getDatabaseUrlSecretName(slug) {
52
63
  return `${slug.toUpperCase().replace(/-/g, "_")}_DATABASE_URL`;
@@ -55,10 +66,8 @@ function extractExpectedTables(migrations) {
55
66
  const tables = /* @__PURE__ */ new Set();
56
67
  const re = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:"([^"]+)"\.)?"([^"]+)"/gi;
57
68
  for (const migration of migrations) for (const stmt of migration.sql) for (const match of stmt.matchAll(re)) {
58
- const schemaName = match[1];
59
69
  const tableName = match[2];
60
- if (schemaName) tables.add(schemaName);
61
- else if (tableName) tables.add(tableName);
70
+ if (tableName) tables.add(tableName);
62
71
  }
63
72
  return [...tables];
64
73
  }
@@ -66,9 +75,8 @@ function extractExpectedTables(migrations) {
66
75
  //#endregion
67
76
  exports.extractExpectedTables = extractExpectedTables;
68
77
  exports.getDatabaseUrlSecretName = getDatabaseUrlSecretName;
69
- exports.getLegacyCandidates = getLegacyCandidates;
70
78
  exports.getMigrationSlug = getMigrationSlug;
71
79
  exports.getMigrationStorage = getMigrationStorage;
72
- exports.migrateSql = migrateSql;
73
80
  exports.pluginMigrationSlug = pluginMigrationSlug;
81
+ exports.toSqlArray = toSqlArray;
74
82
  //# sourceMappingURL=db.cjs.map
package/dist/db.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"db.cjs","names":[],"sources":["../src/db.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\nfunction 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 = dirname(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(dir?: string): MigrationStorage {\n return {\n schema: \"drizzle\",\n table: `__drizzle_migrations_${getMigrationSlug(dir)}`,\n slug: getMigrationSlug(dir),\n };\n}\n\nexport function getLegacyCandidates(): { schema: string; table: string }[] {\n return [\n { schema: \"drizzle\", table: \"__drizzle_migrations\" },\n { schema: \"public\", table: \"drizzle_migrations\" },\n ];\n}\n\nexport function migrateSql(storage: MigrationStorage): MigrationStorage & { qualified: string } {\n return { ...storage, qualified: `\"${storage.schema}\".\"${storage.table}\"` };\n}\n\nexport function pluginMigrationSlug(key: string): string {\n const basename = key.split(\"/\").pop() ?? key;\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 getDatabaseUrlSecretName(slug: string): string {\n return `${slug.toUpperCase().replace(/-/g, \"_\")}_DATABASE_URL`;\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 schemaName = match[1];\n const tableName = match[2];\n if (schemaName) {\n tables.add(schemaName);\n } else if (tableName) {\n tables.add(tableName);\n }\n }\n }\n }\n return [...tables];\n}\n"],"mappings":";;;;;;AASA,SAAS,cAAc,MAAsB;AAE3C,SADiB,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,MAEvC,QAAQ,MAAM,GAAG,CACjB,QAAQ,mBAAmB,IAAI,CAC/B,QAAQ,aAAa,GAAG,CACxB,QAAQ,MAAM,IAAI,CAClB,aAAa;;AAGlB,SAAgB,iBAAiB,KAAsB;AACrD,KAAI,CAAC,IAAK,QAAO,cAAc,QAAQ,IAAI,oBAAoB,UAAU;CACzE,IAAI,iCAAkB,IAAI;AAC1B,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,8BAAe,SAAS,eAAe;AAC7C,8BAAe,QAAQ,CACrB,KAAI;AAEF,UAAO,cADK,KAAK,gCAAmB,SAAS,QAAQ,CAC7B,CAAC,QAAQ,QAAQ;UACnC;AACN,UAAO,cAAc,QAAQ;;EAGjC,MAAM,gCAAiB,QAAQ;AAC/B,MAAI,WAAW,QAAS;AACxB,YAAU;;AAEZ,QAAO,cAAc,IAAI;;AAG3B,SAAgB,oBAAoB,KAAgC;AAClE,QAAO;EACL,QAAQ;EACR,OAAO,wBAAwB,iBAAiB,IAAI;EACpD,MAAM,iBAAiB,IAAI;EAC5B;;AAGH,SAAgB,sBAA2D;AACzE,QAAO,CACL;EAAE,QAAQ;EAAW,OAAO;EAAwB,EACpD;EAAE,QAAQ;EAAU,OAAO;EAAsB,CAClD;;AAGH,SAAgB,WAAW,SAAqE;AAC9F,QAAO;EAAE,GAAG;EAAS,WAAW,IAAI,QAAQ,OAAO,KAAK,QAAQ,MAAM;EAAI;;AAG5E,SAAgB,oBAAoB,KAAqB;AAEvD,SADiB,IAAI,MAAM,IAAI,CAAC,KAAK,IAAI,KAEtC,QAAQ,MAAM,GAAG,CACjB,QAAQ,mBAAmB,IAAI,CAC/B,QAAQ,aAAa,GAAG,CACxB,QAAQ,MAAM,IAAI,CAClB,aAAa;;AAGlB,SAAgB,yBAAyB,MAAsB;AAC7D,QAAO,GAAG,KAAK,aAAa,CAAC,QAAQ,MAAM,IAAI,CAAC;;AAGlD,SAAgB,sBAAsB,YAA2C;CAC/E,MAAM,yBAAS,IAAI,KAAa;CAChC,MAAM,KAAK;AACX,MAAK,MAAM,aAAa,WACtB,MAAK,MAAM,QAAQ,UAAU,IAC3B,MAAK,MAAM,SAAS,KAAK,SAAS,GAAG,EAAE;EACrC,MAAM,aAAa,MAAM;EACzB,MAAM,YAAY,MAAM;AACxB,MAAI,WACF,QAAO,IAAI,WAAW;WACb,UACT,QAAO,IAAI,UAAU;;AAK7B,QAAO,CAAC,GAAG,OAAO"}
1
+ {"version":3,"file":"db.cjs","names":[],"sources":["../src/db.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\nfunction 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 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;CACR;AAED,MAAM,uBAAuB;AAE7B,SAAS,cAAc,MAAsB;AAE3C,SADiB,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,MAEvC,QAAQ,MAAM,GAAG,CACjB,QAAQ,mBAAmB,IAAI,CAC/B,QAAQ,aAAa,GAAG,CACxB,QAAQ,MAAM,IAAI,CAClB,aAAa;;AAGlB,SAAgB,iBAAiB,KAAsB;AACrD,KAAI,CAAC,IAAK,QAAO,cAAc,QAAQ,IAAI,oBAAoB,UAAU;CACzE,IAAI,UAAU;AACd,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,8BAAe,SAAS,eAAe;AAC7C,8BAAe,QAAQ,CACrB,KAAI;AAEF,UAAO,cADK,KAAK,gCAAmB,SAAS,QAAQ,CAC7B,CAAC,QAAQ,QAAQ;UACnC;AACN,UAAO,cAAc,QAAQ;;EAGjC,MAAM,gCAAiB,QAAQ;AAC/B,MAAI,WAAW,QAAS;AACxB,YAAU;;AAEZ,QAAO,cAAc,IAAI;;AAG3B,SAAgB,oBACd,MACA,SACkB;CAClB,MAAM,IAAI,cAAc,QAAQ,kBAAkB,CAAC;AAEnD,KADiB,SAAS,YAAY,qBAEpC,QAAO;EACL,QAAQ,0BAA0B;EAClC,OAAO,wBAAwB;EAC/B,MAAM;EACP;AAEH,QAAO;EACL,QAAQ,0BAA0B;EAClC,OAAO,0BAA0B;EACjC,MAAM;EACP;;;;;;;;;;;;;AAcH,SAAgB,WAAW,KAAuB;AAChD,KAAI,IAAI,WAAW,EAAG,QAAO;AAE7B,QAAO,KADS,IAAI,KAAK,MAAM,EAAE,QAAQ,OAAO,OAAO,CAAC,QAAQ,MAAM,OAAM,CACzD,CAAC,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;;AAGrD,SAAgB,oBAAoB,KAAqB;AACvD,QAAO,cAAc,IAAI;;AAG3B,SAAgB,yBAAyB,MAAsB;AAC7D,QAAO,GAAG,KAAK,aAAa,CAAC,QAAQ,MAAM,IAAI,CAAC;;AAGlD,SAAgB,sBAAsB,YAA2C;CAC/E,MAAM,yBAAS,IAAI,KAAa;CAChC,MAAM,KAAK;AACX,MAAK,MAAM,aAAa,WACtB,MAAK,MAAM,QAAQ,UAAU,IAC3B,MAAK,MAAM,SAAS,KAAK,SAAS,GAAG,EAAE;EACrC,MAAM,YAAY,MAAM;AACxB,MAAI,UACF,QAAO,IAAI,UAAU;;AAK7B,QAAO,CAAC,GAAG,OAAO"}
package/dist/db.d.cts CHANGED
@@ -5,19 +5,26 @@ interface MigrationStorage {
5
5
  slug: string;
6
6
  }
7
7
  declare function getMigrationSlug(dir?: string): string;
8
- declare function getMigrationStorage(dir?: string): MigrationStorage;
9
- declare function getLegacyCandidates(): {
10
- schema: string;
11
- table: string;
12
- }[];
13
- declare function migrateSql(storage: MigrationStorage): MigrationStorage & {
14
- qualified: string;
15
- };
8
+ declare function getMigrationStorage(slug?: string, options?: {
9
+ isolated?: boolean;
10
+ }): MigrationStorage;
11
+ /**
12
+ * Format a JavaScript string array as a PostgreSQL text array literal for use
13
+ * with Drizzle's `sql` tag. Example return:
14
+ * `'{"h1","h2"}'::text[]`
15
+ *
16
+ * Usage: sql`WHERE col = ANY(${toSqlArray(values)})`
17
+ *
18
+ * Drizzle's default parameter binding does not handle array types correctly
19
+ * with the pg driver (it emits `ANY(($1))` with a single string, which
20
+ * Postgres rejects as a malformed array literal).
21
+ */
22
+ declare function toSqlArray(arr: string[]): string;
16
23
  declare function pluginMigrationSlug(key: string): string;
17
24
  declare function getDatabaseUrlSecretName(slug: string): string;
18
25
  declare function extractExpectedTables(migrations: {
19
26
  sql: string[];
20
27
  }[]): string[];
21
28
  //#endregion
22
- export { MigrationStorage, extractExpectedTables, getDatabaseUrlSecretName, getLegacyCandidates, getMigrationSlug, getMigrationStorage, migrateSql, pluginMigrationSlug };
29
+ export { MigrationStorage, extractExpectedTables, getDatabaseUrlSecretName, getMigrationSlug, getMigrationStorage, pluginMigrationSlug, toSqlArray };
23
30
  //# sourceMappingURL=db.d.cts.map
package/dist/db.d.cts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.cts","names":[],"sources":["../src/db.ts"],"mappings":";UAGiB,gBAAA;EACf,MAAA;EACA,KAAA;EACA,IAAA;AAAA;AAAA,iBAac,gBAAA,CAAiB,GAAA;AAAA,iBAoBjB,mBAAA,CAAoB,GAAA,YAAe,gBAAA;AAAA,iBAQnC,mBAAA,CAAA;EAAyB,MAAA;EAAgB,KAAA;AAAA;AAAA,iBAOzC,UAAA,CAAW,OAAA,EAAS,gBAAA,GAAmB,gBAAA;EAAqB,SAAA;AAAA;AAAA,iBAI5D,mBAAA,CAAoB,GAAA;AAAA,iBAUpB,wBAAA,CAAyB,IAAA;AAAA,iBAIzB,qBAAA,CAAsB,UAAA;EAAc,GAAA;AAAA"}
1
+ {"version":3,"file":"db.d.cts","names":[],"sources":["../src/db.ts"],"mappings":";UAGiB,gBAAA;EACf,MAAA;EACA,KAAA;EACA,IAAA;AAAA;AAAA,iBAoBc,gBAAA,CAAiB,GAAA;AAAA,iBAoBjB,mBAAA,CACd,IAAA,WACA,OAAA;EAAY,QAAA;AAAA,IACX,gBAAA;;AAvBH;;;;;AAoBA;;;;;iBA+BgB,UAAA,CAAW,GAAA;AAAA,iBAMX,mBAAA,CAAoB,GAAA;AAAA,iBAIpB,wBAAA,CAAyB,IAAA;AAAA,iBAIzB,qBAAA,CAAsB,UAAA;EAAc,GAAA;AAAA"}
package/dist/db.d.mts CHANGED
@@ -5,19 +5,26 @@ interface MigrationStorage {
5
5
  slug: string;
6
6
  }
7
7
  declare function getMigrationSlug(dir?: string): string;
8
- declare function getMigrationStorage(dir?: string): MigrationStorage;
9
- declare function getLegacyCandidates(): {
10
- schema: string;
11
- table: string;
12
- }[];
13
- declare function migrateSql(storage: MigrationStorage): MigrationStorage & {
14
- qualified: string;
15
- };
8
+ declare function getMigrationStorage(slug?: string, options?: {
9
+ isolated?: boolean;
10
+ }): MigrationStorage;
11
+ /**
12
+ * Format a JavaScript string array as a PostgreSQL text array literal for use
13
+ * with Drizzle's `sql` tag. Example return:
14
+ * `'{"h1","h2"}'::text[]`
15
+ *
16
+ * Usage: sql`WHERE col = ANY(${toSqlArray(values)})`
17
+ *
18
+ * Drizzle's default parameter binding does not handle array types correctly
19
+ * with the pg driver (it emits `ANY(($1))` with a single string, which
20
+ * Postgres rejects as a malformed array literal).
21
+ */
22
+ declare function toSqlArray(arr: string[]): string;
16
23
  declare function pluginMigrationSlug(key: string): string;
17
24
  declare function getDatabaseUrlSecretName(slug: string): string;
18
25
  declare function extractExpectedTables(migrations: {
19
26
  sql: string[];
20
27
  }[]): string[];
21
28
  //#endregion
22
- export { MigrationStorage, extractExpectedTables, getDatabaseUrlSecretName, getLegacyCandidates, getMigrationSlug, getMigrationStorage, migrateSql, pluginMigrationSlug };
29
+ export { MigrationStorage, extractExpectedTables, getDatabaseUrlSecretName, getMigrationSlug, getMigrationStorage, pluginMigrationSlug, toSqlArray };
23
30
  //# sourceMappingURL=db.d.mts.map
package/dist/db.d.mts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.mts","names":[],"sources":["../src/db.ts"],"mappings":";UAGiB,gBAAA;EACf,MAAA;EACA,KAAA;EACA,IAAA;AAAA;AAAA,iBAac,gBAAA,CAAiB,GAAA;AAAA,iBAoBjB,mBAAA,CAAoB,GAAA,YAAe,gBAAA;AAAA,iBAQnC,mBAAA,CAAA;EAAyB,MAAA;EAAgB,KAAA;AAAA;AAAA,iBAOzC,UAAA,CAAW,OAAA,EAAS,gBAAA,GAAmB,gBAAA;EAAqB,SAAA;AAAA;AAAA,iBAI5D,mBAAA,CAAoB,GAAA;AAAA,iBAUpB,wBAAA,CAAyB,IAAA;AAAA,iBAIzB,qBAAA,CAAsB,UAAA;EAAc,GAAA;AAAA"}
1
+ {"version":3,"file":"db.d.mts","names":[],"sources":["../src/db.ts"],"mappings":";UAGiB,gBAAA;EACf,MAAA;EACA,KAAA;EACA,IAAA;AAAA;AAAA,iBAoBc,gBAAA,CAAiB,GAAA;AAAA,iBAoBjB,mBAAA,CACd,IAAA,WACA,OAAA;EAAY,QAAA;AAAA,IACX,gBAAA;;AAvBH;;;;;AAoBA;;;;;iBA+BgB,UAAA,CAAW,GAAA;AAAA,iBAMX,mBAAA,CAAoB,GAAA;AAAA,iBAIpB,wBAAA,CAAyB,IAAA;AAAA,iBAIzB,qBAAA,CAAsB,UAAA;EAAc,GAAA;AAAA"}
package/dist/db.mjs CHANGED
@@ -2,12 +2,17 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
 
4
4
  //#region src/db.ts
5
+ const DEFAULT_MIGRATION_JOURNAL = {
6
+ schema: "drizzle",
7
+ table: "__drizzle_migrations"
8
+ };
9
+ const PER_PLUGIN_ISOLATION = false;
5
10
  function normalizeSlug(name) {
6
11
  return (name.split("/").pop() ?? name).replace(/^@/, "").replace(/[^a-zA-Z0-9_-]/g, "_").replace(/-plugin$/i, "").replace(/-/g, "_").toLowerCase();
7
12
  }
8
13
  function getMigrationSlug(dir) {
9
14
  if (!dir) return normalizeSlug(process.env.npm_package_name ?? "unknown");
10
- let current = dirname(dir);
15
+ let current = dir;
11
16
  for (let i = 0; i < 10; i++) {
12
17
  const pkgPath = join(current, "package.json");
13
18
  if (existsSync(pkgPath)) try {
@@ -21,30 +26,36 @@ function getMigrationSlug(dir) {
21
26
  }
22
27
  return normalizeSlug(dir);
23
28
  }
24
- function getMigrationStorage(dir) {
25
- return {
26
- schema: "drizzle",
27
- table: `__drizzle_migrations_${getMigrationSlug(dir)}`,
28
- slug: getMigrationSlug(dir)
29
+ function getMigrationStorage(slug, options) {
30
+ const s = normalizeSlug(slug ?? getMigrationSlug());
31
+ if (options?.isolated ?? PER_PLUGIN_ISOLATION) return {
32
+ schema: DEFAULT_MIGRATION_JOURNAL.schema,
33
+ table: `__drizzle_migrations_${s}`,
34
+ slug: s
29
35
  };
30
- }
31
- function getLegacyCandidates() {
32
- return [{
33
- schema: "drizzle",
34
- table: "__drizzle_migrations"
35
- }, {
36
- schema: "public",
37
- table: "drizzle_migrations"
38
- }];
39
- }
40
- function migrateSql(storage) {
41
36
  return {
42
- ...storage,
43
- qualified: `"${storage.schema}"."${storage.table}"`
37
+ schema: DEFAULT_MIGRATION_JOURNAL.schema,
38
+ table: DEFAULT_MIGRATION_JOURNAL.table,
39
+ slug: s
44
40
  };
45
41
  }
42
+ /**
43
+ * Format a JavaScript string array as a PostgreSQL text array literal for use
44
+ * with Drizzle's `sql` tag. Example return:
45
+ * `'{"h1","h2"}'::text[]`
46
+ *
47
+ * Usage: sql`WHERE col = ANY(${toSqlArray(values)})`
48
+ *
49
+ * Drizzle's default parameter binding does not handle array types correctly
50
+ * with the pg driver (it emits `ANY(($1))` with a single string, which
51
+ * Postgres rejects as a malformed array literal).
52
+ */
53
+ function toSqlArray(arr) {
54
+ if (arr.length === 0) return `'{}'::text[]`;
55
+ return `'{${arr.map((v) => v.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")).map((v) => `"${v}"`).join(",")}}'::text[]`;
56
+ }
46
57
  function pluginMigrationSlug(key) {
47
- return (key.split("/").pop() ?? key).replace(/^@/, "").replace(/[^a-zA-Z0-9_-]/g, "_").replace(/-plugin$/i, "").replace(/-/g, "_").toLowerCase();
58
+ return normalizeSlug(key);
48
59
  }
49
60
  function getDatabaseUrlSecretName(slug) {
50
61
  return `${slug.toUpperCase().replace(/-/g, "_")}_DATABASE_URL`;
@@ -53,14 +64,12 @@ function extractExpectedTables(migrations) {
53
64
  const tables = /* @__PURE__ */ new Set();
54
65
  const re = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:"([^"]+)"\.)?"([^"]+)"/gi;
55
66
  for (const migration of migrations) for (const stmt of migration.sql) for (const match of stmt.matchAll(re)) {
56
- const schemaName = match[1];
57
67
  const tableName = match[2];
58
- if (schemaName) tables.add(schemaName);
59
- else if (tableName) tables.add(tableName);
68
+ if (tableName) tables.add(tableName);
60
69
  }
61
70
  return [...tables];
62
71
  }
63
72
 
64
73
  //#endregion
65
- export { extractExpectedTables, getDatabaseUrlSecretName, getLegacyCandidates, getMigrationSlug, getMigrationStorage, migrateSql, pluginMigrationSlug };
74
+ export { extractExpectedTables, getDatabaseUrlSecretName, getMigrationSlug, getMigrationStorage, pluginMigrationSlug, toSqlArray };
66
75
  //# sourceMappingURL=db.mjs.map
package/dist/db.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"db.mjs","names":[],"sources":["../src/db.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\nfunction 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 = dirname(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(dir?: string): MigrationStorage {\n return {\n schema: \"drizzle\",\n table: `__drizzle_migrations_${getMigrationSlug(dir)}`,\n slug: getMigrationSlug(dir),\n };\n}\n\nexport function getLegacyCandidates(): { schema: string; table: string }[] {\n return [\n { schema: \"drizzle\", table: \"__drizzle_migrations\" },\n { schema: \"public\", table: \"drizzle_migrations\" },\n ];\n}\n\nexport function migrateSql(storage: MigrationStorage): MigrationStorage & { qualified: string } {\n return { ...storage, qualified: `\"${storage.schema}\".\"${storage.table}\"` };\n}\n\nexport function pluginMigrationSlug(key: string): string {\n const basename = key.split(\"/\").pop() ?? key;\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 getDatabaseUrlSecretName(slug: string): string {\n return `${slug.toUpperCase().replace(/-/g, \"_\")}_DATABASE_URL`;\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 schemaName = match[1];\n const tableName = match[2];\n if (schemaName) {\n tables.add(schemaName);\n } else if (tableName) {\n tables.add(tableName);\n }\n }\n }\n }\n return [...tables];\n}\n"],"mappings":";;;;AASA,SAAS,cAAc,MAAsB;AAE3C,SADiB,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,MAEvC,QAAQ,MAAM,GAAG,CACjB,QAAQ,mBAAmB,IAAI,CAC/B,QAAQ,aAAa,GAAG,CACxB,QAAQ,MAAM,IAAI,CAClB,aAAa;;AAGlB,SAAgB,iBAAiB,KAAsB;AACrD,KAAI,CAAC,IAAK,QAAO,cAAc,QAAQ,IAAI,oBAAoB,UAAU;CACzE,IAAI,UAAU,QAAQ,IAAI;AAC1B,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,UAAU,KAAK,SAAS,eAAe;AAC7C,MAAI,WAAW,QAAQ,CACrB,KAAI;AAEF,UAAO,cADK,KAAK,MAAM,aAAa,SAAS,QAAQ,CAC7B,CAAC,QAAQ,QAAQ;UACnC;AACN,UAAO,cAAc,QAAQ;;EAGjC,MAAM,SAAS,QAAQ,QAAQ;AAC/B,MAAI,WAAW,QAAS;AACxB,YAAU;;AAEZ,QAAO,cAAc,IAAI;;AAG3B,SAAgB,oBAAoB,KAAgC;AAClE,QAAO;EACL,QAAQ;EACR,OAAO,wBAAwB,iBAAiB,IAAI;EACpD,MAAM,iBAAiB,IAAI;EAC5B;;AAGH,SAAgB,sBAA2D;AACzE,QAAO,CACL;EAAE,QAAQ;EAAW,OAAO;EAAwB,EACpD;EAAE,QAAQ;EAAU,OAAO;EAAsB,CAClD;;AAGH,SAAgB,WAAW,SAAqE;AAC9F,QAAO;EAAE,GAAG;EAAS,WAAW,IAAI,QAAQ,OAAO,KAAK,QAAQ,MAAM;EAAI;;AAG5E,SAAgB,oBAAoB,KAAqB;AAEvD,SADiB,IAAI,MAAM,IAAI,CAAC,KAAK,IAAI,KAEtC,QAAQ,MAAM,GAAG,CACjB,QAAQ,mBAAmB,IAAI,CAC/B,QAAQ,aAAa,GAAG,CACxB,QAAQ,MAAM,IAAI,CAClB,aAAa;;AAGlB,SAAgB,yBAAyB,MAAsB;AAC7D,QAAO,GAAG,KAAK,aAAa,CAAC,QAAQ,MAAM,IAAI,CAAC;;AAGlD,SAAgB,sBAAsB,YAA2C;CAC/E,MAAM,yBAAS,IAAI,KAAa;CAChC,MAAM,KAAK;AACX,MAAK,MAAM,aAAa,WACtB,MAAK,MAAM,QAAQ,UAAU,IAC3B,MAAK,MAAM,SAAS,KAAK,SAAS,GAAG,EAAE;EACrC,MAAM,aAAa,MAAM;EACzB,MAAM,YAAY,MAAM;AACxB,MAAI,WACF,QAAO,IAAI,WAAW;WACb,UACT,QAAO,IAAI,UAAU;;AAK7B,QAAO,CAAC,GAAG,OAAO"}
1
+ {"version":3,"file":"db.mjs","names":[],"sources":["../src/db.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\nfunction 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 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;CACR;AAED,MAAM,uBAAuB;AAE7B,SAAS,cAAc,MAAsB;AAE3C,SADiB,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,MAEvC,QAAQ,MAAM,GAAG,CACjB,QAAQ,mBAAmB,IAAI,CAC/B,QAAQ,aAAa,GAAG,CACxB,QAAQ,MAAM,IAAI,CAClB,aAAa;;AAGlB,SAAgB,iBAAiB,KAAsB;AACrD,KAAI,CAAC,IAAK,QAAO,cAAc,QAAQ,IAAI,oBAAoB,UAAU;CACzE,IAAI,UAAU;AACd,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,UAAU,KAAK,SAAS,eAAe;AAC7C,MAAI,WAAW,QAAQ,CACrB,KAAI;AAEF,UAAO,cADK,KAAK,MAAM,aAAa,SAAS,QAAQ,CAC7B,CAAC,QAAQ,QAAQ;UACnC;AACN,UAAO,cAAc,QAAQ;;EAGjC,MAAM,SAAS,QAAQ,QAAQ;AAC/B,MAAI,WAAW,QAAS;AACxB,YAAU;;AAEZ,QAAO,cAAc,IAAI;;AAG3B,SAAgB,oBACd,MACA,SACkB;CAClB,MAAM,IAAI,cAAc,QAAQ,kBAAkB,CAAC;AAEnD,KADiB,SAAS,YAAY,qBAEpC,QAAO;EACL,QAAQ,0BAA0B;EAClC,OAAO,wBAAwB;EAC/B,MAAM;EACP;AAEH,QAAO;EACL,QAAQ,0BAA0B;EAClC,OAAO,0BAA0B;EACjC,MAAM;EACP;;;;;;;;;;;;;AAcH,SAAgB,WAAW,KAAuB;AAChD,KAAI,IAAI,WAAW,EAAG,QAAO;AAE7B,QAAO,KADS,IAAI,KAAK,MAAM,EAAE,QAAQ,OAAO,OAAO,CAAC,QAAQ,MAAM,OAAM,CACzD,CAAC,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;;AAGrD,SAAgB,oBAAoB,KAAqB;AACvD,QAAO,cAAc,IAAI;;AAG3B,SAAgB,yBAAyB,MAAsB;AAC7D,QAAO,GAAG,KAAK,aAAa,CAAC,QAAQ,MAAM,IAAI,CAAC;;AAGlD,SAAgB,sBAAsB,YAA2C;CAC/E,MAAM,yBAAS,IAAI,KAAa;CAChC,MAAM,KAAK;AACX,MAAK,MAAM,aAAa,WACtB,MAAK,MAAM,QAAQ,UAAU,IAC3B,MAAK,MAAM,SAAS,KAAK,SAAS,GAAG,EAAE;EACrC,MAAM,YAAY,MAAM;AACxB,MAAI,UACF,QAAO,IAAI,UAAU;;AAK7B,QAAO,CAAC,GAAG,OAAO"}
@@ -1,5 +1,6 @@
1
1
  const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
2
2
  const require_config = require('./config.cjs');
3
+ const require_process_registry = require('./process-registry.cjs');
3
4
  const require_service_descriptor = require('./service-descriptor.cjs');
4
5
  const require_dev_view = require('./components/dev-view.cjs');
5
6
  const require_streaming_view = require('./components/streaming-view.cjs');
@@ -60,6 +61,7 @@ function formatLogLine(entry) {
60
61
  const runDevSession = (orchestrator, onShutdownReady) => effect.Effect.gen(function* () {
61
62
  const configDir = require_config.getProjectRoot();
62
63
  const services = yield* require_service_descriptor.ServiceDescriptorMap;
64
+ const runtimeConfig = yield* require_service_descriptor.DevRuntimeConfig;
63
65
  const orderedPackages = sortByOrder(orchestrator.packages);
64
66
  const initialProcesses = require_orchestrator.getProcessStates(orderedPackages, services, orchestrator.port);
65
67
  if (process.env.DEBUG === "true" || process.env.DEBUG === "1") {
@@ -73,6 +75,29 @@ const runDevSession = (orchestrator, onShutdownReady) => effect.Effect.gen(funct
73
75
  onShutdownReady?.(() => {
74
76
  effect.Effect.runPromise(effect.Deferred.succeed(shutdown, void 0));
75
77
  });
78
+ const isWorkspaceChild = process.env.BOS_WORKSPACE_CHILD === "1";
79
+ if (!isWorkspaceChild) {
80
+ const regPorts = {};
81
+ const addPort = (key, value) => {
82
+ if (value != null) regPorts[key] = value;
83
+ };
84
+ addPort("host", runtimeConfig.host.port);
85
+ addPort("api", runtimeConfig.api.port);
86
+ addPort("ui", runtimeConfig.ui.port);
87
+ addPort("auth", runtimeConfig.auth?.port);
88
+ addPort("uiSsr", runtimeConfig.ui.ssrUrl ? Number.parseInt(new URL(runtimeConfig.ui.ssrUrl).port, 10) : void 0);
89
+ if (runtimeConfig.plugins) for (const [id, plugin] of Object.entries(runtimeConfig.plugins)) {
90
+ addPort(`plugin:${id}`, plugin.port);
91
+ addPort(`plugin-ui:${id}`, plugin.ui?.port);
92
+ }
93
+ require_process_registry.registerStandalone({
94
+ pid: process.pid,
95
+ configDir,
96
+ ports: regPorts,
97
+ startedAt: Date.now(),
98
+ description: orchestrator.description
99
+ });
100
+ }
76
101
  const allLogs = [];
77
102
  let view = null;
78
103
  let shouldExportLogs = false;
@@ -131,6 +156,9 @@ const runDevSession = (orchestrator, onShutdownReady) => effect.Effect.gen(funct
131
156
  yield* effect.Effect.forEach(allHandles, (h) => h.kill.pipe(effect.Effect.ignore), { concurrency: "unbounded" });
132
157
  yield* effect.Effect.sleep("200 millis");
133
158
  view?.unmount();
159
+ if (!isWorkspaceChild) try {
160
+ require_process_registry.unregisterPid(process.pid);
161
+ } catch {}
134
162
  if (shouldExportLogs) {
135
163
  console.log("\n");
136
164
  console.log("═".repeat(70));
@@ -1 +1 @@
1
- {"version":3,"file":"dev-session.cjs","names":["Effect","getProjectRoot","ServiceDescriptorMap","getProcessStates","createDevLogger","Deferred","renderDevView","renderStreamingView","makeDevProcess","ServiceDescriptorMapLive","DevRuntimeConfigLive","NodeContext","Exit"],"sources":["../src/dev-session.ts"],"sourcesContent":["import * as NodeContext from \"@effect/platform-node/NodeContext\";\nimport { Deferred, Effect, Exit } from \"effect\";\nimport {\n type DevViewHandle,\n type LogEntry,\n type ProcessState,\n renderDevView,\n} from \"./components/dev-view\";\nimport { renderStreamingView } from \"./components/streaming-view\";\nimport { getProjectRoot } from \"./config\";\nimport { createDevLogger } from \"./dev-logs\";\nimport {\n getProcessStates,\n makeDevProcess,\n type ProcessCallbacks,\n type ProcessHandle,\n} from \"./orchestrator\";\nimport {\n type AppOrchestrator,\n DevRuntimeConfigLive,\n type ServiceDescriptor,\n ServiceDescriptorMap,\n ServiceDescriptorMapLive,\n} from \"./service-descriptor\";\nimport type { RuntimeConfig } from \"./types\";\n\nconst LOG_NOISE_PATTERNS = [\n /\\[ Federation Runtime \\] Version .* from (host|ui) of shared singleton module/,\n /Executing an Effect versioned \\d+\\.\\d+\\.\\d+ with a Runtime of version/,\n /you may want to dedupe the effect dependencies/,\n];\n\nconst SSR_LOG_ALLOWLIST = [\n /\\bready\\s+built in\\b/i,\n /\\bcompiled\\b.*successfully/i,\n /\\berror\\b/i,\n /\\bfailed\\b/i,\n /\\bexception\\b/i,\n];\n\nconst shouldDisplayLog = (source: string, line: string, isError?: boolean): boolean => {\n if (process.env.DEBUG === \"true\" || process.env.DEBUG === \"1\") return true;\n if (source === \"ui-ssr\") {\n if (isError) return true;\n return SSR_LOG_ALLOWLIST.some((pattern) => pattern.test(line));\n }\n return !LOG_NOISE_PATTERNS.some((pattern) => pattern.test(line));\n};\n\nconst isInteractiveSupported = (): boolean => {\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n};\n\nconst STARTUP_ORDER = [\"ui-ssr\", \"ui\", \"auth\", \"api\", \"plugin\", \"host-build\", \"host\"];\n\nconst sortByOrder = (packages: string[]): string[] => {\n return [...packages].sort((a, b) => {\n const aIdx = a.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(a);\n const bIdx = b.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return 0;\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n};\n\nfunction formatLogLine(entry: LogEntry): string {\n const ts = new Date(entry.timestamp).toISOString();\n const prefix = entry.isError ? \"ERR\" : \"OUT\";\n return `[${ts}] [${entry.source}] [${prefix}] ${entry.line}`;\n}\n\nexport const runDevSession = (\n orchestrator: AppOrchestrator,\n onShutdownReady?: (requestShutdown: () => void) => void,\n) =>\n Effect.gen(function* () {\n const configDir = getProjectRoot();\n const services = yield* ServiceDescriptorMap;\n const orderedPackages = sortByOrder(orchestrator.packages);\n const initialProcesses: ProcessState[] = getProcessStates(\n orderedPackages,\n services,\n orchestrator.port,\n );\n\n if (process.env.DEBUG === \"true\" || process.env.DEBUG === \"1\") {\n console.error(\"[DEBUG session] orchestrator.packages:\", orchestrator.packages.join(\", \"));\n console.error(\"[DEBUG session] orderedPackages:\", orderedPackages.join(\", \"));\n console.error(\"[DEBUG session] services keys:\", [...services.keys()].join(\", \"));\n console.error(\n \"[DEBUG session] initialProcesses:\",\n initialProcesses.map((p) => `${p.name}=${p.source}`).join(\", \"),\n );\n }\n\n const logger = yield* Effect.promise(() =>\n createDevLogger(configDir, orchestrator.description),\n );\n\n const shutdown = yield* Deferred.make<void>();\n\n onShutdownReady?.(() => {\n void Effect.runPromise(Deferred.succeed(shutdown, undefined));\n });\n\n const allLogs: LogEntry[] = [];\n let view: DevViewHandle | null = null;\n let shouldExportLogs = false;\n\n const requestShutdownAndExport = () => {\n shouldExportLogs = true;\n void Effect.runPromise(Deferred.succeed(shutdown, undefined));\n };\n\n const useInteractive = orchestrator.interactive ?? isInteractiveSupported();\n view = useInteractive\n ? renderDevView(\n initialProcesses,\n orchestrator.description,\n orchestrator.env,\n () => void Effect.runPromise(Deferred.succeed(shutdown, undefined)),\n requestShutdownAndExport,\n )\n : renderStreamingView(\n initialProcesses,\n orchestrator.description,\n orchestrator.env,\n () => void Effect.runPromise(Deferred.succeed(shutdown, undefined)),\n );\n\n const callbacks: ProcessCallbacks = {\n onStatus: (name, status, message) => {\n view?.updateProcess(name, status, message);\n },\n onLog: (name, line, isError) => {\n const entry: LogEntry = {\n id: `${Date.now()}-${allLogs.length + 1}`,\n source: name,\n line,\n timestamp: Date.now(),\n isError,\n };\n allLogs.push(entry);\n if (shouldDisplayLog(name, line, isError)) {\n view?.addLog(name, line, isError);\n }\n if (!orchestrator.noLogs) {\n void logger.write(entry);\n }\n },\n };\n\n const startProcess = (pkg: string) => {\n const portOverride = pkg === \"host\" ? orchestrator.port : undefined;\n return makeDevProcess(pkg, callbacks, portOverride).pipe(\n Effect.tapError((err) =>\n Effect.sync(() => {\n callbacks.onLog(pkg, `Failed to start: ${err}`, true);\n callbacks.onStatus(pkg, \"error\");\n }),\n ),\n Effect.catchAll(() =>\n Effect.succeed({\n name: pkg,\n pid: undefined,\n kill: Effect.void,\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle),\n ),\n );\n };\n\n const startGroup = (packages: string[]) =>\n Effect.forEach(packages, startProcess, { concurrency: \"unbounded\" });\n\n const awaitReady = (pkg: string, handle: ProcessHandle) =>\n handle.waitForReady.pipe(\n Effect.timeout(\"120 seconds\"),\n Effect.catchAll((err) =>\n Effect.sync(() => {\n callbacks.onLog(\n pkg,\n `Timed out or failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }),\n ),\n );\n\n const nonHostPackages = orderedPackages.filter((pkg) => pkg !== \"host\");\n const hostPackages = orderedPackages.filter((pkg) => pkg === \"host\");\n\n const nonHostHandles = yield* startGroup(nonHostPackages);\n\n yield* Effect.forEach(\n nonHostHandles.map((handle, index) => ({\n handle,\n pkg: nonHostPackages[index] ?? handle.name,\n })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const hostHandles = yield* startGroup(hostPackages);\n\n yield* Effect.forEach(\n hostHandles.map((handle, index) => ({ handle, pkg: hostPackages[index] ?? handle.name })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const allHandles = [...nonHostHandles, ...hostHandles];\n\n yield* Effect.addFinalizer(() =>\n Effect.gen(function* () {\n yield* Effect.forEach(allHandles, (h) => h.kill.pipe(Effect.ignore), {\n concurrency: \"unbounded\",\n });\n\n yield* Effect.sleep(\"200 millis\");\n\n view?.unmount();\n\n if (shouldExportLogs) {\n console.log(\"\\n\");\n console.log(\"═\".repeat(70));\n console.log(` SESSION LOGS: ${orchestrator.description}`);\n console.log(` Started: ${new Date(allLogs[0]?.timestamp || Date.now()).toISOString()}`);\n console.log(` Total entries: ${allLogs.length}`);\n console.log(\"═\".repeat(70));\n console.log(\"\");\n for (const entry of allLogs) {\n console.log(formatLogLine(entry));\n }\n console.log(\"\");\n console.log(\"═\".repeat(70));\n console.log(` Full logs saved to: ${logger.logFile}`);\n console.log(\"═\".repeat(70));\n console.log(\"\");\n }\n }),\n );\n\n yield* Deferred.await(shutdown);\n });\n\nconst runApp = (\n orchestrator: AppOrchestrator,\n services: Map<string, ServiceDescriptor>,\n runtimeConfig: RuntimeConfig,\n) => {\n let requestShutdown: (() => void) | null = null;\n let signalCount = 0;\n let forceExitTimer: ReturnType<typeof setTimeout> | null = null;\n\n const forceExit = () => {\n console.log(\"\\n[Dev] Force exit\");\n process.exit(0);\n };\n\n const program = Effect.scoped(\n runDevSession(orchestrator, (shutdown) => {\n requestShutdown = shutdown;\n }),\n ).pipe(\n Effect.provide(ServiceDescriptorMapLive(services)),\n Effect.provide(DevRuntimeConfigLive(runtimeConfig)),\n Effect.provide(NodeContext.layer),\n Effect.catchAllDefect((defect) =>\n Effect.sync(() => {\n console.error(\"[Dev] Unhandled defect in orchestrator:\", defect);\n }),\n ),\n );\n\n const handleSignal = () => {\n signalCount++;\n if (signalCount > 1) {\n forceExit();\n return;\n }\n console.log(\"\\n[Dev] Shutting down...\");\n forceExitTimer = setTimeout(forceExit, 5000);\n requestShutdown?.();\n };\n\n process.on(\"SIGINT\", handleSignal);\n process.on(\"SIGTERM\", handleSignal);\n\n Effect.runPromiseExit(program).then((exit) => {\n if (forceExitTimer) clearTimeout(forceExitTimer);\n process.exit(Exit.isSuccess(exit) ? 0 : 0);\n });\n};\n\nexport const devApp = runApp;\n\nexport const startApp = runApp;\n"],"mappings":";;;;;;;;;;;;AA0BA,MAAM,qBAAqB;CACzB;CACA;CACA;CACD;AAED,MAAM,oBAAoB;CACxB;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,oBAAoB,QAAgB,MAAc,YAA+B;AACrF,KAAI,QAAQ,IAAI,UAAU,UAAU,QAAQ,IAAI,UAAU,IAAK,QAAO;AACtE,KAAI,WAAW,UAAU;AACvB,MAAI,QAAS,QAAO;AACpB,SAAO,kBAAkB,MAAM,YAAY,QAAQ,KAAK,KAAK,CAAC;;AAEhE,QAAO,CAAC,mBAAmB,MAAM,YAAY,QAAQ,KAAK,KAAK,CAAC;;AAGlE,MAAM,+BAAwC;AAC5C,QAAO,QAAQ,MAAM,UAAU,QAAQ,QAAQ,OAAO,UAAU;;AAGlE,MAAM,gBAAgB;CAAC;CAAU;CAAM;CAAQ;CAAO;CAAU;CAAc;CAAO;AAErF,MAAM,eAAe,aAAiC;AACpD,QAAO,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,MAAM;EAClC,MAAM,OAAO,EAAE,WAAW,UAAU,GAChC,cAAc,QAAQ,SAAS,GAC/B,cAAc,QAAQ,EAAE;EAC5B,MAAM,OAAO,EAAE,WAAW,UAAU,GAChC,cAAc,QAAQ,SAAS,GAC/B,cAAc,QAAQ,EAAE;AAC5B,MAAI,SAAS,MAAM,SAAS,GAAI,QAAO;AACvC,MAAI,SAAS,GAAI,QAAO;AACxB,MAAI,SAAS,GAAI,QAAO;AACxB,SAAO,OAAO;GACd;;AAGJ,SAAS,cAAc,OAAyB;CAC9C,MAAM,KAAK,IAAI,KAAK,MAAM,UAAU,CAAC,aAAa;CAClD,MAAM,SAAS,MAAM,UAAU,QAAQ;AACvC,QAAO,IAAI,GAAG,KAAK,MAAM,OAAO,KAAK,OAAO,IAAI,MAAM;;AAGxD,MAAa,iBACX,cACA,oBAEAA,cAAO,IAAI,aAAa;CACtB,MAAM,YAAYC,+BAAgB;CAClC,MAAM,WAAW,OAAOC;CACxB,MAAM,kBAAkB,YAAY,aAAa,SAAS;CAC1D,MAAM,mBAAmCC,sCACvC,iBACA,UACA,aAAa,KACd;AAED,KAAI,QAAQ,IAAI,UAAU,UAAU,QAAQ,IAAI,UAAU,KAAK;AAC7D,UAAQ,MAAM,0CAA0C,aAAa,SAAS,KAAK,KAAK,CAAC;AACzF,UAAQ,MAAM,oCAAoC,gBAAgB,KAAK,KAAK,CAAC;AAC7E,UAAQ,MAAM,kCAAkC,CAAC,GAAG,SAAS,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC;AAChF,UAAQ,MACN,qCACA,iBAAiB,KAAK,MAAM,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS,CAAC,KAAK,KAAK,CAChE;;CAGH,MAAM,SAAS,OAAOH,cAAO,cAC3BI,iCAAgB,WAAW,aAAa,YAAY,CACrD;CAED,MAAM,WAAW,OAAOC,gBAAS,MAAY;AAE7C,yBAAwB;AACtB,EAAKL,cAAO,WAAWK,gBAAS,QAAQ,UAAU,OAAU,CAAC;GAC7D;CAEF,MAAM,UAAsB,EAAE;CAC9B,IAAI,OAA6B;CACjC,IAAI,mBAAmB;CAEvB,MAAM,iCAAiC;AACrC,qBAAmB;AACnB,EAAKL,cAAO,WAAWK,gBAAS,QAAQ,UAAU,OAAU,CAAC;;AAI/D,QADuB,aAAa,eAAe,wBAAwB,GAEvEC,+BACE,kBACA,aAAa,aACb,aAAa,WACP,KAAKN,cAAO,WAAWK,gBAAS,QAAQ,UAAU,OAAU,CAAC,EACnE,yBACD,GACDE,2CACE,kBACA,aAAa,aACb,aAAa,WACP,KAAKP,cAAO,WAAWK,gBAAS,QAAQ,UAAU,OAAU,CAAC,CACpE;CAEL,MAAM,YAA8B;EAClC,WAAW,MAAM,QAAQ,YAAY;AACnC,SAAM,cAAc,MAAM,QAAQ,QAAQ;;EAE5C,QAAQ,MAAM,MAAM,YAAY;GAC9B,MAAM,QAAkB;IACtB,IAAI,GAAG,KAAK,KAAK,CAAC,GAAG,QAAQ,SAAS;IACtC,QAAQ;IACR;IACA,WAAW,KAAK,KAAK;IACrB;IACD;AACD,WAAQ,KAAK,MAAM;AACnB,OAAI,iBAAiB,MAAM,MAAM,QAAQ,CACvC,OAAM,OAAO,MAAM,MAAM,QAAQ;AAEnC,OAAI,CAAC,aAAa,OAChB,CAAK,OAAO,MAAM,MAAM;;EAG7B;CAED,MAAM,gBAAgB,QAAgB;AAEpC,SAAOG,oCAAe,KAAK,WADN,QAAQ,SAAS,aAAa,OAAO,OACP,CAAC,KAClDR,cAAO,UAAU,QACfA,cAAO,WAAW;AAChB,aAAU,MAAM,KAAK,oBAAoB,OAAO,KAAK;AACrD,aAAU,SAAS,KAAK,QAAQ;IAChC,CACH,EACDA,cAAO,eACLA,cAAO,QAAQ;GACb,MAAM;GACN,KAAK;GACL,MAAMA,cAAO;GACb,cAAcA,cAAO;GACrB,aAAaA,cAAO;GACrB,CAAyB,CAC3B,CACF;;CAGH,MAAM,cAAc,aAClBA,cAAO,QAAQ,UAAU,cAAc,EAAE,aAAa,aAAa,CAAC;CAEtE,MAAM,cAAc,KAAa,WAC/B,OAAO,aAAa,KAClBA,cAAO,QAAQ,cAAc,EAC7BA,cAAO,UAAU,QACfA,cAAO,WAAW;AAChB,YAAU,MACR,KACA,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,IACxE,KACD;GACD,CACH,CACF;CAEH,MAAM,kBAAkB,gBAAgB,QAAQ,QAAQ,QAAQ,OAAO;CACvE,MAAM,eAAe,gBAAgB,QAAQ,QAAQ,QAAQ,OAAO;CAEpE,MAAM,iBAAiB,OAAO,WAAW,gBAAgB;AAEzD,QAAOA,cAAO,QACZ,eAAe,KAAK,QAAQ,WAAW;EACrC;EACA,KAAK,gBAAgB,UAAU,OAAO;EACvC,EAAE,GACF,EAAE,QAAQ,UAAU,WAAW,KAAK,OAAO,EAC5C,EAAE,aAAa,aAAa,CAC7B;CAED,MAAM,cAAc,OAAO,WAAW,aAAa;AAEnD,QAAOA,cAAO,QACZ,YAAY,KAAK,QAAQ,WAAW;EAAE;EAAQ,KAAK,aAAa,UAAU,OAAO;EAAM,EAAE,GACxF,EAAE,QAAQ,UAAU,WAAW,KAAK,OAAO,EAC5C,EAAE,aAAa,aAAa,CAC7B;CAED,MAAM,aAAa,CAAC,GAAG,gBAAgB,GAAG,YAAY;AAEtD,QAAOA,cAAO,mBACZA,cAAO,IAAI,aAAa;AACtB,SAAOA,cAAO,QAAQ,aAAa,MAAM,EAAE,KAAK,KAAKA,cAAO,OAAO,EAAE,EACnE,aAAa,aACd,CAAC;AAEF,SAAOA,cAAO,MAAM,aAAa;AAEjC,QAAM,SAAS;AAEf,MAAI,kBAAkB;AACpB,WAAQ,IAAI,KAAK;AACjB,WAAQ,IAAI,IAAI,OAAO,GAAG,CAAC;AAC3B,WAAQ,IAAI,mBAAmB,aAAa,cAAc;AAC1D,WAAQ,IAAI,cAAc,IAAI,KAAK,QAAQ,IAAI,aAAa,KAAK,KAAK,CAAC,CAAC,aAAa,GAAG;AACxF,WAAQ,IAAI,oBAAoB,QAAQ,SAAS;AACjD,WAAQ,IAAI,IAAI,OAAO,GAAG,CAAC;AAC3B,WAAQ,IAAI,GAAG;AACf,QAAK,MAAM,SAAS,QAClB,SAAQ,IAAI,cAAc,MAAM,CAAC;AAEnC,WAAQ,IAAI,GAAG;AACf,WAAQ,IAAI,IAAI,OAAO,GAAG,CAAC;AAC3B,WAAQ,IAAI,yBAAyB,OAAO,UAAU;AACtD,WAAQ,IAAI,IAAI,OAAO,GAAG,CAAC;AAC3B,WAAQ,IAAI,GAAG;;GAEjB,CACH;AAED,QAAOK,gBAAS,MAAM,SAAS;EAC/B;AAEJ,MAAM,UACJ,cACA,UACA,kBACG;CACH,IAAI,kBAAuC;CAC3C,IAAI,cAAc;CAClB,IAAI,iBAAuD;CAE3D,MAAM,kBAAkB;AACtB,UAAQ,IAAI,qBAAqB;AACjC,UAAQ,KAAK,EAAE;;CAGjB,MAAM,UAAUL,cAAO,OACrB,cAAc,eAAe,aAAa;AACxC,oBAAkB;GAClB,CACH,CAAC,KACAA,cAAO,QAAQS,oDAAyB,SAAS,CAAC,EAClDT,cAAO,QAAQU,gDAAqB,cAAc,CAAC,EACnDV,cAAO,QAAQW,kCAAY,MAAM,EACjCX,cAAO,gBAAgB,WACrBA,cAAO,WAAW;AAChB,UAAQ,MAAM,2CAA2C,OAAO;GAChE,CACH,CACF;CAED,MAAM,qBAAqB;AACzB;AACA,MAAI,cAAc,GAAG;AACnB,cAAW;AACX;;AAEF,UAAQ,IAAI,2BAA2B;AACvC,mBAAiB,WAAW,WAAW,IAAK;AAC5C,qBAAmB;;AAGrB,SAAQ,GAAG,UAAU,aAAa;AAClC,SAAQ,GAAG,WAAW,aAAa;AAEnC,eAAO,eAAe,QAAQ,CAAC,MAAM,SAAS;AAC5C,MAAI,eAAgB,cAAa,eAAe;AAChD,UAAQ,KAAKY,YAAK,UAAU,KAAK,GAAG,IAAI,EAAE;GAC1C;;AAGJ,MAAa,SAAS;AAEtB,MAAa,WAAW"}
1
+ {"version":3,"file":"dev-session.cjs","names":["Effect","getProjectRoot","ServiceDescriptorMap","DevRuntimeConfig","getProcessStates","createDevLogger","Deferred","renderDevView","renderStreamingView","makeDevProcess","ServiceDescriptorMapLive","DevRuntimeConfigLive","NodeContext","Exit"],"sources":["../src/dev-session.ts"],"sourcesContent":["import * as NodeContext from \"@effect/platform-node/NodeContext\";\nimport { Deferred, Effect, Exit } from \"effect\";\nimport {\n type DevViewHandle,\n type LogEntry,\n type ProcessState,\n renderDevView,\n} from \"./components/dev-view\";\nimport { renderStreamingView } from \"./components/streaming-view\";\nimport { getProjectRoot } from \"./config\";\nimport { createDevLogger } from \"./dev-logs\";\nimport {\n getProcessStates,\n makeDevProcess,\n type ProcessCallbacks,\n type ProcessHandle,\n} from \"./orchestrator\";\nimport { registerStandalone, unregisterPid } from \"./process-registry\";\nimport {\n type AppOrchestrator,\n DevRuntimeConfig,\n DevRuntimeConfigLive,\n type ServiceDescriptor,\n ServiceDescriptorMap,\n ServiceDescriptorMapLive,\n} from \"./service-descriptor\";\nimport type { RuntimeConfig } from \"./types\";\n\nconst LOG_NOISE_PATTERNS = [\n /\\[ Federation Runtime \\] Version .* from (host|ui) of shared singleton module/,\n /Executing an Effect versioned \\d+\\.\\d+\\.\\d+ with a Runtime of version/,\n /you may want to dedupe the effect dependencies/,\n];\n\nconst SSR_LOG_ALLOWLIST = [\n /\\bready\\s+built in\\b/i,\n /\\bcompiled\\b.*successfully/i,\n /\\berror\\b/i,\n /\\bfailed\\b/i,\n /\\bexception\\b/i,\n];\n\nconst shouldDisplayLog = (source: string, line: string, isError?: boolean): boolean => {\n if (process.env.DEBUG === \"true\" || process.env.DEBUG === \"1\") return true;\n if (source === \"ui-ssr\") {\n if (isError) return true;\n return SSR_LOG_ALLOWLIST.some((pattern) => pattern.test(line));\n }\n return !LOG_NOISE_PATTERNS.some((pattern) => pattern.test(line));\n};\n\nconst isInteractiveSupported = (): boolean => {\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n};\n\nconst STARTUP_ORDER = [\"ui-ssr\", \"ui\", \"auth\", \"api\", \"plugin\", \"host-build\", \"host\"];\n\nconst sortByOrder = (packages: string[]): string[] => {\n return [...packages].sort((a, b) => {\n const aIdx = a.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(a);\n const bIdx = b.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return 0;\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n};\n\nfunction formatLogLine(entry: LogEntry): string {\n const ts = new Date(entry.timestamp).toISOString();\n const prefix = entry.isError ? \"ERR\" : \"OUT\";\n return `[${ts}] [${entry.source}] [${prefix}] ${entry.line}`;\n}\n\nexport const runDevSession = (\n orchestrator: AppOrchestrator,\n onShutdownReady?: (requestShutdown: () => void) => void,\n) =>\n Effect.gen(function* () {\n const configDir = getProjectRoot();\n const services = yield* ServiceDescriptorMap;\n const runtimeConfig = yield* DevRuntimeConfig;\n const orderedPackages = sortByOrder(orchestrator.packages);\n const initialProcesses: ProcessState[] = getProcessStates(\n orderedPackages,\n services,\n orchestrator.port,\n );\n\n if (process.env.DEBUG === \"true\" || process.env.DEBUG === \"1\") {\n console.error(\"[DEBUG session] orchestrator.packages:\", orchestrator.packages.join(\", \"));\n console.error(\"[DEBUG session] orderedPackages:\", orderedPackages.join(\", \"));\n console.error(\"[DEBUG session] services keys:\", [...services.keys()].join(\", \"));\n console.error(\n \"[DEBUG session] initialProcesses:\",\n initialProcesses.map((p) => `${p.name}=${p.source}`).join(\", \"),\n );\n }\n\n const logger = yield* Effect.promise(() =>\n createDevLogger(configDir, orchestrator.description),\n );\n\n const shutdown = yield* Deferred.make<void>();\n\n onShutdownReady?.(() => {\n void Effect.runPromise(Deferred.succeed(shutdown, undefined));\n });\n\n const isWorkspaceChild = process.env.BOS_WORKSPACE_CHILD === \"1\";\n if (!isWorkspaceChild) {\n const regPorts: Record<string, number> = {};\n const addPort = (key: string, value: number | undefined | null) => {\n if (value != null) regPorts[key] = value;\n };\n addPort(\"host\", runtimeConfig.host.port);\n addPort(\"api\", runtimeConfig.api.port);\n addPort(\"ui\", runtimeConfig.ui.port);\n addPort(\"auth\", runtimeConfig.auth?.port);\n addPort(\n \"uiSsr\",\n runtimeConfig.ui.ssrUrl\n ? Number.parseInt(new URL(runtimeConfig.ui.ssrUrl).port, 10)\n : undefined,\n );\n if (runtimeConfig.plugins) {\n for (const [id, plugin] of Object.entries(runtimeConfig.plugins)) {\n addPort(`plugin:${id}`, plugin.port);\n addPort(`plugin-ui:${id}`, plugin.ui?.port);\n }\n }\n registerStandalone({\n pid: process.pid,\n configDir,\n ports: regPorts,\n startedAt: Date.now(),\n description: orchestrator.description,\n });\n }\n\n const allLogs: LogEntry[] = [];\n let view: DevViewHandle | null = null;\n let shouldExportLogs = false;\n\n const requestShutdownAndExport = () => {\n shouldExportLogs = true;\n void Effect.runPromise(Deferred.succeed(shutdown, undefined));\n };\n\n const useInteractive = orchestrator.interactive ?? isInteractiveSupported();\n view = useInteractive\n ? renderDevView(\n initialProcesses,\n orchestrator.description,\n orchestrator.env,\n () => void Effect.runPromise(Deferred.succeed(shutdown, undefined)),\n requestShutdownAndExport,\n )\n : renderStreamingView(\n initialProcesses,\n orchestrator.description,\n orchestrator.env,\n () => void Effect.runPromise(Deferred.succeed(shutdown, undefined)),\n );\n\n const callbacks: ProcessCallbacks = {\n onStatus: (name, status, message) => {\n view?.updateProcess(name, status, message);\n },\n onLog: (name, line, isError) => {\n const entry: LogEntry = {\n id: `${Date.now()}-${allLogs.length + 1}`,\n source: name,\n line,\n timestamp: Date.now(),\n isError,\n };\n allLogs.push(entry);\n if (shouldDisplayLog(name, line, isError)) {\n view?.addLog(name, line, isError);\n }\n if (!orchestrator.noLogs) {\n void logger.write(entry);\n }\n },\n };\n\n const startProcess = (pkg: string) => {\n const portOverride = pkg === \"host\" ? orchestrator.port : undefined;\n return makeDevProcess(pkg, callbacks, portOverride).pipe(\n Effect.tapError((err) =>\n Effect.sync(() => {\n callbacks.onLog(pkg, `Failed to start: ${err}`, true);\n callbacks.onStatus(pkg, \"error\");\n }),\n ),\n Effect.catchAll(() =>\n Effect.succeed({\n name: pkg,\n pid: undefined,\n kill: Effect.void,\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle),\n ),\n );\n };\n\n const startGroup = (packages: string[]) =>\n Effect.forEach(packages, startProcess, { concurrency: \"unbounded\" });\n\n const awaitReady = (pkg: string, handle: ProcessHandle) =>\n handle.waitForReady.pipe(\n Effect.timeout(\"120 seconds\"),\n Effect.catchAll((err) =>\n Effect.sync(() => {\n callbacks.onLog(\n pkg,\n `Timed out or failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }),\n ),\n );\n\n const nonHostPackages = orderedPackages.filter((pkg) => pkg !== \"host\");\n const hostPackages = orderedPackages.filter((pkg) => pkg === \"host\");\n\n const nonHostHandles = yield* startGroup(nonHostPackages);\n\n yield* Effect.forEach(\n nonHostHandles.map((handle, index) => ({\n handle,\n pkg: nonHostPackages[index] ?? handle.name,\n })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const hostHandles = yield* startGroup(hostPackages);\n\n yield* Effect.forEach(\n hostHandles.map((handle, index) => ({ handle, pkg: hostPackages[index] ?? handle.name })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const allHandles = [...nonHostHandles, ...hostHandles];\n\n yield* Effect.addFinalizer(() =>\n Effect.gen(function* () {\n yield* Effect.forEach(allHandles, (h) => h.kill.pipe(Effect.ignore), {\n concurrency: \"unbounded\",\n });\n\n yield* Effect.sleep(\"200 millis\");\n\n view?.unmount();\n\n if (!isWorkspaceChild) {\n try {\n unregisterPid(process.pid);\n } catch {\n // best-effort; pruneDead cleans stale entries on next ps/kill\n }\n }\n\n if (shouldExportLogs) {\n console.log(\"\\n\");\n console.log(\"═\".repeat(70));\n console.log(` SESSION LOGS: ${orchestrator.description}`);\n console.log(` Started: ${new Date(allLogs[0]?.timestamp || Date.now()).toISOString()}`);\n console.log(` Total entries: ${allLogs.length}`);\n console.log(\"═\".repeat(70));\n console.log(\"\");\n for (const entry of allLogs) {\n console.log(formatLogLine(entry));\n }\n console.log(\"\");\n console.log(\"═\".repeat(70));\n console.log(` Full logs saved to: ${logger.logFile}`);\n console.log(\"═\".repeat(70));\n console.log(\"\");\n }\n }),\n );\n\n yield* Deferred.await(shutdown);\n });\n\nconst runApp = (\n orchestrator: AppOrchestrator,\n services: Map<string, ServiceDescriptor>,\n runtimeConfig: RuntimeConfig,\n) => {\n let requestShutdown: (() => void) | null = null;\n let signalCount = 0;\n let forceExitTimer: ReturnType<typeof setTimeout> | null = null;\n\n const forceExit = () => {\n console.log(\"\\n[Dev] Force exit\");\n process.exit(0);\n };\n\n const program = Effect.scoped(\n runDevSession(orchestrator, (shutdown) => {\n requestShutdown = shutdown;\n }),\n ).pipe(\n Effect.provide(ServiceDescriptorMapLive(services)),\n Effect.provide(DevRuntimeConfigLive(runtimeConfig)),\n Effect.provide(NodeContext.layer),\n Effect.catchAllDefect((defect) =>\n Effect.sync(() => {\n console.error(\"[Dev] Unhandled defect in orchestrator:\", defect);\n }),\n ),\n );\n\n const handleSignal = () => {\n signalCount++;\n if (signalCount > 1) {\n forceExit();\n return;\n }\n console.log(\"\\n[Dev] Shutting down...\");\n forceExitTimer = setTimeout(forceExit, 5000);\n requestShutdown?.();\n };\n\n process.on(\"SIGINT\", handleSignal);\n process.on(\"SIGTERM\", handleSignal);\n\n Effect.runPromiseExit(program).then((exit) => {\n if (forceExitTimer) clearTimeout(forceExitTimer);\n process.exit(Exit.isSuccess(exit) ? 0 : 0);\n });\n};\n\nexport const devApp = runApp;\n\nexport const startApp = runApp;\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { getProjectRoot } from "./config.mjs";
2
- import { DevRuntimeConfigLive, ServiceDescriptorMap, ServiceDescriptorMapLive } from "./service-descriptor.mjs";
2
+ import { registerStandalone, unregisterPid } from "./process-registry.mjs";
3
+ import { DevRuntimeConfig, DevRuntimeConfigLive, ServiceDescriptorMap, ServiceDescriptorMapLive } from "./service-descriptor.mjs";
3
4
  import { renderDevView } from "./components/dev-view.mjs";
4
5
  import { renderStreamingView } from "./components/streaming-view.mjs";
5
6
  import { createDevLogger } from "./dev-logs.mjs";
@@ -58,6 +59,7 @@ function formatLogLine(entry) {
58
59
  const runDevSession = (orchestrator, onShutdownReady) => Effect.gen(function* () {
59
60
  const configDir = getProjectRoot();
60
61
  const services = yield* ServiceDescriptorMap;
62
+ const runtimeConfig = yield* DevRuntimeConfig;
61
63
  const orderedPackages = sortByOrder(orchestrator.packages);
62
64
  const initialProcesses = getProcessStates(orderedPackages, services, orchestrator.port);
63
65
  if (process.env.DEBUG === "true" || process.env.DEBUG === "1") {
@@ -71,6 +73,29 @@ const runDevSession = (orchestrator, onShutdownReady) => Effect.gen(function* ()
71
73
  onShutdownReady?.(() => {
72
74
  Effect.runPromise(Deferred.succeed(shutdown, void 0));
73
75
  });
76
+ const isWorkspaceChild = process.env.BOS_WORKSPACE_CHILD === "1";
77
+ if (!isWorkspaceChild) {
78
+ const regPorts = {};
79
+ const addPort = (key, value) => {
80
+ if (value != null) regPorts[key] = value;
81
+ };
82
+ addPort("host", runtimeConfig.host.port);
83
+ addPort("api", runtimeConfig.api.port);
84
+ addPort("ui", runtimeConfig.ui.port);
85
+ addPort("auth", runtimeConfig.auth?.port);
86
+ addPort("uiSsr", runtimeConfig.ui.ssrUrl ? Number.parseInt(new URL(runtimeConfig.ui.ssrUrl).port, 10) : void 0);
87
+ if (runtimeConfig.plugins) for (const [id, plugin] of Object.entries(runtimeConfig.plugins)) {
88
+ addPort(`plugin:${id}`, plugin.port);
89
+ addPort(`plugin-ui:${id}`, plugin.ui?.port);
90
+ }
91
+ registerStandalone({
92
+ pid: process.pid,
93
+ configDir,
94
+ ports: regPorts,
95
+ startedAt: Date.now(),
96
+ description: orchestrator.description
97
+ });
98
+ }
74
99
  const allLogs = [];
75
100
  let view = null;
76
101
  let shouldExportLogs = false;
@@ -129,6 +154,9 @@ const runDevSession = (orchestrator, onShutdownReady) => Effect.gen(function* ()
129
154
  yield* Effect.forEach(allHandles, (h) => h.kill.pipe(Effect.ignore), { concurrency: "unbounded" });
130
155
  yield* Effect.sleep("200 millis");
131
156
  view?.unmount();
157
+ if (!isWorkspaceChild) try {
158
+ unregisterPid(process.pid);
159
+ } catch {}
132
160
  if (shouldExportLogs) {
133
161
  console.log("\n");
134
162
  console.log("═".repeat(70));
@@ -1 +1 @@
1
- {"version":3,"file":"dev-session.mjs","names":[],"sources":["../src/dev-session.ts"],"sourcesContent":["import * as NodeContext from \"@effect/platform-node/NodeContext\";\nimport { Deferred, Effect, Exit } from \"effect\";\nimport {\n type DevViewHandle,\n type LogEntry,\n type ProcessState,\n renderDevView,\n} from \"./components/dev-view\";\nimport { renderStreamingView } from \"./components/streaming-view\";\nimport { getProjectRoot } from \"./config\";\nimport { createDevLogger } from \"./dev-logs\";\nimport {\n getProcessStates,\n makeDevProcess,\n type ProcessCallbacks,\n type ProcessHandle,\n} from \"./orchestrator\";\nimport {\n type AppOrchestrator,\n DevRuntimeConfigLive,\n type ServiceDescriptor,\n ServiceDescriptorMap,\n ServiceDescriptorMapLive,\n} from \"./service-descriptor\";\nimport type { RuntimeConfig } from \"./types\";\n\nconst LOG_NOISE_PATTERNS = [\n /\\[ Federation Runtime \\] Version .* from (host|ui) of shared singleton module/,\n /Executing an Effect versioned \\d+\\.\\d+\\.\\d+ with a Runtime of version/,\n /you may want to dedupe the effect dependencies/,\n];\n\nconst SSR_LOG_ALLOWLIST = [\n /\\bready\\s+built in\\b/i,\n /\\bcompiled\\b.*successfully/i,\n /\\berror\\b/i,\n /\\bfailed\\b/i,\n /\\bexception\\b/i,\n];\n\nconst shouldDisplayLog = (source: string, line: string, isError?: boolean): boolean => {\n if (process.env.DEBUG === \"true\" || process.env.DEBUG === \"1\") return true;\n if (source === \"ui-ssr\") {\n if (isError) return true;\n return SSR_LOG_ALLOWLIST.some((pattern) => pattern.test(line));\n }\n return !LOG_NOISE_PATTERNS.some((pattern) => pattern.test(line));\n};\n\nconst isInteractiveSupported = (): boolean => {\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n};\n\nconst STARTUP_ORDER = [\"ui-ssr\", \"ui\", \"auth\", \"api\", \"plugin\", \"host-build\", \"host\"];\n\nconst sortByOrder = (packages: string[]): string[] => {\n return [...packages].sort((a, b) => {\n const aIdx = a.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(a);\n const bIdx = b.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return 0;\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n};\n\nfunction formatLogLine(entry: LogEntry): string {\n const ts = new Date(entry.timestamp).toISOString();\n const prefix = entry.isError ? \"ERR\" : \"OUT\";\n return `[${ts}] [${entry.source}] [${prefix}] ${entry.line}`;\n}\n\nexport const runDevSession = (\n orchestrator: AppOrchestrator,\n onShutdownReady?: (requestShutdown: () => void) => void,\n) =>\n Effect.gen(function* () {\n const configDir = getProjectRoot();\n const services = yield* ServiceDescriptorMap;\n const orderedPackages = sortByOrder(orchestrator.packages);\n const initialProcesses: ProcessState[] = getProcessStates(\n orderedPackages,\n services,\n orchestrator.port,\n );\n\n if (process.env.DEBUG === \"true\" || process.env.DEBUG === \"1\") {\n console.error(\"[DEBUG session] orchestrator.packages:\", orchestrator.packages.join(\", \"));\n console.error(\"[DEBUG session] orderedPackages:\", orderedPackages.join(\", \"));\n console.error(\"[DEBUG session] services keys:\", [...services.keys()].join(\", \"));\n console.error(\n \"[DEBUG session] initialProcesses:\",\n initialProcesses.map((p) => `${p.name}=${p.source}`).join(\", \"),\n );\n }\n\n const logger = yield* Effect.promise(() =>\n createDevLogger(configDir, orchestrator.description),\n );\n\n const shutdown = yield* Deferred.make<void>();\n\n onShutdownReady?.(() => {\n void Effect.runPromise(Deferred.succeed(shutdown, undefined));\n });\n\n const allLogs: LogEntry[] = [];\n let view: DevViewHandle | null = null;\n let shouldExportLogs = false;\n\n const requestShutdownAndExport = () => {\n shouldExportLogs = true;\n void Effect.runPromise(Deferred.succeed(shutdown, undefined));\n };\n\n const useInteractive = orchestrator.interactive ?? isInteractiveSupported();\n view = useInteractive\n ? renderDevView(\n initialProcesses,\n orchestrator.description,\n orchestrator.env,\n () => void Effect.runPromise(Deferred.succeed(shutdown, undefined)),\n requestShutdownAndExport,\n )\n : renderStreamingView(\n initialProcesses,\n orchestrator.description,\n orchestrator.env,\n () => void Effect.runPromise(Deferred.succeed(shutdown, undefined)),\n );\n\n const callbacks: ProcessCallbacks = {\n onStatus: (name, status, message) => {\n view?.updateProcess(name, status, message);\n },\n onLog: (name, line, isError) => {\n const entry: LogEntry = {\n id: `${Date.now()}-${allLogs.length + 1}`,\n source: name,\n line,\n timestamp: Date.now(),\n isError,\n };\n allLogs.push(entry);\n if (shouldDisplayLog(name, line, isError)) {\n view?.addLog(name, line, isError);\n }\n if (!orchestrator.noLogs) {\n void logger.write(entry);\n }\n },\n };\n\n const startProcess = (pkg: string) => {\n const portOverride = pkg === \"host\" ? orchestrator.port : undefined;\n return makeDevProcess(pkg, callbacks, portOverride).pipe(\n Effect.tapError((err) =>\n Effect.sync(() => {\n callbacks.onLog(pkg, `Failed to start: ${err}`, true);\n callbacks.onStatus(pkg, \"error\");\n }),\n ),\n Effect.catchAll(() =>\n Effect.succeed({\n name: pkg,\n pid: undefined,\n kill: Effect.void,\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle),\n ),\n );\n };\n\n const startGroup = (packages: string[]) =>\n Effect.forEach(packages, startProcess, { concurrency: \"unbounded\" });\n\n const awaitReady = (pkg: string, handle: ProcessHandle) =>\n handle.waitForReady.pipe(\n Effect.timeout(\"120 seconds\"),\n Effect.catchAll((err) =>\n Effect.sync(() => {\n callbacks.onLog(\n pkg,\n `Timed out or failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }),\n ),\n );\n\n const nonHostPackages = orderedPackages.filter((pkg) => pkg !== \"host\");\n const hostPackages = orderedPackages.filter((pkg) => pkg === \"host\");\n\n const nonHostHandles = yield* startGroup(nonHostPackages);\n\n yield* Effect.forEach(\n nonHostHandles.map((handle, index) => ({\n handle,\n pkg: nonHostPackages[index] ?? handle.name,\n })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const hostHandles = yield* startGroup(hostPackages);\n\n yield* Effect.forEach(\n hostHandles.map((handle, index) => ({ handle, pkg: hostPackages[index] ?? handle.name })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const allHandles = [...nonHostHandles, ...hostHandles];\n\n yield* Effect.addFinalizer(() =>\n Effect.gen(function* () {\n yield* Effect.forEach(allHandles, (h) => h.kill.pipe(Effect.ignore), {\n concurrency: \"unbounded\",\n });\n\n yield* Effect.sleep(\"200 millis\");\n\n view?.unmount();\n\n if (shouldExportLogs) {\n console.log(\"\\n\");\n console.log(\"═\".repeat(70));\n console.log(` SESSION LOGS: ${orchestrator.description}`);\n console.log(` Started: ${new Date(allLogs[0]?.timestamp || Date.now()).toISOString()}`);\n console.log(` Total entries: ${allLogs.length}`);\n console.log(\"═\".repeat(70));\n console.log(\"\");\n for (const entry of allLogs) {\n console.log(formatLogLine(entry));\n }\n console.log(\"\");\n console.log(\"═\".repeat(70));\n console.log(` Full logs saved to: ${logger.logFile}`);\n console.log(\"═\".repeat(70));\n console.log(\"\");\n }\n }),\n );\n\n yield* Deferred.await(shutdown);\n });\n\nconst runApp = (\n orchestrator: AppOrchestrator,\n services: Map<string, ServiceDescriptor>,\n runtimeConfig: RuntimeConfig,\n) => {\n let requestShutdown: (() => void) | null = null;\n let signalCount = 0;\n let forceExitTimer: ReturnType<typeof setTimeout> | null = null;\n\n const forceExit = () => {\n console.log(\"\\n[Dev] Force exit\");\n process.exit(0);\n };\n\n const program = Effect.scoped(\n runDevSession(orchestrator, (shutdown) => {\n requestShutdown = shutdown;\n }),\n ).pipe(\n Effect.provide(ServiceDescriptorMapLive(services)),\n Effect.provide(DevRuntimeConfigLive(runtimeConfig)),\n Effect.provide(NodeContext.layer),\n Effect.catchAllDefect((defect) =>\n Effect.sync(() => {\n console.error(\"[Dev] Unhandled defect in orchestrator:\", defect);\n }),\n ),\n );\n\n const handleSignal = () => {\n signalCount++;\n if (signalCount > 1) {\n forceExit();\n return;\n }\n console.log(\"\\n[Dev] Shutting down...\");\n forceExitTimer = setTimeout(forceExit, 5000);\n requestShutdown?.();\n };\n\n process.on(\"SIGINT\", handleSignal);\n process.on(\"SIGTERM\", handleSignal);\n\n Effect.runPromiseExit(program).then((exit) => {\n if (forceExitTimer) clearTimeout(forceExitTimer);\n process.exit(Exit.isSuccess(exit) ? 0 : 0);\n });\n};\n\nexport const devApp = runApp;\n\nexport const startApp = runApp;\n"],"mappings":";;;;;;;;;;AA0BA,MAAM,qBAAqB;CACzB;CACA;CACA;CACD;AAED,MAAM,oBAAoB;CACxB;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,oBAAoB,QAAgB,MAAc,YAA+B;AACrF,KAAI,QAAQ,IAAI,UAAU,UAAU,QAAQ,IAAI,UAAU,IAAK,QAAO;AACtE,KAAI,WAAW,UAAU;AACvB,MAAI,QAAS,QAAO;AACpB,SAAO,kBAAkB,MAAM,YAAY,QAAQ,KAAK,KAAK,CAAC;;AAEhE,QAAO,CAAC,mBAAmB,MAAM,YAAY,QAAQ,KAAK,KAAK,CAAC;;AAGlE,MAAM,+BAAwC;AAC5C,QAAO,QAAQ,MAAM,UAAU,QAAQ,QAAQ,OAAO,UAAU;;AAGlE,MAAM,gBAAgB;CAAC;CAAU;CAAM;CAAQ;CAAO;CAAU;CAAc;CAAO;AAErF,MAAM,eAAe,aAAiC;AACpD,QAAO,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,MAAM;EAClC,MAAM,OAAO,EAAE,WAAW,UAAU,GAChC,cAAc,QAAQ,SAAS,GAC/B,cAAc,QAAQ,EAAE;EAC5B,MAAM,OAAO,EAAE,WAAW,UAAU,GAChC,cAAc,QAAQ,SAAS,GAC/B,cAAc,QAAQ,EAAE;AAC5B,MAAI,SAAS,MAAM,SAAS,GAAI,QAAO;AACvC,MAAI,SAAS,GAAI,QAAO;AACxB,MAAI,SAAS,GAAI,QAAO;AACxB,SAAO,OAAO;GACd;;AAGJ,SAAS,cAAc,OAAyB;CAC9C,MAAM,KAAK,IAAI,KAAK,MAAM,UAAU,CAAC,aAAa;CAClD,MAAM,SAAS,MAAM,UAAU,QAAQ;AACvC,QAAO,IAAI,GAAG,KAAK,MAAM,OAAO,KAAK,OAAO,IAAI,MAAM;;AAGxD,MAAa,iBACX,cACA,oBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,YAAY,gBAAgB;CAClC,MAAM,WAAW,OAAO;CACxB,MAAM,kBAAkB,YAAY,aAAa,SAAS;CAC1D,MAAM,mBAAmC,iBACvC,iBACA,UACA,aAAa,KACd;AAED,KAAI,QAAQ,IAAI,UAAU,UAAU,QAAQ,IAAI,UAAU,KAAK;AAC7D,UAAQ,MAAM,0CAA0C,aAAa,SAAS,KAAK,KAAK,CAAC;AACzF,UAAQ,MAAM,oCAAoC,gBAAgB,KAAK,KAAK,CAAC;AAC7E,UAAQ,MAAM,kCAAkC,CAAC,GAAG,SAAS,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC;AAChF,UAAQ,MACN,qCACA,iBAAiB,KAAK,MAAM,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS,CAAC,KAAK,KAAK,CAChE;;CAGH,MAAM,SAAS,OAAO,OAAO,cAC3B,gBAAgB,WAAW,aAAa,YAAY,CACrD;CAED,MAAM,WAAW,OAAO,SAAS,MAAY;AAE7C,yBAAwB;AACtB,EAAK,OAAO,WAAW,SAAS,QAAQ,UAAU,OAAU,CAAC;GAC7D;CAEF,MAAM,UAAsB,EAAE;CAC9B,IAAI,OAA6B;CACjC,IAAI,mBAAmB;CAEvB,MAAM,iCAAiC;AACrC,qBAAmB;AACnB,EAAK,OAAO,WAAW,SAAS,QAAQ,UAAU,OAAU,CAAC;;AAI/D,QADuB,aAAa,eAAe,wBAAwB,GAEvE,cACE,kBACA,aAAa,aACb,aAAa,WACP,KAAK,OAAO,WAAW,SAAS,QAAQ,UAAU,OAAU,CAAC,EACnE,yBACD,GACD,oBACE,kBACA,aAAa,aACb,aAAa,WACP,KAAK,OAAO,WAAW,SAAS,QAAQ,UAAU,OAAU,CAAC,CACpE;CAEL,MAAM,YAA8B;EAClC,WAAW,MAAM,QAAQ,YAAY;AACnC,SAAM,cAAc,MAAM,QAAQ,QAAQ;;EAE5C,QAAQ,MAAM,MAAM,YAAY;GAC9B,MAAM,QAAkB;IACtB,IAAI,GAAG,KAAK,KAAK,CAAC,GAAG,QAAQ,SAAS;IACtC,QAAQ;IACR;IACA,WAAW,KAAK,KAAK;IACrB;IACD;AACD,WAAQ,KAAK,MAAM;AACnB,OAAI,iBAAiB,MAAM,MAAM,QAAQ,CACvC,OAAM,OAAO,MAAM,MAAM,QAAQ;AAEnC,OAAI,CAAC,aAAa,OAChB,CAAK,OAAO,MAAM,MAAM;;EAG7B;CAED,MAAM,gBAAgB,QAAgB;AAEpC,SAAO,eAAe,KAAK,WADN,QAAQ,SAAS,aAAa,OAAO,OACP,CAAC,KAClD,OAAO,UAAU,QACf,OAAO,WAAW;AAChB,aAAU,MAAM,KAAK,oBAAoB,OAAO,KAAK;AACrD,aAAU,SAAS,KAAK,QAAQ;IAChC,CACH,EACD,OAAO,eACL,OAAO,QAAQ;GACb,MAAM;GACN,KAAK;GACL,MAAM,OAAO;GACb,cAAc,OAAO;GACrB,aAAa,OAAO;GACrB,CAAyB,CAC3B,CACF;;CAGH,MAAM,cAAc,aAClB,OAAO,QAAQ,UAAU,cAAc,EAAE,aAAa,aAAa,CAAC;CAEtE,MAAM,cAAc,KAAa,WAC/B,OAAO,aAAa,KAClB,OAAO,QAAQ,cAAc,EAC7B,OAAO,UAAU,QACf,OAAO,WAAW;AAChB,YAAU,MACR,KACA,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,IACxE,KACD;GACD,CACH,CACF;CAEH,MAAM,kBAAkB,gBAAgB,QAAQ,QAAQ,QAAQ,OAAO;CACvE,MAAM,eAAe,gBAAgB,QAAQ,QAAQ,QAAQ,OAAO;CAEpE,MAAM,iBAAiB,OAAO,WAAW,gBAAgB;AAEzD,QAAO,OAAO,QACZ,eAAe,KAAK,QAAQ,WAAW;EACrC;EACA,KAAK,gBAAgB,UAAU,OAAO;EACvC,EAAE,GACF,EAAE,QAAQ,UAAU,WAAW,KAAK,OAAO,EAC5C,EAAE,aAAa,aAAa,CAC7B;CAED,MAAM,cAAc,OAAO,WAAW,aAAa;AAEnD,QAAO,OAAO,QACZ,YAAY,KAAK,QAAQ,WAAW;EAAE;EAAQ,KAAK,aAAa,UAAU,OAAO;EAAM,EAAE,GACxF,EAAE,QAAQ,UAAU,WAAW,KAAK,OAAO,EAC5C,EAAE,aAAa,aAAa,CAC7B;CAED,MAAM,aAAa,CAAC,GAAG,gBAAgB,GAAG,YAAY;AAEtD,QAAO,OAAO,mBACZ,OAAO,IAAI,aAAa;AACtB,SAAO,OAAO,QAAQ,aAAa,MAAM,EAAE,KAAK,KAAK,OAAO,OAAO,EAAE,EACnE,aAAa,aACd,CAAC;AAEF,SAAO,OAAO,MAAM,aAAa;AAEjC,QAAM,SAAS;AAEf,MAAI,kBAAkB;AACpB,WAAQ,IAAI,KAAK;AACjB,WAAQ,IAAI,IAAI,OAAO,GAAG,CAAC;AAC3B,WAAQ,IAAI,mBAAmB,aAAa,cAAc;AAC1D,WAAQ,IAAI,cAAc,IAAI,KAAK,QAAQ,IAAI,aAAa,KAAK,KAAK,CAAC,CAAC,aAAa,GAAG;AACxF,WAAQ,IAAI,oBAAoB,QAAQ,SAAS;AACjD,WAAQ,IAAI,IAAI,OAAO,GAAG,CAAC;AAC3B,WAAQ,IAAI,GAAG;AACf,QAAK,MAAM,SAAS,QAClB,SAAQ,IAAI,cAAc,MAAM,CAAC;AAEnC,WAAQ,IAAI,GAAG;AACf,WAAQ,IAAI,IAAI,OAAO,GAAG,CAAC;AAC3B,WAAQ,IAAI,yBAAyB,OAAO,UAAU;AACtD,WAAQ,IAAI,IAAI,OAAO,GAAG,CAAC;AAC3B,WAAQ,IAAI,GAAG;;GAEjB,CACH;AAED,QAAO,SAAS,MAAM,SAAS;EAC/B;AAEJ,MAAM,UACJ,cACA,UACA,kBACG;CACH,IAAI,kBAAuC;CAC3C,IAAI,cAAc;CAClB,IAAI,iBAAuD;CAE3D,MAAM,kBAAkB;AACtB,UAAQ,IAAI,qBAAqB;AACjC,UAAQ,KAAK,EAAE;;CAGjB,MAAM,UAAU,OAAO,OACrB,cAAc,eAAe,aAAa;AACxC,oBAAkB;GAClB,CACH,CAAC,KACA,OAAO,QAAQ,yBAAyB,SAAS,CAAC,EAClD,OAAO,QAAQ,qBAAqB,cAAc,CAAC,EACnD,OAAO,QAAQ,YAAY,MAAM,EACjC,OAAO,gBAAgB,WACrB,OAAO,WAAW;AAChB,UAAQ,MAAM,2CAA2C,OAAO;GAChE,CACH,CACF;CAED,MAAM,qBAAqB;AACzB;AACA,MAAI,cAAc,GAAG;AACnB,cAAW;AACX;;AAEF,UAAQ,IAAI,2BAA2B;AACvC,mBAAiB,WAAW,WAAW,IAAK;AAC5C,qBAAmB;;AAGrB,SAAQ,GAAG,UAAU,aAAa;AAClC,SAAQ,GAAG,WAAW,aAAa;AAEnC,QAAO,eAAe,QAAQ,CAAC,MAAM,SAAS;AAC5C,MAAI,eAAgB,cAAa,eAAe;AAChD,UAAQ,KAAK,KAAK,UAAU,KAAK,GAAG,IAAI,EAAE;GAC1C;;AAGJ,MAAa,SAAS;AAEtB,MAAa,WAAW"}
1
+ {"version":3,"file":"dev-session.mjs","names":[],"sources":["../src/dev-session.ts"],"sourcesContent":["import * as NodeContext from \"@effect/platform-node/NodeContext\";\nimport { Deferred, Effect, Exit } from \"effect\";\nimport {\n type DevViewHandle,\n type LogEntry,\n type ProcessState,\n renderDevView,\n} from \"./components/dev-view\";\nimport { renderStreamingView } from \"./components/streaming-view\";\nimport { getProjectRoot } from \"./config\";\nimport { createDevLogger } from \"./dev-logs\";\nimport {\n getProcessStates,\n makeDevProcess,\n type ProcessCallbacks,\n type ProcessHandle,\n} from \"./orchestrator\";\nimport { registerStandalone, unregisterPid } from \"./process-registry\";\nimport {\n type AppOrchestrator,\n DevRuntimeConfig,\n DevRuntimeConfigLive,\n type ServiceDescriptor,\n ServiceDescriptorMap,\n ServiceDescriptorMapLive,\n} from \"./service-descriptor\";\nimport type { RuntimeConfig } from \"./types\";\n\nconst LOG_NOISE_PATTERNS = [\n /\\[ Federation Runtime \\] Version .* from (host|ui) of shared singleton module/,\n /Executing an Effect versioned \\d+\\.\\d+\\.\\d+ with a Runtime of version/,\n /you may want to dedupe the effect dependencies/,\n];\n\nconst SSR_LOG_ALLOWLIST = [\n /\\bready\\s+built in\\b/i,\n /\\bcompiled\\b.*successfully/i,\n /\\berror\\b/i,\n /\\bfailed\\b/i,\n /\\bexception\\b/i,\n];\n\nconst shouldDisplayLog = (source: string, line: string, isError?: boolean): boolean => {\n if (process.env.DEBUG === \"true\" || process.env.DEBUG === \"1\") return true;\n if (source === \"ui-ssr\") {\n if (isError) return true;\n return SSR_LOG_ALLOWLIST.some((pattern) => pattern.test(line));\n }\n return !LOG_NOISE_PATTERNS.some((pattern) => pattern.test(line));\n};\n\nconst isInteractiveSupported = (): boolean => {\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n};\n\nconst STARTUP_ORDER = [\"ui-ssr\", \"ui\", \"auth\", \"api\", \"plugin\", \"host-build\", \"host\"];\n\nconst sortByOrder = (packages: string[]): string[] => {\n return [...packages].sort((a, b) => {\n const aIdx = a.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(a);\n const bIdx = b.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return 0;\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n};\n\nfunction formatLogLine(entry: LogEntry): string {\n const ts = new Date(entry.timestamp).toISOString();\n const prefix = entry.isError ? \"ERR\" : \"OUT\";\n return `[${ts}] [${entry.source}] [${prefix}] ${entry.line}`;\n}\n\nexport const runDevSession = (\n orchestrator: AppOrchestrator,\n onShutdownReady?: (requestShutdown: () => void) => void,\n) =>\n Effect.gen(function* () {\n const configDir = getProjectRoot();\n const services = yield* ServiceDescriptorMap;\n const runtimeConfig = yield* DevRuntimeConfig;\n const orderedPackages = sortByOrder(orchestrator.packages);\n const initialProcesses: ProcessState[] = getProcessStates(\n orderedPackages,\n services,\n orchestrator.port,\n );\n\n if (process.env.DEBUG === \"true\" || process.env.DEBUG === \"1\") {\n console.error(\"[DEBUG session] orchestrator.packages:\", orchestrator.packages.join(\", \"));\n console.error(\"[DEBUG session] orderedPackages:\", orderedPackages.join(\", \"));\n console.error(\"[DEBUG session] services keys:\", [...services.keys()].join(\", \"));\n console.error(\n \"[DEBUG session] initialProcesses:\",\n initialProcesses.map((p) => `${p.name}=${p.source}`).join(\", \"),\n );\n }\n\n const logger = yield* Effect.promise(() =>\n createDevLogger(configDir, orchestrator.description),\n );\n\n const shutdown = yield* Deferred.make<void>();\n\n onShutdownReady?.(() => {\n void Effect.runPromise(Deferred.succeed(shutdown, undefined));\n });\n\n const isWorkspaceChild = process.env.BOS_WORKSPACE_CHILD === \"1\";\n if (!isWorkspaceChild) {\n const regPorts: Record<string, number> = {};\n const addPort = (key: string, value: number | undefined | null) => {\n if (value != null) regPorts[key] = value;\n };\n addPort(\"host\", runtimeConfig.host.port);\n addPort(\"api\", runtimeConfig.api.port);\n addPort(\"ui\", runtimeConfig.ui.port);\n addPort(\"auth\", runtimeConfig.auth?.port);\n addPort(\n \"uiSsr\",\n runtimeConfig.ui.ssrUrl\n ? Number.parseInt(new URL(runtimeConfig.ui.ssrUrl).port, 10)\n : undefined,\n );\n if (runtimeConfig.plugins) {\n for (const [id, plugin] of Object.entries(runtimeConfig.plugins)) {\n addPort(`plugin:${id}`, plugin.port);\n addPort(`plugin-ui:${id}`, plugin.ui?.port);\n }\n }\n registerStandalone({\n pid: process.pid,\n configDir,\n ports: regPorts,\n startedAt: Date.now(),\n description: orchestrator.description,\n });\n }\n\n const allLogs: LogEntry[] = [];\n let view: DevViewHandle | null = null;\n let shouldExportLogs = false;\n\n const requestShutdownAndExport = () => {\n shouldExportLogs = true;\n void Effect.runPromise(Deferred.succeed(shutdown, undefined));\n };\n\n const useInteractive = orchestrator.interactive ?? isInteractiveSupported();\n view = useInteractive\n ? renderDevView(\n initialProcesses,\n orchestrator.description,\n orchestrator.env,\n () => void Effect.runPromise(Deferred.succeed(shutdown, undefined)),\n requestShutdownAndExport,\n )\n : renderStreamingView(\n initialProcesses,\n orchestrator.description,\n orchestrator.env,\n () => void Effect.runPromise(Deferred.succeed(shutdown, undefined)),\n );\n\n const callbacks: ProcessCallbacks = {\n onStatus: (name, status, message) => {\n view?.updateProcess(name, status, message);\n },\n onLog: (name, line, isError) => {\n const entry: LogEntry = {\n id: `${Date.now()}-${allLogs.length + 1}`,\n source: name,\n line,\n timestamp: Date.now(),\n isError,\n };\n allLogs.push(entry);\n if (shouldDisplayLog(name, line, isError)) {\n view?.addLog(name, line, isError);\n }\n if (!orchestrator.noLogs) {\n void logger.write(entry);\n }\n },\n };\n\n const startProcess = (pkg: string) => {\n const portOverride = pkg === \"host\" ? orchestrator.port : undefined;\n return makeDevProcess(pkg, callbacks, portOverride).pipe(\n Effect.tapError((err) =>\n Effect.sync(() => {\n callbacks.onLog(pkg, `Failed to start: ${err}`, true);\n callbacks.onStatus(pkg, \"error\");\n }),\n ),\n Effect.catchAll(() =>\n Effect.succeed({\n name: pkg,\n pid: undefined,\n kill: Effect.void,\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n } satisfies ProcessHandle),\n ),\n );\n };\n\n const startGroup = (packages: string[]) =>\n Effect.forEach(packages, startProcess, { concurrency: \"unbounded\" });\n\n const awaitReady = (pkg: string, handle: ProcessHandle) =>\n handle.waitForReady.pipe(\n Effect.timeout(\"120 seconds\"),\n Effect.catchAll((err) =>\n Effect.sync(() => {\n callbacks.onLog(\n pkg,\n `Timed out or failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }),\n ),\n );\n\n const nonHostPackages = orderedPackages.filter((pkg) => pkg !== \"host\");\n const hostPackages = orderedPackages.filter((pkg) => pkg === \"host\");\n\n const nonHostHandles = yield* startGroup(nonHostPackages);\n\n yield* Effect.forEach(\n nonHostHandles.map((handle, index) => ({\n handle,\n pkg: nonHostPackages[index] ?? handle.name,\n })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const hostHandles = yield* startGroup(hostPackages);\n\n yield* Effect.forEach(\n hostHandles.map((handle, index) => ({ handle, pkg: hostPackages[index] ?? handle.name })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const allHandles = [...nonHostHandles, ...hostHandles];\n\n yield* Effect.addFinalizer(() =>\n Effect.gen(function* () {\n yield* Effect.forEach(allHandles, (h) => h.kill.pipe(Effect.ignore), {\n concurrency: \"unbounded\",\n });\n\n yield* Effect.sleep(\"200 millis\");\n\n view?.unmount();\n\n if (!isWorkspaceChild) {\n try {\n unregisterPid(process.pid);\n } catch {\n // best-effort; pruneDead cleans stale entries on next ps/kill\n }\n }\n\n if (shouldExportLogs) {\n console.log(\"\\n\");\n console.log(\"═\".repeat(70));\n console.log(` SESSION LOGS: ${orchestrator.description}`);\n console.log(` Started: ${new Date(allLogs[0]?.timestamp || Date.now()).toISOString()}`);\n console.log(` Total entries: ${allLogs.length}`);\n console.log(\"═\".repeat(70));\n console.log(\"\");\n for (const entry of allLogs) {\n console.log(formatLogLine(entry));\n }\n console.log(\"\");\n console.log(\"═\".repeat(70));\n console.log(` Full logs saved to: ${logger.logFile}`);\n console.log(\"═\".repeat(70));\n console.log(\"\");\n }\n }),\n );\n\n yield* Deferred.await(shutdown);\n });\n\nconst runApp = (\n orchestrator: AppOrchestrator,\n services: Map<string, ServiceDescriptor>,\n runtimeConfig: RuntimeConfig,\n) => {\n let requestShutdown: (() => void) | null = null;\n let signalCount = 0;\n let forceExitTimer: ReturnType<typeof setTimeout> | null = null;\n\n const forceExit = () => {\n console.log(\"\\n[Dev] Force exit\");\n process.exit(0);\n };\n\n const program = Effect.scoped(\n runDevSession(orchestrator, (shutdown) => {\n requestShutdown = shutdown;\n }),\n ).pipe(\n Effect.provide(ServiceDescriptorMapLive(services)),\n Effect.provide(DevRuntimeConfigLive(runtimeConfig)),\n Effect.provide(NodeContext.layer),\n Effect.catchAllDefect((defect) =>\n Effect.sync(() => {\n console.error(\"[Dev] Unhandled defect in orchestrator:\", defect);\n }),\n ),\n );\n\n const handleSignal = () => {\n signalCount++;\n if (signalCount > 1) {\n forceExit();\n return;\n }\n console.log(\"\\n[Dev] Shutting down...\");\n forceExitTimer = setTimeout(forceExit, 5000);\n requestShutdown?.();\n };\n\n process.on(\"SIGINT\", handleSignal);\n process.on(\"SIGTERM\", handleSignal);\n\n Effect.runPromiseExit(program).then((exit) => {\n if (forceExitTimer) clearTimeout(forceExitTimer);\n process.exit(Exit.isSuccess(exit) ? 0 : 0);\n });\n};\n\nexport const devApp = runApp;\n\nexport const startApp = runApp;\n"],"mappings":"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"}