drizzle-auto 1.1.25 → 1.1.26
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 +124 -109
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* 🍵 Drizzle-Auto v2.
|
|
5
|
-
* 🔹
|
|
6
|
-
* 🔹 Stops immediately
|
|
7
|
-
* 🔹
|
|
4
|
+
* 🍵 Drizzle-Auto v2.3 - Flexible Config + Fail-Fast
|
|
5
|
+
* 🔹 Detects any drizzle.config.{js,ts,mjs,cjs,mts} automatically
|
|
6
|
+
* 🔹 Stops immediately if config or schema missing
|
|
7
|
+
* 🔹 Beginner-friendly logs
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
const { spawn } = require("child_process");
|
|
11
11
|
const path = require("path");
|
|
12
12
|
const fs = require("fs");
|
|
13
13
|
|
|
14
|
-
//
|
|
15
|
-
try { require("ts-node").register({ transpileOnly: true }); } catch
|
|
14
|
+
// TS support
|
|
15
|
+
try { require("ts-node").register({ transpileOnly: true }); } catch(e){}
|
|
16
16
|
|
|
17
|
-
//
|
|
17
|
+
// ---------------- COLORS ----------------
|
|
18
18
|
const T = {
|
|
19
19
|
reset: "\x1b[0m",
|
|
20
20
|
bold: "\x1b[1m",
|
|
@@ -25,152 +25,167 @@ const T = {
|
|
|
25
25
|
gray: "\x1b[38;5;244m",
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
let spinInterval;
|
|
29
|
+
const frames = ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];
|
|
30
|
+
let spinIdx = 0;
|
|
30
31
|
|
|
31
|
-
function startLoading(msg)
|
|
32
|
+
function startLoading(msg){
|
|
32
33
|
stopLoading();
|
|
33
|
-
spinInterval = setInterval(()
|
|
34
|
+
spinInterval = setInterval(()=>{
|
|
34
35
|
process.stdout.write(`\r${T.cyan}${frames[spinIdx++ % frames.length]}${T.reset} ${T.bold}${msg}${T.reset} `);
|
|
35
|
-
},
|
|
36
|
+
},80);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
function stopLoading()
|
|
39
|
-
if
|
|
39
|
+
function stopLoading(){
|
|
40
|
+
if(spinInterval){
|
|
40
41
|
clearInterval(spinInterval);
|
|
41
|
-
spinInterval
|
|
42
|
+
spinInterval=null;
|
|
42
43
|
process.stdout.write("\r\x1b[K");
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
//
|
|
47
|
-
const
|
|
48
|
-
function
|
|
49
|
-
if
|
|
50
|
-
try
|
|
51
|
-
const pkg = JSON.parse(fs.readFileSync(
|
|
47
|
+
// ---------------- ADD "tea" SCRIPT ----------------
|
|
48
|
+
const PKG = path.join(process.cwd(),"package.json");
|
|
49
|
+
function addTeaScript(){
|
|
50
|
+
if(!fs.existsSync(PKG)) return;
|
|
51
|
+
try{
|
|
52
|
+
const pkg = JSON.parse(fs.readFileSync(PKG,"utf8"));
|
|
52
53
|
pkg.scripts ||= {};
|
|
53
|
-
if
|
|
54
|
+
if(!pkg.scripts.tea){
|
|
54
55
|
pkg.scripts.tea = "drizzle-auto";
|
|
55
|
-
fs.writeFileSync(
|
|
56
|
-
console.log(`${T.lime}🍵
|
|
56
|
+
fs.writeFileSync(PKG, JSON.stringify(pkg,null,2));
|
|
57
|
+
console.log(`${T.lime}🍵 Added script → npm run tea${T.reset}`);
|
|
57
58
|
}
|
|
58
|
-
} catch
|
|
59
|
+
} catch(e){}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
//
|
|
62
|
-
function
|
|
63
|
-
|
|
62
|
+
// ---------------- FIND ANY DRIZZLE CONFIG ----------------
|
|
63
|
+
function findConfig(){
|
|
64
|
+
const allowedExts = ["js","ts","mjs","cjs","mts"];
|
|
65
|
+
const rootFiles = fs.readdirSync(process.cwd());
|
|
66
|
+
for(const file of rootFiles){
|
|
67
|
+
const match = file.match(/^drizzle\.config\.(.+)$/i);
|
|
68
|
+
if(match && allowedExts.includes(match[1])) return path.join(process.cwd(),file);
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ---------------- CHECK SCHEMA ----------------
|
|
74
|
+
function checkSchema(configPath){
|
|
75
|
+
try{
|
|
76
|
+
const cfg = require(configPath);
|
|
77
|
+
const schemaPath = cfg.default?.schema || cfg.schema;
|
|
78
|
+
if(!schemaPath){
|
|
79
|
+
console.log(`${T.yellow}⚠ Warning: schema not defined in ${path.basename(configPath)}${T.reset}`);
|
|
80
|
+
return true; // optional
|
|
81
|
+
}
|
|
82
|
+
const fullSchema = path.resolve(path.dirname(configPath), schemaPath);
|
|
83
|
+
if(!fs.existsSync(fullSchema)){
|
|
84
|
+
console.log(`${T.red}❌ ERROR: Schema file missing → ${fullSchema}${T.reset}`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
} catch(e){
|
|
89
|
+
console.log(`${T.red}❌ ERROR: Cannot read config → ${e.message}${T.reset}`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ---------------- RUN SHELL COMMAND ----------------
|
|
95
|
+
function runCommand(cmd,label){
|
|
96
|
+
return new Promise((resolve,reject)=>{
|
|
64
97
|
startLoading(label);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
child.stderr.on("data", (data) => {
|
|
71
|
-
const str = data.toString();
|
|
72
|
-
errorOutput += str;
|
|
73
|
-
process.stderr.write(str); // Still show the error to the user
|
|
98
|
+
const child = spawn(cmd,{shell:true,stdio:["inherit","inherit","pipe"]});
|
|
99
|
+
let stderrData = "";
|
|
100
|
+
child.stderr.on("data", d=>{
|
|
101
|
+
stderrData += d.toString();
|
|
102
|
+
process.stderr.write(d);
|
|
74
103
|
});
|
|
75
|
-
|
|
76
|
-
child.on("close", (code) => {
|
|
104
|
+
child.on("close", code=>{
|
|
77
105
|
stopLoading();
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// 2. Presence of "ErrorEvent" or "ENOTFOUND" in stderr (Neon driver specific)
|
|
82
|
-
const hasDriverError = /ErrorEvent|ENOTFOUND|failed to connect/i.test(errorOutput);
|
|
83
|
-
|
|
84
|
-
if (code !== 0 || hasDriverError) {
|
|
85
|
-
reject(new Error(`${label} failed execution.`));
|
|
86
|
-
} else {
|
|
87
|
-
resolve();
|
|
88
|
-
}
|
|
106
|
+
const hasError = code!==0 || /ErrorEvent|ENOTFOUND|failed to connect/i.test(stderrData);
|
|
107
|
+
if(hasError) reject(new Error(`${label} failed!`));
|
|
108
|
+
else resolve();
|
|
89
109
|
});
|
|
90
|
-
|
|
91
|
-
child.on("error", (err) => {
|
|
110
|
+
child.on("error", err=>{
|
|
92
111
|
stopLoading();
|
|
93
112
|
reject(err);
|
|
94
113
|
});
|
|
95
114
|
});
|
|
96
115
|
}
|
|
97
116
|
|
|
98
|
-
//
|
|
99
|
-
let isRunning
|
|
100
|
-
|
|
117
|
+
// ---------------- ENGINE ----------------
|
|
118
|
+
let isRunning=false;
|
|
119
|
+
async function triggerEngine(){
|
|
120
|
+
if(isRunning) return;
|
|
121
|
+
isRunning=true;
|
|
122
|
+
|
|
123
|
+
const configPath = findConfig();
|
|
124
|
+
if(!configPath){
|
|
125
|
+
console.log(`${T.red}❌ ERROR: No drizzle config found!${T.reset}`);
|
|
126
|
+
console.log(`${T.yellow}Expected one of: drizzle.config.js/ts/mjs/cjs/mts${T.reset}`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
101
129
|
|
|
102
|
-
|
|
103
|
-
if (isRunning) return;
|
|
104
|
-
isRunning = true;
|
|
130
|
+
checkSchema(configPath);
|
|
105
131
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
];
|
|
132
|
+
const steps = [
|
|
133
|
+
{name:"Integrity Check", cmd:"npx drizzle-kit check"},
|
|
134
|
+
{name:"Generate Migration", cmd:"npx drizzle-kit generate"},
|
|
135
|
+
{name:"Push Database", cmd:"npx drizzle-kit push"}
|
|
136
|
+
];
|
|
112
137
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
console.log(`\n${T.lime}${T.bold}🎉 SUCCESS: Database synced.${T.reset}\n`);
|
|
118
|
-
isBroken = false;
|
|
119
|
-
} catch (err) {
|
|
120
|
-
isBroken = true;
|
|
121
|
-
console.log(`\n${T.red}${T.bold}🚨 CRITICAL STOP:${T.reset} ${err.message}`);
|
|
122
|
-
console.log(`${T.yellow}Execution paused. Fix the error and save any file to retry.${T.reset}\n`);
|
|
123
|
-
|
|
124
|
-
if (process.argv.includes('--postinstall')) {
|
|
125
|
-
process.exit(1);
|
|
138
|
+
try{
|
|
139
|
+
for(const step of steps){
|
|
140
|
+
await runCommand(step.cmd,step.name);
|
|
126
141
|
}
|
|
127
|
-
|
|
128
|
-
|
|
142
|
+
console.log(`\n${T.lime}🎉 SUCCESS: All steps finished.${T.reset}\n`);
|
|
143
|
+
} catch(e){
|
|
144
|
+
console.log(`\n${T.red}🚨 CRITICAL STOP: ${e.message}${T.reset}`);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
} finally{
|
|
147
|
+
isRunning=false;
|
|
129
148
|
}
|
|
130
149
|
}
|
|
131
150
|
|
|
132
|
-
//
|
|
133
|
-
|
|
151
|
+
// ---------------- MAIN ----------------
|
|
152
|
+
addTeaScript();
|
|
134
153
|
|
|
135
|
-
const skipWatcher = process.argv.includes(
|
|
154
|
+
const skipWatcher = process.argv.includes("--postinstall");
|
|
136
155
|
|
|
137
|
-
if
|
|
156
|
+
if(skipWatcher){
|
|
138
157
|
triggerEngine();
|
|
139
|
-
}
|
|
158
|
+
}else{
|
|
140
159
|
triggerEngine();
|
|
141
160
|
|
|
142
|
-
try
|
|
161
|
+
try{
|
|
143
162
|
const chokidar = require("chokidar");
|
|
144
|
-
let
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
clearTimeout(debounceTimer);
|
|
155
|
-
debounceTimer = setTimeout(() => {
|
|
156
|
-
if (isBroken) console.log(`${T.cyan}🔄 Change detected in ${path}. Retrying...${T.reset}`);
|
|
163
|
+
let timer;
|
|
164
|
+
chokidar.watch(".",{
|
|
165
|
+
ignored:[/node_modules/,/\.git/,/\.next/,/dist/,/out/],
|
|
166
|
+
ignoreInitial:true,
|
|
167
|
+
usePolling:true,
|
|
168
|
+
interval:300
|
|
169
|
+
}).on("all",(e,f)=>{
|
|
170
|
+
clearTimeout(timer);
|
|
171
|
+
timer=setTimeout(()=>{
|
|
172
|
+
console.log(`${T.gray}🔄 Change detected, re-running...${T.reset}`);
|
|
157
173
|
triggerEngine();
|
|
158
|
-
},
|
|
174
|
+
},500);
|
|
159
175
|
});
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
console.log(`${T.yellow}⚠ Chokidar not found. Watch mode disabled.${T.reset}`);
|
|
176
|
+
console.log(`${T.gray}👀 Watching for changes in config/schema...${T.reset}`);
|
|
177
|
+
} catch(e){
|
|
178
|
+
console.log(`${T.yellow}⚠ Chokidar not installed. Watch mode disabled.${T.reset}`);
|
|
164
179
|
}
|
|
165
180
|
}
|
|
166
181
|
|
|
167
|
-
//
|
|
168
|
-
process.on("uncaughtException",
|
|
169
|
-
console.log(
|
|
182
|
+
// ---------------- GLOBAL ERROR CATCH ----------------
|
|
183
|
+
process.on("uncaughtException",err=>{
|
|
184
|
+
console.log(`${T.red}🛡️ UNCAUGHT ERROR: ${err.message}${T.reset}`);
|
|
170
185
|
process.exit(1);
|
|
171
186
|
});
|
|
172
187
|
|
|
173
|
-
process.on("SIGINT",
|
|
174
|
-
console.log(
|
|
188
|
+
process.on("SIGINT",()=>{
|
|
189
|
+
console.log(`${T.yellow}Shutting down Drizzle-Auto...${T.reset}`);
|
|
175
190
|
process.exit(0);
|
|
176
|
-
});
|
|
191
|
+
});
|