drizzle-auto 1.1.3 → 1.1.4
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 +147 -121
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,155 +1,181 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
const path = require("path");
|
|
5
3
|
const chokidar = require("chokidar");
|
|
6
4
|
const { spawn } = require("child_process");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const fs = require("fs");
|
|
7
7
|
|
|
8
|
-
/*
|
|
9
|
-
🎨
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
console.log(`${C.green}☕ Added:${C.reset} npm run tea`);
|
|
8
|
+
/* =======================
|
|
9
|
+
🎨 NeonPulse UI Core
|
|
10
|
+
======================= */
|
|
11
|
+
const PALETTE = ["\x1b[31m", "\x1b[32m", "\x1b[33m", "\x1b[34m", "\x1b[35m", "\x1b[36m"];
|
|
12
|
+
const RESET = "\x1b[0m";
|
|
13
|
+
const BOLD = "\x1b[1m";
|
|
14
|
+
const DIM = "\x1b[90m";
|
|
15
|
+
|
|
16
|
+
let colorIndex = 0;
|
|
17
|
+
const nextColor = () => PALETTE[colorIndex++ % PALETTE.length];
|
|
18
|
+
const rainbow = (text) => text.split("").map((c) => `${nextColor()}${c}`).join("") + RESET;
|
|
19
|
+
|
|
20
|
+
/* =======================
|
|
21
|
+
⏳ Dynamic Spinner
|
|
22
|
+
======================= */
|
|
23
|
+
const spinnerFrames = ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];
|
|
24
|
+
let spinIndex = 0;
|
|
25
|
+
let spinnerInterval;
|
|
26
|
+
|
|
27
|
+
function startSpinner(text) {
|
|
28
|
+
stopSpinner();
|
|
29
|
+
spinnerInterval = setInterval(() => {
|
|
30
|
+
process.stdout.write(`\r${nextColor()}${spinnerFrames[spinIndex++ % spinnerFrames.length]} ${text}${RESET}`);
|
|
31
|
+
}, 80);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function stopSpinner() {
|
|
35
|
+
if (spinnerInterval) {
|
|
36
|
+
clearInterval(spinnerInterval);
|
|
37
|
+
spinnerInterval = null;
|
|
38
|
+
process.stdout.write("\r\x1b[K");
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
/*
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
42
|
+
/* =======================
|
|
43
|
+
🧠 5-Step Logic Engine
|
|
44
|
+
======================= */
|
|
45
|
+
let isRunning = false;
|
|
46
|
+
let hasActiveError = false;
|
|
47
|
+
|
|
48
|
+
// [STEP 2]: Justify All Infrastructure Files (Dynamic Format Support)
|
|
49
|
+
function justifyFiles() {
|
|
50
|
+
const root = process.cwd();
|
|
51
|
+
|
|
52
|
+
// চেক ১: কনফিগ ফাইল (js, mjs, ts, mts)
|
|
53
|
+
const config = ["ts", "js", "mjs", "mts"]
|
|
54
|
+
.map(ext => `drizzle.config.${ext}`)
|
|
55
|
+
.find(f => fs.existsSync(path.join(root, f)));
|
|
56
|
+
|
|
57
|
+
if (!config) return { ok: false, msg: "drizzle.config.(ts/js/mjs/mts) not found in project." };
|
|
58
|
+
|
|
59
|
+
// চেক ২: স্কিমা ফাইল জাস্টিফিকেশন (কনফিগ থেকে ডাইনামিকালি পাথ রিড করা)
|
|
60
|
+
try {
|
|
61
|
+
const content = fs.readFileSync(path.join(root, config), "utf8");
|
|
62
|
+
const schemaMatch = content.match(/schema:\s*["'](.+?)["']/);
|
|
63
|
+
if (schemaMatch && schemaMatch[1]) {
|
|
64
|
+
const schemaPath = path.join(root, schemaMatch[1]);
|
|
65
|
+
if (!fs.existsSync(schemaPath)) return { ok: false, msg: `Schema file missing at: ${schemaMatch[1]}` };
|
|
64
66
|
}
|
|
65
|
-
}
|
|
67
|
+
} catch (e) {
|
|
68
|
+
return { ok: false, msg: "Failed to read or parse config file." };
|
|
69
|
+
}
|
|
66
70
|
|
|
67
|
-
return
|
|
71
|
+
return { ok: true };
|
|
68
72
|
}
|
|
69
73
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
========================= */
|
|
73
|
-
function run(cmd, args) {
|
|
74
|
+
// [STEP 3, 4, 5]: Command Executor with Strict Error Halt
|
|
75
|
+
function executeCommand(args, stepName) {
|
|
74
76
|
return new Promise((resolve) => {
|
|
75
|
-
let
|
|
77
|
+
let hasError = false;
|
|
78
|
+
startSpinner(`[${stepName}] In Progress...`);
|
|
79
|
+
|
|
80
|
+
const child = spawn("npx", args, { shell: true });
|
|
76
81
|
|
|
77
|
-
|
|
82
|
+
child.stdout.on("data", (data) => {
|
|
83
|
+
const out = data.toString();
|
|
84
|
+
// Spam filter for cloud/server-side DB pulling logs
|
|
85
|
+
if (!out.includes('Pulling schema')) {
|
|
86
|
+
stopSpinner();
|
|
87
|
+
process.stdout.write(`${DIM}${out}${RESET}`);
|
|
88
|
+
}
|
|
89
|
+
if (/error|failed|ENOTFOUND|ECONNREFUSED/i.test(out)) hasError = true;
|
|
90
|
+
});
|
|
78
91
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
process.stderr.write(
|
|
92
|
+
child.stderr.on("data", (data) => {
|
|
93
|
+
const err = data.toString();
|
|
94
|
+
stopSpinner();
|
|
95
|
+
process.stderr.write(`\x1b[31m${err}${RESET}`);
|
|
96
|
+
hasError = true;
|
|
83
97
|
});
|
|
84
98
|
|
|
85
|
-
|
|
86
|
-
|
|
99
|
+
child.on("close", (code) => {
|
|
100
|
+
stopSpinner();
|
|
101
|
+
resolve(code === 0 && !hasError);
|
|
87
102
|
});
|
|
88
103
|
});
|
|
89
104
|
}
|
|
90
105
|
|
|
91
|
-
/*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
console.log(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
/* =======================
|
|
107
|
+
🔄 The Sequential Workflow
|
|
108
|
+
======================= */
|
|
109
|
+
async function startWorkflow(trigger) {
|
|
110
|
+
if (isRunning) return;
|
|
111
|
+
isRunning = true;
|
|
112
|
+
|
|
113
|
+
if (!hasActiveError) console.clear();
|
|
114
|
+
console.log(BOLD + rainbow("🚀 DRIZZLE-AUTO // UNIVERSAL SERVER-SIDE ENGINE"));
|
|
115
|
+
console.log(`${nextColor()}⚡ Trigger → ${trigger}${RESET}\n`);
|
|
116
|
+
|
|
117
|
+
// STEP 2: Justify Files (Infrastructure Check)
|
|
118
|
+
const audit = justifyFiles();
|
|
119
|
+
if (!audit.ok) {
|
|
120
|
+
console.log(`\n\x1b[31m🛑 STEP 2 FAILED: ${audit.msg}${RESET}`);
|
|
121
|
+
hasActiveError = true;
|
|
122
|
+
isRunning = false;
|
|
106
123
|
return;
|
|
107
124
|
}
|
|
108
125
|
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
if (!
|
|
112
|
-
console.log(
|
|
113
|
-
|
|
126
|
+
// STEP 3: Confirm no bug in code (Integrity Check)
|
|
127
|
+
const step3 = await executeCommand(["drizzle-kit", "check"], "Step 3: Bug Check");
|
|
128
|
+
if (!step3) {
|
|
129
|
+
console.log(`\n\x1b[31m🛑 STEP 3 FAILED: Bugs or Drifts detected. Halting Pipeline.${RESET}`);
|
|
130
|
+
hasActiveError = true;
|
|
131
|
+
isRunning = false;
|
|
114
132
|
return;
|
|
115
133
|
}
|
|
116
134
|
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
push.stderr.includes("websocket")
|
|
126
|
-
) {
|
|
127
|
-
console.log(
|
|
128
|
-
`${C.yellow}⚠ Neon / network issue detected${C.reset}\n` +
|
|
129
|
-
`${C.dim}• Check internet\n` +
|
|
130
|
-
`• Check DATABASE_URL\n` +
|
|
131
|
-
`• Neon endpoint may be sleeping${C.reset}`
|
|
132
|
-
);
|
|
133
|
-
}
|
|
135
|
+
// STEP 4: Run Drizzle Generate
|
|
136
|
+
const step4 = await executeCommand(["drizzle-kit", "generate"], "Step 4: Generate");
|
|
137
|
+
if (!step4) {
|
|
138
|
+
console.log(`\n\x1b[31m🛑 STEP 4 FAILED: Migration generation failed.${RESET}`);
|
|
139
|
+
hasActiveError = true;
|
|
140
|
+
isRunning = false;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
134
143
|
|
|
135
|
-
|
|
136
|
-
|
|
144
|
+
// STEP 5: Push Changes
|
|
145
|
+
const step5 = await executeCommand(["drizzle-kit", "push"], "Step 5: Push");
|
|
146
|
+
if (!step5) {
|
|
147
|
+
console.log(`\n\x1b[31m🛑 STEP 5 FAILED: DB Push failed. Check connection.${RESET}`);
|
|
148
|
+
hasActiveError = true;
|
|
149
|
+
isRunning = false;
|
|
137
150
|
return;
|
|
138
151
|
}
|
|
139
152
|
|
|
140
|
-
|
|
141
|
-
|
|
153
|
+
// ALL STEPS SUCCESS
|
|
154
|
+
hasActiveError = false;
|
|
155
|
+
console.log(`\n\x1b[32m${BOLD}✨ SUCCESS: 5/5 Steps Completed. All systems justified!${RESET}`);
|
|
156
|
+
|
|
157
|
+
setTimeout(() => {
|
|
158
|
+
isRunning = false;
|
|
159
|
+
console.log(`\n${DIM}🛰️ System justified. Watching for next change...${RESET}`);
|
|
160
|
+
}, 2000);
|
|
142
161
|
}
|
|
143
162
|
|
|
144
|
-
/*
|
|
145
|
-
👀
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
chokidar.watch(ROOT, {
|
|
151
|
-
ignored: [/node_modules/, /\.git/, /\.next/, /dist/],
|
|
163
|
+
/* =======================
|
|
164
|
+
👀 Universal Watcher
|
|
165
|
+
======================= */
|
|
166
|
+
chokidar.watch(".", {
|
|
167
|
+
ignored: [/node_modules/, /\.git/, /\.next/, /dist/, /drizzle/],
|
|
152
168
|
ignoreInitial: true,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
});
|
|
169
|
+
usePolling: true,
|
|
170
|
+
interval: 300
|
|
171
|
+
}).on("all", (e, f) => startWorkflow(`${e.toUpperCase()} → ${path.basename(f)}`));
|
|
172
|
+
|
|
173
|
+
// Init Call
|
|
174
|
+
startWorkflow("Initial System Audit");
|
|
175
|
+
|
|
176
|
+
// Safety Net
|
|
177
|
+
process.on("uncaughtException", (err) => {
|
|
178
|
+
stopSpinner();
|
|
179
|
+
console.log(`\n\x1b[31m🛡️ Shield Error: ${err.message}${RESET}`);
|
|
180
|
+
isRunning = false;
|
|
181
|
+
});
|