turbine-orm 0.5.0 → 0.7.0

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.
Files changed (46) hide show
  1. package/README.md +194 -26
  2. package/dist/cjs/cli/config.js +5 -15
  3. package/dist/cjs/cli/index.js +240 -41
  4. package/dist/cjs/cli/migrate.js +71 -46
  5. package/dist/cjs/cli/ui.js +5 -9
  6. package/dist/cjs/client.js +109 -46
  7. package/dist/cjs/errors.js +293 -0
  8. package/dist/cjs/generate.js +33 -13
  9. package/dist/cjs/index.js +39 -20
  10. package/dist/cjs/introspect.js +3 -5
  11. package/dist/cjs/pipeline.js +9 -2
  12. package/dist/cjs/query.js +442 -109
  13. package/dist/cjs/schema-builder.js +93 -24
  14. package/dist/cjs/schema-sql.js +157 -19
  15. package/dist/cjs/schema.js +5 -2
  16. package/dist/cjs/serverless.js +87 -176
  17. package/dist/cli/config.js +6 -16
  18. package/dist/cli/index.js +245 -46
  19. package/dist/cli/migrate.d.ts +6 -1
  20. package/dist/cli/migrate.js +72 -47
  21. package/dist/cli/ui.js +5 -9
  22. package/dist/client.d.ts +77 -4
  23. package/dist/client.js +109 -46
  24. package/dist/errors.d.ts +138 -0
  25. package/dist/errors.js +278 -0
  26. package/dist/generate.d.ts +1 -1
  27. package/dist/generate.js +36 -16
  28. package/dist/index.d.ts +11 -9
  29. package/dist/index.js +16 -12
  30. package/dist/introspect.d.ts +1 -1
  31. package/dist/introspect.js +4 -6
  32. package/dist/pipeline.d.ts +1 -1
  33. package/dist/pipeline.js +9 -2
  34. package/dist/query.d.ts +257 -36
  35. package/dist/query.js +443 -110
  36. package/dist/schema-builder.d.ts +2 -2
  37. package/dist/schema-builder.js +93 -25
  38. package/dist/schema-sql.d.ts +7 -3
  39. package/dist/schema-sql.js +157 -19
  40. package/dist/schema.d.ts +1 -1
  41. package/dist/schema.js +5 -2
  42. package/dist/serverless.d.ts +91 -139
  43. package/dist/serverless.js +86 -173
  44. package/package.json +33 -16
  45. package/dist/types.d.ts +0 -93
  46. package/dist/types.js +0 -126
@@ -56,13 +56,13 @@ var __importStar = (this && this.__importStar) || (function () {
56
56
  Object.defineProperty(exports, "__esModule", { value: true });
57
57
  const node_fs_1 = require("node:fs");
58
58
  const node_path_1 = require("node:path");
59
- const introspect_js_1 = require("../introspect.js");
59
+ const node_url_1 = require("node:url");
60
60
  const generate_js_1 = require("../generate.js");
61
+ const introspect_js_1 = require("../introspect.js");
61
62
  const schema_sql_js_1 = require("../schema-sql.js");
62
63
  const config_js_1 = require("./config.js");
63
64
  const migrate_js_1 = require("./migrate.js");
64
65
  const ui_js_1 = require("./ui.js");
65
- const node_url_1 = require("node:url");
66
66
  function parseArgs() {
67
67
  const args = process.argv.slice(2);
68
68
  const result = {
@@ -110,6 +110,9 @@ function parseArgs() {
110
110
  case '--dry-run':
111
111
  result.dryRun = true;
112
112
  break;
113
+ case '--auto':
114
+ result.auto = true;
115
+ break;
113
116
  case '--force':
114
117
  case '-f':
115
118
  result.force = true;
@@ -118,6 +121,10 @@ function parseArgs() {
118
121
  case '-v':
119
122
  result.verbose = true;
120
123
  break;
124
+ case '--help':
125
+ case '-h':
126
+ result.help = true;
127
+ break;
121
128
  default:
122
129
  if (!arg.startsWith('-')) {
123
130
  result.positional.push(arg);
@@ -175,7 +182,7 @@ async function cmdInit(args, config) {
175
182
  (0, ui_js_1.banner)();
176
183
  (0, ui_js_1.header)('Initializing Turbine project');
177
184
  // Detect environment
178
- const envUrl = process.env['DATABASE_URL'];
185
+ const envUrl = process.env.DATABASE_URL;
179
186
  const hasEnvFile = (0, node_fs_1.existsSync)('.env');
180
187
  const hasEnvLocal = (0, node_fs_1.existsSync)('.env.local');
181
188
  if (envUrl) {
@@ -214,7 +221,7 @@ async function cmdInit(args, config) {
214
221
  (0, node_fs_1.mkdirSync)(migrDir, { recursive: true });
215
222
  // Create .gitkeep
216
223
  (0, node_fs_1.writeFileSync)(`${migrDir}/.gitkeep`, '', 'utf-8');
217
- (0, ui_js_1.success)(`Created ${(0, ui_js_1.cyan)(migrDir + '/')}`);
224
+ (0, ui_js_1.success)(`Created ${(0, ui_js_1.cyan)(`${migrDir}/`)}`);
218
225
  }
219
226
  else {
220
227
  (0, ui_js_1.info)(`Migrations dir already exists: ${(0, ui_js_1.dim)(migrDir)}`);
@@ -222,7 +229,7 @@ async function cmdInit(args, config) {
222
229
  // Create output directory
223
230
  if (!(0, node_fs_1.existsSync)(config.out)) {
224
231
  (0, node_fs_1.mkdirSync)(config.out, { recursive: true });
225
- (0, ui_js_1.success)(`Created ${(0, ui_js_1.cyan)(config.out + '/')}`);
232
+ (0, ui_js_1.success)(`Created ${(0, ui_js_1.cyan)(`${config.out}/`)}`);
226
233
  }
227
234
  // Create seed file template
228
235
  const seedDir = config.seedFile.substring(0, config.seedFile.lastIndexOf('/'));
@@ -266,7 +273,7 @@ async function cmdInit(args, config) {
266
273
  * Define your database schema in TypeScript.
267
274
  * Use \`npx turbine push\` to sync it to your database.
268
275
  *
269
- * @see https://batadata.com/docs/turbine/schema
276
+ * @see https://turbineorm.dev
270
277
  */
271
278
 
272
279
  import { defineSchema } from 'turbine-orm';
@@ -317,15 +324,15 @@ export default defineSchema({
317
324
  spinner.succeed(`Found ${(0, ui_js_1.bold)(String(tableCount))} tables`);
318
325
  const genSpinner = new ui_js_1.Spinner('Generating TypeScript client').start();
319
326
  const result = (0, generate_js_1.generate)({ schema, outDir: config.out, connectionString: url });
320
- genSpinner.succeed(`Generated ${(0, ui_js_1.bold)(String(result.files.length))} files to ${(0, ui_js_1.cyan)(config.out + '/')}`);
327
+ genSpinner.succeed(`Generated ${(0, ui_js_1.bold)(String(result.files.length))} files to ${(0, ui_js_1.cyan)(`${config.out}/`)}`);
321
328
  }
322
329
  catch (err) {
323
330
  spinner.fail('Could not connect to database');
324
331
  if (err instanceof Error) {
325
- console.log(` ${(0, ui_js_1.dim)(err.message)}`);
332
+ console.log(` ${(0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.message))}`);
326
333
  }
327
334
  (0, ui_js_1.newline)();
328
- (0, ui_js_1.info)('You can run generation later with: ' + (0, ui_js_1.cyan)('npx turbine generate'));
335
+ (0, ui_js_1.info)(`You can run generation later with: ${(0, ui_js_1.cyan)('npx turbine generate')}`);
329
336
  }
330
337
  }
331
338
  // Next steps
@@ -401,7 +408,7 @@ async function cmdGenerate(args, config) {
401
408
  genSpinner.succeed(`Generated ${(0, ui_js_1.bold)(String(result.files.length))} files in ${(0, ui_js_1.elapsed)(startTime)}`);
402
409
  // List files
403
410
  for (const file of result.files) {
404
- console.log(` ${(0, ui_js_1.dim)(ui_js_1.symbols.teeEnd)} ${(0, ui_js_1.cyan)(result.outDir + '/' + file)}`);
411
+ console.log(` ${(0, ui_js_1.dim)(ui_js_1.symbols.teeEnd)} ${(0, ui_js_1.cyan)(`${result.outDir}/${file}`)}`);
405
412
  }
406
413
  // Usage hint
407
414
  (0, ui_js_1.newline)();
@@ -449,9 +456,11 @@ async function cmdPush(args, config) {
449
456
  for (const a of diff.alter) {
450
457
  console.log(` ${(0, ui_js_1.yellow)(ui_js_1.symbols.arrowRight)} ${a.table}`);
451
458
  for (const col of a.columns) {
452
- const actionLabel = col.action === 'add' ? (0, ui_js_1.green)('+ add') :
453
- col.action === 'drop' ? (0, ui_js_1.red)('- drop') :
454
- (0, ui_js_1.yellow)('~ ' + col.action.replace('_', ' '));
459
+ const actionLabel = col.action === 'add'
460
+ ? (0, ui_js_1.green)('+ add')
461
+ : col.action === 'drop'
462
+ ? (0, ui_js_1.red)('- drop')
463
+ : (0, ui_js_1.yellow)(`~ ${col.action.replace('_', ' ')}`);
455
464
  console.log(` ${actionLabel} ${col.column}`);
456
465
  }
457
466
  }
@@ -505,17 +514,20 @@ async function cmdMigrate(args, config) {
505
514
  console.log(` ${(0, ui_js_1.bold)('turbine migrate')} ${(0, ui_js_1.dim)('— SQL-first migration system')}`);
506
515
  (0, ui_js_1.newline)();
507
516
  console.log(` ${(0, ui_js_1.bold)('Commands:')}`);
508
- console.log(` ${(0, ui_js_1.cyan)('create <name>')} Create a new migration file`);
509
- console.log(` ${(0, ui_js_1.cyan)('up')} Apply pending migrations`);
510
- console.log(` ${(0, ui_js_1.cyan)('down')} Rollback last migration`);
511
- console.log(` ${(0, ui_js_1.cyan)('status')} Show migration status`);
517
+ console.log(` ${(0, ui_js_1.cyan)('create <name>')} Create a new migration file`);
518
+ console.log(` ${(0, ui_js_1.cyan)('create <name> --auto')} Auto-generate from schema diff`);
519
+ console.log(` ${(0, ui_js_1.cyan)('up')} Apply pending migrations`);
520
+ console.log(` ${(0, ui_js_1.cyan)('down')} Rollback last migration`);
521
+ console.log(` ${(0, ui_js_1.cyan)('status')} Show migration status`);
512
522
  (0, ui_js_1.newline)();
513
523
  console.log(` ${(0, ui_js_1.bold)('Options:')}`);
524
+ console.log(` ${(0, ui_js_1.cyan)('--auto')} Auto-generate UP/DOWN SQL from schema diff`);
514
525
  console.log(` ${(0, ui_js_1.cyan)('--step, -n')} Number of migrations to apply/rollback`);
515
526
  console.log(` ${(0, ui_js_1.cyan)('--dry-run')} Show SQL without executing`);
516
527
  (0, ui_js_1.newline)();
517
528
  console.log(` ${(0, ui_js_1.bold)('Examples:')}`);
518
529
  console.log(` ${(0, ui_js_1.dim)('npx turbine migrate create add_users_table')}`);
530
+ console.log(` ${(0, ui_js_1.dim)('npx turbine migrate create add_email_index --auto')}`);
519
531
  console.log(` ${(0, ui_js_1.dim)('npx turbine migrate up')}`);
520
532
  console.log(` ${(0, ui_js_1.dim)('npx turbine migrate down --step 2')}`);
521
533
  (0, ui_js_1.newline)();
@@ -549,9 +561,61 @@ async function cmdMigrateCreate(args, config) {
549
561
  (0, ui_js_1.newline)();
550
562
  console.log(` ${(0, ui_js_1.dim)('Usage:')} ${(0, ui_js_1.cyan)('npx turbine migrate create <name>')}`);
551
563
  console.log(` ${(0, ui_js_1.dim)('Example:')} ${(0, ui_js_1.cyan)('npx turbine migrate create add_users_table')}`);
564
+ console.log(` ${(0, ui_js_1.dim)('Auto:')} ${(0, ui_js_1.cyan)('npx turbine migrate create my_change --auto')}`);
552
565
  (0, ui_js_1.newline)();
553
566
  process.exit(1);
554
567
  }
568
+ if (args.auto) {
569
+ // Auto-generate migration from schema diff
570
+ const url = requireUrl(config);
571
+ (0, ui_js_1.label)('Database', (0, ui_js_1.redactUrl)(url));
572
+ (0, ui_js_1.label)('Schema file', config.schemaFile);
573
+ (0, ui_js_1.newline)();
574
+ const schemaDef = await loadSchemaFile(config.schemaFile);
575
+ const diffSpinner = new ui_js_1.Spinner('Computing schema diff').start();
576
+ const diff = await (0, schema_sql_js_1.schemaDiff)(schemaDef, url);
577
+ if (diff.statements.length === 0) {
578
+ diffSpinner.succeed('Database is already in sync — nothing to migrate');
579
+ (0, ui_js_1.newline)();
580
+ return;
581
+ }
582
+ diffSpinner.succeed(`Found ${(0, ui_js_1.bold)(String(diff.statements.length))} change(s)`);
583
+ (0, ui_js_1.newline)();
584
+ const upSQL = diff.statements.join('\n');
585
+ const downSQL = diff.reverseStatements.join('\n');
586
+ const file = (0, migrate_js_1.createMigration)(config.migrationsDir, name, { up: upSQL, down: downSQL });
587
+ const relPath = (0, node_path_1.relative)(process.cwd(), file.path);
588
+ (0, ui_js_1.success)(`Created auto-migration: ${(0, ui_js_1.bold)(file.filename)}`);
589
+ (0, ui_js_1.newline)();
590
+ console.log(` ${(0, ui_js_1.dim)('File:')} ${(0, ui_js_1.cyan)(relPath)}`);
591
+ (0, ui_js_1.newline)();
592
+ // Show summary of changes
593
+ if (diff.create.length > 0) {
594
+ console.log(` ${(0, ui_js_1.green)('+ Create')} ${diff.create.length} table(s): ${diff.create.map((t) => t.name).join(', ')}`);
595
+ }
596
+ if (diff.alter.length > 0) {
597
+ console.log(` ${(0, ui_js_1.yellow)('~ Alter')} ${diff.alter.length} table(s):`);
598
+ for (const a of diff.alter) {
599
+ for (const col of a.columns) {
600
+ const actionLabel = col.action === 'add'
601
+ ? (0, ui_js_1.green)('+ add')
602
+ : col.action === 'drop'
603
+ ? (0, ui_js_1.red)('- drop')
604
+ : col.action === 'add_unique'
605
+ ? (0, ui_js_1.green)('+ unique')
606
+ : col.action === 'drop_unique'
607
+ ? (0, ui_js_1.red)('- unique')
608
+ : (0, ui_js_1.yellow)(`~ ${col.action.replace(/_/g, ' ')}`);
609
+ console.log(` ${actionLabel} ${a.table}.${col.column}`);
610
+ }
611
+ }
612
+ }
613
+ (0, ui_js_1.newline)();
614
+ console.log(` ${(0, ui_js_1.dim)('Review the migration, then run:')}`);
615
+ console.log(` ${(0, ui_js_1.cyan)('npx turbine migrate up')}`);
616
+ (0, ui_js_1.newline)();
617
+ return;
618
+ }
555
619
  const file = (0, migrate_js_1.createMigration)(config.migrationsDir, name);
556
620
  const relPath = (0, node_path_1.relative)(process.cwd(), file.path);
557
621
  (0, ui_js_1.success)(`Created migration: ${(0, ui_js_1.bold)(file.filename)}`);
@@ -633,7 +697,7 @@ async function cmdMigrateDown(args, config) {
633
697
  }
634
698
  (0, ui_js_1.newline)();
635
699
  }
636
- async function cmdMigrateStatus(args, config) {
700
+ async function cmdMigrateStatus(_args, config) {
637
701
  (0, ui_js_1.banner)();
638
702
  const url = requireUrl(config);
639
703
  (0, ui_js_1.label)('Database', (0, ui_js_1.redactUrl)(url));
@@ -663,19 +727,22 @@ async function cmdMigrateStatus(args, config) {
663
727
  const rows = statuses.map((s) => {
664
728
  let status;
665
729
  if (s.applied && s.checksumValid === false) {
666
- status = (0, ui_js_1.red)(ui_js_1.symbols.warning + ' Drifted');
730
+ status = (0, ui_js_1.red)(`${ui_js_1.symbols.warning} Drifted`);
667
731
  }
668
732
  else if (s.applied) {
669
- status = (0, ui_js_1.green)(ui_js_1.symbols.check + ' Applied');
733
+ status = (0, ui_js_1.green)(`${ui_js_1.symbols.check} Applied`);
670
734
  }
671
735
  else {
672
- status = (0, ui_js_1.yellow)(ui_js_1.symbols.dot + ' Pending');
736
+ status = (0, ui_js_1.yellow)(`${ui_js_1.symbols.dot} Pending`);
673
737
  }
674
738
  return [
675
739
  status,
676
740
  s.file.filename,
677
741
  s.appliedAt
678
- ? (0, ui_js_1.dim)(s.appliedAt.toISOString().replace('T', ' ').replace(/\.\d+Z$/, ' UTC'))
742
+ ? (0, ui_js_1.dim)(s.appliedAt
743
+ .toISOString()
744
+ .replace('T', ' ')
745
+ .replace(/\.\d+Z$/, ' UTC'))
679
746
  : (0, ui_js_1.dim)('—'),
680
747
  ];
681
748
  });
@@ -689,7 +756,7 @@ async function cmdMigrateStatus(args, config) {
689
756
  // ---------------------------------------------------------------------------
690
757
  // Command: seed
691
758
  // ---------------------------------------------------------------------------
692
- async function cmdSeed(args, config) {
759
+ async function cmdSeed(_args, config) {
693
760
  (0, ui_js_1.banner)();
694
761
  const seedFile = (0, node_path_1.resolve)(config.seedFile);
695
762
  (0, ui_js_1.label)('Seed file', config.seedFile);
@@ -705,22 +772,20 @@ async function cmdSeed(args, config) {
705
772
  const spinner = new ui_js_1.Spinner('Running seed file').start();
706
773
  try {
707
774
  // Use child_process to run the seed file via tsx or node
708
- const { execSync } = await Promise.resolve().then(() => __importStar(require('node:child_process')));
775
+ const { execFileSync } = await Promise.resolve().then(() => __importStar(require('node:child_process')));
709
776
  // Try tsx first (most compatible with .ts files), fall back to node --experimental-strip-types
710
777
  const runners = [
711
- { cmd: 'npx tsx', name: 'tsx' },
712
- { cmd: 'node --experimental-strip-types', name: 'node' },
778
+ { cmd: 'npx', args: ['tsx', seedFile], name: 'tsx' },
779
+ { cmd: 'node', args: ['--experimental-strip-types', seedFile], name: 'node' },
713
780
  ];
714
- // Shell-escape the seed file path to prevent injection
715
- const escapedSeedFile = seedFile.replace(/'/g, "'\\''");
716
781
  let ran = false;
717
782
  for (const runner of runners) {
718
783
  try {
719
- execSync(`${runner.cmd} '${escapedSeedFile}'`, {
784
+ execFileSync(runner.cmd, runner.args, {
720
785
  stdio: 'inherit',
721
786
  env: {
722
787
  ...process.env,
723
- DATABASE_URL: config.url || process.env['DATABASE_URL'],
788
+ DATABASE_URL: config.url || process.env.DATABASE_URL,
724
789
  },
725
790
  });
726
791
  ran = true;
@@ -742,7 +807,7 @@ async function cmdSeed(args, config) {
742
807
  catch (err) {
743
808
  spinner.fail('Seed failed');
744
809
  if (err instanceof Error) {
745
- console.log(` ${(0, ui_js_1.dim)(err.message)}`);
810
+ console.log(` ${(0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.message))}`);
746
811
  }
747
812
  (0, ui_js_1.newline)();
748
813
  process.exit(1);
@@ -752,7 +817,7 @@ async function cmdSeed(args, config) {
752
817
  // ---------------------------------------------------------------------------
753
818
  // Command: status
754
819
  // ---------------------------------------------------------------------------
755
- async function cmdStatus(args, config) {
820
+ async function cmdStatus(_args, config) {
756
821
  (0, ui_js_1.banner)();
757
822
  const url = requireUrl(config);
758
823
  (0, ui_js_1.label)('Database', (0, ui_js_1.redactUrl)(url));
@@ -770,7 +835,7 @@ async function cmdStatus(args, config) {
770
835
  (0, ui_js_1.newline)();
771
836
  for (const tbl of Object.values(schema.tables)) {
772
837
  const relCount = Object.keys(tbl.relations).length;
773
- const pk = tbl.primaryKey.join(', ') || (0, ui_js_1.dim)('(none)');
838
+ const _pk = tbl.primaryKey.join(', ') || (0, ui_js_1.dim)('(none)');
774
839
  console.log(` ${(0, ui_js_1.bold)((0, ui_js_1.cyan)(tbl.name))}`);
775
840
  for (let i = 0; i < tbl.columns.length; i++) {
776
841
  const col = tbl.columns[i];
@@ -779,7 +844,7 @@ async function cmdStatus(args, config) {
779
844
  const nullable = col.nullable ? (0, ui_js_1.dim)('?') : '';
780
845
  const def = col.hasDefault ? (0, ui_js_1.dim)(' (default)') : '';
781
846
  const pkLabel = tbl.primaryKey.includes(col.name) ? ` ${(0, ui_js_1.magenta)('PK')}` : '';
782
- console.log(` ${(0, ui_js_1.dim)(prefix)} ${col.field}${nullable}: ${(0, ui_js_1.green)(col.tsType)}${pkLabel}${def} ${(0, ui_js_1.gray)(ui_js_1.symbols.arrow + ' ' + col.pgType)}`);
847
+ console.log(` ${(0, ui_js_1.dim)(prefix)} ${col.field}${nullable}: ${(0, ui_js_1.green)(col.tsType)}${pkLabel}${def} ${(0, ui_js_1.gray)(`${ui_js_1.symbols.arrow} ${col.pgType}`)}`);
783
848
  }
784
849
  const rels = Object.entries(tbl.relations);
785
850
  if (rels.length > 0) {
@@ -812,11 +877,138 @@ async function cmdStudio(_args, _config) {
812
877
  'A local web UI for browsing your database,',
813
878
  'exploring relations, and managing data.',
814
879
  '',
815
- `Follow ${(0, ui_js_1.cyan)('@batadata')} for updates.`,
880
+ `Follow ${(0, ui_js_1.cyan)('@turbineorm')} for updates.`,
816
881
  ].join('\n'), { title: (0, ui_js_1.bold)((0, ui_js_1.cyan)('Studio')), padding: 2 }));
817
882
  (0, ui_js_1.newline)();
818
883
  }
819
884
  // ---------------------------------------------------------------------------
885
+ // Subcommand help
886
+ // ---------------------------------------------------------------------------
887
+ function showSubcommandHelp(command) {
888
+ const helpMap = {
889
+ init: showInitHelp,
890
+ generate: showGenerateHelp,
891
+ pull: showGenerateHelp,
892
+ push: showPushHelp,
893
+ migrate: showMigrateHelp,
894
+ migration: showMigrateHelp,
895
+ seed: showSeedHelp,
896
+ status: showStatusHelp,
897
+ };
898
+ const fn = helpMap[command];
899
+ if (fn) {
900
+ fn();
901
+ return true;
902
+ }
903
+ return false;
904
+ }
905
+ function showInitHelp() {
906
+ (0, ui_js_1.banner)();
907
+ console.log(` ${(0, ui_js_1.bold)('turbine init')} — Initialize a Turbine project`);
908
+ (0, ui_js_1.newline)();
909
+ console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
910
+ console.log(` npx turbine init ${(0, ui_js_1.dim)('[options]')}`);
911
+ (0, ui_js_1.newline)();
912
+ console.log(` Creates ${(0, ui_js_1.cyan)('turbine.config.ts')}, migrations directory, seed file template,`);
913
+ console.log(` and schema file template.`);
914
+ (0, ui_js_1.newline)();
915
+ console.log(` ${(0, ui_js_1.bold)('Options:')}`);
916
+ console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string to embed in config`);
917
+ console.log(` ${(0, ui_js_1.cyan)('--force, -f')} Overwrite existing config file`);
918
+ (0, ui_js_1.newline)();
919
+ }
920
+ function showGenerateHelp() {
921
+ (0, ui_js_1.banner)();
922
+ console.log(` ${(0, ui_js_1.bold)('turbine generate')} — Introspect database and generate TypeScript types`);
923
+ (0, ui_js_1.newline)();
924
+ console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
925
+ console.log(` npx turbine generate ${(0, ui_js_1.dim)('[options]')}`);
926
+ (0, ui_js_1.newline)();
927
+ console.log(` Connects to your database, reads the schema, and generates:`);
928
+ console.log(` ${(0, ui_js_1.dim)('•')} ${(0, ui_js_1.cyan)('types.ts')} — Entity interfaces, Create/Update input types`);
929
+ console.log(` ${(0, ui_js_1.dim)('•')} ${(0, ui_js_1.cyan)('metadata.ts')} — Runtime schema metadata`);
930
+ console.log(` ${(0, ui_js_1.dim)('•')} ${(0, ui_js_1.cyan)('index.ts')} — Configured client with typed table accessors`);
931
+ (0, ui_js_1.newline)();
932
+ console.log(` ${(0, ui_js_1.bold)('Options:')}`);
933
+ console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string`);
934
+ console.log(` ${(0, ui_js_1.cyan)('--out, -o')} ${(0, ui_js_1.dim)('<dir>')} Output directory ${(0, ui_js_1.dim)('(default: ./generated/turbine)')}`);
935
+ console.log(` ${(0, ui_js_1.cyan)('--schema, -s')} ${(0, ui_js_1.dim)('<name>')} Postgres schema ${(0, ui_js_1.dim)('(default: public)')}`);
936
+ console.log(` ${(0, ui_js_1.cyan)('--include')} ${(0, ui_js_1.dim)('<tables>')} Comma-separated tables to include`);
937
+ console.log(` ${(0, ui_js_1.cyan)('--exclude')} ${(0, ui_js_1.dim)('<tables>')} Comma-separated tables to exclude`);
938
+ (0, ui_js_1.newline)();
939
+ }
940
+ function showPushHelp() {
941
+ (0, ui_js_1.banner)();
942
+ console.log(` ${(0, ui_js_1.bold)('turbine push')} — Apply schema-builder definitions to database`);
943
+ (0, ui_js_1.newline)();
944
+ console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
945
+ console.log(` npx turbine push ${(0, ui_js_1.dim)('[options]')}`);
946
+ (0, ui_js_1.newline)();
947
+ console.log(` Reads your ${(0, ui_js_1.cyan)('turbine/schema.ts')} file, diffs against the live database,`);
948
+ console.log(` and applies CREATE/ALTER statements.`);
949
+ (0, ui_js_1.newline)();
950
+ console.log(` ${(0, ui_js_1.bold)('Options:')}`);
951
+ console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string`);
952
+ console.log(` ${(0, ui_js_1.cyan)('--dry-run')} Show SQL without executing`);
953
+ console.log(` ${(0, ui_js_1.cyan)('--verbose, -v')} Show detailed output`);
954
+ (0, ui_js_1.newline)();
955
+ }
956
+ function showMigrateHelp() {
957
+ (0, ui_js_1.banner)();
958
+ console.log(` ${(0, ui_js_1.bold)('turbine migrate')} — SQL migration management`);
959
+ (0, ui_js_1.newline)();
960
+ console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
961
+ console.log(` npx turbine migrate ${(0, ui_js_1.cyan)('<subcommand>')} ${(0, ui_js_1.dim)('[options]')}`);
962
+ (0, ui_js_1.newline)();
963
+ console.log(` ${(0, ui_js_1.bold)('Subcommands:')}`);
964
+ console.log(` ${(0, ui_js_1.cyan)('create')} ${(0, ui_js_1.dim)('<name>')} Create a new migration file`);
965
+ console.log(` ${(0, ui_js_1.cyan)('up')} Apply pending migrations`);
966
+ console.log(` ${(0, ui_js_1.cyan)('down')} Rollback last migration`);
967
+ console.log(` ${(0, ui_js_1.cyan)('status')} Show applied/pending migrations`);
968
+ (0, ui_js_1.newline)();
969
+ console.log(` ${(0, ui_js_1.bold)('Options:')}`);
970
+ console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string`);
971
+ console.log(` ${(0, ui_js_1.cyan)('--step, -n')} ${(0, ui_js_1.dim)('<N>')} Number of migrations to apply/rollback`);
972
+ console.log(` ${(0, ui_js_1.cyan)('--dry-run')} Show SQL without executing`);
973
+ console.log(` ${(0, ui_js_1.cyan)('--verbose, -v')} Show detailed output`);
974
+ (0, ui_js_1.newline)();
975
+ console.log(` ${(0, ui_js_1.bold)('Examples:')}`);
976
+ console.log(` ${(0, ui_js_1.dim)('$')} npx turbine migrate create add_users_table`);
977
+ console.log(` ${(0, ui_js_1.dim)('$')} npx turbine migrate up`);
978
+ console.log(` ${(0, ui_js_1.dim)('$')} npx turbine migrate down --step 2`);
979
+ console.log(` ${(0, ui_js_1.dim)('$')} npx turbine migrate status`);
980
+ (0, ui_js_1.newline)();
981
+ }
982
+ function showSeedHelp() {
983
+ (0, ui_js_1.banner)();
984
+ console.log(` ${(0, ui_js_1.bold)('turbine seed')} — Run seed file`);
985
+ (0, ui_js_1.newline)();
986
+ console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
987
+ console.log(` npx turbine seed ${(0, ui_js_1.dim)('[options]')}`);
988
+ (0, ui_js_1.newline)();
989
+ console.log(` Runs the seed file specified in ${(0, ui_js_1.cyan)('turbine.config.ts')}`);
990
+ console.log(` ${(0, ui_js_1.dim)('(default: ./turbine/seed.ts)')}`);
991
+ (0, ui_js_1.newline)();
992
+ console.log(` ${(0, ui_js_1.bold)('Options:')}`);
993
+ console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string`);
994
+ (0, ui_js_1.newline)();
995
+ }
996
+ function showStatusHelp() {
997
+ (0, ui_js_1.banner)();
998
+ console.log(` ${(0, ui_js_1.bold)('turbine status')} — Show database schema summary`);
999
+ (0, ui_js_1.newline)();
1000
+ console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
1001
+ console.log(` npx turbine status ${(0, ui_js_1.dim)('[options]')}`);
1002
+ (0, ui_js_1.newline)();
1003
+ console.log(` Introspects your database and displays tables, columns,`);
1004
+ console.log(` types, relations, and indexes.`);
1005
+ (0, ui_js_1.newline)();
1006
+ console.log(` ${(0, ui_js_1.bold)('Options:')}`);
1007
+ console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string`);
1008
+ console.log(` ${(0, ui_js_1.cyan)('--schema, -s')} ${(0, ui_js_1.dim)('<name>')} Postgres schema ${(0, ui_js_1.dim)('(default: public)')}`);
1009
+ (0, ui_js_1.newline)();
1010
+ }
1011
+ // ---------------------------------------------------------------------------
820
1012
  // Help
821
1013
  // ---------------------------------------------------------------------------
822
1014
  function showHelp() {
@@ -875,6 +1067,13 @@ async function main() {
875
1067
  showHelp();
876
1068
  return;
877
1069
  }
1070
+ // Subcommand help: e.g. `turbine migrate --help`
1071
+ if (args.help) {
1072
+ if (showSubcommandHelp(args.command))
1073
+ return;
1074
+ showHelp();
1075
+ return;
1076
+ }
878
1077
  if (args.command === 'version' || args.command === '--version' || args.command === '-V') {
879
1078
  showVersion();
880
1079
  return;
@@ -940,7 +1139,7 @@ async function main() {
940
1139
  if (err.message.includes('ECONNREFUSED') || err.message.includes('connection')) {
941
1140
  (0, ui_js_1.newline)();
942
1141
  (0, ui_js_1.error)(`Could not connect to database`);
943
- console.log(` ${(0, ui_js_1.dim)(err.message)}`);
1142
+ console.log(` ${(0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.message))}`);
944
1143
  (0, ui_js_1.newline)();
945
1144
  console.log(` ${(0, ui_js_1.dim)('Check that:')}`);
946
1145
  console.log(` ${(0, ui_js_1.dim)('1.')} Your database is running`);
@@ -950,25 +1149,25 @@ async function main() {
950
1149
  else if (err.message.includes('authentication')) {
951
1150
  (0, ui_js_1.newline)();
952
1151
  (0, ui_js_1.error)(`Authentication failed`);
953
- console.log(` ${(0, ui_js_1.dim)(err.message)}`);
1152
+ console.log(` ${(0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.message))}`);
954
1153
  }
955
1154
  else if (err.message.includes('does not exist')) {
956
1155
  (0, ui_js_1.newline)();
957
1156
  (0, ui_js_1.error)(`Database or schema not found`);
958
- console.log(` ${(0, ui_js_1.dim)(err.message)}`);
1157
+ console.log(` ${(0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.message))}`);
959
1158
  }
960
1159
  else {
961
1160
  (0, ui_js_1.newline)();
962
- (0, ui_js_1.error)(err.message);
1161
+ (0, ui_js_1.error)((0, ui_js_1.redactUrl)(err.message));
963
1162
  if (args.verbose && err.stack) {
964
1163
  (0, ui_js_1.newline)();
965
- console.log((0, ui_js_1.dim)(err.stack));
1164
+ console.log((0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.stack)));
966
1165
  }
967
1166
  }
968
1167
  }
969
1168
  else {
970
1169
  (0, ui_js_1.newline)();
971
- (0, ui_js_1.error)(`Unexpected error: ${String(err)}`);
1170
+ (0, ui_js_1.error)(`Unexpected error: ${(0, ui_js_1.redactUrl)(String(err))}`);
972
1171
  }
973
1172
  (0, ui_js_1.newline)();
974
1173
  process.exit(1);