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,475 @@
1
+ import {
2
+ areContainersRunning,
3
+ isContainerRunning,
4
+ startContainers,
5
+ startService,
6
+ stopContainers,
7
+ waitForServiceByType
8
+ } from "./index-2ckr49sf.js";
9
+ import {
10
+ getLocalIp,
11
+ isCI,
12
+ logExpoApiUrl,
13
+ logFrontendPort,
14
+ waitForDevServers,
15
+ waitForServer
16
+ } from "./index-thdkwnv7.js";
17
+ import {
18
+ computeDevIdentity,
19
+ computePorts,
20
+ computeUrls,
21
+ findMonorepoRoot
22
+ } from "./index-fb29934k.js";
23
+ import {
24
+ getGeneratedComposePath,
25
+ writeGeneratedComposeFile
26
+ } from "./index-5t9jxqm0.js";
27
+ import {
28
+ logEnvironmentInfo
29
+ } from "./index-bnk6nr0g.js";
30
+ import {
31
+ spawnWatchdog,
32
+ startHeartbeat,
33
+ stopHeartbeat,
34
+ stopWatchdog
35
+ } from "./index-mam0bcyz.js";
36
+ import {
37
+ buildApps,
38
+ execAsync,
39
+ startDevServers,
40
+ stopProcess
41
+ } from "./index-mm412dkp.js";
42
+ import {
43
+ assertValidConfig
44
+ } from "./index-t0fj6gg1.js";
45
+
46
+ // src/prisma/prisma.ts
47
+ import { spawn } from "node:child_process";
48
+ import { join } from "node:path";
49
+ function createPrismaRunner(env, config) {
50
+ const {
51
+ cwd = "packages/prisma",
52
+ service = "postgres",
53
+ urlEnvVar = "DATABASE_URL"
54
+ } = config;
55
+ const healthCheckTypes = {
56
+ postgres: "pg_isready",
57
+ redis: "redis-cli",
58
+ clickhouse: "http"
59
+ };
60
+ function getDatabaseUrl() {
61
+ const envVars = env.buildEnvVars();
62
+ const url = envVars[urlEnvVar];
63
+ if (!url) {
64
+ throw new Error(`Environment variable ${urlEnvVar} not found. Make sure your dev config defines it in envVars.`);
65
+ }
66
+ return url;
67
+ }
68
+ async function ensureDatabase() {
69
+ const alreadyRunning = await isContainerRunning(env.projectName, service);
70
+ if (alreadyRunning) {
71
+ console.log(`✓ ${service} already running`);
72
+ return;
73
+ }
74
+ console.log(`\uD83D\uDC33 Starting ${service}...`);
75
+ const composeFile = env.ensureComposeFile();
76
+ const envVars = env.buildEnvVars();
77
+ startService(env.root, env.projectName, service, envVars, {
78
+ verbose: false,
79
+ composeFile
80
+ });
81
+ const port = env.ports[service];
82
+ if (!port) {
83
+ throw new Error(`Service ${service} not found in dev environment ports`);
84
+ }
85
+ const healthCheckType = healthCheckTypes[service] ?? "tcp";
86
+ console.log(`⏳ Waiting for ${service} to be healthy...`);
87
+ await waitForServiceByType(service, healthCheckType, port, {
88
+ verbose: true
89
+ });
90
+ }
91
+ async function run(args) {
92
+ if (args.length === 0) {
93
+ console.log(`
94
+ Usage: bun prisma <command> [args...]
95
+
96
+ Examples:
97
+ bun prisma migrate dev # Create new migration
98
+ bun prisma migrate deploy # Apply migrations
99
+ bun prisma db push # Push schema changes
100
+ bun prisma studio # Open Prisma Studio
101
+ bun prisma migrate reset # Reset database
102
+ `);
103
+ return 0;
104
+ }
105
+ const port = env.ports[service];
106
+ console.log(`
107
+ \uD83D\uDD27 Prisma CLI
108
+ Project: ${env.projectName}
109
+ Database: localhost:${port}
110
+ ${env.portOffset > 0 ? `(port offset +${env.portOffset})` : ""}
111
+ `);
112
+ await ensureDatabase();
113
+ const envVars = env.buildEnvVars();
114
+ const workingDir = join(env.root, cwd);
115
+ const fullEnv = {
116
+ ...process.env,
117
+ ...envVars,
118
+ [urlEnvVar]: getDatabaseUrl()
119
+ };
120
+ console.log(`\uD83D\uDD04 Running: prisma ${args.join(" ")}
121
+ `);
122
+ return new Promise((resolve) => {
123
+ const proc = spawn("bunx", ["prisma", ...args], {
124
+ cwd: workingDir,
125
+ env: fullEnv,
126
+ stdio: "inherit"
127
+ });
128
+ proc.on("close", (code) => {
129
+ resolve(code ?? 0);
130
+ });
131
+ proc.on("error", () => {
132
+ resolve(1);
133
+ });
134
+ });
135
+ }
136
+ return { run, getDatabaseUrl, ensureDatabase };
137
+ }
138
+ // src/environment/seeding.ts
139
+ function createCheckTableHelper(urls, exec) {
140
+ return async (tableName, service) => {
141
+ const serviceName = service ?? "postgres";
142
+ const serviceUrl = urls[serviceName];
143
+ if (!serviceUrl) {
144
+ console.warn(`⚠️ Service "${serviceName}" not found for checkTable`);
145
+ return true;
146
+ }
147
+ const checkResult = await exec(`psql "${serviceUrl}" -tAc 'SELECT COUNT(*) FROM "${tableName}" LIMIT 1'`, { throwOnError: false });
148
+ const count = checkResult.stdout.trim();
149
+ const shouldSeed = checkResult.exitCode !== 0 || count === "0" || count === "";
150
+ if (!shouldSeed) {
151
+ console.log(` \uD83D\uDCCA Table "${tableName}" has ${count} rows`);
152
+ }
153
+ return shouldSeed;
154
+ };
155
+ }
156
+ function createSeedCheckContext(baseContext, checkTable) {
157
+ return {
158
+ ...baseContext,
159
+ checkTable
160
+ };
161
+ }
162
+
163
+ // src/environment/create-dev-environment.ts
164
+ function createDevEnvironment(config, options = {}) {
165
+ assertValidConfig(config);
166
+ const root = findMonorepoRoot();
167
+ const suffix = options.suffix;
168
+ const identity = computeDevIdentity({
169
+ projectPrefix: config.projectPrefix,
170
+ suffix,
171
+ root,
172
+ worktreeIsolation: config.options?.worktreeIsolation
173
+ });
174
+ const { worktree, projectSuffix, portOffset, projectName } = identity;
175
+ const localIp = getLocalIp();
176
+ const services = config.services;
177
+ const apps = config.apps ?? {};
178
+ const composeFile = getGeneratedComposePath(root, config.docker).composeFileArg;
179
+ function ensureComposeFile() {
180
+ return writeGeneratedComposeFile(root, services, config.docker);
181
+ }
182
+ const ports = computePorts(services, apps, portOffset);
183
+ const urls = computeUrls(services, apps, ports, localIp);
184
+ function buildEnvVars(production = false) {
185
+ const baseEnv = {
186
+ COMPOSE_PROJECT_NAME: projectName,
187
+ NODE_ENV: production ? "production" : "development"
188
+ };
189
+ for (const [name, port] of Object.entries(ports)) {
190
+ const envName = `${name.toUpperCase()}_PORT`;
191
+ baseEnv[envName] = String(port);
192
+ }
193
+ for (const [name, url] of Object.entries(urls)) {
194
+ const envName = `${name.toUpperCase()}_URL`;
195
+ baseEnv[envName] = url;
196
+ }
197
+ if (config.envVars) {
198
+ const userEnv = config.envVars(ports, urls, {
199
+ projectName,
200
+ localIp,
201
+ portOffset
202
+ });
203
+ for (const [key, value] of Object.entries(userEnv)) {
204
+ baseEnv[key] = String(value);
205
+ }
206
+ }
207
+ return baseEnv;
208
+ }
209
+ let hookContext = null;
210
+ function getHookContext() {
211
+ if (!hookContext) {
212
+ hookContext = {
213
+ projectName,
214
+ ports,
215
+ urls,
216
+ root,
217
+ isCI: isCI(),
218
+ portOffset,
219
+ localIp,
220
+ exec: async (cmd, opts) => {
221
+ const envVars = buildEnvVars();
222
+ return execAsync(cmd, root, envVars, opts);
223
+ }
224
+ };
225
+ }
226
+ return hookContext;
227
+ }
228
+ function exec(cmd, options2) {
229
+ const envVars = buildEnvVars();
230
+ return execAsync(cmd, root, envVars, options2);
231
+ }
232
+ async function start(startOptions = {}) {
233
+ const isCI2 = process.env.CI === "true";
234
+ const {
235
+ verbose = config.options?.verbose ?? true,
236
+ wait = true,
237
+ startServers: shouldStartServers = true,
238
+ productionBuild = isCI2,
239
+ skipSeed = false
240
+ } = startOptions;
241
+ const envVars = buildEnvVars(productionBuild);
242
+ ensureComposeFile();
243
+ if (verbose) {
244
+ logInfo(productionBuild ? "Production Environment" : "Dev Environment");
245
+ }
246
+ const serviceCount = Object.keys(services).length;
247
+ const alreadyRunning = await areContainersRunning(projectName, serviceCount);
248
+ if (alreadyRunning) {
249
+ if (verbose)
250
+ console.log("✓ Containers already running");
251
+ } else {
252
+ startContainers(root, projectName, envVars, {
253
+ verbose,
254
+ wait,
255
+ composeFile
256
+ });
257
+ }
258
+ const allMigrations = [
259
+ ...config.prisma ? [
260
+ {
261
+ name: "prisma",
262
+ command: "bunx prisma migrate deploy",
263
+ cwd: config.prisma.cwd ?? "packages/prisma"
264
+ }
265
+ ] : [],
266
+ ...config.migrations ?? []
267
+ ];
268
+ if (allMigrations.length > 0) {
269
+ if (verbose)
270
+ console.log("\uD83D\uDCE6 Running migrations...");
271
+ const migrationResults = await Promise.all(allMigrations.map(async (migration) => {
272
+ const result = await exec(migration.command, {
273
+ cwd: migration.cwd,
274
+ throwOnError: false
275
+ });
276
+ return { name: migration.name, result };
277
+ }));
278
+ for (const { name, result } of migrationResults) {
279
+ if (result.exitCode !== 0) {
280
+ console.error(`❌ Migration "${name}" failed`);
281
+ if (result.stdout) {
282
+ console.error(result.stdout);
283
+ }
284
+ if (result.stderr) {
285
+ console.error(result.stderr);
286
+ }
287
+ throw new Error(`Migration "${name}" failed`);
288
+ }
289
+ }
290
+ if (verbose)
291
+ console.log("✓ Migrations complete");
292
+ }
293
+ if (config.hooks?.afterContainersReady) {
294
+ await config.hooks.afterContainersReady(getHookContext());
295
+ }
296
+ if (config.seed && !skipSeed) {
297
+ let shouldSeed = true;
298
+ if (config.seed.check) {
299
+ const checkTable = createCheckTableHelper(urls, exec);
300
+ const seedCheckContext = createSeedCheckContext(getHookContext(), checkTable);
301
+ shouldSeed = await config.seed.check(seedCheckContext);
302
+ }
303
+ if (shouldSeed) {
304
+ if (verbose)
305
+ console.log("\uD83C\uDF31 Running seeders...");
306
+ const seedResult = await exec(config.seed.command, {
307
+ cwd: config.seed.cwd,
308
+ verbose,
309
+ throwOnError: false
310
+ });
311
+ if (seedResult.exitCode !== 0) {
312
+ console.error("❌ Seeding failed");
313
+ console.error(seedResult.stderr);
314
+ } else {
315
+ if (verbose)
316
+ console.log("✓ Seeding complete");
317
+ }
318
+ } else {
319
+ if (verbose)
320
+ console.log("✓ Database already has data, skipping seeders");
321
+ }
322
+ }
323
+ if (shouldStartServers && Object.keys(apps).length > 0) {
324
+ if (config.hooks?.beforeServers) {
325
+ await config.hooks.beforeServers(getHookContext());
326
+ }
327
+ if (productionBuild) {
328
+ buildApps(apps, root, envVars, { verbose });
329
+ }
330
+ const pids = await startDevServers(apps, root, envVars, ports, {
331
+ verbose,
332
+ productionBuild,
333
+ isCI: isCI2
334
+ });
335
+ if (verbose)
336
+ console.log("⏳ Waiting for servers to be ready...");
337
+ await waitForDevServers(apps, ports, {
338
+ timeout: isCI2 ? 120000 : 60000,
339
+ verbose,
340
+ productionBuild
341
+ });
342
+ if (config.hooks?.afterServers) {
343
+ await config.hooks.afterServers(getHookContext());
344
+ }
345
+ if (verbose)
346
+ console.log(`✅ Environment ready
347
+ `);
348
+ return pids;
349
+ }
350
+ if (verbose)
351
+ console.log(`✅ Containers ready
352
+ `);
353
+ return null;
354
+ }
355
+ async function stop(stopOptions = {}) {
356
+ const { verbose = true, removeVolumes = false } = stopOptions;
357
+ ensureComposeFile();
358
+ if (config.hooks?.beforeStop) {
359
+ await config.hooks.beforeStop(getHookContext());
360
+ }
361
+ stopContainers(root, projectName, {
362
+ verbose,
363
+ removeVolumes,
364
+ composeFile
365
+ });
366
+ }
367
+ async function restart() {
368
+ await stop();
369
+ await start({ startServers: false });
370
+ }
371
+ async function isRunning() {
372
+ const serviceCount = Object.keys(services).length;
373
+ return areContainersRunning(projectName, serviceCount);
374
+ }
375
+ async function startServersOnly(options2 = {}) {
376
+ const { productionBuild = false, verbose = true } = options2;
377
+ const envVars = buildEnvVars(productionBuild);
378
+ const isCI2 = process.env.CI === "true";
379
+ if (productionBuild) {
380
+ buildApps(apps, root, envVars, { verbose });
381
+ }
382
+ return startDevServers(apps, root, envVars, ports, {
383
+ verbose,
384
+ productionBuild,
385
+ isCI: isCI2
386
+ });
387
+ }
388
+ async function waitForServersReady(options2 = {}) {
389
+ const { timeout = 60000, productionBuild = false } = options2;
390
+ await waitForDevServers(apps, ports, { timeout, productionBuild });
391
+ }
392
+ function logInfo(label = "Docker Dev") {
393
+ logEnvironmentInfo({
394
+ label,
395
+ projectName,
396
+ services,
397
+ apps,
398
+ ports,
399
+ localIp,
400
+ worktree,
401
+ portOffset,
402
+ projectSuffix
403
+ });
404
+ }
405
+ async function waitForServerUrl(url, timeout) {
406
+ await waitForServer(url, { timeout });
407
+ }
408
+ function startHeartbeat2(intervalMs) {
409
+ startHeartbeat(projectName, intervalMs);
410
+ }
411
+ function stopHeartbeat2() {
412
+ stopHeartbeat();
413
+ }
414
+ async function spawnWatchdog2(timeoutMinutes) {
415
+ await spawnWatchdog(projectName, root, {
416
+ timeoutMinutes,
417
+ verbose: true,
418
+ composeFile
419
+ });
420
+ }
421
+ function stopWatchdog2() {
422
+ stopWatchdog(projectName);
423
+ }
424
+ function getExpoApiUrl() {
425
+ const apiPort = ports.api;
426
+ const url = `http://${localIp}:${apiPort}`;
427
+ logExpoApiUrl(url);
428
+ return url;
429
+ }
430
+ function getFrontendPort() {
431
+ const port = ports.platform;
432
+ logFrontendPort(port);
433
+ return port;
434
+ }
435
+ function withSuffix(newSuffix) {
436
+ return createDevEnvironment(config, { suffix: newSuffix });
437
+ }
438
+ const env = {
439
+ projectName,
440
+ ports,
441
+ urls,
442
+ services,
443
+ apps,
444
+ portOffset,
445
+ isWorktree: worktree,
446
+ localIp,
447
+ root,
448
+ composeFile,
449
+ start,
450
+ stop,
451
+ restart,
452
+ isRunning,
453
+ startServers: startServersOnly,
454
+ stopProcess,
455
+ waitForServers: waitForServersReady,
456
+ buildEnvVars,
457
+ ensureComposeFile,
458
+ exec,
459
+ waitForServer: waitForServerUrl,
460
+ logInfo,
461
+ getExpoApiUrl,
462
+ getFrontendPort,
463
+ startHeartbeat: startHeartbeat2,
464
+ stopHeartbeat: stopHeartbeat2,
465
+ spawnWatchdog: spawnWatchdog2,
466
+ stopWatchdog: stopWatchdog2,
467
+ prisma: undefined,
468
+ withSuffix
469
+ };
470
+ if (config.prisma) {
471
+ env.prisma = createPrismaRunner(env, config.prisma);
472
+ }
473
+ return env;
474
+ }
475
+ export { createDevEnvironment };
@@ -0,0 +1,228 @@
1
+ import {
2
+ sleep
3
+ } from "./index-thdkwnv7.js";
4
+
5
+ // src/docker/runtime.ts
6
+ import { execSync } from "node:child_process";
7
+ var POLL_INTERVAL = 250;
8
+ var MAX_ATTEMPTS = 120;
9
+ var DOCKER_NOT_RUNNING_MESSAGE = "Docker is not running. Please start Docker and try again.";
10
+ async function isContainerRunning(project, service) {
11
+ try {
12
+ const result = execSync(`docker ps --filter "label=com.docker.compose.project=${project}" --filter "label=com.docker.compose.service=${service}" --format "{{.State}}"`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
13
+ return result.trim() === "running";
14
+ } catch {
15
+ return false;
16
+ }
17
+ }
18
+ function isDockerRunning() {
19
+ try {
20
+ execSync('docker info --format "{{.ServerVersion}}"', {
21
+ encoding: "utf-8",
22
+ stdio: ["pipe", "pipe", "pipe"]
23
+ });
24
+ return true;
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+ function assertDockerRunning() {
30
+ if (!isDockerRunning()) {
31
+ throw new Error(DOCKER_NOT_RUNNING_MESSAGE);
32
+ }
33
+ }
34
+ async function areContainersRunning(project, minCount = 1) {
35
+ try {
36
+ const result = execSync(`docker ps --filter "label=com.docker.compose.project=${project}" --format "{{.State}}"`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
37
+ const states = result.trim().split(`
38
+ `).filter(Boolean);
39
+ if (states.length < minCount)
40
+ return false;
41
+ return states.every((state) => state === "running");
42
+ } catch {
43
+ return false;
44
+ }
45
+ }
46
+ function getComposeArg(composeFile) {
47
+ return composeFile ? `-f "${composeFile}"` : "";
48
+ }
49
+ function startContainers(root, projectName, envVars, options = {}) {
50
+ const { verbose = true, wait = true, composeFile } = options;
51
+ assertDockerRunning();
52
+ if (verbose)
53
+ console.log("\uD83D\uDC33 Starting Docker containers...");
54
+ const composeArg = getComposeArg(composeFile);
55
+ const waitFlag = wait ? "--wait" : "";
56
+ const cmd = `docker compose ${composeArg} up -d ${waitFlag}`.trim();
57
+ execSync(cmd, {
58
+ cwd: root,
59
+ env: { ...process.env, ...envVars, COMPOSE_PROJECT_NAME: projectName },
60
+ stdio: verbose ? "inherit" : "ignore"
61
+ });
62
+ if (verbose)
63
+ console.log("✓ Containers started");
64
+ }
65
+ function stopContainers(root, projectName, options = {}) {
66
+ const { verbose = true, removeVolumes = false, composeFile } = options;
67
+ assertDockerRunning();
68
+ if (verbose) {
69
+ console.log(removeVolumes ? "\uD83D\uDDD1️ Stopping containers and removing volumes..." : "\uD83D\uDED1 Stopping containers...");
70
+ }
71
+ const composeArg = getComposeArg(composeFile);
72
+ const volumeFlag = removeVolumes ? "-v" : "";
73
+ const cmd = `docker compose ${composeArg} down ${volumeFlag}`.trim();
74
+ execSync(cmd, {
75
+ cwd: root,
76
+ env: { ...process.env, COMPOSE_PROJECT_NAME: projectName },
77
+ stdio: verbose ? "inherit" : "ignore"
78
+ });
79
+ if (verbose)
80
+ console.log("✓ Containers stopped");
81
+ }
82
+ function startService(root, projectName, serviceName, envVars, options = {}) {
83
+ const { verbose = true, composeFile } = options;
84
+ assertDockerRunning();
85
+ if (verbose)
86
+ console.log(`\uD83D\uDC33 Starting ${serviceName}...`);
87
+ const composeArg = getComposeArg(composeFile);
88
+ const cmd = `docker compose ${composeArg} up -d ${serviceName}`.trim();
89
+ execSync(cmd, {
90
+ cwd: root,
91
+ env: { ...process.env, ...envVars, COMPOSE_PROJECT_NAME: projectName },
92
+ stdio: verbose ? "inherit" : "ignore"
93
+ });
94
+ }
95
+ function createBuiltInHealthCheck(type, serviceName, context = {}) {
96
+ const { projectName, root } = context;
97
+ switch (type) {
98
+ case "pg_isready":
99
+ return async () => {
100
+ try {
101
+ const projectArg = projectName ? `-p ${projectName}` : "";
102
+ execSync(`docker compose ${projectArg} exec -T ${serviceName} pg_isready -U postgres`, {
103
+ cwd: root,
104
+ stdio: ["pipe", "pipe", "pipe"]
105
+ });
106
+ return true;
107
+ } catch {
108
+ return false;
109
+ }
110
+ };
111
+ case "redis-cli":
112
+ return async () => {
113
+ try {
114
+ const projectArg = projectName ? `-p ${projectName}` : "";
115
+ execSync(`docker compose ${projectArg} exec -T ${serviceName} redis-cli ping`, {
116
+ cwd: root,
117
+ stdio: ["pipe", "pipe", "pipe"]
118
+ });
119
+ return true;
120
+ } catch {
121
+ return false;
122
+ }
123
+ };
124
+ case "http":
125
+ return async (port) => {
126
+ try {
127
+ const controller = new AbortController;
128
+ const timeoutId = setTimeout(() => controller.abort(), 2000);
129
+ try {
130
+ const response = await fetch(`http://localhost:${port}/`, {
131
+ signal: controller.signal
132
+ });
133
+ clearTimeout(timeoutId);
134
+ return response.ok || response.status === 404;
135
+ } catch {
136
+ clearTimeout(timeoutId);
137
+ return false;
138
+ }
139
+ } catch {
140
+ return false;
141
+ }
142
+ };
143
+ case "tcp":
144
+ return async (port) => {
145
+ try {
146
+ const controller = new AbortController;
147
+ const timeoutId = setTimeout(() => controller.abort(), 1000);
148
+ try {
149
+ await fetch(`http://localhost:${port}/`, {
150
+ signal: controller.signal
151
+ });
152
+ clearTimeout(timeoutId);
153
+ return true;
154
+ } catch (error) {
155
+ clearTimeout(timeoutId);
156
+ if (error instanceof Error && error.message.includes("ECONNREFUSED")) {
157
+ return false;
158
+ }
159
+ return true;
160
+ }
161
+ } catch {
162
+ return false;
163
+ }
164
+ };
165
+ default:
166
+ return async () => true;
167
+ }
168
+ }
169
+ async function waitForService(serviceName, config, port, options = {}) {
170
+ const {
171
+ maxAttempts = MAX_ATTEMPTS,
172
+ pollInterval = POLL_INTERVAL,
173
+ projectName,
174
+ root
175
+ } = options;
176
+ if (config.healthCheck === false || config.healthCheck === undefined) {
177
+ return;
178
+ }
179
+ const healthCheckFn = typeof config.healthCheck === "function" ? config.healthCheck : createBuiltInHealthCheck(config.healthCheck, config.serviceName ?? serviceName, { projectName, root });
180
+ for (let i = 0;i < maxAttempts; i++) {
181
+ const isHealthy = await healthCheckFn(port);
182
+ if (isHealthy)
183
+ return;
184
+ await sleep(pollInterval);
185
+ }
186
+ throw new Error(`Service ${serviceName} did not become ready in time`);
187
+ }
188
+ async function waitForAllServices(services, ports, options = {}) {
189
+ const { verbose = true, ...waitOptions } = options;
190
+ if (verbose)
191
+ console.log("⏳ Waiting for services to be healthy...");
192
+ const promises = Object.entries(services).map(([name, config]) => {
193
+ const port = ports[name];
194
+ if (port === undefined) {
195
+ console.warn(`⚠️ No port found for service ${name}, skipping health check`);
196
+ return Promise.resolve();
197
+ }
198
+ return waitForService(name, config, port, waitOptions);
199
+ });
200
+ await Promise.all(promises);
201
+ if (verbose)
202
+ console.log("✓ All services healthy");
203
+ }
204
+ async function waitForServiceByType(serviceName, healthCheckType, port, options = {}) {
205
+ const {
206
+ maxAttempts = MAX_ATTEMPTS,
207
+ pollInterval = POLL_INTERVAL,
208
+ verbose = false,
209
+ projectName,
210
+ root
211
+ } = options;
212
+ const healthCheckFn = createBuiltInHealthCheck(healthCheckType, serviceName, {
213
+ projectName,
214
+ root
215
+ });
216
+ for (let i = 0;i < maxAttempts; i++) {
217
+ const isHealthy = await healthCheckFn(port);
218
+ if (isHealthy) {
219
+ if (verbose)
220
+ console.log(`✓ ${serviceName} is ready`);
221
+ return;
222
+ }
223
+ await sleep(pollInterval);
224
+ }
225
+ throw new Error(`Service ${serviceName} did not become ready in time`);
226
+ }
227
+
228
+ export { POLL_INTERVAL, MAX_ATTEMPTS, DOCKER_NOT_RUNNING_MESSAGE, isContainerRunning, isDockerRunning, assertDockerRunning, areContainersRunning, getComposeArg, startContainers, stopContainers, startService, createBuiltInHealthCheck, waitForService, waitForAllServices, waitForServiceByType };