gencow 0.1.116 → 0.1.118
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/bin/gencow.mjs +116 -15
- package/core/index.js +3 -1
- package/dashboard/assets/index-C26b7MIs.js +372 -0
- package/dashboard/index.html +1 -1
- package/package.json +1 -1
- package/server/index.js +9173 -5
- package/server/index.js.map +4 -4
- package/dashboard/assets/index-Bur5ZNpv.js +0 -372
package/bin/gencow.mjs
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { execSync, spawn } from "child_process";
|
|
19
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, cpSync, readdirSync, rmSync, statSync, symlinkSync, copyFileSync } from "fs";
|
|
19
|
+
import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync, unlinkSync, cpSync, readdirSync, rmSync, statSync, symlinkSync, copyFileSync } from "fs";
|
|
20
20
|
import { resolve, dirname, basename } from "path";
|
|
21
21
|
import { homedir } from "os";
|
|
22
22
|
import { fileURLToPath } from "url";
|
|
@@ -232,17 +232,108 @@ function isStandaloneProject() {
|
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
/**
|
|
235
|
-
* drizzle-kit CLI 명령어 빌드 — 로컬 바이너리 우선
|
|
235
|
+
* drizzle-kit CLI 명령어 빌드 — 로컬 바이너리 우선 사용 + esbuild 정합성 체크.
|
|
236
236
|
* pnpm 모노레포에서 npx가 esbuild 네이티브 바이너리를 잘못 resolve하여
|
|
237
237
|
* "Host version X does not match binary version Y" 에러 방지.
|
|
238
|
-
*
|
|
238
|
+
*
|
|
239
|
+
* 반환: { cmd: string, env: Record<string, string> }
|
|
240
|
+
* - cmd: 실행할 drizzle-kit 명령어
|
|
241
|
+
* - env: esbuild 불일치 시 ESBUILD_BINARY_PATH를 포함한 환경변수
|
|
239
242
|
*/
|
|
240
243
|
function _drizzleKitCmd(subcmd) {
|
|
241
244
|
const localBin = resolve(process.cwd(), "node_modules/.bin/drizzle-kit");
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
|
|
245
|
+
const cmd = existsSync(localBin) ? `"${localBin}" ${subcmd}` : `npx drizzle-kit ${subcmd}`;
|
|
246
|
+
const env = _ensureEsbuildConsistency();
|
|
247
|
+
return { cmd, env };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* esbuild JS host와 네이티브 바이너리 버전 정합성 체크.
|
|
252
|
+
* 불일치 감지 시:
|
|
253
|
+
* 1) 즉시: ESBUILD_BINARY_PATH로 올바른 바이너리 지정 (이번 실행 성공)
|
|
254
|
+
* 2) 영구: .npmrc에 hoisting 차단 규칙 추가 (다음 pnpm install 시 완전 해결)
|
|
255
|
+
*
|
|
256
|
+
* 결과는 프로세스당 1회만 계산하여 캐싱 (watch 모드에서 반복 파일 I/O 방지).
|
|
257
|
+
*
|
|
258
|
+
* @returns {Record<string, string>} 환경변수 (정상이면 빈 객체)
|
|
259
|
+
*/
|
|
260
|
+
let _esbuildEnvCache = null;
|
|
261
|
+
function _ensureEsbuildConsistency() {
|
|
262
|
+
if (_esbuildEnvCache !== null) return _esbuildEnvCache;
|
|
263
|
+
try {
|
|
264
|
+
const cwd = process.cwd();
|
|
265
|
+
const esbuildPkg = resolve(cwd, "node_modules/esbuild/package.json");
|
|
266
|
+
if (!existsSync(esbuildPkg)) return (_esbuildEnvCache = {});
|
|
267
|
+
|
|
268
|
+
const hostVersion = JSON.parse(readFileSync(esbuildPkg, "utf8")).version;
|
|
269
|
+
const platform = process.platform;
|
|
270
|
+
const arch = process.arch;
|
|
271
|
+
const binaryPkg = resolve(cwd, `node_modules/@esbuild/${platform}-${arch}/package.json`);
|
|
272
|
+
if (!existsSync(binaryPkg)) return (_esbuildEnvCache = {});
|
|
273
|
+
|
|
274
|
+
const binaryVersion = JSON.parse(readFileSync(binaryPkg, "utf8")).version;
|
|
275
|
+
if (hostVersion === binaryVersion) return (_esbuildEnvCache = {});
|
|
276
|
+
|
|
277
|
+
// ── 불일치 감지 → 2단계 수정 ──
|
|
278
|
+
warn(`esbuild 버전 불일치 감지: host=${hostVersion}, binary=${binaryVersion}`);
|
|
279
|
+
|
|
280
|
+
const env = {};
|
|
281
|
+
|
|
282
|
+
// 1) 즉시 우회: pnpm virtual store에서 올바른 바이너리 resolve
|
|
283
|
+
try {
|
|
284
|
+
const req = createRequire(resolve(cwd, "node_modules/drizzle-kit/package.json"));
|
|
285
|
+
const esbuildDir = dirname(req.resolve("esbuild/package.json"));
|
|
286
|
+
const esbuildVer = JSON.parse(readFileSync(resolve(esbuildDir, "package.json"), "utf8")).version;
|
|
287
|
+
const reqFromEsbuild = createRequire(resolve(esbuildDir, "package.json"));
|
|
288
|
+
try {
|
|
289
|
+
const platformPkgDir = dirname(reqFromEsbuild.resolve(`@esbuild/${platform}-${arch}/package.json`));
|
|
290
|
+
const binary = resolve(platformPkgDir, "bin/esbuild");
|
|
291
|
+
if (existsSync(binary)) {
|
|
292
|
+
env.ESBUILD_BINARY_PATH = binary;
|
|
293
|
+
info(`ESBUILD_BINARY_PATH → esbuild@${esbuildVer} 바이너리 사용`);
|
|
294
|
+
}
|
|
295
|
+
} catch { /* platform binary resolve 실패 — fallback 없이 계속 */ }
|
|
296
|
+
} catch { /* drizzle-kit esbuild resolve 실패 */ }
|
|
297
|
+
|
|
298
|
+
// 2) 영구 수정: .npmrc에 hoisting 차단 규칙 추가
|
|
299
|
+
_patchNpmrcForEsbuild(cwd);
|
|
300
|
+
|
|
301
|
+
return (_esbuildEnvCache = env);
|
|
302
|
+
} catch { return (_esbuildEnvCache = {}); }
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* 모노레포 루트의 .npmrc에 esbuild hoisting 차단 규칙을 추가.
|
|
307
|
+
* 이미 존재하면 스킵.
|
|
308
|
+
*/
|
|
309
|
+
function _patchNpmrcForEsbuild(cwd) {
|
|
310
|
+
try {
|
|
311
|
+
// pnpm-workspace.yaml이 있는 디렉토리를 모노레포 루트로 판단
|
|
312
|
+
let dir = cwd;
|
|
313
|
+
for (let i = 0; i < 10; i++) {
|
|
314
|
+
if (existsSync(resolve(dir, "pnpm-workspace.yaml"))) {
|
|
315
|
+
const npmrcPath = resolve(dir, ".npmrc");
|
|
316
|
+
const content = existsSync(npmrcPath) ? readFileSync(npmrcPath, "utf8") : "";
|
|
317
|
+
if (!content.includes("hoist-pattern[]=!@esbuild/*")) {
|
|
318
|
+
const patch = [
|
|
319
|
+
"",
|
|
320
|
+
"# [gencow] esbuild 네이티브 바이너리 hoisting 충돌 방지 (자동 추가)",
|
|
321
|
+
"# 📄 docs/analysis/analysis-deploy-esbuild-version-mismatch.md",
|
|
322
|
+
"hoist-pattern[]=!@esbuild/*",
|
|
323
|
+
"hoist-pattern[]=!esbuild",
|
|
324
|
+
"",
|
|
325
|
+
].join("\n");
|
|
326
|
+
appendFileSync(npmrcPath, patch);
|
|
327
|
+
info(".npmrc에 esbuild hoisting 차단 규칙을 추가했습니다.");
|
|
328
|
+
info("다음 pnpm install 시 영구 적용됩니다.");
|
|
329
|
+
}
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const parent = resolve(dir, "..");
|
|
333
|
+
if (parent === dir) break;
|
|
334
|
+
dir = parent;
|
|
335
|
+
}
|
|
336
|
+
} catch { /* .npmrc 수정 실패 — 무시 (즉시 우회로 이번 실행은 문제 없음) */ }
|
|
246
337
|
}
|
|
247
338
|
|
|
248
339
|
function findServerRoot() {
|
|
@@ -1310,9 +1401,10 @@ ${hasPrompt ? `
|
|
|
1310
1401
|
});
|
|
1311
1402
|
} else {
|
|
1312
1403
|
// Standalone: use npx drizzle-kit directly
|
|
1313
|
-
|
|
1404
|
+
const dk = _drizzleKitCmd("generate");
|
|
1405
|
+
execSync(dk.cmd, {
|
|
1314
1406
|
cwd: process.cwd(),
|
|
1315
|
-
env: genEnv,
|
|
1407
|
+
env: { ...genEnv, ...dk.env },
|
|
1316
1408
|
stdio: "inherit", // 프롬프트 패스스루 (rename 등)
|
|
1317
1409
|
});
|
|
1318
1410
|
}
|
|
@@ -1494,8 +1586,10 @@ ${hasPrompt ? `
|
|
|
1494
1586
|
// 🆕 로컬 drizzle-kit generate 실행 (프롬프트 패스스루)
|
|
1495
1587
|
info("스키마 마이그레이션 생성 중...");
|
|
1496
1588
|
try {
|
|
1497
|
-
|
|
1589
|
+
const dk = _drizzleKitCmd("generate");
|
|
1590
|
+
execSync(dk.cmd, {
|
|
1498
1591
|
cwd: process.cwd(),
|
|
1592
|
+
env: { ...process.env, ...dk.env },
|
|
1499
1593
|
stdio: "inherit",
|
|
1500
1594
|
});
|
|
1501
1595
|
success("마이그레이션 생성 완료");
|
|
@@ -1562,9 +1656,10 @@ ${hasPrompt ? `
|
|
|
1562
1656
|
runInServer("pnpm db:generate", buildEnv(config));
|
|
1563
1657
|
} else {
|
|
1564
1658
|
// Standalone: npx drizzle-kit generate (프롬프트 패스스루)
|
|
1565
|
-
|
|
1659
|
+
const dk = _drizzleKitCmd("generate");
|
|
1660
|
+
execSync(dk.cmd, {
|
|
1566
1661
|
cwd: process.cwd(),
|
|
1567
|
-
env: buildEnv(config),
|
|
1662
|
+
env: { ...buildEnv(config), ...dk.env },
|
|
1568
1663
|
stdio: "inherit",
|
|
1569
1664
|
});
|
|
1570
1665
|
}
|
|
@@ -2046,8 +2141,10 @@ ${BOLD}Examples:${RESET}
|
|
|
2046
2141
|
});
|
|
2047
2142
|
} else {
|
|
2048
2143
|
// Standalone: npx drizzle-kit generate (프롬프트 패스스루 — rename 감지 대화형 포함)
|
|
2049
|
-
|
|
2144
|
+
const dk = _drizzleKitCmd("generate");
|
|
2145
|
+
execGen(dk.cmd, {
|
|
2050
2146
|
cwd: process.cwd(),
|
|
2147
|
+
env: { ...process.env, ...dk.env },
|
|
2051
2148
|
stdio: "inherit",
|
|
2052
2149
|
});
|
|
2053
2150
|
}
|
|
@@ -2572,8 +2669,10 @@ ${BOLD}Examples:${RESET}
|
|
|
2572
2669
|
if (existsSync(schemaPath)) {
|
|
2573
2670
|
info("스키마 마이그레이션 생성 중...");
|
|
2574
2671
|
try {
|
|
2575
|
-
|
|
2672
|
+
const dk = _drizzleKitCmd("generate");
|
|
2673
|
+
execSync(dk.cmd, {
|
|
2576
2674
|
cwd: backendRoot,
|
|
2675
|
+
env: { ...process.env, ...dk.env },
|
|
2577
2676
|
stdio: "inherit", // ← 프롬프트 패스스루!
|
|
2578
2677
|
});
|
|
2579
2678
|
success("마이그레이션 생성 완료");
|
|
@@ -4333,8 +4432,10 @@ process.exit(0);
|
|
|
4333
4432
|
}
|
|
4334
4433
|
try {
|
|
4335
4434
|
const { execSync } = await import("child_process");
|
|
4336
|
-
|
|
4435
|
+
const dk = _drizzleKitCmd("generate");
|
|
4436
|
+
execSync(dk.cmd, {
|
|
4337
4437
|
cwd: process.cwd(),
|
|
4438
|
+
env: { ...process.env, ...dk.env },
|
|
4338
4439
|
stdio: "inherit",
|
|
4339
4440
|
});
|
|
4340
4441
|
log(`${DIM}${ts}${RESET} ${GREEN}[migrate]${RESET} ✔ 마이그레이션 생성 완료`);
|
package/core/index.js
CHANGED
|
@@ -1800,11 +1800,13 @@ function parseArgs(schema, args) {
|
|
|
1800
1800
|
}
|
|
1801
1801
|
}
|
|
1802
1802
|
if (typeof schema === "object" && schema !== null) {
|
|
1803
|
+
const schemaKeys = Object.keys(schema);
|
|
1804
|
+
if (schemaKeys.length === 0) return args;
|
|
1803
1805
|
if (typeof args !== "object" || args === null) {
|
|
1804
1806
|
throw new GencowValidationError("Expected an object for arguments");
|
|
1805
1807
|
}
|
|
1806
1808
|
const result = {};
|
|
1807
|
-
for (const key
|
|
1809
|
+
for (const key of schemaKeys) {
|
|
1808
1810
|
const validator = schema[key];
|
|
1809
1811
|
if (validator && typeof validator.parse === "function") {
|
|
1810
1812
|
try {
|