buncargo 1.0.29 → 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 (221) hide show
  1. package/dist/bin.d.ts +1 -12
  2. package/dist/bin.js +261 -253
  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 -83
  22. package/dist/core/docker.js +35 -32
  23. package/dist/core/index.d.ts +1 -1
  24. package/dist/core/index.js +123 -118
  25. package/dist/core/network.js +2 -2
  26. package/dist/core/ports.js +1 -1
  27. package/dist/core/process.js +1 -1
  28. package/dist/core/tunnel.d.ts +33 -0
  29. package/dist/core/utils.js +2 -2
  30. package/dist/core/watchdog-runner.js +45 -42
  31. package/dist/core/watchdog.d.ts +1 -0
  32. package/dist/core/watchdog.js +4 -2
  33. package/dist/docker/index.d.ts +1 -0
  34. package/dist/docker/index.js +38 -0
  35. package/dist/docker/runtime.d.ts +87 -0
  36. package/dist/docker/runtime.js +37 -0
  37. package/dist/docker-compose/compose.d.ts +1 -0
  38. package/dist/docker-compose/generated-file.d.ts +7 -0
  39. package/dist/docker-compose/index.d.ts +3 -0
  40. package/dist/docker-compose/index.js +15 -0
  41. package/dist/docker-compose/model.d.ts +6 -0
  42. package/dist/docker-compose/services/clickhouse.d.ts +16 -0
  43. package/dist/docker-compose/services/define-docker-service.d.ts +41 -0
  44. package/dist/docker-compose/services/index.d.ts +23 -0
  45. package/dist/docker-compose/services/index.js +17 -0
  46. package/dist/docker-compose/services/postgres.d.ts +12 -0
  47. package/dist/docker-compose/services/redis.d.ts +12 -0
  48. package/dist/docker-compose/services/shared.d.ts +7 -0
  49. package/dist/docker-compose/yaml.d.ts +2 -0
  50. package/dist/environment/create-dev-environment.d.ts +23 -0
  51. package/dist/environment/index.d.ts +1 -0
  52. package/dist/environment/index.js +15 -0
  53. package/dist/environment/logging.d.ts +17 -0
  54. package/dist/environment/seeding.d.ts +9 -0
  55. package/dist/environment.d.ts +1 -23
  56. package/dist/environment.js +12 -14
  57. package/dist/index-045jksh5.js +147 -0
  58. package/dist/index-08wa79cs.js +125 -117
  59. package/dist/index-0kxnae3z.js +335 -0
  60. package/dist/index-1mdrf7nz.js +51 -43
  61. package/dist/index-1yvbwj4k.js +262 -242
  62. package/dist/index-23ev345g.js +475 -0
  63. package/dist/index-2ckr49sf.js +228 -0
  64. package/dist/index-2f47khe5.js +376 -369
  65. package/dist/index-2fr3g85b.js +220 -183
  66. package/dist/index-38xnzpa6.js +450 -0
  67. package/dist/index-3h3dhtf2.js +51 -43
  68. package/dist/index-42x95209.js +51 -43
  69. package/dist/index-4gp0az1g.js +145 -0
  70. package/dist/index-4xrxh8yv.js +72 -0
  71. package/dist/index-5gmws6ah.js +181 -0
  72. package/dist/index-5hka0tff.js +78 -76
  73. package/dist/index-5rfqps4b.js +3 -0
  74. package/dist/index-5t9jxqm0.js +428 -0
  75. package/dist/index-6c1w1xk5.js +101 -0
  76. package/dist/index-6fm7mvwj.js +118 -97
  77. package/dist/index-6srpc523.js +127 -128
  78. package/dist/index-731rzzfp.js +157 -142
  79. package/dist/index-75y4cg2z.js +51 -43
  80. package/dist/index-7ja4ywyj.js +126 -127
  81. package/dist/index-8bw1cmz4.js +531 -0
  82. package/dist/index-8hbbj1mp.js +120 -121
  83. package/dist/index-8xj2p5n5.js +118 -97
  84. package/dist/index-bj79tw5w.js +0 -0
  85. package/dist/index-bnk6nr0g.js +73 -0
  86. package/dist/index-brbbzyks.js +72 -0
  87. package/dist/index-c0dr6mcv.js +123 -0
  88. package/dist/index-cty0bcry.js +235 -218
  89. package/dist/index-d8tyv5se.js +228 -0
  90. package/dist/index-d9efy0n4.js +176 -150
  91. package/dist/index-etfmqjjf.js +427 -0
  92. package/dist/index-fb29934k.js +172 -0
  93. package/dist/index-g50jw1yf.js +72 -0
  94. package/dist/index-g6eb5wdw.js +118 -117
  95. package/dist/index-ggq3yryx.js +99 -95
  96. package/dist/index-h70tce00.js +177 -0
  97. package/dist/index-hkxtfqtc.js +333 -0
  98. package/dist/index-kf3dhser.js +146 -143
  99. package/dist/index-ma6tgdb2.js +500 -0
  100. package/dist/index-mam0bcyz.js +123 -0
  101. package/dist/index-mm412dkp.js +274 -0
  102. package/dist/index-n8v18aeb.js +0 -0
  103. package/dist/index-ndnmnsej.js +378 -371
  104. package/dist/index-p8wty0e2.js +389 -379
  105. package/dist/index-qfphr2fd.js +78 -76
  106. package/dist/index-qqmms8rs.js +51 -43
  107. package/dist/index-qw4093g2.js +51 -43
  108. package/dist/index-qzwpzjbx.js +121 -122
  109. package/dist/index-segbnm0h.js +146 -143
  110. package/dist/index-t0fj6gg1.js +112 -0
  111. package/dist/index-thdkwnv7.js +122 -0
  112. package/dist/index-tjbx2r2t.js +270 -0
  113. package/dist/index-tjqw9vtj.js +62 -54
  114. package/dist/index-vbpb89jy.js +248 -0
  115. package/dist/index-vhs88xhe.js +99 -95
  116. package/dist/index-w8zxnjka.js +249 -0
  117. package/dist/index-wk2na3t9.js +385 -375
  118. package/dist/index-wz9x8g7z.js +383 -373
  119. package/dist/index-x249gyde.js +388 -378
  120. package/dist/index-xkvd0nsd.js +187 -0
  121. package/dist/index-yedqxm1z.js +80 -0
  122. package/dist/index-zfjzzjkf.js +240 -199
  123. package/dist/index.d.ts +12 -8
  124. package/dist/index.js +56 -35
  125. package/dist/lint.d.ts +1 -46
  126. package/dist/lint.js +3 -7
  127. package/dist/loader/cache.d.ts +4 -0
  128. package/dist/loader/find-config-file.d.ts +2 -0
  129. package/dist/loader/index.d.ts +5 -0
  130. package/dist/loader/index.js +24 -0
  131. package/dist/loader/load-dev-env.d.ts +5 -0
  132. package/dist/loader/loader.d.ts +1 -0
  133. package/dist/loader.d.ts +1 -45
  134. package/dist/loader.js +22 -20
  135. package/dist/prisma/index.d.ts +1 -0
  136. package/dist/prisma/prisma.d.ts +29 -0
  137. package/dist/prisma.d.ts +1 -29
  138. package/dist/prisma.js +6 -10
  139. package/dist/src/bin.js +309 -0
  140. package/dist/src/cli.js +5 -0
  141. package/dist/src/config.js +15 -0
  142. package/dist/src/core/docker.js +38 -0
  143. package/dist/src/core/index.js +130 -0
  144. package/dist/src/core/network.js +9 -0
  145. package/dist/src/core/ports.js +23 -0
  146. package/dist/src/core/process.js +31 -0
  147. package/dist/src/core/utils.js +11 -0
  148. package/dist/src/core/watchdog-runner.js +69 -0
  149. package/dist/src/core/watchdog.js +28 -0
  150. package/dist/src/docker/runtime.js +37 -0
  151. package/dist/src/docker-compose/index.js +16 -0
  152. package/dist/src/docker-compose/services/index.js +17 -0
  153. package/dist/src/environment.js +12 -0
  154. package/dist/src/index.js +122 -0
  155. package/dist/src/lint.js +3 -0
  156. package/dist/src/loader.js +25 -0
  157. package/dist/src/prisma.js +6 -0
  158. package/dist/src/types.js +0 -0
  159. package/dist/typecheck/index.d.ts +1 -0
  160. package/dist/typecheck/index.js +7 -0
  161. package/dist/typecheck/typecheck.d.ts +46 -0
  162. package/dist/types/all-types.d.ts +501 -0
  163. package/dist/types/cli.d.ts +1 -0
  164. package/dist/types/config.d.ts +6 -0
  165. package/dist/types/docker.d.ts +15 -0
  166. package/dist/types/environment.d.ts +8 -0
  167. package/dist/types/hooks.d.ts +9 -0
  168. package/dist/types/index.d.ts +1 -0
  169. package/dist/types/index.js +0 -0
  170. package/dist/types/prisma.d.ts +1 -0
  171. package/dist/types.d.ts +1 -399
  172. package/package.json +145 -140
  173. package/readme.md +349 -109
  174. package/src/cli/bin.ts +77 -0
  175. package/src/cli/commands/help.ts +39 -0
  176. package/src/cli/commands/runtime.ts +72 -0
  177. package/src/cli/commands/version.ts +4 -0
  178. package/src/cli/index.ts +1 -0
  179. package/{cli.ts → src/cli/run-cli.ts} +95 -6
  180. package/src/config/define-config.ts +30 -0
  181. package/src/config/index.ts +3 -0
  182. package/src/config/merge-configs.ts +33 -0
  183. package/src/config/validate-config.ts +136 -0
  184. package/{core → src/core}/index.ts +2 -2
  185. package/{core → src/core}/ports.ts +5 -2
  186. package/{core → src/core}/process.ts +6 -2
  187. package/src/core/tunnel.ts +151 -0
  188. package/{core → src/core}/utils.ts +1 -0
  189. package/{core → src/core}/watchdog.ts +5 -1
  190. package/src/docker/index.ts +1 -0
  191. package/{core/docker.ts → src/docker/runtime.ts} +11 -4
  192. package/src/docker-compose/generated-file.ts +45 -0
  193. package/src/docker-compose/index.ts +7 -0
  194. package/src/docker-compose/model.ts +197 -0
  195. package/src/docker-compose/services/clickhouse.ts +79 -0
  196. package/src/docker-compose/services/define-docker-service.ts +109 -0
  197. package/src/docker-compose/services/index.ts +67 -0
  198. package/src/docker-compose/services/postgres.ts +60 -0
  199. package/src/docker-compose/services/redis.ts +48 -0
  200. package/src/docker-compose/services/shared.ts +79 -0
  201. package/src/docker-compose/yaml.ts +88 -0
  202. package/{environment.ts → src/environment/create-dev-environment.ts} +93 -130
  203. package/src/environment/index.ts +1 -0
  204. package/src/environment/logging.ts +101 -0
  205. package/src/environment/seeding.ts +57 -0
  206. package/{index.ts → src/index.ts} +49 -20
  207. package/src/loader/cache.ts +23 -0
  208. package/src/loader/find-config-file.ts +29 -0
  209. package/src/loader/index.ts +17 -0
  210. package/src/loader/load-dev-env.ts +38 -0
  211. package/src/prisma/index.ts +1 -0
  212. package/{prisma.ts → src/prisma/prisma.ts} +4 -2
  213. package/src/typecheck/index.ts +1 -0
  214. package/{types.ts → src/types/all-types.ts} +130 -5
  215. package/src/types/index.ts +1 -0
  216. package/bin.ts +0 -192
  217. package/config.ts +0 -194
  218. package/loader.ts +0 -126
  219. /package/{core → src/core}/network.ts +0 -0
  220. /package/{core → src/core}/watchdog-runner.ts +0 -0
  221. /package/{lint.ts → src/typecheck/typecheck.ts} +0 -0
@@ -0,0 +1,500 @@
1
+ import {
2
+ areContainersRunning,
3
+ isContainerRunning,
4
+ startContainers,
5
+ startService,
6
+ stopContainers,
7
+ waitForServiceByType
8
+ } from "./index-d8tyv5se.js";
9
+ import {
10
+ getLocalIp,
11
+ isCI,
12
+ logExpoApiUrl,
13
+ logFrontendPort,
14
+ waitForDevServers,
15
+ waitForServer
16
+ } from "./index-c0dr6mcv.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
+ const publicUrls = {};
185
+ function setPublicUrls(urlsInput) {
186
+ for (const key of Object.keys(publicUrls)) {
187
+ delete publicUrls[key];
188
+ }
189
+ for (const [key, value] of Object.entries(urlsInput)) {
190
+ publicUrls[key] = value;
191
+ }
192
+ }
193
+ function clearPublicUrls() {
194
+ for (const key of Object.keys(publicUrls)) {
195
+ delete publicUrls[key];
196
+ }
197
+ }
198
+ function buildEnvVars(production = false) {
199
+ const baseEnv = {
200
+ COMPOSE_PROJECT_NAME: projectName,
201
+ NODE_ENV: production ? "production" : "development"
202
+ };
203
+ for (const [name, port] of Object.entries(ports)) {
204
+ const envName = `${name.toUpperCase()}_PORT`;
205
+ baseEnv[envName] = String(port);
206
+ }
207
+ for (const [name, url] of Object.entries(urls)) {
208
+ const envName = `${name.toUpperCase()}_URL`;
209
+ baseEnv[envName] = url;
210
+ }
211
+ for (const [name, url] of Object.entries(publicUrls)) {
212
+ const envName = `${name.toUpperCase()}_PUBLIC_URL`;
213
+ baseEnv[envName] = url;
214
+ }
215
+ if (config.envVars) {
216
+ const userEnv = config.envVars(ports, urls, {
217
+ projectName,
218
+ localIp,
219
+ portOffset,
220
+ publicUrls
221
+ });
222
+ for (const [key, value] of Object.entries(userEnv)) {
223
+ baseEnv[key] = String(value);
224
+ }
225
+ }
226
+ return baseEnv;
227
+ }
228
+ let hookContext = null;
229
+ function getHookContext() {
230
+ if (!hookContext) {
231
+ hookContext = {
232
+ projectName,
233
+ ports,
234
+ urls,
235
+ publicUrls,
236
+ root,
237
+ isCI: isCI(),
238
+ portOffset,
239
+ localIp,
240
+ exec: async (cmd, opts) => {
241
+ const envVars = buildEnvVars();
242
+ return execAsync(cmd, root, envVars, opts);
243
+ }
244
+ };
245
+ }
246
+ return hookContext;
247
+ }
248
+ function exec(cmd, options2) {
249
+ const envVars = buildEnvVars();
250
+ return execAsync(cmd, root, envVars, options2);
251
+ }
252
+ async function start(startOptions = {}) {
253
+ const isCI2 = process.env.CI === "true";
254
+ const {
255
+ verbose = config.options?.verbose ?? true,
256
+ wait = true,
257
+ startServers: shouldStartServers = true,
258
+ productionBuild = isCI2,
259
+ skipSeed = false
260
+ } = startOptions;
261
+ const envVars = buildEnvVars(productionBuild);
262
+ ensureComposeFile();
263
+ if (verbose) {
264
+ logInfo(productionBuild ? "Production Environment" : "Dev Environment");
265
+ }
266
+ const serviceCount = Object.keys(services).length;
267
+ const alreadyRunning = await areContainersRunning(projectName, serviceCount);
268
+ if (alreadyRunning) {
269
+ if (verbose)
270
+ console.log("✓ Containers already running");
271
+ } else {
272
+ startContainers(root, projectName, envVars, {
273
+ verbose,
274
+ wait,
275
+ composeFile
276
+ });
277
+ }
278
+ const allMigrations = [
279
+ ...config.prisma ? [
280
+ {
281
+ name: "prisma",
282
+ command: "bunx prisma migrate deploy",
283
+ cwd: config.prisma.cwd ?? "packages/prisma"
284
+ }
285
+ ] : [],
286
+ ...config.migrations ?? []
287
+ ];
288
+ if (allMigrations.length > 0) {
289
+ if (verbose)
290
+ console.log("\uD83D\uDCE6 Running migrations...");
291
+ const migrationResults = await Promise.all(allMigrations.map(async (migration) => {
292
+ const result = await exec(migration.command, {
293
+ cwd: migration.cwd,
294
+ throwOnError: false
295
+ });
296
+ return { name: migration.name, result };
297
+ }));
298
+ for (const { name, result } of migrationResults) {
299
+ if (result.exitCode !== 0) {
300
+ console.error(`❌ Migration "${name}" failed`);
301
+ if (result.stdout) {
302
+ console.error(result.stdout);
303
+ }
304
+ if (result.stderr) {
305
+ console.error(result.stderr);
306
+ }
307
+ throw new Error(`Migration "${name}" failed`);
308
+ }
309
+ }
310
+ if (verbose)
311
+ console.log("✓ Migrations complete");
312
+ }
313
+ if (config.hooks?.afterContainersReady) {
314
+ await config.hooks.afterContainersReady(getHookContext());
315
+ }
316
+ if (config.seed && !skipSeed) {
317
+ let shouldSeed = true;
318
+ if (config.seed.check) {
319
+ const checkTable = createCheckTableHelper(urls, exec);
320
+ const seedCheckContext = createSeedCheckContext(getHookContext(), checkTable);
321
+ shouldSeed = await config.seed.check(seedCheckContext);
322
+ }
323
+ if (shouldSeed) {
324
+ if (verbose)
325
+ console.log("\uD83C\uDF31 Running seeders...");
326
+ const seedResult = await exec(config.seed.command, {
327
+ cwd: config.seed.cwd,
328
+ verbose,
329
+ throwOnError: false
330
+ });
331
+ if (seedResult.exitCode !== 0) {
332
+ console.error("❌ Seeding failed");
333
+ console.error(seedResult.stderr);
334
+ } else {
335
+ if (verbose)
336
+ console.log("✓ Seeding complete");
337
+ }
338
+ } else {
339
+ if (verbose)
340
+ console.log("✓ Database already has data, skipping seeders");
341
+ }
342
+ }
343
+ if (shouldStartServers && Object.keys(apps).length > 0) {
344
+ if (config.hooks?.beforeServers) {
345
+ await config.hooks.beforeServers(getHookContext());
346
+ }
347
+ if (productionBuild) {
348
+ buildApps(apps, root, envVars, { verbose });
349
+ }
350
+ const pids = await startDevServers(apps, root, envVars, ports, {
351
+ verbose,
352
+ productionBuild,
353
+ isCI: isCI2
354
+ });
355
+ if (verbose)
356
+ console.log("⏳ Waiting for servers to be ready...");
357
+ await waitForDevServers(apps, ports, {
358
+ timeout: isCI2 ? 120000 : 60000,
359
+ verbose,
360
+ productionBuild
361
+ });
362
+ if (config.hooks?.afterServers) {
363
+ await config.hooks.afterServers(getHookContext());
364
+ }
365
+ if (verbose)
366
+ console.log(`✅ Environment ready
367
+ `);
368
+ return pids;
369
+ }
370
+ if (verbose)
371
+ console.log(`✅ Containers ready
372
+ `);
373
+ return null;
374
+ }
375
+ async function stop(stopOptions = {}) {
376
+ const { verbose = true, removeVolumes = false } = stopOptions;
377
+ ensureComposeFile();
378
+ if (config.hooks?.beforeStop) {
379
+ await config.hooks.beforeStop(getHookContext());
380
+ }
381
+ stopContainers(root, projectName, {
382
+ verbose,
383
+ removeVolumes,
384
+ composeFile
385
+ });
386
+ }
387
+ async function restart() {
388
+ await stop();
389
+ await start({ startServers: false });
390
+ }
391
+ async function isRunning() {
392
+ const serviceCount = Object.keys(services).length;
393
+ return areContainersRunning(projectName, serviceCount);
394
+ }
395
+ async function startServersOnly(options2 = {}) {
396
+ const { productionBuild = false, verbose = true } = options2;
397
+ const envVars = buildEnvVars(productionBuild);
398
+ const isCI2 = process.env.CI === "true";
399
+ if (productionBuild) {
400
+ buildApps(apps, root, envVars, { verbose });
401
+ }
402
+ return startDevServers(apps, root, envVars, ports, {
403
+ verbose,
404
+ productionBuild,
405
+ isCI: isCI2
406
+ });
407
+ }
408
+ async function waitForServersReady(options2 = {}) {
409
+ const { timeout = 60000, productionBuild = false } = options2;
410
+ await waitForDevServers(apps, ports, { timeout, productionBuild });
411
+ }
412
+ function logInfo(label = "Docker Dev") {
413
+ logEnvironmentInfo({
414
+ label,
415
+ projectName,
416
+ services,
417
+ apps,
418
+ ports,
419
+ localIp,
420
+ worktree,
421
+ portOffset,
422
+ projectSuffix
423
+ });
424
+ }
425
+ async function waitForServerUrl(url, timeout) {
426
+ await waitForServer(url, { timeout });
427
+ }
428
+ function startHeartbeat2(intervalMs) {
429
+ startHeartbeat(projectName, intervalMs);
430
+ }
431
+ function stopHeartbeat2() {
432
+ stopHeartbeat();
433
+ }
434
+ async function spawnWatchdog2(timeoutMinutes) {
435
+ await spawnWatchdog(projectName, root, {
436
+ timeoutMinutes,
437
+ verbose: true,
438
+ composeFile
439
+ });
440
+ }
441
+ function stopWatchdog2() {
442
+ stopWatchdog(projectName);
443
+ }
444
+ function getExpoApiUrl() {
445
+ const apiPort = ports.api;
446
+ const url = `http://${localIp}:${apiPort}`;
447
+ logExpoApiUrl(url);
448
+ return url;
449
+ }
450
+ function getFrontendPort() {
451
+ const port = ports.platform;
452
+ logFrontendPort(port);
453
+ return port;
454
+ }
455
+ function withSuffix(newSuffix) {
456
+ return createDevEnvironment(config, { suffix: newSuffix });
457
+ }
458
+ const env = {
459
+ projectName,
460
+ ports,
461
+ urls,
462
+ publicUrls,
463
+ services,
464
+ apps,
465
+ portOffset,
466
+ isWorktree: worktree,
467
+ localIp,
468
+ root,
469
+ composeFile,
470
+ start,
471
+ stop,
472
+ restart,
473
+ isRunning,
474
+ startServers: startServersOnly,
475
+ stopProcess,
476
+ waitForServers: waitForServersReady,
477
+ buildEnvVars,
478
+ setPublicUrls: (urlsInput) => {
479
+ setPublicUrls(urlsInput);
480
+ },
481
+ clearPublicUrls,
482
+ ensureComposeFile,
483
+ exec,
484
+ waitForServer: waitForServerUrl,
485
+ logInfo,
486
+ getExpoApiUrl,
487
+ getFrontendPort,
488
+ startHeartbeat: startHeartbeat2,
489
+ stopHeartbeat: stopHeartbeat2,
490
+ spawnWatchdog: spawnWatchdog2,
491
+ stopWatchdog: stopWatchdog2,
492
+ prisma: undefined,
493
+ withSuffix
494
+ };
495
+ if (config.prisma) {
496
+ env.prisma = createPrismaRunner(env, config.prisma);
497
+ }
498
+ return env;
499
+ }
500
+ export { createDevEnvironment };
@@ -0,0 +1,123 @@
1
+ import {
2
+ isProcessAlive
3
+ } from "./index-mm412dkp.js";
4
+
5
+ // src/core/watchdog.ts
6
+ import { spawn } from "node:child_process";
7
+ import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
8
+ function getHeartbeatFile(projectName) {
9
+ return `/tmp/${projectName}-heartbeat`;
10
+ }
11
+ function getWatchdogPidFile(projectName) {
12
+ return `/tmp/${projectName}-watchdog.pid`;
13
+ }
14
+ var heartbeatInterval = null;
15
+ function startHeartbeat(projectName, intervalMs = 30000) {
16
+ const heartbeatFile = getHeartbeatFile(projectName);
17
+ writeFileSync(heartbeatFile, Date.now().toString());
18
+ heartbeatInterval = setInterval(() => {
19
+ writeFileSync(heartbeatFile, Date.now().toString());
20
+ }, intervalMs);
21
+ }
22
+ function stopHeartbeat() {
23
+ if (heartbeatInterval) {
24
+ clearInterval(heartbeatInterval);
25
+ heartbeatInterval = null;
26
+ }
27
+ }
28
+ function readHeartbeat(projectName) {
29
+ const heartbeatFile = getHeartbeatFile(projectName);
30
+ try {
31
+ if (!existsSync(heartbeatFile))
32
+ return null;
33
+ const content = readFileSync(heartbeatFile, "utf-8");
34
+ const timestamp = parseInt(content, 10);
35
+ return Number.isNaN(timestamp) ? null : timestamp;
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+ function removeHeartbeatFile(projectName) {
41
+ const heartbeatFile = getHeartbeatFile(projectName);
42
+ try {
43
+ unlinkSync(heartbeatFile);
44
+ } catch {}
45
+ }
46
+ function isWatchdogRunning(projectName) {
47
+ const pidFile = getWatchdogPidFile(projectName);
48
+ try {
49
+ if (!existsSync(pidFile))
50
+ return false;
51
+ const content = readFileSync(pidFile, "utf-8");
52
+ const pid = parseInt(content, 10);
53
+ if (Number.isNaN(pid))
54
+ return false;
55
+ return isProcessAlive(pid);
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
60
+ function getWatchdogPid(projectName) {
61
+ const pidFile = getWatchdogPidFile(projectName);
62
+ try {
63
+ if (!existsSync(pidFile))
64
+ return null;
65
+ const content = readFileSync(pidFile, "utf-8");
66
+ const pid = parseInt(content, 10);
67
+ if (Number.isNaN(pid))
68
+ return null;
69
+ if (!isProcessAlive(pid))
70
+ return null;
71
+ return pid;
72
+ } catch {
73
+ return null;
74
+ }
75
+ }
76
+ function getWatchdogComposeArg(composeFile) {
77
+ return composeFile ? `-f "${composeFile}"` : "";
78
+ }
79
+ async function spawnWatchdog(projectName, root, options = {}) {
80
+ const { timeoutMinutes = 10, verbose = true, composeFile } = options;
81
+ const existingPid = getWatchdogPid(projectName);
82
+ if (existingPid) {
83
+ if (verbose)
84
+ console.log(`✓ Watchdog already running (PID: ${existingPid})`);
85
+ return;
86
+ }
87
+ const pidFile = getWatchdogPidFile(projectName);
88
+ try {
89
+ unlinkSync(pidFile);
90
+ } catch {}
91
+ const watchdogScript = new URL("./watchdog-runner.ts", import.meta.url).pathname;
92
+ const proc = spawn("bun", ["run", watchdogScript], {
93
+ cwd: root,
94
+ detached: true,
95
+ stdio: "ignore",
96
+ env: {
97
+ ...process.env,
98
+ WATCHDOG_PROJECT_NAME: projectName,
99
+ WATCHDOG_HEARTBEAT_FILE: getHeartbeatFile(projectName),
100
+ WATCHDOG_PID_FILE: pidFile,
101
+ WATCHDOG_TIMEOUT_MS: String(timeoutMinutes * 60 * 1000),
102
+ WATCHDOG_COMPOSE_ARG: getWatchdogComposeArg(composeFile)
103
+ }
104
+ });
105
+ proc.unref();
106
+ if (verbose && proc.pid) {
107
+ console.log(`✓ Watchdog started (PID: ${proc.pid})`);
108
+ }
109
+ }
110
+ function stopWatchdog(projectName) {
111
+ const pid = getWatchdogPid(projectName);
112
+ if (pid) {
113
+ try {
114
+ process.kill(pid, "SIGTERM");
115
+ } catch {}
116
+ }
117
+ const pidFile = getWatchdogPidFile(projectName);
118
+ try {
119
+ unlinkSync(pidFile);
120
+ } catch {}
121
+ }
122
+
123
+ export { getHeartbeatFile, getWatchdogPidFile, startHeartbeat, stopHeartbeat, readHeartbeat, removeHeartbeatFile, isWatchdogRunning, getWatchdogPid, getWatchdogComposeArg, spawnWatchdog, stopWatchdog };