buncargo 1.0.26 → 3.0.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 (222) hide show
  1. package/dist/bin.d.ts +1 -12
  2. package/dist/bin.js +261 -252
  3. package/dist/cli/bin.d.ts +13 -0
  4. package/dist/cli/bin.js +315 -0
  5. package/dist/cli/commands/help.d.ts +1 -0
  6. package/dist/cli/commands/runtime.d.ts +5 -0
  7. package/dist/cli/commands/version.d.ts +1 -0
  8. package/dist/cli/index.d.ts +1 -0
  9. package/dist/cli/index.js +14 -0
  10. package/dist/cli/run-cli.d.ts +22 -0
  11. package/dist/cli.d.ts +1 -22
  12. package/dist/cli.js +5 -13
  13. package/dist/config/config.d.ts +1 -0
  14. package/dist/config/define-config.d.ts +13 -0
  15. package/dist/config/index.d.ts +3 -0
  16. package/dist/config/index.js +15 -0
  17. package/dist/config/merge-configs.d.ts +3 -0
  18. package/dist/config/validate-config.d.ts +3 -0
  19. package/dist/config.d.ts +1 -72
  20. package/dist/config.js +12 -12
  21. package/dist/core/docker.d.ts +1 -74
  22. package/dist/core/docker.js +35 -26
  23. package/dist/core/index.d.ts +1 -1
  24. package/dist/core/index.js +123 -108
  25. package/dist/core/network.js +2 -2
  26. package/dist/core/ports.d.ts +22 -0
  27. package/dist/core/ports.js +5 -1
  28. package/dist/core/process.js +1 -1
  29. package/dist/core/tunnel.d.ts +33 -0
  30. package/dist/core/utils.js +2 -2
  31. package/dist/core/watchdog-runner.js +45 -42
  32. package/dist/core/watchdog.d.ts +1 -0
  33. package/dist/core/watchdog.js +4 -2
  34. package/dist/docker/index.d.ts +1 -0
  35. package/dist/docker/index.js +38 -0
  36. package/dist/docker/runtime.d.ts +87 -0
  37. package/dist/docker/runtime.js +37 -0
  38. package/dist/docker-compose/compose.d.ts +1 -0
  39. package/dist/docker-compose/generated-file.d.ts +7 -0
  40. package/dist/docker-compose/index.d.ts +3 -0
  41. package/dist/docker-compose/index.js +15 -0
  42. package/dist/docker-compose/model.d.ts +6 -0
  43. package/dist/docker-compose/services/clickhouse.d.ts +16 -0
  44. package/dist/docker-compose/services/define-docker-service.d.ts +41 -0
  45. package/dist/docker-compose/services/index.d.ts +23 -0
  46. package/dist/docker-compose/services/index.js +17 -0
  47. package/dist/docker-compose/services/postgres.d.ts +12 -0
  48. package/dist/docker-compose/services/redis.d.ts +12 -0
  49. package/dist/docker-compose/services/shared.d.ts +7 -0
  50. package/dist/docker-compose/yaml.d.ts +2 -0
  51. package/dist/environment/create-dev-environment.d.ts +23 -0
  52. package/dist/environment/index.d.ts +1 -0
  53. package/dist/environment/index.js +15 -0
  54. package/dist/environment/logging.d.ts +17 -0
  55. package/dist/environment/seeding.d.ts +9 -0
  56. package/dist/environment.d.ts +1 -23
  57. package/dist/environment.js +12 -14
  58. package/dist/index-045jksh5.js +147 -0
  59. package/dist/index-08wa79cs.js +125 -117
  60. package/dist/index-0kxnae3z.js +335 -0
  61. package/dist/index-1mdrf7nz.js +66 -0
  62. package/dist/index-1yvbwj4k.js +262 -242
  63. package/dist/index-23ev345g.js +475 -0
  64. package/dist/index-2ckr49sf.js +228 -0
  65. package/dist/index-2f47khe5.js +376 -369
  66. package/dist/index-2fr3g85b.js +220 -183
  67. package/dist/index-38xnzpa6.js +450 -0
  68. package/dist/index-3h3dhtf2.js +51 -43
  69. package/dist/index-42x95209.js +51 -43
  70. package/dist/index-4gp0az1g.js +145 -0
  71. package/dist/index-4xrxh8yv.js +72 -0
  72. package/dist/index-5gmws6ah.js +181 -0
  73. package/dist/index-5hka0tff.js +78 -76
  74. package/dist/index-5rfqps4b.js +3 -0
  75. package/dist/index-5t9jxqm0.js +428 -0
  76. package/dist/index-6c1w1xk5.js +101 -0
  77. package/dist/index-6fm7mvwj.js +118 -97
  78. package/dist/index-6srpc523.js +127 -128
  79. package/dist/index-731rzzfp.js +187 -0
  80. package/dist/index-75y4cg2z.js +51 -43
  81. package/dist/index-7ja4ywyj.js +126 -127
  82. package/dist/index-8bw1cmz4.js +531 -0
  83. package/dist/index-8hbbj1mp.js +120 -121
  84. package/dist/index-8xj2p5n5.js +145 -0
  85. package/dist/index-bj79tw5w.js +0 -0
  86. package/dist/index-bnk6nr0g.js +73 -0
  87. package/dist/index-brbbzyks.js +72 -0
  88. package/dist/index-c0dr6mcv.js +123 -0
  89. package/dist/index-cty0bcry.js +235 -218
  90. package/dist/index-d8tyv5se.js +228 -0
  91. package/dist/index-d9efy0n4.js +176 -150
  92. package/dist/index-etfmqjjf.js +427 -0
  93. package/dist/index-fb29934k.js +172 -0
  94. package/dist/index-g50jw1yf.js +72 -0
  95. package/dist/index-g6eb5wdw.js +118 -117
  96. package/dist/index-ggq3yryx.js +99 -95
  97. package/dist/index-h70tce00.js +177 -0
  98. package/dist/index-hkxtfqtc.js +333 -0
  99. package/dist/index-kf3dhser.js +146 -143
  100. package/dist/index-ma6tgdb2.js +500 -0
  101. package/dist/index-mam0bcyz.js +123 -0
  102. package/dist/index-mm412dkp.js +274 -0
  103. package/dist/index-n8v18aeb.js +0 -0
  104. package/dist/index-ndnmnsej.js +378 -371
  105. package/dist/index-p8wty0e2.js +389 -379
  106. package/dist/index-qfphr2fd.js +100 -0
  107. package/dist/index-qqmms8rs.js +51 -43
  108. package/dist/index-qw4093g2.js +51 -43
  109. package/dist/index-qzwpzjbx.js +121 -122
  110. package/dist/index-segbnm0h.js +146 -143
  111. package/dist/index-t0fj6gg1.js +112 -0
  112. package/dist/index-thdkwnv7.js +122 -0
  113. package/dist/index-tjbx2r2t.js +270 -0
  114. package/dist/index-tjqw9vtj.js +62 -54
  115. package/dist/index-vbpb89jy.js +248 -0
  116. package/dist/index-vhs88xhe.js +99 -95
  117. package/dist/index-w8zxnjka.js +249 -0
  118. package/dist/index-wk2na3t9.js +404 -0
  119. package/dist/index-wz9x8g7z.js +383 -373
  120. package/dist/index-x249gyde.js +388 -378
  121. package/dist/index-xkvd0nsd.js +187 -0
  122. package/dist/index-yedqxm1z.js +80 -0
  123. package/dist/index-zfjzzjkf.js +266 -0
  124. package/dist/index.d.ts +12 -8
  125. package/dist/index.js +66 -35
  126. package/dist/lint.d.ts +1 -46
  127. package/dist/lint.js +3 -7
  128. package/dist/loader/cache.d.ts +4 -0
  129. package/dist/loader/find-config-file.d.ts +2 -0
  130. package/dist/loader/index.d.ts +5 -0
  131. package/dist/loader/index.js +24 -0
  132. package/dist/loader/load-dev-env.d.ts +5 -0
  133. package/dist/loader/loader.d.ts +1 -0
  134. package/dist/loader.d.ts +1 -45
  135. package/dist/loader.js +22 -20
  136. package/dist/prisma/index.d.ts +1 -0
  137. package/dist/prisma/prisma.d.ts +29 -0
  138. package/dist/prisma.d.ts +1 -29
  139. package/dist/prisma.js +6 -10
  140. package/dist/src/bin.js +309 -0
  141. package/dist/src/cli.js +5 -0
  142. package/dist/src/config.js +15 -0
  143. package/dist/src/core/docker.js +38 -0
  144. package/dist/src/core/index.js +130 -0
  145. package/dist/src/core/network.js +9 -0
  146. package/dist/src/core/ports.js +23 -0
  147. package/dist/src/core/process.js +31 -0
  148. package/dist/src/core/utils.js +11 -0
  149. package/dist/src/core/watchdog-runner.js +69 -0
  150. package/dist/src/core/watchdog.js +28 -0
  151. package/dist/src/docker/runtime.js +37 -0
  152. package/dist/src/docker-compose/index.js +16 -0
  153. package/dist/src/docker-compose/services/index.js +17 -0
  154. package/dist/src/environment.js +12 -0
  155. package/dist/src/index.js +122 -0
  156. package/dist/src/lint.js +3 -0
  157. package/dist/src/loader.js +25 -0
  158. package/dist/src/prisma.js +6 -0
  159. package/dist/src/types.js +0 -0
  160. package/dist/typecheck/index.d.ts +1 -0
  161. package/dist/typecheck/index.js +7 -0
  162. package/dist/typecheck/typecheck.d.ts +46 -0
  163. package/dist/types/all-types.d.ts +501 -0
  164. package/dist/types/cli.d.ts +1 -0
  165. package/dist/types/config.d.ts +6 -0
  166. package/dist/types/docker.d.ts +15 -0
  167. package/dist/types/environment.d.ts +8 -0
  168. package/dist/types/hooks.d.ts +9 -0
  169. package/dist/types/index.d.ts +1 -0
  170. package/dist/types/index.js +0 -0
  171. package/dist/types/prisma.d.ts +1 -0
  172. package/dist/types.d.ts +1 -393
  173. package/package.json +145 -140
  174. package/readme.md +358 -105
  175. package/src/cli/bin.ts +77 -0
  176. package/src/cli/commands/help.ts +39 -0
  177. package/src/cli/commands/runtime.ts +72 -0
  178. package/src/cli/commands/version.ts +4 -0
  179. package/src/cli/index.ts +1 -0
  180. package/{cli.ts → src/cli/run-cli.ts} +95 -6
  181. package/src/config/define-config.ts +30 -0
  182. package/src/config/index.ts +3 -0
  183. package/src/config/merge-configs.ts +33 -0
  184. package/src/config/validate-config.ts +136 -0
  185. package/{core → src/core}/index.ts +2 -2
  186. package/{core → src/core}/ports.ts +68 -1
  187. package/{core → src/core}/process.ts +6 -2
  188. package/src/core/tunnel.ts +151 -0
  189. package/{core → src/core}/utils.ts +1 -0
  190. package/{core → src/core}/watchdog.ts +5 -1
  191. package/src/docker/index.ts +1 -0
  192. package/{core/docker.ts → src/docker/runtime.ts} +40 -4
  193. package/src/docker-compose/generated-file.ts +45 -0
  194. package/src/docker-compose/index.ts +7 -0
  195. package/src/docker-compose/model.ts +197 -0
  196. package/src/docker-compose/services/clickhouse.ts +79 -0
  197. package/src/docker-compose/services/define-docker-service.ts +109 -0
  198. package/src/docker-compose/services/index.ts +67 -0
  199. package/src/docker-compose/services/postgres.ts +60 -0
  200. package/src/docker-compose/services/redis.ts +48 -0
  201. package/src/docker-compose/services/shared.ts +79 -0
  202. package/src/docker-compose/yaml.ts +88 -0
  203. package/{environment.ts → src/environment/create-dev-environment.ts} +101 -146
  204. package/src/environment/index.ts +1 -0
  205. package/src/environment/logging.ts +101 -0
  206. package/src/environment/seeding.ts +57 -0
  207. package/{index.ts → src/index.ts} +49 -15
  208. package/src/loader/cache.ts +23 -0
  209. package/src/loader/find-config-file.ts +29 -0
  210. package/src/loader/index.ts +17 -0
  211. package/src/loader/load-dev-env.ts +38 -0
  212. package/src/prisma/index.ts +1 -0
  213. package/{prisma.ts → src/prisma/prisma.ts} +4 -2
  214. package/src/typecheck/index.ts +1 -0
  215. package/{types.ts → src/types/all-types.ts} +137 -6
  216. package/src/types/index.ts +1 -0
  217. package/bin.ts +0 -191
  218. package/config.ts +0 -194
  219. package/loader.ts +0 -126
  220. /package/{core → src/core}/network.ts +0 -0
  221. /package/{core → src/core}/watchdog-runner.ts +0 -0
  222. /package/{lint.ts → src/typecheck/typecheck.ts} +0 -0
@@ -0,0 +1,187 @@
1
+ // src/core/ports.ts
2
+ import { existsSync, readFileSync, statSync } from "node:fs";
3
+ import { basename, dirname, resolve } from "node:path";
4
+
5
+ function findMonorepoRoot(startDir) {
6
+ let dir = startDir ?? process.cwd();
7
+ while (dir !== "/") {
8
+ try {
9
+ const pkgPath = resolve(dir, "package.json");
10
+ if (existsSync(pkgPath)) {
11
+ const content = readFileSync(pkgPath, "utf-8");
12
+ const pkg = JSON.parse(content);
13
+ if (pkg.workspaces) {
14
+ return dir;
15
+ }
16
+ }
17
+ } catch {}
18
+ dir = dirname(dir);
19
+ }
20
+ return process.cwd();
21
+ }
22
+ function getWorktreeName(root) {
23
+ const monorepoRoot = root ?? findMonorepoRoot();
24
+ const gitPath = resolve(monorepoRoot, ".git");
25
+ try {
26
+ if (!existsSync(gitPath) || !statSync(gitPath).isFile()) return null;
27
+ const content = readFileSync(gitPath, "utf-8").trim();
28
+ const match = content.match(/^gitdir:\s*(.+)$/);
29
+ if (!match?.[1]) return null;
30
+ return basename(match[1]);
31
+ } catch {
32
+ return null;
33
+ }
34
+ }
35
+ function isWorktree(root) {
36
+ return getWorktreeName(root) !== null;
37
+ }
38
+ function sanitizeProjectSuffix(value) {
39
+ return value
40
+ .toLowerCase()
41
+ .replace(/[^a-z0-9-]/g, "-")
42
+ .replace(/-+/g, "-")
43
+ .replace(/^-+|-+$/g, "");
44
+ }
45
+ function getWorktreeProjectSuffix(root) {
46
+ const worktreeName = getWorktreeName(root);
47
+ if (!worktreeName) return null;
48
+ const sanitized = sanitizeProjectSuffix(worktreeName);
49
+ return sanitized || "worktree";
50
+ }
51
+ function simpleHash(str) {
52
+ let hash = 0;
53
+ for (let i = 0; i < str.length; i++) {
54
+ const char = str.charCodeAt(i);
55
+ hash = (hash << 5) - hash + char;
56
+ hash = hash & hash;
57
+ }
58
+ return Math.abs(hash);
59
+ }
60
+ function calculatePortOffset(suffix, root) {
61
+ const worktreeName = getWorktreeName(root);
62
+ if (!worktreeName) return 0;
63
+ const hashInput = suffix ? `${worktreeName}-${suffix}` : worktreeName;
64
+ return 10 + (simpleHash(hashInput) % 90);
65
+ }
66
+ function getProjectName(prefix, suffix, root) {
67
+ const monorepoRoot = root ?? findMonorepoRoot();
68
+ const dirName = basename(monorepoRoot);
69
+ const baseName = `${prefix}-${dirName.toLowerCase().replace(/[^a-z0-9-]/g, "-")}`;
70
+ return suffix ? `${baseName}-${suffix}` : baseName;
71
+ }
72
+ function computeDevIdentity(options) {
73
+ const {
74
+ projectPrefix,
75
+ suffix,
76
+ root: providedRoot,
77
+ worktreeIsolation = true,
78
+ } = options;
79
+ const root = providedRoot ?? findMonorepoRoot();
80
+ const worktree = isWorktree(root);
81
+ const worktreeSuffix =
82
+ worktree && worktreeIsolation ? getWorktreeProjectSuffix(root) : null;
83
+ const projectSuffix =
84
+ [suffix, worktreeSuffix].filter(Boolean).join("-") || undefined;
85
+ const projectName = getProjectName(projectPrefix, projectSuffix, root);
86
+ const portOffset = calculatePortOffset(suffix, root);
87
+ return {
88
+ worktree,
89
+ worktreeSuffix,
90
+ projectSuffix,
91
+ projectName,
92
+ portOffset,
93
+ };
94
+ }
95
+ function computePorts(services, apps, offset) {
96
+ const ports = {};
97
+ for (const [name, config] of Object.entries(services)) {
98
+ ports[name] = config.port + offset;
99
+ if (config.secondaryPort) {
100
+ ports[`${name}Secondary`] = config.secondaryPort + offset;
101
+ }
102
+ }
103
+ if (apps) {
104
+ for (const [name, config] of Object.entries(apps)) {
105
+ ports[name] = config.port + offset;
106
+ }
107
+ }
108
+ return ports;
109
+ }
110
+ var SERVICE_DEFAULTS = {
111
+ postgres: { user: "postgres", password: "postgres", database: "postgres" },
112
+ postgresql: { user: "postgres", password: "postgres", database: "postgres" },
113
+ redis: { user: "", password: "", database: "" },
114
+ clickhouse: { user: "default", password: "clickhouse", database: "default" },
115
+ mysql: { user: "root", password: "root", database: "mysql" },
116
+ mongodb: { user: "", password: "", database: "" },
117
+ };
118
+ function buildServiceUrl(serviceName, ctx, config) {
119
+ const defaults = SERVICE_DEFAULTS[serviceName];
120
+ if (!defaults && !config.database) return null;
121
+ const user = config.user ?? defaults?.user ?? "";
122
+ const password = config.password ?? defaults?.password ?? "";
123
+ const database = config.database ?? defaults?.database ?? "";
124
+ switch (serviceName) {
125
+ case "postgres":
126
+ case "postgresql":
127
+ return `postgresql://${user}:${password}@${ctx.host}:${ctx.port}/${database}`;
128
+ case "redis":
129
+ return `redis://${ctx.host}:${ctx.port}`;
130
+ case "clickhouse":
131
+ return `http://${user}:${password}@${ctx.host}:${ctx.port}/${database}`;
132
+ case "mysql":
133
+ return `mysql://${user}:${password}@${ctx.host}:${ctx.port}/${database}`;
134
+ case "mongodb":
135
+ return `mongodb://${ctx.host}:${ctx.port}/${database}`;
136
+ default:
137
+ return null;
138
+ }
139
+ }
140
+ function computeUrls(services, apps, ports, localIp) {
141
+ const urls = {};
142
+ const host = "localhost";
143
+ for (const [name, config] of Object.entries(services)) {
144
+ const port = ports[name];
145
+ const secondaryPort = ports[`${name}Secondary`];
146
+ if (port === undefined) continue;
147
+ const ctx = { port, secondaryPort, host, localIp };
148
+ if (config.urlTemplate) {
149
+ urls[name] = config.urlTemplate(ctx);
150
+ } else {
151
+ const builtUrl = buildServiceUrl(
152
+ name,
153
+ { port, host },
154
+ {
155
+ database: config.database,
156
+ user: config.user,
157
+ password: config.password,
158
+ },
159
+ );
160
+ if (builtUrl) {
161
+ urls[name] = builtUrl;
162
+ } else {
163
+ urls[name] = `http://${host}:${port}`;
164
+ }
165
+ }
166
+ }
167
+ if (apps) {
168
+ for (const [name, _config] of Object.entries(apps)) {
169
+ const port = ports[name];
170
+ urls[name] = `http://${host}:${port}`;
171
+ urls[`${name}Local`] = `http://${localIp}:${port}`;
172
+ }
173
+ }
174
+ return urls;
175
+ }
176
+
177
+ export {
178
+ findMonorepoRoot,
179
+ getWorktreeName,
180
+ isWorktree,
181
+ getWorktreeProjectSuffix,
182
+ calculatePortOffset,
183
+ getProjectName,
184
+ computeDevIdentity,
185
+ computePorts,
186
+ computeUrls,
187
+ };
@@ -0,0 +1,80 @@
1
+ import { createDevEnvironment } from "./index-38xnzpa6.js";
2
+
3
+ // src/loader/cache.ts
4
+ var cachedEnv = null;
5
+ function setCachedDevEnv(env) {
6
+ cachedEnv = env;
7
+ }
8
+ function getCachedDevEnv() {
9
+ return cachedEnv;
10
+ }
11
+ function clearDevEnvCache() {
12
+ cachedEnv = null;
13
+ }
14
+
15
+ // src/loader/find-config-file.ts
16
+ import { existsSync } from "node:fs";
17
+ import { dirname, join } from "node:path";
18
+
19
+ var CONFIG_FILES = [
20
+ "dev.config.ts",
21
+ "dev.config.js",
22
+ "dev-tools.config.ts",
23
+ "dev-tools.config.js",
24
+ ];
25
+ function findConfigFile(startDir) {
26
+ let currentDir = startDir;
27
+ while (true) {
28
+ for (const file of CONFIG_FILES) {
29
+ const configPath = join(currentDir, file);
30
+ if (existsSync(configPath)) {
31
+ return configPath;
32
+ }
33
+ }
34
+ const parentDir = dirname(currentDir);
35
+ if (parentDir === currentDir) {
36
+ return null;
37
+ }
38
+ currentDir = parentDir;
39
+ }
40
+ }
41
+ // src/loader/load-dev-env.ts
42
+ async function loadDevEnv(options) {
43
+ if (!options?.reload) {
44
+ const cached = getCachedDevEnv();
45
+ if (cached) return cached;
46
+ }
47
+ const cwd = options?.cwd ?? process.cwd();
48
+ const configPath = findConfigFile(cwd);
49
+ if (configPath) {
50
+ const mod = await import(configPath);
51
+ const config = mod.default;
52
+ if (!config?.projectPrefix || !config?.services) {
53
+ throw new Error(
54
+ `Invalid config in "${configPath}". Use defineDevConfig() and export as default.`,
55
+ );
56
+ }
57
+ const env = createDevEnvironment(config);
58
+ setCachedDevEnv(env);
59
+ return env;
60
+ }
61
+ throw new Error(
62
+ "No config file found. Create dev.config.ts with: export default defineDevConfig({ ... })",
63
+ );
64
+ }
65
+
66
+ // src/loader/index.ts
67
+ function getDevEnv() {
68
+ const env = getCachedDevEnv();
69
+ if (!env) {
70
+ throw new Error("Dev environment not loaded. Call loadDevEnv() first.");
71
+ }
72
+ return env;
73
+ }
74
+ export {
75
+ clearDevEnvCache,
76
+ CONFIG_FILES,
77
+ findConfigFile,
78
+ loadDevEnv,
79
+ getDevEnv,
80
+ };
@@ -0,0 +1,266 @@
1
+ // core/docker.ts
2
+ import { execSync } from "node:child_process";
3
+ import { sleep } from "./index-8xj2p5n5.js";
4
+
5
+ var POLL_INTERVAL = 250;
6
+ var MAX_ATTEMPTS = 120;
7
+ var DOCKER_NOT_RUNNING_MESSAGE =
8
+ "Docker is not running. Please start Docker and try again.";
9
+ async function isContainerRunning(project, service) {
10
+ try {
11
+ const result = execSync(
12
+ `docker ps --filter "label=com.docker.compose.project=${project}" --filter "label=com.docker.compose.service=${service}" --format "{{.State}}"`,
13
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] },
14
+ );
15
+ return result.trim() === "running";
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
20
+ function isDockerRunning() {
21
+ try {
22
+ execSync('docker info --format "{{.ServerVersion}}"', {
23
+ encoding: "utf-8",
24
+ stdio: ["pipe", "pipe", "pipe"],
25
+ });
26
+ return true;
27
+ } catch {
28
+ return false;
29
+ }
30
+ }
31
+ function assertDockerRunning() {
32
+ if (!isDockerRunning()) {
33
+ throw new Error(DOCKER_NOT_RUNNING_MESSAGE);
34
+ }
35
+ }
36
+ async function areContainersRunning(project, minCount = 1) {
37
+ try {
38
+ const result = execSync(
39
+ `docker ps --filter "label=com.docker.compose.project=${project}" --format "{{.State}}"`,
40
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] },
41
+ );
42
+ const states = result
43
+ .trim()
44
+ .split(`
45
+ `)
46
+ .filter(Boolean);
47
+ if (states.length < minCount) return false;
48
+ return states.every((state) => state === "running");
49
+ } catch {
50
+ return false;
51
+ }
52
+ }
53
+ function startContainers(root, projectName, envVars, options = {}) {
54
+ const { verbose = true, wait = true, composeFile } = options;
55
+ assertDockerRunning();
56
+ if (verbose) console.log("\uD83D\uDC33 Starting Docker containers...");
57
+ const composeArg = composeFile ? `-f ${composeFile}` : "";
58
+ const waitFlag = wait ? "--wait" : "";
59
+ const cmd = `docker compose ${composeArg} up -d ${waitFlag}`.trim();
60
+ execSync(cmd, {
61
+ cwd: root,
62
+ env: { ...process.env, ...envVars, COMPOSE_PROJECT_NAME: projectName },
63
+ stdio: verbose ? "inherit" : "ignore",
64
+ });
65
+ if (verbose) console.log("✓ Containers started");
66
+ }
67
+ function stopContainers(root, projectName, options = {}) {
68
+ const { verbose = true, removeVolumes = false, composeFile } = options;
69
+ assertDockerRunning();
70
+ if (verbose) {
71
+ console.log(
72
+ removeVolumes
73
+ ? "\uD83D\uDDD1️ Stopping containers and removing volumes..."
74
+ : "\uD83D\uDED1 Stopping containers...",
75
+ );
76
+ }
77
+ const composeArg = composeFile ? `-f ${composeFile}` : "";
78
+ const volumeFlag = removeVolumes ? "-v" : "";
79
+ const cmd = `docker compose ${composeArg} down ${volumeFlag}`.trim();
80
+ execSync(cmd, {
81
+ cwd: root,
82
+ env: { ...process.env, COMPOSE_PROJECT_NAME: projectName },
83
+ stdio: verbose ? "inherit" : "ignore",
84
+ });
85
+ if (verbose) console.log("✓ Containers stopped");
86
+ }
87
+ function startService(root, projectName, serviceName, envVars, options = {}) {
88
+ const { verbose = true, composeFile } = options;
89
+ assertDockerRunning();
90
+ if (verbose) console.log(`\uD83D\uDC33 Starting ${serviceName}...`);
91
+ const composeArg = composeFile ? `-f ${composeFile}` : "";
92
+ const cmd = `docker compose ${composeArg} up -d ${serviceName}`.trim();
93
+ execSync(cmd, {
94
+ cwd: root,
95
+ env: { ...process.env, ...envVars, COMPOSE_PROJECT_NAME: projectName },
96
+ stdio: verbose ? "inherit" : "ignore",
97
+ });
98
+ }
99
+ function createBuiltInHealthCheck(type, serviceName, context = {}) {
100
+ const { projectName, root } = context;
101
+ switch (type) {
102
+ case "pg_isready":
103
+ return async () => {
104
+ try {
105
+ const projectArg = projectName ? `-p ${projectName}` : "";
106
+ execSync(
107
+ `docker compose ${projectArg} exec -T ${serviceName} pg_isready -U postgres`,
108
+ {
109
+ cwd: root,
110
+ stdio: ["pipe", "pipe", "pipe"],
111
+ },
112
+ );
113
+ return true;
114
+ } catch {
115
+ return false;
116
+ }
117
+ };
118
+ case "redis-cli":
119
+ return async () => {
120
+ try {
121
+ const projectArg = projectName ? `-p ${projectName}` : "";
122
+ execSync(
123
+ `docker compose ${projectArg} exec -T ${serviceName} redis-cli ping`,
124
+ {
125
+ cwd: root,
126
+ stdio: ["pipe", "pipe", "pipe"],
127
+ },
128
+ );
129
+ return true;
130
+ } catch {
131
+ return false;
132
+ }
133
+ };
134
+ case "http":
135
+ return async (port) => {
136
+ try {
137
+ const controller = new AbortController();
138
+ const timeoutId = setTimeout(() => controller.abort(), 2000);
139
+ try {
140
+ const response = await fetch(`http://localhost:${port}/`, {
141
+ signal: controller.signal,
142
+ });
143
+ clearTimeout(timeoutId);
144
+ return response.ok || response.status === 404;
145
+ } catch {
146
+ clearTimeout(timeoutId);
147
+ return false;
148
+ }
149
+ } catch {
150
+ return false;
151
+ }
152
+ };
153
+ case "tcp":
154
+ return async (port) => {
155
+ try {
156
+ const controller = new AbortController();
157
+ const timeoutId = setTimeout(() => controller.abort(), 1000);
158
+ try {
159
+ await fetch(`http://localhost:${port}/`, {
160
+ signal: controller.signal,
161
+ });
162
+ clearTimeout(timeoutId);
163
+ return true;
164
+ } catch (error) {
165
+ clearTimeout(timeoutId);
166
+ if (
167
+ error instanceof Error &&
168
+ error.message.includes("ECONNREFUSED")
169
+ ) {
170
+ return false;
171
+ }
172
+ return true;
173
+ }
174
+ } catch {
175
+ return false;
176
+ }
177
+ };
178
+ default:
179
+ return async () => true;
180
+ }
181
+ }
182
+ async function waitForService(serviceName, config, port, options = {}) {
183
+ const {
184
+ maxAttempts = MAX_ATTEMPTS,
185
+ pollInterval = POLL_INTERVAL,
186
+ projectName,
187
+ root,
188
+ } = options;
189
+ if (config.healthCheck === false || config.healthCheck === undefined) {
190
+ return;
191
+ }
192
+ const healthCheckFn =
193
+ typeof config.healthCheck === "function"
194
+ ? config.healthCheck
195
+ : createBuiltInHealthCheck(
196
+ config.healthCheck,
197
+ config.serviceName ?? serviceName,
198
+ { projectName, root },
199
+ );
200
+ for (let i = 0; i < maxAttempts; i++) {
201
+ const isHealthy = await healthCheckFn(port);
202
+ if (isHealthy) return;
203
+ await sleep(pollInterval);
204
+ }
205
+ throw new Error(`Service ${serviceName} did not become ready in time`);
206
+ }
207
+ async function waitForAllServices(services, ports, options = {}) {
208
+ const { verbose = true, ...waitOptions } = options;
209
+ if (verbose) console.log("⏳ Waiting for services to be healthy...");
210
+ const promises = Object.entries(services).map(([name, config]) => {
211
+ const port = ports[name];
212
+ if (port === undefined) {
213
+ console.warn(
214
+ `⚠️ No port found for service ${name}, skipping health check`,
215
+ );
216
+ return Promise.resolve();
217
+ }
218
+ return waitForService(name, config, port, waitOptions);
219
+ });
220
+ await Promise.all(promises);
221
+ if (verbose) console.log("✓ All services healthy");
222
+ }
223
+ async function waitForServiceByType(
224
+ serviceName,
225
+ healthCheckType,
226
+ port,
227
+ options = {},
228
+ ) {
229
+ const {
230
+ maxAttempts = MAX_ATTEMPTS,
231
+ pollInterval = POLL_INTERVAL,
232
+ verbose = false,
233
+ projectName,
234
+ root,
235
+ } = options;
236
+ const healthCheckFn = createBuiltInHealthCheck(healthCheckType, serviceName, {
237
+ projectName,
238
+ root,
239
+ });
240
+ for (let i = 0; i < maxAttempts; i++) {
241
+ const isHealthy = await healthCheckFn(port);
242
+ if (isHealthy) {
243
+ if (verbose) console.log(`✓ ${serviceName} is ready`);
244
+ return;
245
+ }
246
+ await sleep(pollInterval);
247
+ }
248
+ throw new Error(`Service ${serviceName} did not become ready in time`);
249
+ }
250
+
251
+ export {
252
+ POLL_INTERVAL,
253
+ MAX_ATTEMPTS,
254
+ DOCKER_NOT_RUNNING_MESSAGE,
255
+ isContainerRunning,
256
+ isDockerRunning,
257
+ assertDockerRunning,
258
+ areContainersRunning,
259
+ startContainers,
260
+ stopContainers,
261
+ startService,
262
+ createBuiltInHealthCheck,
263
+ waitForService,
264
+ waitForAllServices,
265
+ waitForServiceByType,
266
+ };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,16 @@
1
- export { getFlagValue, hasFlag, runCli } from "./cli";
2
- export { assertValidConfig, defineDevConfig, mergeConfigs, validateConfig, } from "./config";
3
- export { createDevEnvironment } from "./environment";
4
- export { runWorkspaceTypecheck, type TypecheckResult, type WorkspaceTypecheckOptions, type WorkspaceTypecheckResult, } from "./lint";
5
- export { clearDevEnvCache, getDevEnv, loadDevEnv } from "./loader";
6
- export type { AppConfig, BuiltInHealthCheck, CliOptions, ComputedPorts, ComputedUrls, DevConfig, DevEnvironment, DevHooks, DevOptions, DevServerPids, EnvVarsBuilder, ExecOptions, HealthCheckFn, HookContext, MigrationConfig, PrismaConfig, PrismaRunner, SeedCheckContext, SeedCheckHelpers, SeedConfig, ServiceConfig, StartOptions, StopOptions, UrlBuilderContext, UrlBuilderFn, } from "./types";
7
- export { areContainersRunning, isContainerRunning, MAX_ATTEMPTS, POLL_INTERVAL, } from "./core/docker";
1
+ export { getFlagValue, hasFlag, runCli } from "./cli/run-cli";
2
+ export { assertValidConfig, defineDevConfig, mergeConfigs, validateConfig, } from "./config/index";
3
+ export type { ClickhouseServiceOptions, CustomServiceOptions, PostgresServiceOptions, RedisServiceOptions, } from "./docker-compose/services";
4
+ export { service } from "./docker-compose/services";
5
+ export { createDevEnvironment } from "./environment/index";
6
+ export { clearDevEnvCache, getDevEnv, loadDevEnv } from "./loader/index";
7
+ export { runWorkspaceTypecheck, type TypecheckResult, type WorkspaceTypecheckOptions, type WorkspaceTypecheckResult, } from "./typecheck/index";
8
+ export type { AppConfig, BuiltInHealthCheck, CliOptions, ComputedPorts, ComputedPublicUrls, ComputedUrls, DevConfig, DevEnvironment, DevHooks, DevOptions, DevServerPids, DockerComposeGenerationOptions, DockerComposeHealthcheckRaw, DockerComposeNode, DockerComposeServiceRaw, DockerComposeVolumeRaw, DockerPresetName, DockerPresetServiceDefinition, DockerServiceDefinition, EnvVarsBuilder, ExecOptions, HealthCheckFn, HookContext, MigrationConfig, PrismaConfig, PrismaRunner, SeedCheckContext, SeedCheckHelpers, SeedConfig, ServiceConfig, StartOptions, StopOptions, UrlBuilderContext, UrlBuilderFn, } from "./types/index";
8
9
  export { getLocalIp, isPortAvailable, waitForServer } from "./core/network";
9
- export { calculatePortOffset, findMonorepoRoot, getProjectName, getWorktreeName, isWorktree, } from "./core/ports";
10
+ export { calculatePortOffset, computeDevIdentity, findMonorepoRoot, getProjectName, getWorktreeName, getWorktreeProjectSuffix, isWorktree, } from "./core/ports";
10
11
  export { getProcessOnPort, isPortInUse, isProcessAlive, killProcessesOnAppPorts, killProcessOnPort, killProcessOnPortAndWait, } from "./core/process";
12
+ export { type PublicExposeTarget, type PublicTunnel, resolveExposeTargets, startPublicTunnels, stopPublicTunnels, } from "./core/tunnel";
11
13
  export { getEnvVar, isCI, logApiUrl, logExpoApiUrl, logFrontendPort, sleep, } from "./core/utils";
12
14
  export { getHeartbeatFile, getWatchdogPidFile, isWatchdogRunning, spawnWatchdog, startHeartbeat, stopHeartbeat, stopWatchdog, } from "./core/watchdog";
15
+ export { areContainersRunning, assertDockerRunning, DOCKER_NOT_RUNNING_MESSAGE, isContainerRunning, isDockerRunning, MAX_ATTEMPTS, POLL_INTERVAL, } from "./docker/index";
16
+ export { buildComposeModel, composeToYaml, DEFAULT_GENERATED_COMPOSE_FILE, getGeneratedComposePath, writeGeneratedComposeFile, } from "./docker-compose/index";