@invect/cli 0.1.1 → 0.1.2
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/dist/{chunk-5XRZFNIV.js → chunk-ILVFFEI6.js} +258 -106
- package/dist/{generate-SCRZDVJT.js → generate-NXZRLIMQ.js} +1 -2
- package/dist/index.js +212 -85
- package/package.json +2 -2
- package/dist/chunk-LKWAVX5Z.js +0 -109
- package/dist/chunk-Q6JKV7VX.js +0 -157
- package/dist/migrate-A2N3YKVS.js +0 -9
package/dist/index.js
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
generateCommand
|
|
4
|
-
} from "./chunk-5XRZFNIV.js";
|
|
5
|
-
import "./chunk-K4RRNATQ.js";
|
|
6
|
-
import {
|
|
7
|
-
migrateCommand
|
|
8
|
-
} from "./chunk-LKWAVX5Z.js";
|
|
9
2
|
import {
|
|
10
3
|
findConfigPath,
|
|
4
|
+
generateCommand,
|
|
11
5
|
loadConfig
|
|
12
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ILVFFEI6.js";
|
|
7
|
+
import "./chunk-K4RRNATQ.js";
|
|
13
8
|
|
|
14
9
|
// src/index.ts
|
|
15
|
-
import { Command as
|
|
10
|
+
import { Command as Command5 } from "commander";
|
|
16
11
|
|
|
17
12
|
// src/commands/init.ts
|
|
18
13
|
import { Command } from "commander";
|
|
@@ -186,20 +181,35 @@ ${envLine}
|
|
|
186
181
|
`);
|
|
187
182
|
console.log(pc.green(` \u2713 Created .env with INVECT_ENCRYPTION_KEY`));
|
|
188
183
|
}
|
|
184
|
+
step("Setup Drizzle");
|
|
185
|
+
const existingDrizzleConfig = findExistingDrizzleConfig();
|
|
186
|
+
const schemaDir = fs.existsSync(path.join(process.cwd(), "src")) ? "./src/database" : "./database";
|
|
187
|
+
if (existingDrizzleConfig) {
|
|
188
|
+
console.log(pc.dim(` Found existing ${existingDrizzleConfig} \u2014 Invect tables will be appended to your schema`));
|
|
189
|
+
} else {
|
|
190
|
+
const schemaPath = `${schemaDir}/schema.ts`;
|
|
191
|
+
const drizzleConfigCode = generateDrizzleConfigFile(database, schemaPath);
|
|
192
|
+
fs.writeFileSync(
|
|
193
|
+
path.join(process.cwd(), "drizzle.config.ts"),
|
|
194
|
+
drizzleConfigCode,
|
|
195
|
+
"utf-8"
|
|
196
|
+
);
|
|
197
|
+
console.log(pc.green(` \u2713 Created drizzle.config.ts`));
|
|
198
|
+
}
|
|
189
199
|
step("Generate Database Schema");
|
|
190
200
|
const { shouldGenerate } = await prompts({
|
|
191
201
|
type: "confirm",
|
|
192
202
|
name: "shouldGenerate",
|
|
193
|
-
message: "Generate database schema files now?",
|
|
203
|
+
message: existingDrizzleConfig ? "Append Invect tables to your existing schema now?" : "Generate database schema files now?",
|
|
194
204
|
initial: true
|
|
195
205
|
});
|
|
196
206
|
if (shouldGenerate) {
|
|
197
207
|
try {
|
|
198
|
-
const { generateAction } = await import("./generate-
|
|
199
|
-
const schemaDir = fs.existsSync(path.join(process.cwd(), "src")) ? "./src/database" : "./database";
|
|
208
|
+
const { generateAction } = await import("./generate-NXZRLIMQ.js");
|
|
200
209
|
await generateAction({
|
|
201
210
|
config: configPath,
|
|
202
211
|
output: schemaDir,
|
|
212
|
+
dialect: database.id,
|
|
203
213
|
yes: true
|
|
204
214
|
});
|
|
205
215
|
} catch (error) {
|
|
@@ -215,29 +225,6 @@ ${envLine}
|
|
|
215
225
|
)
|
|
216
226
|
);
|
|
217
227
|
}
|
|
218
|
-
if (database.id === "sqlite" && shouldGenerate) {
|
|
219
|
-
const { shouldMigrate } = await prompts({
|
|
220
|
-
type: "confirm",
|
|
221
|
-
name: "shouldMigrate",
|
|
222
|
-
message: "Run database migration now? (creates the SQLite database)",
|
|
223
|
-
initial: true
|
|
224
|
-
});
|
|
225
|
-
if (shouldMigrate) {
|
|
226
|
-
try {
|
|
227
|
-
const { migrateAction } = await import("./migrate-A2N3YKVS.js");
|
|
228
|
-
await migrateAction({
|
|
229
|
-
config: configPath,
|
|
230
|
-
yes: true,
|
|
231
|
-
push: true
|
|
232
|
-
// Use push for quick dev setup
|
|
233
|
-
});
|
|
234
|
-
} catch {
|
|
235
|
-
console.error(
|
|
236
|
-
pc.yellow(" \u26A0 Migration failed. You can run it manually:") + "\n" + pc.dim(" npx invect-cli migrate\n")
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
228
|
console.log(pc.bold(pc.green("\n\u2713 Invect initialized successfully!\n")));
|
|
242
229
|
console.log(pc.dim(" Next steps:"));
|
|
243
230
|
const nextSteps = [];
|
|
@@ -250,8 +237,8 @@ ${envLine}
|
|
|
250
237
|
}
|
|
251
238
|
if (!shouldGenerate) {
|
|
252
239
|
nextSteps.push(` ${n++}. Run ${pc.cyan("npx invect-cli generate")} to create schema files`);
|
|
240
|
+
nextSteps.push(` ${n++}. Run ${pc.cyan("npx drizzle-kit push")} to apply the schema`);
|
|
253
241
|
}
|
|
254
|
-
nextSteps.push(` ${n++}. Run ${pc.cyan("npx invect-cli migrate")} to apply the schema`);
|
|
255
242
|
if (framework.id === "express") {
|
|
256
243
|
nextSteps.push(` ${n++}. Mount the router: ${pc.cyan("app.use('/invect', createInvectRouter(config))")}`);
|
|
257
244
|
} else if (framework.id === "nextjs") {
|
|
@@ -355,14 +342,154 @@ function getInstallCommand(pm, packages, isDev) {
|
|
|
355
342
|
const cmd = pm === "npm" ? "npm install" : `${pm} add`;
|
|
356
343
|
return `${cmd} ${flag} ${packages.join(" ")}`.replace(/\s+/g, " ").trim();
|
|
357
344
|
}
|
|
345
|
+
function findExistingDrizzleConfig() {
|
|
346
|
+
const candidates = [
|
|
347
|
+
"drizzle.config.ts",
|
|
348
|
+
"drizzle.config.js",
|
|
349
|
+
"drizzle.config.mjs"
|
|
350
|
+
];
|
|
351
|
+
for (const file of candidates) {
|
|
352
|
+
if (fs.existsSync(path.join(process.cwd(), file))) {
|
|
353
|
+
return file;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
function generateDrizzleConfigFile(database, schemaPath) {
|
|
359
|
+
const dbCredentials = {
|
|
360
|
+
sqlite: ` dbCredentials: {
|
|
361
|
+
url: process.env.DATABASE_URL || './dev.db',
|
|
362
|
+
},`,
|
|
363
|
+
postgresql: ` dbCredentials: {
|
|
364
|
+
url: process.env.DATABASE_URL || 'postgresql://localhost:5432/invect',
|
|
365
|
+
},`,
|
|
366
|
+
mysql: ` dbCredentials: {
|
|
367
|
+
url: process.env.DATABASE_URL || 'mysql://root@localhost:3306/invect',
|
|
368
|
+
},`
|
|
369
|
+
};
|
|
370
|
+
const dialectMap = {
|
|
371
|
+
sqlite: "sqlite",
|
|
372
|
+
postgresql: "postgresql",
|
|
373
|
+
mysql: "mysql"
|
|
374
|
+
};
|
|
375
|
+
return `import { defineConfig } from 'drizzle-kit';
|
|
358
376
|
|
|
359
|
-
|
|
377
|
+
export default defineConfig({
|
|
378
|
+
out: './drizzle',
|
|
379
|
+
schema: '${schemaPath}',
|
|
380
|
+
dialect: '${dialectMap[database.id]}',
|
|
381
|
+
${dbCredentials[database.id]}
|
|
382
|
+
});
|
|
383
|
+
`;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/commands/migrate.ts
|
|
360
387
|
import { Command as Command2 } from "commander";
|
|
361
388
|
import path2 from "path";
|
|
362
389
|
import fs2 from "fs";
|
|
363
|
-
import os from "os";
|
|
364
390
|
import pc2 from "picocolors";
|
|
365
|
-
|
|
391
|
+
import prompts2 from "prompts";
|
|
392
|
+
import { execSync as execSync2 } from "child_process";
|
|
393
|
+
var migrateCommand = new Command2("migrate").description("Apply pending database migrations via Drizzle Kit").option("--config <path>", "Path to your Invect config file").option("-y, --yes", "Skip confirmation prompt").option("--push", "Push schema directly without migration files (dev mode)").action(migrateAction);
|
|
394
|
+
async function migrateAction(options) {
|
|
395
|
+
console.log(pc2.bold("\n\u{1F5C4}\uFE0F Invect Migration\n"));
|
|
396
|
+
const configPath = findConfigPath(options.config);
|
|
397
|
+
if (!configPath) {
|
|
398
|
+
console.error(
|
|
399
|
+
pc2.red("\u2717 Could not find Invect config file.") + "\n" + pc2.dim(" Use --config <path> to specify the config file explicitly.") + "\n\n" + pc2.dim(" You can create one with: " + pc2.cyan("npx invect-cli init")) + "\n"
|
|
400
|
+
);
|
|
401
|
+
process.exit(1);
|
|
402
|
+
}
|
|
403
|
+
console.log(pc2.dim(` Config: ${path2.relative(process.cwd(), configPath)}`));
|
|
404
|
+
let config;
|
|
405
|
+
try {
|
|
406
|
+
config = await loadConfig(configPath);
|
|
407
|
+
} catch (error) {
|
|
408
|
+
console.error(pc2.red(`\u2717 ${error instanceof Error ? error.message : String(error)}`));
|
|
409
|
+
process.exit(1);
|
|
410
|
+
}
|
|
411
|
+
const dbType = config.baseDatabaseConfig?.type;
|
|
412
|
+
const dbUrl = config.baseDatabaseConfig?.connectionString;
|
|
413
|
+
if (!dbType) {
|
|
414
|
+
console.error(
|
|
415
|
+
pc2.red("\u2717 No baseDatabaseConfig.type found in your config.") + "\n" + pc2.dim(
|
|
416
|
+
' Expected: baseDatabaseConfig: { type: "sqlite" | "postgresql" | "mysql", ... }'
|
|
417
|
+
) + "\n"
|
|
418
|
+
);
|
|
419
|
+
process.exit(1);
|
|
420
|
+
}
|
|
421
|
+
console.log(pc2.dim(` Database: ${dbType}`));
|
|
422
|
+
if (dbUrl) {
|
|
423
|
+
const redacted = dbUrl.replace(/:\/\/[^@]+@/, "://***@");
|
|
424
|
+
console.log(pc2.dim(` Connection: ${redacted}`));
|
|
425
|
+
}
|
|
426
|
+
const mode = options.push ? "push" : "migrate";
|
|
427
|
+
console.log(pc2.dim(` Mode: ${mode === "push" ? "push (direct schema sync)" : "migrate (SQL migration files)"}`));
|
|
428
|
+
if (!options.yes) {
|
|
429
|
+
const message = mode === "push" ? `Push schema directly to your ${dbType} database?` : `Apply pending migrations to your ${dbType} database?`;
|
|
430
|
+
const response = await prompts2({
|
|
431
|
+
type: "confirm",
|
|
432
|
+
name: "proceed",
|
|
433
|
+
message,
|
|
434
|
+
initial: true
|
|
435
|
+
});
|
|
436
|
+
if (!response.proceed) {
|
|
437
|
+
console.log(pc2.dim("\n Cancelled.\n"));
|
|
438
|
+
process.exit(0);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
console.log(pc2.dim(`
|
|
442
|
+
Running drizzle-kit ${mode}...
|
|
443
|
+
`));
|
|
444
|
+
try {
|
|
445
|
+
const drizzleConfigFile = detectDrizzleConfig(dbType);
|
|
446
|
+
const configFlag = drizzleConfigFile ? ` --config ${drizzleConfigFile}` : "";
|
|
447
|
+
const cmd = `npx drizzle-kit ${mode}${configFlag}`;
|
|
448
|
+
execSync2(cmd, {
|
|
449
|
+
stdio: "inherit",
|
|
450
|
+
cwd: process.cwd()
|
|
451
|
+
});
|
|
452
|
+
if (mode === "push") {
|
|
453
|
+
console.log(pc2.bold(pc2.green("\n\u2713 Schema pushed successfully!\n")));
|
|
454
|
+
} else {
|
|
455
|
+
console.log(pc2.bold(pc2.green("\n\u2713 Migrations applied successfully!\n")));
|
|
456
|
+
}
|
|
457
|
+
} catch {
|
|
458
|
+
console.error(pc2.red(`
|
|
459
|
+
\u2717 drizzle-kit ${mode} failed.`));
|
|
460
|
+
console.error(
|
|
461
|
+
pc2.dim(" Make sure drizzle-kit is installed and your drizzle config is correct.\n")
|
|
462
|
+
);
|
|
463
|
+
if (mode === "migrate") {
|
|
464
|
+
console.error(
|
|
465
|
+
pc2.dim(" Have you generated migrations? Run: ") + pc2.cyan("npx invect-cli generate") + "\n"
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
process.exit(1);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
function detectDrizzleConfig(dbType) {
|
|
472
|
+
const candidates = {
|
|
473
|
+
sqlite: ["drizzle.config.sqlite.ts", "drizzle.config.ts"],
|
|
474
|
+
postgresql: ["drizzle.config.postgres.ts", "drizzle.config.postgresql.ts", "drizzle.config.ts"],
|
|
475
|
+
mysql: ["drizzle.config.mysql.ts", "drizzle.config.ts"]
|
|
476
|
+
};
|
|
477
|
+
const searchPaths = candidates[dbType] || ["drizzle.config.ts"];
|
|
478
|
+
for (const filename of searchPaths) {
|
|
479
|
+
if (fs2.existsSync(path2.resolve(process.cwd(), filename))) {
|
|
480
|
+
return filename;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// src/commands/info.ts
|
|
487
|
+
import { Command as Command3 } from "commander";
|
|
488
|
+
import path3 from "path";
|
|
489
|
+
import fs3 from "fs";
|
|
490
|
+
import os from "os";
|
|
491
|
+
import pc3 from "picocolors";
|
|
492
|
+
var infoCommand = new Command3("info").description("Display diagnostic information about your Invect setup").option("--config <path>", "Path to your Invect config file").option("--json", "Output as JSON").action(async (options) => {
|
|
366
493
|
const info = {};
|
|
367
494
|
info.system = {
|
|
368
495
|
os: `${os.platform()} ${os.release()} (${os.arch()})`,
|
|
@@ -379,7 +506,7 @@ var infoCommand = new Command2("info").description("Display diagnostic informati
|
|
|
379
506
|
info.databases = detectDatabaseTools();
|
|
380
507
|
const configPath = findConfigPath(options.config);
|
|
381
508
|
if (configPath) {
|
|
382
|
-
info.configPath =
|
|
509
|
+
info.configPath = path3.relative(process.cwd(), configPath);
|
|
383
510
|
try {
|
|
384
511
|
const config = await loadConfig(configPath);
|
|
385
512
|
info.plugins = config.plugins.map((p) => ({
|
|
@@ -404,73 +531,73 @@ var infoCommand = new Command2("info").description("Display diagnostic informati
|
|
|
404
531
|
}
|
|
405
532
|
});
|
|
406
533
|
function printInfo(info) {
|
|
407
|
-
console.log(
|
|
534
|
+
console.log(pc3.bold("\n\u{1F4CB} Invect Info\n"));
|
|
408
535
|
const sys = info.system;
|
|
409
|
-
console.log(
|
|
410
|
-
console.log(
|
|
411
|
-
console.log(
|
|
412
|
-
console.log(
|
|
413
|
-
console.log(
|
|
536
|
+
console.log(pc3.bold(" System:"));
|
|
537
|
+
console.log(pc3.dim(` OS: ${sys.os}`));
|
|
538
|
+
console.log(pc3.dim(` CPU: ${sys.cpu}`));
|
|
539
|
+
console.log(pc3.dim(` Memory: ${sys.memory}`));
|
|
540
|
+
console.log(pc3.dim(` Node: ${sys.nodeVersion}`));
|
|
414
541
|
console.log("");
|
|
415
542
|
const pm = info.packageManager;
|
|
416
|
-
console.log(
|
|
417
|
-
console.log(
|
|
543
|
+
console.log(pc3.bold(" Package Manager:"));
|
|
544
|
+
console.log(pc3.dim(` ${pm}`));
|
|
418
545
|
console.log("");
|
|
419
546
|
const imp = info.invect;
|
|
420
|
-
console.log(
|
|
421
|
-
console.log(
|
|
422
|
-
console.log(
|
|
547
|
+
console.log(pc3.bold(" Invect:"));
|
|
548
|
+
console.log(pc3.dim(` CLI: ${imp.cliVersion}`));
|
|
549
|
+
console.log(pc3.dim(` Core: ${imp.coreVersion}`));
|
|
423
550
|
console.log("");
|
|
424
551
|
const fw = info.frameworks;
|
|
425
|
-
console.log(
|
|
552
|
+
console.log(pc3.bold(" Frameworks:"));
|
|
426
553
|
if (fw.length > 0) {
|
|
427
554
|
for (const f of fw) {
|
|
428
|
-
console.log(
|
|
555
|
+
console.log(pc3.dim(` \u2713 ${f}`));
|
|
429
556
|
}
|
|
430
557
|
} else {
|
|
431
|
-
console.log(
|
|
558
|
+
console.log(pc3.dim(" (none detected)"));
|
|
432
559
|
}
|
|
433
560
|
console.log("");
|
|
434
561
|
const db = info.databases;
|
|
435
|
-
console.log(
|
|
562
|
+
console.log(pc3.bold(" Database Tools:"));
|
|
436
563
|
if (db.length > 0) {
|
|
437
564
|
for (const d of db) {
|
|
438
|
-
console.log(
|
|
565
|
+
console.log(pc3.dim(` \u2713 ${d}`));
|
|
439
566
|
}
|
|
440
567
|
} else {
|
|
441
|
-
console.log(
|
|
568
|
+
console.log(pc3.dim(" (none detected)"));
|
|
442
569
|
}
|
|
443
570
|
console.log("");
|
|
444
|
-
console.log(
|
|
571
|
+
console.log(pc3.bold(" Config:"));
|
|
445
572
|
if (info.configPath) {
|
|
446
|
-
console.log(
|
|
573
|
+
console.log(pc3.dim(` File: ${info.configPath}`));
|
|
447
574
|
} else {
|
|
448
|
-
console.log(
|
|
575
|
+
console.log(pc3.yellow(` \u26A0 ${info.configError || "Not found"}`));
|
|
449
576
|
}
|
|
450
577
|
const plugins = info.plugins;
|
|
451
578
|
if (plugins && plugins.length > 0) {
|
|
452
579
|
console.log("");
|
|
453
|
-
console.log(
|
|
580
|
+
console.log(pc3.bold(" Plugins:"));
|
|
454
581
|
for (const p of plugins) {
|
|
455
582
|
const schemaInfo = p.hasSchema ? ` (${p.schemaTablesCount} table(s))` : "";
|
|
456
|
-
console.log(
|
|
583
|
+
console.log(pc3.dim(` \u2713 ${p.name}${schemaInfo}`));
|
|
457
584
|
}
|
|
458
585
|
}
|
|
459
586
|
console.log("");
|
|
460
587
|
}
|
|
461
588
|
function detectPackageManager2() {
|
|
462
589
|
const cwd = process.cwd();
|
|
463
|
-
if (
|
|
464
|
-
if (
|
|
465
|
-
if (
|
|
466
|
-
if (
|
|
590
|
+
if (fs3.existsSync(path3.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
591
|
+
if (fs3.existsSync(path3.join(cwd, "bun.lockb")) || fs3.existsSync(path3.join(cwd, "bun.lock"))) return "bun";
|
|
592
|
+
if (fs3.existsSync(path3.join(cwd, "yarn.lock"))) return "yarn";
|
|
593
|
+
if (fs3.existsSync(path3.join(cwd, "package-lock.json"))) return "npm";
|
|
467
594
|
return "unknown";
|
|
468
595
|
}
|
|
469
596
|
async function detectPackageVersion(pkg) {
|
|
470
597
|
try {
|
|
471
|
-
const pkgJsonPath =
|
|
472
|
-
if (
|
|
473
|
-
const pkgJson = JSON.parse(
|
|
598
|
+
const pkgJsonPath = path3.join(process.cwd(), "node_modules", pkg, "package.json");
|
|
599
|
+
if (fs3.existsSync(pkgJsonPath)) {
|
|
600
|
+
const pkgJson = JSON.parse(fs3.readFileSync(pkgJsonPath, "utf-8"));
|
|
474
601
|
return pkgJson.version || "unknown";
|
|
475
602
|
}
|
|
476
603
|
} catch {
|
|
@@ -479,10 +606,10 @@ async function detectPackageVersion(pkg) {
|
|
|
479
606
|
}
|
|
480
607
|
function detectFrameworks() {
|
|
481
608
|
const frameworks = [];
|
|
482
|
-
const pkgPath =
|
|
483
|
-
if (!
|
|
609
|
+
const pkgPath = path3.join(process.cwd(), "package.json");
|
|
610
|
+
if (!fs3.existsSync(pkgPath)) return frameworks;
|
|
484
611
|
try {
|
|
485
|
-
const pkg = JSON.parse(
|
|
612
|
+
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
486
613
|
const allDeps = {
|
|
487
614
|
...pkg.dependencies,
|
|
488
615
|
...pkg.devDependencies
|
|
@@ -501,10 +628,10 @@ function detectFrameworks() {
|
|
|
501
628
|
}
|
|
502
629
|
function detectDatabaseTools() {
|
|
503
630
|
const tools = [];
|
|
504
|
-
const pkgPath =
|
|
505
|
-
if (!
|
|
631
|
+
const pkgPath = path3.join(process.cwd(), "package.json");
|
|
632
|
+
if (!fs3.existsSync(pkgPath)) return tools;
|
|
506
633
|
try {
|
|
507
|
-
const pkg = JSON.parse(
|
|
634
|
+
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
508
635
|
const allDeps = {
|
|
509
636
|
...pkg.dependencies,
|
|
510
637
|
...pkg.devDependencies
|
|
@@ -550,19 +677,19 @@ function redactSensitive(config) {
|
|
|
550
677
|
}
|
|
551
678
|
|
|
552
679
|
// src/commands/secret.ts
|
|
553
|
-
import { Command as
|
|
680
|
+
import { Command as Command4 } from "commander";
|
|
554
681
|
import crypto from "crypto";
|
|
555
|
-
import
|
|
556
|
-
var secretCommand = new
|
|
682
|
+
import pc4 from "picocolors";
|
|
683
|
+
var secretCommand = new Command4("secret").description("Generate a secure encryption key for INVECT_ENCRYPTION_KEY").action(() => {
|
|
557
684
|
const key = crypto.randomBytes(32).toString("base64");
|
|
558
|
-
console.log(
|
|
559
|
-
console.log(` ${
|
|
685
|
+
console.log(pc4.bold("\n\u{1F511} Generated Encryption Key\n"));
|
|
686
|
+
console.log(` ${pc4.green(key)}`);
|
|
560
687
|
console.log("");
|
|
561
|
-
console.log(
|
|
562
|
-
console.log(
|
|
688
|
+
console.log(pc4.dim(" Add this to your environment:"));
|
|
689
|
+
console.log(pc4.dim(` INVECT_ENCRYPTION_KEY="${key}"`));
|
|
563
690
|
console.log("");
|
|
564
|
-
console.log(
|
|
565
|
-
console.log(
|
|
691
|
+
console.log(pc4.dim(" This key is used for AES-256-GCM encryption of credentials."));
|
|
692
|
+
console.log(pc4.dim(" Store it securely \u2014 losing it means losing access to encrypted data.\n"));
|
|
566
693
|
});
|
|
567
694
|
|
|
568
695
|
// src/index.ts
|
|
@@ -570,7 +697,7 @@ import "dotenv/config";
|
|
|
570
697
|
process.on("SIGINT", () => process.exit(0));
|
|
571
698
|
process.on("SIGTERM", () => process.exit(0));
|
|
572
699
|
async function main() {
|
|
573
|
-
const program = new
|
|
700
|
+
const program = new Command5("invect");
|
|
574
701
|
program.description("CLI for managing Invect workflow engine projects").version("0.1.0");
|
|
575
702
|
program.addCommand(generateCommand).addCommand(migrateCommand).addCommand(initCommand).addCommand(infoCommand).addCommand(secretCommand).action(() => program.help());
|
|
576
703
|
await program.parseAsync(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@invect/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for managing Invect database schemas, migrations, and project setup",
|
|
6
6
|
"bin": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"jiti": "^2.4.2",
|
|
26
26
|
"picocolors": "^1.1.1",
|
|
27
27
|
"prompts": "^2.4.2",
|
|
28
|
-
"@invect/core": "0.1.
|
|
28
|
+
"@invect/core": "0.1.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/prompts": "^2.4.9",
|
package/dist/chunk-LKWAVX5Z.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
findConfigPath,
|
|
3
|
-
loadConfig
|
|
4
|
-
} from "./chunk-Q6JKV7VX.js";
|
|
5
|
-
|
|
6
|
-
// src/commands/migrate.ts
|
|
7
|
-
import { Command } from "commander";
|
|
8
|
-
import path from "path";
|
|
9
|
-
import fs from "fs";
|
|
10
|
-
import pc from "picocolors";
|
|
11
|
-
import prompts from "prompts";
|
|
12
|
-
import { execSync } from "child_process";
|
|
13
|
-
var migrateCommand = new Command("migrate").description("Apply pending database migrations via Drizzle Kit").option("--config <path>", "Path to your Invect config file").option("-y, --yes", "Skip confirmation prompt").option("--push", "Push schema directly without migration files (dev mode)").action(migrateAction);
|
|
14
|
-
async function migrateAction(options) {
|
|
15
|
-
console.log(pc.bold("\n\u{1F5C4}\uFE0F Invect Migration\n"));
|
|
16
|
-
const configPath = findConfigPath(options.config);
|
|
17
|
-
if (!configPath) {
|
|
18
|
-
console.error(
|
|
19
|
-
pc.red("\u2717 Could not find Invect config file.") + "\n" + pc.dim(" Use --config <path> to specify the config file explicitly.") + "\n\n" + pc.dim(" You can create one with: " + pc.cyan("npx invect-cli init")) + "\n"
|
|
20
|
-
);
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
23
|
-
console.log(pc.dim(` Config: ${path.relative(process.cwd(), configPath)}`));
|
|
24
|
-
let config;
|
|
25
|
-
try {
|
|
26
|
-
config = await loadConfig(configPath);
|
|
27
|
-
} catch (error) {
|
|
28
|
-
console.error(pc.red(`\u2717 ${error instanceof Error ? error.message : String(error)}`));
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
const dbType = config.baseDatabaseConfig?.type;
|
|
32
|
-
const dbUrl = config.baseDatabaseConfig?.connectionString;
|
|
33
|
-
if (!dbType) {
|
|
34
|
-
console.error(
|
|
35
|
-
pc.red("\u2717 No baseDatabaseConfig.type found in your config.") + "\n" + pc.dim(
|
|
36
|
-
' Expected: baseDatabaseConfig: { type: "sqlite" | "postgresql" | "mysql", ... }'
|
|
37
|
-
) + "\n"
|
|
38
|
-
);
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
console.log(pc.dim(` Database: ${dbType}`));
|
|
42
|
-
if (dbUrl) {
|
|
43
|
-
const redacted = dbUrl.replace(/:\/\/[^@]+@/, "://***@");
|
|
44
|
-
console.log(pc.dim(` Connection: ${redacted}`));
|
|
45
|
-
}
|
|
46
|
-
const mode = options.push ? "push" : "migrate";
|
|
47
|
-
console.log(pc.dim(` Mode: ${mode === "push" ? "push (direct schema sync)" : "migrate (SQL migration files)"}`));
|
|
48
|
-
if (!options.yes) {
|
|
49
|
-
const message = mode === "push" ? `Push schema directly to your ${dbType} database?` : `Apply pending migrations to your ${dbType} database?`;
|
|
50
|
-
const response = await prompts({
|
|
51
|
-
type: "confirm",
|
|
52
|
-
name: "proceed",
|
|
53
|
-
message,
|
|
54
|
-
initial: true
|
|
55
|
-
});
|
|
56
|
-
if (!response.proceed) {
|
|
57
|
-
console.log(pc.dim("\n Cancelled.\n"));
|
|
58
|
-
process.exit(0);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
console.log(pc.dim(`
|
|
62
|
-
Running drizzle-kit ${mode}...
|
|
63
|
-
`));
|
|
64
|
-
try {
|
|
65
|
-
const drizzleConfigFile = detectDrizzleConfig(dbType);
|
|
66
|
-
const configFlag = drizzleConfigFile ? ` --config ${drizzleConfigFile}` : "";
|
|
67
|
-
const cmd = `npx drizzle-kit ${mode}${configFlag}`;
|
|
68
|
-
execSync(cmd, {
|
|
69
|
-
stdio: "inherit",
|
|
70
|
-
cwd: process.cwd()
|
|
71
|
-
});
|
|
72
|
-
if (mode === "push") {
|
|
73
|
-
console.log(pc.bold(pc.green("\n\u2713 Schema pushed successfully!\n")));
|
|
74
|
-
} else {
|
|
75
|
-
console.log(pc.bold(pc.green("\n\u2713 Migrations applied successfully!\n")));
|
|
76
|
-
}
|
|
77
|
-
} catch {
|
|
78
|
-
console.error(pc.red(`
|
|
79
|
-
\u2717 drizzle-kit ${mode} failed.`));
|
|
80
|
-
console.error(
|
|
81
|
-
pc.dim(" Make sure drizzle-kit is installed and your drizzle config is correct.\n")
|
|
82
|
-
);
|
|
83
|
-
if (mode === "migrate") {
|
|
84
|
-
console.error(
|
|
85
|
-
pc.dim(" Have you generated migrations? Run: ") + pc.cyan("npx invect-cli generate") + "\n"
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function detectDrizzleConfig(dbType) {
|
|
92
|
-
const candidates = {
|
|
93
|
-
sqlite: ["drizzle.config.sqlite.ts", "drizzle.config.ts"],
|
|
94
|
-
postgresql: ["drizzle.config.postgres.ts", "drizzle.config.postgresql.ts", "drizzle.config.ts"],
|
|
95
|
-
mysql: ["drizzle.config.mysql.ts", "drizzle.config.ts"]
|
|
96
|
-
};
|
|
97
|
-
const searchPaths = candidates[dbType] || ["drizzle.config.ts"];
|
|
98
|
-
for (const filename of searchPaths) {
|
|
99
|
-
if (fs.existsSync(path.resolve(process.cwd(), filename))) {
|
|
100
|
-
return filename;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export {
|
|
107
|
-
migrateCommand,
|
|
108
|
-
migrateAction
|
|
109
|
-
};
|