buncargo 1.0.17 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.ts +6 -0
- package/dist/bin.js +4 -4
- package/dist/cli.js +1 -1
- package/dist/environment.js +1 -1
- package/dist/index-3h3dhtf2.js +58 -0
- package/dist/index-7ja4ywyj.js +142 -0
- package/dist/index-wz9x8g7z.js +394 -0
- package/dist/index.js +3 -3
- package/dist/loader.js +2 -2
- package/environment.ts +10 -6
- package/package.json +1 -1
package/cli.ts
CHANGED
|
@@ -76,6 +76,12 @@ export async function runCli<
|
|
|
76
76
|
});
|
|
77
77
|
if (result.exitCode !== 0) {
|
|
78
78
|
console.error("❌ Seeding failed");
|
|
79
|
+
if (result.stderr) {
|
|
80
|
+
console.error(result.stderr);
|
|
81
|
+
}
|
|
82
|
+
if (result.stdout) {
|
|
83
|
+
console.error(result.stdout);
|
|
84
|
+
}
|
|
79
85
|
process.exit(1);
|
|
80
86
|
}
|
|
81
87
|
console.log("");
|
package/dist/bin.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import {
|
|
3
3
|
runCli
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-7ja4ywyj.js";
|
|
5
5
|
import {
|
|
6
6
|
loadDevEnv
|
|
7
|
-
} from "./index-
|
|
8
|
-
import"./index-
|
|
7
|
+
} from "./index-3h3dhtf2.js";
|
|
8
|
+
import"./index-wz9x8g7z.js";
|
|
9
9
|
import"./index-ggq3yryx.js";
|
|
10
10
|
import"./index-1yvbwj4k.js";
|
|
11
11
|
import"./index-tjqw9vtj.js";
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
var require_package = __commonJS((exports, module) => {
|
|
23
23
|
module.exports = {
|
|
24
24
|
name: "buncargo",
|
|
25
|
-
version: "1.0.
|
|
25
|
+
version: "1.0.19",
|
|
26
26
|
description: "A Bun-powered development environment CLI for managing Docker Compose services, dev servers, and environment variables",
|
|
27
27
|
type: "module",
|
|
28
28
|
module: "./dist/index.js",
|
package/dist/cli.js
CHANGED
package/dist/environment.js
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createDevEnvironment
|
|
3
|
+
} from "./index-wz9x8g7z.js";
|
|
4
|
+
|
|
5
|
+
// loader.ts
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
var CONFIG_FILES = [
|
|
9
|
+
"dev.config.ts",
|
|
10
|
+
"dev.config.js",
|
|
11
|
+
"dev-tools.config.ts",
|
|
12
|
+
"dev-tools.config.js"
|
|
13
|
+
];
|
|
14
|
+
function findConfigFile(startDir) {
|
|
15
|
+
let currentDir = startDir;
|
|
16
|
+
while (true) {
|
|
17
|
+
for (const file of CONFIG_FILES) {
|
|
18
|
+
const configPath = join(currentDir, file);
|
|
19
|
+
if (existsSync(configPath)) {
|
|
20
|
+
return configPath;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const parentDir = dirname(currentDir);
|
|
24
|
+
if (parentDir === currentDir) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
currentDir = parentDir;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
var cachedEnv = null;
|
|
31
|
+
async function loadDevEnv(options) {
|
|
32
|
+
if (cachedEnv && !options?.reload) {
|
|
33
|
+
return cachedEnv;
|
|
34
|
+
}
|
|
35
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
36
|
+
const configPath = findConfigFile(cwd);
|
|
37
|
+
if (configPath) {
|
|
38
|
+
const mod = await import(configPath);
|
|
39
|
+
const config = mod.default;
|
|
40
|
+
if (!config?.projectPrefix || !config?.services) {
|
|
41
|
+
throw new Error(`Invalid config in "${configPath}". Use defineDevConfig() and export as default.`);
|
|
42
|
+
}
|
|
43
|
+
cachedEnv = createDevEnvironment(config);
|
|
44
|
+
return cachedEnv;
|
|
45
|
+
}
|
|
46
|
+
throw new Error(`No config file found. Create dev.config.ts with: export default defineDevConfig({ ... })`);
|
|
47
|
+
}
|
|
48
|
+
function getDevEnv() {
|
|
49
|
+
if (!cachedEnv) {
|
|
50
|
+
throw new Error("Dev environment not loaded. Call loadDevEnv() first.");
|
|
51
|
+
}
|
|
52
|
+
return cachedEnv;
|
|
53
|
+
}
|
|
54
|
+
function clearDevEnvCache() {
|
|
55
|
+
cachedEnv = null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { CONFIG_FILES, findConfigFile, loadDevEnv, getDevEnv, clearDevEnvCache };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import {
|
|
2
|
+
spawnWatchdog,
|
|
3
|
+
startHeartbeat,
|
|
4
|
+
stopHeartbeat
|
|
5
|
+
} from "./index-ggq3yryx.js";
|
|
6
|
+
import {
|
|
7
|
+
killProcessesOnAppPorts
|
|
8
|
+
} from "./index-1yvbwj4k.js";
|
|
9
|
+
|
|
10
|
+
// cli.ts
|
|
11
|
+
import { spawn } from "node:child_process";
|
|
12
|
+
async function runCli(env, options = {}) {
|
|
13
|
+
const {
|
|
14
|
+
args = process.argv.slice(2),
|
|
15
|
+
watchdog = true,
|
|
16
|
+
watchdogTimeout = 10,
|
|
17
|
+
devServersCommand
|
|
18
|
+
} = options;
|
|
19
|
+
env.logInfo();
|
|
20
|
+
if (args.includes("--down")) {
|
|
21
|
+
await env.stop();
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
if (args.includes("--reset")) {
|
|
25
|
+
await env.stop({ removeVolumes: true });
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
const running = await env.isRunning();
|
|
29
|
+
if (running) {
|
|
30
|
+
console.log("✓ Containers already running");
|
|
31
|
+
} else {
|
|
32
|
+
await env.start({ startServers: false, wait: true });
|
|
33
|
+
}
|
|
34
|
+
if (args.includes("--migrate")) {
|
|
35
|
+
console.log("");
|
|
36
|
+
console.log("✅ Migrations applied successfully");
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
if (args.includes("--seed")) {
|
|
40
|
+
console.log("\uD83C\uDF31 Running seeders...");
|
|
41
|
+
const result = await env.exec("bun run run:seeder", {
|
|
42
|
+
throwOnError: false
|
|
43
|
+
});
|
|
44
|
+
if (result.exitCode !== 0) {
|
|
45
|
+
console.error("❌ Seeding failed");
|
|
46
|
+
if (result.stderr) {
|
|
47
|
+
console.error(result.stderr);
|
|
48
|
+
}
|
|
49
|
+
if (result.stdout) {
|
|
50
|
+
console.error(result.stdout);
|
|
51
|
+
}
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
console.log("");
|
|
55
|
+
console.log("✅ Seeding complete");
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
if (args.includes("--up-only")) {
|
|
59
|
+
console.log("");
|
|
60
|
+
console.log("✅ Containers started. Environment ready.");
|
|
61
|
+
console.log("");
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
if (watchdog) {
|
|
65
|
+
await spawnWatchdog(env.projectName, env.root, {
|
|
66
|
+
timeoutMinutes: watchdogTimeout,
|
|
67
|
+
verbose: true
|
|
68
|
+
});
|
|
69
|
+
startHeartbeat(env.projectName);
|
|
70
|
+
}
|
|
71
|
+
const command = devServersCommand ?? buildDevServersCommand(env.apps);
|
|
72
|
+
if (!command) {
|
|
73
|
+
console.log("✅ Containers ready. No apps configured.");
|
|
74
|
+
await new Promise(() => {});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
await killProcessesOnAppPorts(env.apps, env.ports);
|
|
78
|
+
console.log("");
|
|
79
|
+
console.log("\uD83D\uDD27 Starting dev servers...");
|
|
80
|
+
console.log("");
|
|
81
|
+
await runCommand(command, env.root, env.buildEnvVars());
|
|
82
|
+
stopHeartbeat();
|
|
83
|
+
}
|
|
84
|
+
function buildDevServersCommand(apps) {
|
|
85
|
+
const appEntries = Object.entries(apps);
|
|
86
|
+
if (appEntries.length === 0)
|
|
87
|
+
return null;
|
|
88
|
+
const commands = [];
|
|
89
|
+
const names = [];
|
|
90
|
+
const colors = ["blue", "green", "yellow", "magenta", "cyan", "red"];
|
|
91
|
+
for (const [name, config] of appEntries) {
|
|
92
|
+
names.push(name);
|
|
93
|
+
const cwdPart = config.cwd ? `--cwd ${config.cwd}` : "";
|
|
94
|
+
commands.push(`"bun run ${cwdPart} ${config.devCommand}"`.replace(/\s+/g, " ").trim());
|
|
95
|
+
}
|
|
96
|
+
const namesArg = `-n ${names.join(",")}`;
|
|
97
|
+
const colorsArg = `-c ${colors.slice(0, names.length).join(",")}`;
|
|
98
|
+
const commandsArg = commands.join(" ");
|
|
99
|
+
return `bun concurrently ${namesArg} ${colorsArg} ${commandsArg}`;
|
|
100
|
+
}
|
|
101
|
+
function runCommand(command, cwd, envVars) {
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
103
|
+
const proc = spawn(command, [], {
|
|
104
|
+
cwd,
|
|
105
|
+
env: { ...process.env, ...envVars },
|
|
106
|
+
stdio: "inherit",
|
|
107
|
+
shell: true
|
|
108
|
+
});
|
|
109
|
+
proc.on("close", (code) => {
|
|
110
|
+
if (code === 0 || code === null) {
|
|
111
|
+
resolve();
|
|
112
|
+
} else {
|
|
113
|
+
reject(new Error(`Command exited with code ${code}`));
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
proc.on("error", reject);
|
|
117
|
+
const cleanup = () => {
|
|
118
|
+
proc.kill("SIGTERM");
|
|
119
|
+
};
|
|
120
|
+
process.on("SIGINT", cleanup);
|
|
121
|
+
process.on("SIGTERM", cleanup);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function hasFlag(args, flag) {
|
|
125
|
+
return args.includes(flag);
|
|
126
|
+
}
|
|
127
|
+
function getFlagValue(args, flag) {
|
|
128
|
+
const prefixed = args.find((arg) => arg.startsWith(`${flag}=`));
|
|
129
|
+
if (prefixed) {
|
|
130
|
+
return prefixed.split("=")[1];
|
|
131
|
+
}
|
|
132
|
+
const index = args.indexOf(flag);
|
|
133
|
+
if (index !== -1 && index + 1 < args.length) {
|
|
134
|
+
const nextArg = args[index + 1];
|
|
135
|
+
if (nextArg !== undefined && !nextArg.startsWith("-")) {
|
|
136
|
+
return nextArg;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export { runCli, hasFlag, getFlagValue };
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import {
|
|
2
|
+
spawnWatchdog,
|
|
3
|
+
startHeartbeat,
|
|
4
|
+
stopHeartbeat,
|
|
5
|
+
stopWatchdog
|
|
6
|
+
} from "./index-ggq3yryx.js";
|
|
7
|
+
import {
|
|
8
|
+
buildApps,
|
|
9
|
+
execAsync,
|
|
10
|
+
startDevServers,
|
|
11
|
+
stopProcess
|
|
12
|
+
} from "./index-1yvbwj4k.js";
|
|
13
|
+
import {
|
|
14
|
+
assertValidConfig
|
|
15
|
+
} from "./index-tjqw9vtj.js";
|
|
16
|
+
import {
|
|
17
|
+
createPrismaRunner
|
|
18
|
+
} from "./index-5hka0tff.js";
|
|
19
|
+
import {
|
|
20
|
+
areContainersRunning,
|
|
21
|
+
startContainers,
|
|
22
|
+
stopContainers,
|
|
23
|
+
waitForAllServices
|
|
24
|
+
} from "./index-2fr3g85b.js";
|
|
25
|
+
import {
|
|
26
|
+
getLocalIp,
|
|
27
|
+
isCI,
|
|
28
|
+
logExpoApiUrl,
|
|
29
|
+
logFrontendPort,
|
|
30
|
+
waitForDevServers,
|
|
31
|
+
waitForServer
|
|
32
|
+
} from "./index-6fm7mvwj.js";
|
|
33
|
+
import {
|
|
34
|
+
calculatePortOffset,
|
|
35
|
+
computePorts,
|
|
36
|
+
computeUrls,
|
|
37
|
+
findMonorepoRoot,
|
|
38
|
+
getProjectName,
|
|
39
|
+
isWorktree
|
|
40
|
+
} from "./index-08wa79cs.js";
|
|
41
|
+
|
|
42
|
+
// environment.ts
|
|
43
|
+
import pc from "picocolors";
|
|
44
|
+
function formatUrl(url) {
|
|
45
|
+
return pc.cyan(url.replace(/:(\d+)(\/?)/, (_, port, slash) => `:${pc.bold(port)}${slash}`));
|
|
46
|
+
}
|
|
47
|
+
function formatLabel(label, value, arrow = "➜") {
|
|
48
|
+
return ` ${pc.green(arrow)} ${pc.bold(label.padEnd(10))} ${value}`;
|
|
49
|
+
}
|
|
50
|
+
function formatDimLabel(label, value) {
|
|
51
|
+
return ` ${pc.dim("•")} ${pc.dim(label.padEnd(10))} ${pc.dim(value)}`;
|
|
52
|
+
}
|
|
53
|
+
function createDevEnvironment(config, options = {}) {
|
|
54
|
+
assertValidConfig(config);
|
|
55
|
+
const root = findMonorepoRoot();
|
|
56
|
+
const suffix = options.suffix;
|
|
57
|
+
const worktree = isWorktree(root);
|
|
58
|
+
const portOffset = calculatePortOffset(suffix, root);
|
|
59
|
+
const projectName = getProjectName(config.projectPrefix, suffix, root);
|
|
60
|
+
const localIp = getLocalIp();
|
|
61
|
+
const services = config.services;
|
|
62
|
+
const apps = config.apps ?? {};
|
|
63
|
+
const ports = computePorts(services, apps, portOffset);
|
|
64
|
+
const urls = computeUrls(services, apps, ports, localIp);
|
|
65
|
+
function buildEnvVars(production = false) {
|
|
66
|
+
const baseEnv = {
|
|
67
|
+
COMPOSE_PROJECT_NAME: projectName,
|
|
68
|
+
NODE_ENV: production ? "production" : "development"
|
|
69
|
+
};
|
|
70
|
+
for (const [name, port] of Object.entries(ports)) {
|
|
71
|
+
const envName = `${name.toUpperCase()}_PORT`;
|
|
72
|
+
baseEnv[envName] = String(port);
|
|
73
|
+
}
|
|
74
|
+
for (const [name, url] of Object.entries(urls)) {
|
|
75
|
+
const envName = `${name.toUpperCase()}_URL`;
|
|
76
|
+
baseEnv[envName] = url;
|
|
77
|
+
}
|
|
78
|
+
if (config.envVars) {
|
|
79
|
+
const userEnv = config.envVars(ports, urls, {
|
|
80
|
+
projectName,
|
|
81
|
+
localIp,
|
|
82
|
+
portOffset
|
|
83
|
+
});
|
|
84
|
+
for (const [key, value] of Object.entries(userEnv)) {
|
|
85
|
+
baseEnv[key] = String(value);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return baseEnv;
|
|
89
|
+
}
|
|
90
|
+
let hookContext = null;
|
|
91
|
+
function getHookContext() {
|
|
92
|
+
if (!hookContext) {
|
|
93
|
+
hookContext = {
|
|
94
|
+
projectName,
|
|
95
|
+
ports,
|
|
96
|
+
urls,
|
|
97
|
+
root,
|
|
98
|
+
isCI: isCI(),
|
|
99
|
+
portOffset,
|
|
100
|
+
localIp,
|
|
101
|
+
exec: async (cmd, opts) => {
|
|
102
|
+
const envVars = buildEnvVars();
|
|
103
|
+
return execAsync(cmd, root, envVars, opts);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return hookContext;
|
|
108
|
+
}
|
|
109
|
+
function exec(cmd, options2) {
|
|
110
|
+
const envVars = buildEnvVars();
|
|
111
|
+
return execAsync(cmd, root, envVars, options2);
|
|
112
|
+
}
|
|
113
|
+
async function start(startOptions = {}) {
|
|
114
|
+
const isCI2 = process.env.CI === "true";
|
|
115
|
+
const {
|
|
116
|
+
verbose = config.options?.verbose ?? true,
|
|
117
|
+
wait = true,
|
|
118
|
+
startServers: shouldStartServers = true,
|
|
119
|
+
productionBuild = isCI2
|
|
120
|
+
} = startOptions;
|
|
121
|
+
const envVars = buildEnvVars(productionBuild);
|
|
122
|
+
if (verbose) {
|
|
123
|
+
logInfo(productionBuild ? "Production Environment" : "Dev Environment");
|
|
124
|
+
}
|
|
125
|
+
const serviceCount = Object.keys(services).length;
|
|
126
|
+
const alreadyRunning = await areContainersRunning(projectName, serviceCount);
|
|
127
|
+
if (alreadyRunning) {
|
|
128
|
+
if (verbose)
|
|
129
|
+
console.log("✓ Containers already running");
|
|
130
|
+
} else {
|
|
131
|
+
startContainers(root, projectName, envVars, {
|
|
132
|
+
verbose,
|
|
133
|
+
wait,
|
|
134
|
+
composeFile: config.options?.composeFile
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (wait) {
|
|
138
|
+
await waitForAllServices(services, ports, {
|
|
139
|
+
verbose,
|
|
140
|
+
projectName,
|
|
141
|
+
root
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
const allMigrations = [
|
|
145
|
+
...config.prisma ? [
|
|
146
|
+
{
|
|
147
|
+
name: "prisma",
|
|
148
|
+
command: "bunx prisma migrate deploy",
|
|
149
|
+
cwd: config.prisma.cwd ?? "packages/prisma"
|
|
150
|
+
}
|
|
151
|
+
] : [],
|
|
152
|
+
...config.migrations ?? []
|
|
153
|
+
];
|
|
154
|
+
if (allMigrations.length > 0) {
|
|
155
|
+
if (verbose)
|
|
156
|
+
console.log("\uD83D\uDCE6 Running migrations...");
|
|
157
|
+
const migrationResults = await Promise.all(allMigrations.map(async (migration) => {
|
|
158
|
+
const result = await exec(migration.command, {
|
|
159
|
+
cwd: migration.cwd,
|
|
160
|
+
throwOnError: false
|
|
161
|
+
});
|
|
162
|
+
return { name: migration.name, result };
|
|
163
|
+
}));
|
|
164
|
+
for (const { name, result } of migrationResults) {
|
|
165
|
+
if (result.exitCode !== 0) {
|
|
166
|
+
console.error(`❌ Migration "${name}" failed`);
|
|
167
|
+
console.error(result.stderr);
|
|
168
|
+
throw new Error(`Migration "${name}" failed`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (verbose)
|
|
172
|
+
console.log("✓ Migrations complete");
|
|
173
|
+
}
|
|
174
|
+
if (config.hooks?.afterContainersReady) {
|
|
175
|
+
await config.hooks.afterContainersReady(getHookContext());
|
|
176
|
+
}
|
|
177
|
+
if (config.seed) {
|
|
178
|
+
let shouldSeed = true;
|
|
179
|
+
if (config.seed.check) {
|
|
180
|
+
const checkTable = async (tableName, service) => {
|
|
181
|
+
const serviceName = service ?? "postgres";
|
|
182
|
+
const serviceUrl = urls[serviceName];
|
|
183
|
+
if (!serviceUrl) {
|
|
184
|
+
console.warn(`⚠️ Service "${serviceName}" not found for checkTable`);
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
const checkResult = await exec(`psql "${serviceUrl}" -tAc 'SELECT COUNT(*) FROM "${tableName}" LIMIT 1'`, { throwOnError: false });
|
|
188
|
+
const count = checkResult.stdout.trim();
|
|
189
|
+
const shouldSeed2 = checkResult.exitCode !== 0 || count === "0" || count === "";
|
|
190
|
+
if (!shouldSeed2) {
|
|
191
|
+
console.log(` \uD83D\uDCCA Table "${tableName}" has ${count} rows`);
|
|
192
|
+
}
|
|
193
|
+
return shouldSeed2;
|
|
194
|
+
};
|
|
195
|
+
const seedCheckContext = {
|
|
196
|
+
...getHookContext(),
|
|
197
|
+
checkTable
|
|
198
|
+
};
|
|
199
|
+
shouldSeed = await config.seed.check(seedCheckContext);
|
|
200
|
+
}
|
|
201
|
+
if (shouldSeed) {
|
|
202
|
+
if (verbose)
|
|
203
|
+
console.log("\uD83C\uDF31 Running seeders...");
|
|
204
|
+
const seedResult = await exec(config.seed.command, {
|
|
205
|
+
cwd: config.seed.cwd,
|
|
206
|
+
verbose,
|
|
207
|
+
throwOnError: false
|
|
208
|
+
});
|
|
209
|
+
if (seedResult.exitCode !== 0) {
|
|
210
|
+
console.error("❌ Seeding failed");
|
|
211
|
+
console.error(seedResult.stderr);
|
|
212
|
+
} else {
|
|
213
|
+
if (verbose)
|
|
214
|
+
console.log("✓ Seeding complete");
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
if (verbose)
|
|
218
|
+
console.log("✓ Database already has data, skipping seeders");
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (shouldStartServers && Object.keys(apps).length > 0) {
|
|
222
|
+
if (config.hooks?.beforeServers) {
|
|
223
|
+
await config.hooks.beforeServers(getHookContext());
|
|
224
|
+
}
|
|
225
|
+
if (productionBuild) {
|
|
226
|
+
buildApps(apps, root, envVars, { verbose });
|
|
227
|
+
}
|
|
228
|
+
const pids = await startDevServers(apps, root, envVars, ports, {
|
|
229
|
+
verbose,
|
|
230
|
+
productionBuild,
|
|
231
|
+
isCI: isCI2
|
|
232
|
+
});
|
|
233
|
+
if (verbose)
|
|
234
|
+
console.log("⏳ Waiting for servers to be ready...");
|
|
235
|
+
await waitForDevServers(apps, ports, {
|
|
236
|
+
timeout: isCI2 ? 120000 : 60000,
|
|
237
|
+
verbose,
|
|
238
|
+
productionBuild
|
|
239
|
+
});
|
|
240
|
+
if (config.hooks?.afterServers) {
|
|
241
|
+
await config.hooks.afterServers(getHookContext());
|
|
242
|
+
}
|
|
243
|
+
if (verbose)
|
|
244
|
+
console.log(`✅ Environment ready
|
|
245
|
+
`);
|
|
246
|
+
return pids;
|
|
247
|
+
}
|
|
248
|
+
if (verbose)
|
|
249
|
+
console.log(`✅ Containers ready
|
|
250
|
+
`);
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
async function stop(stopOptions = {}) {
|
|
254
|
+
const { verbose = true, removeVolumes = false } = stopOptions;
|
|
255
|
+
if (config.hooks?.beforeStop) {
|
|
256
|
+
await config.hooks.beforeStop(getHookContext());
|
|
257
|
+
}
|
|
258
|
+
stopContainers(root, projectName, {
|
|
259
|
+
verbose,
|
|
260
|
+
removeVolumes,
|
|
261
|
+
composeFile: config.options?.composeFile
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
async function restart() {
|
|
265
|
+
await stop();
|
|
266
|
+
await start({ startServers: false });
|
|
267
|
+
}
|
|
268
|
+
async function isRunning() {
|
|
269
|
+
const serviceCount = Object.keys(services).length;
|
|
270
|
+
return areContainersRunning(projectName, serviceCount);
|
|
271
|
+
}
|
|
272
|
+
async function startServersOnly(options2 = {}) {
|
|
273
|
+
const { productionBuild = false, verbose = true } = options2;
|
|
274
|
+
const envVars = buildEnvVars(productionBuild);
|
|
275
|
+
const isCI2 = process.env.CI === "true";
|
|
276
|
+
if (productionBuild) {
|
|
277
|
+
buildApps(apps, root, envVars, { verbose });
|
|
278
|
+
}
|
|
279
|
+
return startDevServers(apps, root, envVars, ports, {
|
|
280
|
+
verbose,
|
|
281
|
+
productionBuild,
|
|
282
|
+
isCI: isCI2
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
async function waitForServersReady(options2 = {}) {
|
|
286
|
+
const { timeout = 60000, productionBuild = false } = options2;
|
|
287
|
+
await waitForDevServers(apps, ports, { timeout, productionBuild });
|
|
288
|
+
}
|
|
289
|
+
function logInfo(label = "Docker Dev") {
|
|
290
|
+
const serviceNames = Object.keys(services);
|
|
291
|
+
const appNames = Object.keys(apps);
|
|
292
|
+
console.log("");
|
|
293
|
+
console.log(` ${pc.cyan(pc.bold(`\uD83D\uDC33 ${label}`))}`);
|
|
294
|
+
console.log(formatLabel("Project:", pc.white(projectName)));
|
|
295
|
+
if (serviceNames.length > 0) {
|
|
296
|
+
console.log("");
|
|
297
|
+
console.log(` ${pc.dim("─── Services ───")}`);
|
|
298
|
+
for (const name of serviceNames) {
|
|
299
|
+
const port = ports[name];
|
|
300
|
+
const url = `localhost:${port}`;
|
|
301
|
+
console.log(formatLabel(`${name}:`, formatUrl(`http://${url}`)));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (appNames.length > 0) {
|
|
305
|
+
console.log("");
|
|
306
|
+
console.log(` ${pc.dim("─── Applications ───")}`);
|
|
307
|
+
for (const name of appNames) {
|
|
308
|
+
const port = ports[name];
|
|
309
|
+
const localUrl = `http://localhost:${port}`;
|
|
310
|
+
const networkUrl = `http://${localIp}:${port}`;
|
|
311
|
+
console.log(` ${pc.green("➜")} ${pc.bold(pc.cyan(name))}`);
|
|
312
|
+
console.log(` ${pc.dim("Local:")} ${formatUrl(localUrl)}`);
|
|
313
|
+
console.log(` ${pc.dim("Network:")} ${formatUrl(networkUrl)}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
console.log("");
|
|
317
|
+
console.log(` ${pc.dim("─── Environment ───")}`);
|
|
318
|
+
console.log(formatDimLabel("Worktree:", worktree ? "yes" : "no"));
|
|
319
|
+
console.log(formatDimLabel("Port offset:", portOffset > 0 ? `+${portOffset}` : "none"));
|
|
320
|
+
if (suffix) {
|
|
321
|
+
console.log(formatDimLabel("Suffix:", suffix));
|
|
322
|
+
}
|
|
323
|
+
console.log(formatDimLabel("Local IP:", localIp));
|
|
324
|
+
console.log("");
|
|
325
|
+
}
|
|
326
|
+
async function waitForServerUrl(url, timeout) {
|
|
327
|
+
await waitForServer(url, { timeout });
|
|
328
|
+
}
|
|
329
|
+
function startHeartbeat2(intervalMs) {
|
|
330
|
+
startHeartbeat(projectName, intervalMs);
|
|
331
|
+
}
|
|
332
|
+
function stopHeartbeat2() {
|
|
333
|
+
stopHeartbeat();
|
|
334
|
+
}
|
|
335
|
+
async function spawnWatchdog2(timeoutMinutes) {
|
|
336
|
+
await spawnWatchdog(projectName, root, {
|
|
337
|
+
timeoutMinutes,
|
|
338
|
+
verbose: true,
|
|
339
|
+
composeFile: config.options?.composeFile
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
function stopWatchdog2() {
|
|
343
|
+
stopWatchdog(projectName);
|
|
344
|
+
}
|
|
345
|
+
function getExpoApiUrl() {
|
|
346
|
+
const apiPort = ports.api;
|
|
347
|
+
const url = `http://${localIp}:${apiPort}`;
|
|
348
|
+
logExpoApiUrl(url);
|
|
349
|
+
return url;
|
|
350
|
+
}
|
|
351
|
+
function getFrontendPort() {
|
|
352
|
+
const port = ports.platform;
|
|
353
|
+
logFrontendPort(port);
|
|
354
|
+
return port;
|
|
355
|
+
}
|
|
356
|
+
function withSuffix(newSuffix) {
|
|
357
|
+
return createDevEnvironment(config, { suffix: newSuffix });
|
|
358
|
+
}
|
|
359
|
+
const env = {
|
|
360
|
+
projectName,
|
|
361
|
+
ports,
|
|
362
|
+
urls,
|
|
363
|
+
apps,
|
|
364
|
+
portOffset,
|
|
365
|
+
isWorktree: worktree,
|
|
366
|
+
localIp,
|
|
367
|
+
root,
|
|
368
|
+
start,
|
|
369
|
+
stop,
|
|
370
|
+
restart,
|
|
371
|
+
isRunning,
|
|
372
|
+
startServers: startServersOnly,
|
|
373
|
+
stopProcess,
|
|
374
|
+
waitForServers: waitForServersReady,
|
|
375
|
+
buildEnvVars,
|
|
376
|
+
exec,
|
|
377
|
+
waitForServer: waitForServerUrl,
|
|
378
|
+
logInfo,
|
|
379
|
+
getExpoApiUrl,
|
|
380
|
+
getFrontendPort,
|
|
381
|
+
startHeartbeat: startHeartbeat2,
|
|
382
|
+
stopHeartbeat: stopHeartbeat2,
|
|
383
|
+
spawnWatchdog: spawnWatchdog2,
|
|
384
|
+
stopWatchdog: stopWatchdog2,
|
|
385
|
+
prisma: undefined,
|
|
386
|
+
withSuffix
|
|
387
|
+
};
|
|
388
|
+
if (config.prisma) {
|
|
389
|
+
env.prisma = createPrismaRunner(env, config.prisma);
|
|
390
|
+
}
|
|
391
|
+
return env;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export { createDevEnvironment };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
getFlagValue,
|
|
3
3
|
hasFlag,
|
|
4
4
|
runCli
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-7ja4ywyj.js";
|
|
6
6
|
import {
|
|
7
7
|
runWorkspaceTypecheck
|
|
8
8
|
} from "./index-d9efy0n4.js";
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
clearDevEnvCache,
|
|
11
11
|
getDevEnv,
|
|
12
12
|
loadDevEnv
|
|
13
|
-
} from "./index-
|
|
13
|
+
} from "./index-3h3dhtf2.js";
|
|
14
14
|
import {
|
|
15
15
|
createDevEnvironment
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-wz9x8g7z.js";
|
|
17
17
|
import {
|
|
18
18
|
getHeartbeatFile,
|
|
19
19
|
getWatchdogPidFile,
|
package/dist/loader.js
CHANGED
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
findConfigFile,
|
|
5
5
|
getDevEnv,
|
|
6
6
|
loadDevEnv
|
|
7
|
-
} from "./index-
|
|
8
|
-
import"./index-
|
|
7
|
+
} from "./index-3h3dhtf2.js";
|
|
8
|
+
import"./index-wz9x8g7z.js";
|
|
9
9
|
import"./index-ggq3yryx.js";
|
|
10
10
|
import"./index-1yvbwj4k.js";
|
|
11
11
|
import"./index-tjqw9vtj.js";
|
package/environment.ts
CHANGED
|
@@ -299,12 +299,16 @@ export function createDevEnvironment<
|
|
|
299
299
|
console.warn(`⚠️ Service "${serviceName}" not found for checkTable`);
|
|
300
300
|
return true; // Default to seeding if service not found
|
|
301
301
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
302
|
+
const checkResult = await exec(
|
|
303
|
+
`psql "${serviceUrl}" -tAc 'SELECT COUNT(*) FROM "${tableName}" LIMIT 1'`,
|
|
304
|
+
{ throwOnError: false },
|
|
305
|
+
);
|
|
306
|
+
const count = checkResult.stdout.trim();
|
|
307
|
+
const shouldSeed = checkResult.exitCode !== 0 || count === "0" || count === "";
|
|
308
|
+
if (!shouldSeed) {
|
|
309
|
+
console.log(` 📊 Table "${tableName}" has ${count} rows`);
|
|
310
|
+
}
|
|
311
|
+
return shouldSeed;
|
|
308
312
|
};
|
|
309
313
|
|
|
310
314
|
// Build seed check context with helpers
|
package/package.json
CHANGED