@invect/cli 0.1.1 → 0.1.3

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.
@@ -1,9 +1,8 @@
1
1
  import {
2
2
  generateAction,
3
3
  generateCommand
4
- } from "./chunk-5XRZFNIV.js";
4
+ } from "./chunk-ILVFFEI6.js";
5
5
  import "./chunk-K4RRNATQ.js";
6
- import "./chunk-Q6JKV7VX.js";
7
6
  export {
8
7
  generateAction,
9
8
  generateCommand
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-Q6JKV7VX.js";
6
+ } from "./chunk-ILVFFEI6.js";
7
+ import "./chunk-K4RRNATQ.js";
13
8
 
14
9
  // src/index.ts
15
- import { Command as Command4 } from "commander";
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-SCRZDVJT.js");
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
- // src/commands/info.ts
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
- var infoCommand = new Command2("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) => {
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 = path2.relative(process.cwd(), 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(pc2.bold("\n\u{1F4CB} Invect Info\n"));
534
+ console.log(pc3.bold("\n\u{1F4CB} Invect Info\n"));
408
535
  const sys = info.system;
409
- console.log(pc2.bold(" System:"));
410
- console.log(pc2.dim(` OS: ${sys.os}`));
411
- console.log(pc2.dim(` CPU: ${sys.cpu}`));
412
- console.log(pc2.dim(` Memory: ${sys.memory}`));
413
- console.log(pc2.dim(` Node: ${sys.nodeVersion}`));
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(pc2.bold(" Package Manager:"));
417
- console.log(pc2.dim(` ${pm}`));
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(pc2.bold(" Invect:"));
421
- console.log(pc2.dim(` CLI: ${imp.cliVersion}`));
422
- console.log(pc2.dim(` Core: ${imp.coreVersion}`));
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(pc2.bold(" Frameworks:"));
552
+ console.log(pc3.bold(" Frameworks:"));
426
553
  if (fw.length > 0) {
427
554
  for (const f of fw) {
428
- console.log(pc2.dim(` \u2713 ${f}`));
555
+ console.log(pc3.dim(` \u2713 ${f}`));
429
556
  }
430
557
  } else {
431
- console.log(pc2.dim(" (none detected)"));
558
+ console.log(pc3.dim(" (none detected)"));
432
559
  }
433
560
  console.log("");
434
561
  const db = info.databases;
435
- console.log(pc2.bold(" Database Tools:"));
562
+ console.log(pc3.bold(" Database Tools:"));
436
563
  if (db.length > 0) {
437
564
  for (const d of db) {
438
- console.log(pc2.dim(` \u2713 ${d}`));
565
+ console.log(pc3.dim(` \u2713 ${d}`));
439
566
  }
440
567
  } else {
441
- console.log(pc2.dim(" (none detected)"));
568
+ console.log(pc3.dim(" (none detected)"));
442
569
  }
443
570
  console.log("");
444
- console.log(pc2.bold(" Config:"));
571
+ console.log(pc3.bold(" Config:"));
445
572
  if (info.configPath) {
446
- console.log(pc2.dim(` File: ${info.configPath}`));
573
+ console.log(pc3.dim(` File: ${info.configPath}`));
447
574
  } else {
448
- console.log(pc2.yellow(` \u26A0 ${info.configError || "Not found"}`));
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(pc2.bold(" Plugins:"));
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(pc2.dim(` \u2713 ${p.name}${schemaInfo}`));
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 (fs2.existsSync(path2.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
464
- if (fs2.existsSync(path2.join(cwd, "bun.lockb")) || fs2.existsSync(path2.join(cwd, "bun.lock"))) return "bun";
465
- if (fs2.existsSync(path2.join(cwd, "yarn.lock"))) return "yarn";
466
- if (fs2.existsSync(path2.join(cwd, "package-lock.json"))) return "npm";
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 = path2.join(process.cwd(), "node_modules", pkg, "package.json");
472
- if (fs2.existsSync(pkgJsonPath)) {
473
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
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 = path2.join(process.cwd(), "package.json");
483
- if (!fs2.existsSync(pkgPath)) return frameworks;
609
+ const pkgPath = path3.join(process.cwd(), "package.json");
610
+ if (!fs3.existsSync(pkgPath)) return frameworks;
484
611
  try {
485
- const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
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 = path2.join(process.cwd(), "package.json");
505
- if (!fs2.existsSync(pkgPath)) return tools;
631
+ const pkgPath = path3.join(process.cwd(), "package.json");
632
+ if (!fs3.existsSync(pkgPath)) return tools;
506
633
  try {
507
- const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
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 Command3 } from "commander";
680
+ import { Command as Command4 } from "commander";
554
681
  import crypto from "crypto";
555
- import pc3 from "picocolors";
556
- var secretCommand = new Command3("secret").description("Generate a secure encryption key for INVECT_ENCRYPTION_KEY").action(() => {
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(pc3.bold("\n\u{1F511} Generated Encryption Key\n"));
559
- console.log(` ${pc3.green(key)}`);
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(pc3.dim(" Add this to your environment:"));
562
- console.log(pc3.dim(` INVECT_ENCRYPTION_KEY="${key}"`));
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(pc3.dim(" This key is used for AES-256-GCM encryption of credentials."));
565
- console.log(pc3.dim(" Store it securely \u2014 losing it means losing access to encrypted data.\n"));
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 Command4("invect");
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.1",
3
+ "version": "0.1.3",
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.1"
28
+ "@invect/core": "0.1.3"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/prompts": "^2.4.9",
@@ -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
- };