drizzle-auto 1.1.0 → 1.1.1
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/index.js +101 -70
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -6,28 +6,37 @@ const chokidar = require("chokidar");
|
|
|
6
6
|
const { spawn } = require("child_process");
|
|
7
7
|
|
|
8
8
|
/* =========================
|
|
9
|
-
|
|
9
|
+
🎨 COLORS (clean & pro)
|
|
10
10
|
========================= */
|
|
11
11
|
const C = {
|
|
12
12
|
reset: "\x1b[0m",
|
|
13
|
-
|
|
13
|
+
dim: "\x1b[2m",
|
|
14
|
+
bold: "\x1b[1m",
|
|
14
15
|
cyan: "\x1b[36m",
|
|
15
16
|
green: "\x1b[32m",
|
|
16
17
|
yellow: "\x1b[33m",
|
|
17
18
|
red: "\x1b[31m",
|
|
18
|
-
|
|
19
|
+
magenta: "\x1b[35m",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const log = {
|
|
23
|
+
info: (m) => console.log(`${C.cyan}ℹ ${m}${C.reset}`),
|
|
24
|
+
ok: (m) => console.log(`${C.green}✓ ${m}${C.reset}`),
|
|
25
|
+
warn: (m) => console.log(`${C.yellow}⚠ ${m}${C.reset}`),
|
|
26
|
+
err: (m) => console.log(`${C.red}✗ ${m}${C.reset}`),
|
|
27
|
+
trig: (m) => console.log(`${C.magenta}⚡ ${m}${C.reset}`),
|
|
19
28
|
};
|
|
20
29
|
|
|
21
30
|
/* =========================
|
|
22
|
-
|
|
31
|
+
🧭 PROJECT ROOT
|
|
23
32
|
========================= */
|
|
24
33
|
const ROOT = process.cwd();
|
|
25
34
|
const PKG = path.join(ROOT, "package.json");
|
|
26
35
|
|
|
27
36
|
/* =========================
|
|
28
|
-
|
|
37
|
+
🧩 SCRIPT INJECTOR
|
|
29
38
|
========================= */
|
|
30
|
-
function
|
|
39
|
+
function injectScript() {
|
|
31
40
|
if (!fs.existsSync(PKG)) return;
|
|
32
41
|
|
|
33
42
|
const pkg = JSON.parse(fs.readFileSync(PKG, "utf8"));
|
|
@@ -36,115 +45,137 @@ function injectTea() {
|
|
|
36
45
|
if (!pkg.scripts.tea) {
|
|
37
46
|
pkg.scripts.tea = "drizzle-auto";
|
|
38
47
|
fs.writeFileSync(PKG, JSON.stringify(pkg, null, 2));
|
|
39
|
-
|
|
48
|
+
log.ok("Added script → npm run tea");
|
|
40
49
|
}
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
/* =========================
|
|
44
|
-
|
|
53
|
+
🔍 FIND DRIZZLE CONFIG
|
|
54
|
+
(js | mjs | ts | mts)
|
|
45
55
|
========================= */
|
|
46
|
-
function walk(dir, results = []) {
|
|
47
|
-
for (const file of fs.readdirSync(dir)) {
|
|
48
|
-
const p = path.join(dir, file);
|
|
49
|
-
if (p.includes("node_modules") || p.includes(".git")) continue;
|
|
50
|
-
|
|
51
|
-
const stat = fs.statSync(p);
|
|
52
|
-
if (stat.isDirectory()) walk(p, results);
|
|
53
|
-
else results.push(p);
|
|
54
|
-
}
|
|
55
|
-
return results;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
56
|
function findDrizzleConfig() {
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (!config) {
|
|
65
|
-
console.log(`${C.yellow}⚠️ drizzle.config not found (anywhere)${C.reset}`);
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let schemaPath = null;
|
|
70
|
-
try {
|
|
71
|
-
const content = fs.readFileSync(config, "utf8");
|
|
72
|
-
const match = content.match(/schema:\s*["'](.+?)["']/);
|
|
73
|
-
if (match) {
|
|
74
|
-
schemaPath = path.resolve(path.dirname(config), match[1]);
|
|
75
|
-
}
|
|
76
|
-
} catch {}
|
|
77
|
-
|
|
78
|
-
if (schemaPath && !fs.existsSync(schemaPath)) {
|
|
79
|
-
console.log(`${C.red}❌ Schema missing: ${schemaPath}${C.reset}`);
|
|
80
|
-
return null;
|
|
57
|
+
const exts = ["js", "mjs", "ts", "mts"];
|
|
58
|
+
for (const e of exts) {
|
|
59
|
+
const p = path.join(ROOT, `drizzle.config.${e}`);
|
|
60
|
+
if (fs.existsSync(p)) return p;
|
|
81
61
|
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
82
64
|
|
|
83
|
-
|
|
84
|
-
|
|
65
|
+
/* =========================
|
|
66
|
+
🔎 FILE FILTER (ALL TYPES)
|
|
67
|
+
========================= */
|
|
68
|
+
const WATCH_EXTS = [
|
|
69
|
+
".js", ".mjs", ".cjs",
|
|
70
|
+
".ts", ".mts",
|
|
71
|
+
".jsx", ".tsx",
|
|
72
|
+
".sql"
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
function isValidFile(file) {
|
|
76
|
+
return WATCH_EXTS.includes(path.extname(file));
|
|
85
77
|
}
|
|
86
78
|
|
|
87
79
|
/* =========================
|
|
88
|
-
|
|
80
|
+
⚙️ SAFE SPAWN (NO SHELL)
|
|
89
81
|
========================= */
|
|
90
|
-
function
|
|
91
|
-
return new Promise(resolve => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
);
|
|
98
|
-
p.stderr.on("data", d => {
|
|
99
|
-
failed = true;
|
|
100
|
-
process.stderr.write(C.red + d.toString() + C.reset);
|
|
82
|
+
function exec(cmd, args = []) {
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
const p = spawn(cmd, args, { stdio: "inherit" });
|
|
85
|
+
|
|
86
|
+
p.on("error", (e) => {
|
|
87
|
+
log.err(`Process error: ${e.message}`);
|
|
88
|
+
resolve(false);
|
|
101
89
|
});
|
|
102
90
|
|
|
103
|
-
p.on("close", code =>
|
|
91
|
+
p.on("close", (code) => {
|
|
92
|
+
resolve(code === 0);
|
|
93
|
+
});
|
|
104
94
|
});
|
|
105
95
|
}
|
|
106
96
|
|
|
107
97
|
/* =========================
|
|
108
|
-
|
|
98
|
+
🛡️ CRASH PROTECTION
|
|
99
|
+
========================= */
|
|
100
|
+
process.on("uncaughtException", (e) => {
|
|
101
|
+
log.err(`Crash prevented: ${e.message}`);
|
|
102
|
+
});
|
|
103
|
+
process.on("unhandledRejection", (e) => {
|
|
104
|
+
log.err(`Promise rejected: ${e}`);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
/* =========================
|
|
108
|
+
🔁 PIPELINE (DEV SAFE)
|
|
109
109
|
========================= */
|
|
110
110
|
let running = false;
|
|
111
|
+
let lastPush = 0;
|
|
112
|
+
|
|
113
|
+
const DEV_MODE = process.argv.includes("--dev");
|
|
114
|
+
const PUSH_COOLDOWN = DEV_MODE ? 120_000 : 30_000; // safer in dev
|
|
111
115
|
|
|
112
116
|
async function pipeline(trigger) {
|
|
113
117
|
if (running) return;
|
|
114
118
|
running = true;
|
|
115
119
|
|
|
116
|
-
|
|
120
|
+
log.trig(`Trigger → ${trigger}`);
|
|
117
121
|
|
|
118
|
-
|
|
122
|
+
const config = findDrizzleConfig();
|
|
123
|
+
if (!config) {
|
|
124
|
+
log.warn("No drizzle.config found");
|
|
119
125
|
running = false;
|
|
120
126
|
return;
|
|
121
127
|
}
|
|
122
128
|
|
|
123
|
-
|
|
124
|
-
|
|
129
|
+
log.info("Running drizzle generate…");
|
|
130
|
+
const gen = await exec("npx", ["drizzle-kit", "generate"]);
|
|
131
|
+
if (!gen) {
|
|
132
|
+
log.err("Generate failed — watching continues");
|
|
125
133
|
running = false;
|
|
126
134
|
return;
|
|
127
135
|
}
|
|
128
136
|
|
|
129
|
-
|
|
130
|
-
|
|
137
|
+
const now = Date.now();
|
|
138
|
+
if (now - lastPush < PUSH_COOLDOWN) {
|
|
139
|
+
log.warn("Push skipped (cooldown)");
|
|
131
140
|
running = false;
|
|
132
141
|
return;
|
|
133
142
|
}
|
|
134
143
|
|
|
135
|
-
|
|
144
|
+
log.info("Running drizzle push…");
|
|
145
|
+
lastPush = now;
|
|
146
|
+
|
|
147
|
+
const push = await exec("npx", ["drizzle-kit", "push"]);
|
|
148
|
+
if (!push) {
|
|
149
|
+
log.err("Push failed — DB untouched, server alive");
|
|
150
|
+
running = false;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
log.ok("Drizzle fully synced");
|
|
136
155
|
running = false;
|
|
137
156
|
}
|
|
138
157
|
|
|
139
158
|
/* =========================
|
|
140
|
-
|
|
159
|
+
👀 WATCHER (ALL FILES)
|
|
141
160
|
========================= */
|
|
142
|
-
|
|
143
|
-
pipeline("
|
|
161
|
+
injectScript();
|
|
162
|
+
pipeline("Initial");
|
|
163
|
+
|
|
164
|
+
log.info(`Watching files (${DEV_MODE ? "DEV MODE" : "SAFE MODE"})…`);
|
|
144
165
|
|
|
145
166
|
chokidar.watch(ROOT, {
|
|
146
|
-
ignored: [
|
|
167
|
+
ignored: [
|
|
168
|
+
/node_modules/,
|
|
169
|
+
/\.git/,
|
|
170
|
+
/\.next/,
|
|
171
|
+
/dist/,
|
|
172
|
+
/build/
|
|
173
|
+
],
|
|
147
174
|
ignoreInitial: true,
|
|
148
175
|
usePolling: true,
|
|
149
176
|
interval: 300,
|
|
150
|
-
}).on("all", (_, file) =>
|
|
177
|
+
}).on("all", (_, file) => {
|
|
178
|
+
if (isValidFile(file)) {
|
|
179
|
+
pipeline(path.relative(ROOT, file));
|
|
180
|
+
}
|
|
181
|
+
});
|