realitydb 1.4.4 → 1.5.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 (2) hide show
  1. package/dist/index.js +373 -133
  2. package/package.json +1 -3
package/dist/index.js CHANGED
@@ -3476,83 +3476,10 @@ var {
3476
3476
  Help
3477
3477
  } = import_index.default;
3478
3478
 
3479
- // ../../packages/config/dist/loadConfig.js
3480
- var import_promises = require("fs/promises");
3481
- var import_node_path = require("path");
3482
-
3483
- // ../../packages/config/dist/defaults.js
3484
- var DEFAULT_CONFIG = {
3485
- seed: {
3486
- defaultRecords: 5e3,
3487
- batchSize: 1e3,
3488
- environment: "dev"
3489
- },
3490
- export: {
3491
- defaultFormat: "json",
3492
- outputDir: "./.databox"
3493
- }
3494
- };
3495
-
3496
- // ../../packages/config/dist/loadConfig.js
3497
- var CONFIG_FILES = ["realitydb.config.json", "seedforge.config.json", "databox.config.json"];
3498
- async function findConfigFile(basePath) {
3499
- for (const name of CONFIG_FILES) {
3500
- const fullPath = (0, import_node_path.resolve)(basePath, name);
3501
- try {
3502
- await (0, import_promises.access)(fullPath);
3503
- return fullPath;
3504
- } catch {
3505
- continue;
3506
- }
3507
- }
3508
- return null;
3509
- }
3510
- async function loadConfig(filePath) {
3511
- let resolvedPath;
3512
- if (filePath) {
3513
- resolvedPath = (0, import_node_path.resolve)(filePath);
3514
- } else {
3515
- const found = await findConfigFile(".");
3516
- if (!found) {
3517
- throw new Error(`[realitydb] Config file not found.
3518
- Create a realitydb.config.json or specify a path with --config.`);
3519
- }
3520
- resolvedPath = found;
3521
- }
3522
- let raw;
3523
- try {
3524
- raw = await (0, import_promises.readFile)(resolvedPath, "utf-8");
3525
- } catch {
3526
- throw new Error(`[realitydb] Config file not found: ${resolvedPath}
3527
- Create a realitydb.config.json or specify a path with --config.`);
3528
- }
3529
- let parsed;
3530
- try {
3531
- parsed = JSON.parse(raw);
3532
- } catch {
3533
- throw new Error(`[realitydb] Invalid JSON in config file: ${resolvedPath}`);
3534
- }
3535
- const config = parsed;
3536
- const database = config["database"];
3537
- if (!database || typeof database["connectionString"] !== "string") {
3538
- throw new Error("[realitydb] Config validation failed: database.connectionString is required.");
3539
- }
3540
- return {
3541
- database: {
3542
- client: "postgres",
3543
- connectionString: database["connectionString"]
3544
- },
3545
- seed: {
3546
- ...DEFAULT_CONFIG.seed,
3547
- ...config["seed"] ?? {}
3548
- },
3549
- template: config["template"],
3550
- export: {
3551
- ...DEFAULT_CONFIG.export,
3552
- ...config["export"] ?? {}
3553
- }
3554
- };
3555
- }
3479
+ // src/commands/init.ts
3480
+ var import_node_readline = require("readline");
3481
+ var import_node_process = require("process");
3482
+ var import_node_fs7 = require("fs");
3556
3483
 
3557
3484
  // ../../packages/core/dist/planning/dependencyGraph.js
3558
3485
  function buildDependencyGraph(foreignKeys) {
@@ -4390,32 +4317,32 @@ function generateDataset(plan) {
4390
4317
  }
4391
4318
 
4392
4319
  // ../../packages/generators/dist/exporters/json.js
4393
- var import_promises2 = require("fs/promises");
4394
- var import_node_path2 = require("path");
4320
+ var import_promises = require("fs/promises");
4321
+ var import_node_path = require("path");
4395
4322
  async function exportToJson(dataset, outputDir) {
4396
- await (0, import_promises2.mkdir)(outputDir, { recursive: true });
4323
+ await (0, import_promises.mkdir)(outputDir, { recursive: true });
4397
4324
  const files = [];
4398
4325
  for (const [tableName, table] of dataset.tables) {
4399
- const filePath = (0, import_node_path2.join)(outputDir, `${tableName}.json`);
4326
+ const filePath = (0, import_node_path.join)(outputDir, `${tableName}.json`);
4400
4327
  const content = JSON.stringify(table.rows, null, 2);
4401
- await (0, import_promises2.writeFile)(filePath, content, "utf-8");
4328
+ await (0, import_promises.writeFile)(filePath, content, "utf-8");
4402
4329
  files.push(filePath);
4403
4330
  }
4404
4331
  return files;
4405
4332
  }
4406
4333
 
4407
4334
  // ../../packages/generators/dist/exporters/csv.js
4408
- var import_promises3 = require("fs/promises");
4409
- var import_node_path3 = require("path");
4335
+ var import_promises2 = require("fs/promises");
4336
+ var import_node_path2 = require("path");
4410
4337
  async function exportToCsv(dataset, outputDir) {
4411
- await (0, import_promises3.mkdir)(outputDir, { recursive: true });
4338
+ await (0, import_promises2.mkdir)(outputDir, { recursive: true });
4412
4339
  const files = [];
4413
4340
  for (const [tableName, table] of dataset.tables) {
4414
- const filePath = (0, import_node_path3.join)(outputDir, `${tableName}.csv`);
4341
+ const filePath = (0, import_node_path2.join)(outputDir, `${tableName}.csv`);
4415
4342
  const header = table.columns.map(escapeCsvField).join(",");
4416
4343
  const rows = table.rows.map((row) => table.columns.map((col) => escapeCsvField(String(row[col] ?? ""))).join(","));
4417
4344
  const content = [header, ...rows].join("\n");
4418
- await (0, import_promises3.writeFile)(filePath, content, "utf-8");
4345
+ await (0, import_promises2.writeFile)(filePath, content, "utf-8");
4419
4346
  files.push(filePath);
4420
4347
  }
4421
4348
  return files;
@@ -4428,10 +4355,10 @@ function escapeCsvField(value) {
4428
4355
  }
4429
4356
 
4430
4357
  // ../../packages/generators/dist/exporters/sql.js
4431
- var import_promises4 = require("fs/promises");
4432
- var import_node_path4 = require("path");
4358
+ var import_promises3 = require("fs/promises");
4359
+ var import_node_path3 = require("path");
4433
4360
  async function exportToSql(dataset, outputDir, tableOrder) {
4434
- await (0, import_promises4.mkdir)(outputDir, { recursive: true });
4361
+ await (0, import_promises3.mkdir)(outputDir, { recursive: true });
4435
4362
  const lines = [];
4436
4363
  lines.push("-- Generated by DataBox");
4437
4364
  lines.push(`-- Seed: ${dataset.seed}`);
@@ -4448,8 +4375,8 @@ async function exportToSql(dataset, outputDir, tableOrder) {
4448
4375
  }
4449
4376
  lines.push("");
4450
4377
  }
4451
- const filePath = (0, import_node_path4.join)(outputDir, "seed.sql");
4452
- await (0, import_promises4.writeFile)(filePath, lines.join("\n"), "utf-8");
4378
+ const filePath = (0, import_node_path3.join)(outputDir, "seed.sql");
4379
+ await (0, import_promises3.writeFile)(filePath, lines.join("\n"), "utf-8");
4453
4380
  return [filePath];
4454
4381
  }
4455
4382
  function escapeSqlValue(value) {
@@ -5731,7 +5658,7 @@ function countRows2(dataset) {
5731
5658
 
5732
5659
  // ../../packages/generators/dist/scenarios/loadScenario.js
5733
5660
  var import_node_fs = require("fs");
5734
- var import_node_path5 = require("path");
5661
+ var import_node_path4 = require("path");
5735
5662
  function scaffoldCustomScenario(name) {
5736
5663
  return {
5737
5664
  name,
@@ -5802,8 +5729,8 @@ function extractTablesFromModifications(modifications) {
5802
5729
  }
5803
5730
 
5804
5731
  // ../../packages/generators/dist/packExporter.js
5805
- var import_promises5 = require("fs/promises");
5806
- var import_node_path6 = require("path");
5732
+ var import_promises4 = require("fs/promises");
5733
+ var import_node_path5 = require("path");
5807
5734
  function exportRealityPack(dataset, plan, schema, options) {
5808
5735
  const name = options?.name ?? plan.config.templateName ?? "realitydb-pack";
5809
5736
  const packSchema = {
@@ -5851,14 +5778,14 @@ function exportRealityPack(dataset, plan, schema, options) {
5851
5778
  }
5852
5779
  async function saveRealityPack(pack, outputPath) {
5853
5780
  const filePath = outputPath.endsWith(".realitydb-pack.json") || outputPath.endsWith(".databox-pack.json") ? outputPath : `${outputPath}/${pack.metadata.name}.realitydb-pack.json`;
5854
- await (0, import_promises5.mkdir)((0, import_node_path6.dirname)(filePath), { recursive: true });
5855
- await (0, import_promises5.writeFile)(filePath, JSON.stringify(pack, null, 2), "utf-8");
5781
+ await (0, import_promises4.mkdir)((0, import_node_path5.dirname)(filePath), { recursive: true });
5782
+ await (0, import_promises4.writeFile)(filePath, JSON.stringify(pack, null, 2), "utf-8");
5856
5783
  return filePath;
5857
5784
  }
5858
5785
  async function loadRealityPack(filePath) {
5859
5786
  let raw;
5860
5787
  try {
5861
- raw = await (0, import_promises5.readFile)(filePath, "utf-8");
5788
+ raw = await (0, import_promises4.readFile)(filePath, "utf-8");
5862
5789
  } catch (err) {
5863
5790
  const message = err instanceof Error ? err.message : String(err);
5864
5791
  throw new Error(`Failed to read Reality Pack file: ${message}`);
@@ -6414,7 +6341,7 @@ function isIntLike(value) {
6414
6341
  }
6415
6342
 
6416
6343
  // ../../packages/generators/dist/writers/parquet.js
6417
- var import_promises6 = require("fs/promises");
6344
+ var import_promises5 = require("fs/promises");
6418
6345
  async function appendParquetBatch(rows, filePath) {
6419
6346
  const { appendFile: appendFile3 } = await import("fs/promises");
6420
6347
  const lines = rows.map((row) => JSON.stringify(row)).join("\n") + "\n";
@@ -6422,14 +6349,14 @@ async function appendParquetBatch(rows, filePath) {
6422
6349
  }
6423
6350
 
6424
6351
  // ../../packages/generators/dist/writers/csv.js
6425
- var import_promises7 = require("fs/promises");
6352
+ var import_promises6 = require("fs/promises");
6426
6353
  async function writeCsvHeader(columns, filePath) {
6427
6354
  const header = columns.map(escapeCsvField2).join(",") + "\n";
6428
- await (0, import_promises7.writeFile)(filePath, header, "utf-8");
6355
+ await (0, import_promises6.writeFile)(filePath, header, "utf-8");
6429
6356
  }
6430
6357
  async function appendCsvBatch(rows, columns, filePath) {
6431
6358
  const lines = rows.map((row) => columns.map((col) => escapeCsvField2(String(row[col] ?? ""))).join(",")).join("\n") + "\n";
6432
- await (0, import_promises7.appendFile)(filePath, lines, "utf-8");
6359
+ await (0, import_promises6.appendFile)(filePath, lines, "utf-8");
6433
6360
  }
6434
6361
  function escapeCsvField2(value) {
6435
6362
  if (value.includes(",") || value.includes('"') || value.includes("\n") || value.includes("\r")) {
@@ -6439,13 +6366,13 @@ function escapeCsvField2(value) {
6439
6366
  }
6440
6367
 
6441
6368
  // ../../packages/generators/dist/writers/json.js
6442
- var import_promises8 = require("fs/promises");
6369
+ var import_promises7 = require("fs/promises");
6443
6370
  async function writeJsonHeader(filePath) {
6444
- await (0, import_promises8.writeFile)(filePath, "", "utf-8");
6371
+ await (0, import_promises7.writeFile)(filePath, "", "utf-8");
6445
6372
  }
6446
6373
  async function appendJsonBatch(rows, filePath) {
6447
6374
  const lines = rows.map((row) => JSON.stringify(row)).join("\n") + "\n";
6448
- await (0, import_promises8.appendFile)(filePath, lines, "utf-8");
6375
+ await (0, import_promises7.appendFile)(filePath, lines, "utf-8");
6449
6376
  }
6450
6377
 
6451
6378
  // ../../packages/generators/dist/analyze/columnDetector.js
@@ -7309,13 +7236,13 @@ var CourseRegistry = class {
7309
7236
 
7310
7237
  // ../../packages/generators/dist/classroom/progressTracker.js
7311
7238
  var import_node_fs2 = require("fs");
7312
- var import_node_path7 = require("path");
7239
+ var import_node_path6 = require("path");
7313
7240
  var import_node_os = require("os");
7314
7241
  function getProgressDir() {
7315
- return (0, import_node_path7.join)((0, import_node_os.homedir)(), ".realitydb");
7242
+ return (0, import_node_path6.join)((0, import_node_os.homedir)(), ".realitydb");
7316
7243
  }
7317
7244
  function getProgressPath() {
7318
- return (0, import_node_path7.join)(getProgressDir(), "progress.json");
7245
+ return (0, import_node_path6.join)(getProgressDir(), "progress.json");
7319
7246
  }
7320
7247
  function loadProgress() {
7321
7248
  const filePath = getProgressPath();
@@ -10304,7 +10231,7 @@ var VALID_STRATEGY_KINDS = [
10304
10231
 
10305
10232
  // ../../packages/templates/dist/loadTemplate.js
10306
10233
  var import_node_fs3 = require("fs");
10307
- var import_node_path8 = require("path");
10234
+ var import_node_path7 = require("path");
10308
10235
 
10309
10236
  // ../../packages/templates/dist/validateTemplate.js
10310
10237
  function validateTemplateJSON(json) {
@@ -10388,7 +10315,7 @@ function assertValidTemplate(json) {
10388
10315
 
10389
10316
  // ../../packages/templates/dist/loadTemplate.js
10390
10317
  function loadTemplateFromJSON(filePath) {
10391
- const resolvedPath = (0, import_node_path8.resolve)(filePath);
10318
+ const resolvedPath = (0, import_node_path7.resolve)(filePath);
10392
10319
  let raw;
10393
10320
  try {
10394
10321
  raw = (0, import_node_fs3.readFileSync)(resolvedPath, "utf-8");
@@ -10441,11 +10368,11 @@ function convertToDomainTemplate(json) {
10441
10368
 
10442
10369
  // ../../packages/templates/dist/userTemplates.js
10443
10370
  var import_node_os2 = require("os");
10444
- var import_node_path9 = require("path");
10371
+ var import_node_path8 = require("path");
10445
10372
  var import_node_fs4 = require("fs");
10446
10373
  var USER_TEMPLATE_DIR_NAME = ".realitydb/templates";
10447
10374
  function getUserTemplateDir() {
10448
- return (0, import_node_path9.join)((0, import_node_os2.homedir)(), USER_TEMPLATE_DIR_NAME);
10375
+ return (0, import_node_path8.join)((0, import_node_os2.homedir)(), USER_TEMPLATE_DIR_NAME);
10449
10376
  }
10450
10377
  function listUserTemplates() {
10451
10378
  const dir = getUserTemplateDir();
@@ -10456,14 +10383,14 @@ function listUserTemplates() {
10456
10383
  const files = (0, import_node_fs4.readdirSync)(dir);
10457
10384
  return files.filter((f) => f.endsWith(".json")).map((f) => ({
10458
10385
  name: f.replace(/\.json$/, ""),
10459
- filePath: (0, import_node_path9.join)(dir, f)
10386
+ filePath: (0, import_node_path8.join)(dir, f)
10460
10387
  }));
10461
10388
  } catch {
10462
10389
  return [];
10463
10390
  }
10464
10391
  }
10465
10392
  function resolveUserTemplate(name) {
10466
- const filePath = (0, import_node_path9.join)(getUserTemplateDir(), `${name}.json`);
10393
+ const filePath = (0, import_node_path8.join)(getUserTemplateDir(), `${name}.json`);
10467
10394
  if ((0, import_node_fs4.existsSync)(filePath)) {
10468
10395
  return filePath;
10469
10396
  }
@@ -12200,7 +12127,7 @@ async function captureDatabase(config, options) {
12200
12127
  }
12201
12128
 
12202
12129
  // ../../packages/core/dist/sharePipeline.js
12203
- var import_promises9 = require("fs/promises");
12130
+ var import_promises8 = require("fs/promises");
12204
12131
 
12205
12132
  // ../../packages/core/dist/sharing/gistUpload.js
12206
12133
  var import_node_https = __toESM(require("https"), 1);
@@ -12288,11 +12215,11 @@ function formatSize(bytes) {
12288
12215
  }
12289
12216
  async function shareRealityPack(filePath, options) {
12290
12217
  const pack = await loadRealityPack(filePath);
12291
- const fileStat = await (0, import_promises9.stat)(filePath);
12218
+ const fileStat = await (0, import_promises8.stat)(filePath);
12292
12219
  const size = formatSize(fileStat.size);
12293
12220
  const method = options?.method ?? "file";
12294
12221
  if (method === "gist") {
12295
- const content = await (0, import_promises9.readFile)(filePath, "utf-8");
12222
+ const content = await (0, import_promises8.readFile)(filePath, "utf-8");
12296
12223
  const compressed = await compressPack(content);
12297
12224
  const compressedSize = formatSize(compressed.length);
12298
12225
  const filename = `${pack.metadata.name}.realitydb-pack.json`;
@@ -12764,6 +12691,316 @@ function maskConnectionString(connectionString) {
12764
12691
  }
12765
12692
  }
12766
12693
 
12694
+ // src/commands/init.ts
12695
+ var CONFIG_FILE = "realitydb.config.json";
12696
+ var DEFAULT_CONNECTION = "postgres://postgres:postgres@localhost:5432/myapp_dev";
12697
+ function ask(rl, prompt) {
12698
+ return new Promise((resolve12) => {
12699
+ rl.question(prompt, (answer) => {
12700
+ resolve12(answer);
12701
+ });
12702
+ });
12703
+ }
12704
+ async function initCommand() {
12705
+ const rl = (0, import_node_readline.createInterface)({ input: import_node_process.stdin, output: import_node_process.stdout });
12706
+ rl.on("close", () => {
12707
+ if (!wizardComplete) {
12708
+ console.log("");
12709
+ console.log("");
12710
+ console.log("Init cancelled.");
12711
+ console.log("");
12712
+ process.exit(0);
12713
+ }
12714
+ });
12715
+ let wizardComplete = false;
12716
+ try {
12717
+ console.log("");
12718
+ console.log("Welcome to RealityDB");
12719
+ console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
12720
+ console.log("");
12721
+ console.log("Let's connect to your database and fill it with realistic data.");
12722
+ console.log("");
12723
+ if ((0, import_node_fs7.existsSync)(CONFIG_FILE)) {
12724
+ const overwrite = await ask(rl, `${CONFIG_FILE} already exists. Overwrite? (y/N) `);
12725
+ if (overwrite.toLowerCase() !== "y") {
12726
+ wizardComplete = true;
12727
+ console.log("");
12728
+ console.log("Init cancelled. Existing config preserved.");
12729
+ console.log("");
12730
+ return;
12731
+ }
12732
+ console.log("");
12733
+ }
12734
+ let connectionString;
12735
+ let scanResult;
12736
+ let masked;
12737
+ while (true) {
12738
+ console.log("Step 1: Database Connection");
12739
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12740
+ connectionString = await promptWithDefault(
12741
+ rl,
12742
+ "PostgreSQL connection string",
12743
+ DEFAULT_CONNECTION
12744
+ );
12745
+ console.log("");
12746
+ console.log("Step 2: Connecting & Scanning");
12747
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12748
+ masked = maskConnectionString(connectionString);
12749
+ console.log(` Connecting to ${masked}...`);
12750
+ const scanConfig = {
12751
+ database: { client: "postgres", connectionString },
12752
+ seed: { defaultRecords: 50, batchSize: 1e3, environment: "dev" }
12753
+ };
12754
+ try {
12755
+ scanResult = await scanDatabase(scanConfig);
12756
+ break;
12757
+ } catch (err) {
12758
+ const msg = err instanceof Error ? err.message : String(err);
12759
+ console.error("");
12760
+ console.error(` Connection failed: ${msg}`);
12761
+ console.error("");
12762
+ console.error("Hints:");
12763
+ console.error(" - Is PostgreSQL running? (docker ps, pg_isready)");
12764
+ console.error(" - Check host, port, username, password, and database name");
12765
+ console.error(" - Ensure the database exists (createdb myapp_dev)");
12766
+ console.error("");
12767
+ const retry = await ask(rl, "Try a different connection string? (Y/n) ");
12768
+ if (retry.toLowerCase() === "n") {
12769
+ wizardComplete = true;
12770
+ process.exit(1);
12771
+ }
12772
+ console.log("");
12773
+ }
12774
+ }
12775
+ const { schema } = scanResult;
12776
+ console.log(" Connected successfully.");
12777
+ console.log("");
12778
+ if (schema.tables.length === 0) {
12779
+ wizardComplete = true;
12780
+ console.log(" No tables found in the public schema.");
12781
+ console.log("");
12782
+ console.log(" Run your migrations first, then try again:");
12783
+ console.log(" npx prisma migrate dev");
12784
+ console.log(" npx knex migrate:latest");
12785
+ console.log(" rails db:migrate");
12786
+ console.log("");
12787
+ process.exit(1);
12788
+ }
12789
+ console.log("Step 3: Schema");
12790
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12791
+ console.log(` Found ${schema.tables.length} tables, ${schema.foreignKeys.length} foreign keys`);
12792
+ console.log("");
12793
+ console.log(" Tables:");
12794
+ for (const table of schema.tables) {
12795
+ const colCount = table.columns.length;
12796
+ const pkLabel = table.primaryKey ? ` PK: ${table.primaryKey.columnName}` : "";
12797
+ console.log(` ${table.name} (${colCount} cols${pkLabel})`);
12798
+ }
12799
+ console.log("");
12800
+ console.log("Step 4: Template Selection");
12801
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12802
+ const registry = getDefaultRegistry();
12803
+ const allTemplates = registry.list();
12804
+ const detected = detectTemplate(schema.tables.map((t) => t.name), allTemplates);
12805
+ let templateName;
12806
+ if (detected) {
12807
+ console.log(` Auto-detected domain: ${detected.name}`);
12808
+ console.log(` ${detected.description}`);
12809
+ console.log("");
12810
+ const useDetected = await ask(rl, ` Use "${detected.name}" template? (Y/n) `);
12811
+ if (useDetected.toLowerCase() !== "n") {
12812
+ templateName = detected.name;
12813
+ }
12814
+ }
12815
+ if (!templateName) {
12816
+ console.log("");
12817
+ console.log(" Available templates:");
12818
+ for (let i = 0; i < allTemplates.length; i++) {
12819
+ console.log(` ${i + 1}. ${allTemplates[i].name} \u2014 ${allTemplates[i].description}`);
12820
+ }
12821
+ console.log(` ${allTemplates.length + 1}. none \u2014 use schema-only generation`);
12822
+ console.log("");
12823
+ const choice = await ask(rl, ` Choose template (1-${allTemplates.length + 1}): `);
12824
+ const choiceNum = parseInt(choice, 10);
12825
+ if (choiceNum >= 1 && choiceNum <= allTemplates.length) {
12826
+ templateName = allTemplates[choiceNum - 1].name;
12827
+ }
12828
+ }
12829
+ console.log("");
12830
+ console.log("Step 5: Configuration");
12831
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12832
+ const recordsStr = await promptWithDefault(rl, "Records per table", "50");
12833
+ const records = parseInt(recordsStr, 10) || 50;
12834
+ console.log("");
12835
+ console.log("Step 6: Writing Config");
12836
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12837
+ const config = {
12838
+ database: {
12839
+ client: "postgres",
12840
+ connectionString
12841
+ },
12842
+ seed: {
12843
+ defaultRecords: records,
12844
+ batchSize: 1e3,
12845
+ environment: "dev",
12846
+ randomSeed: 42
12847
+ },
12848
+ ...templateName ? { template: templateName } : {}
12849
+ };
12850
+ (0, import_node_fs7.writeFileSync)(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
12851
+ console.log(` Created ${CONFIG_FILE}`);
12852
+ console.log("");
12853
+ const runSeed = await ask(rl, "Run initial seed now? (Y/n) ");
12854
+ if (runSeed.toLowerCase() !== "n") {
12855
+ console.log("");
12856
+ console.log("Seeding...");
12857
+ try {
12858
+ const result = await seedDatabase(config, {
12859
+ records,
12860
+ seed: 42,
12861
+ template: templateName
12862
+ });
12863
+ console.log("");
12864
+ for (const tableResult of result.insertResult.tables) {
12865
+ console.log(
12866
+ ` ${tableResult.tableName}: ${tableResult.rowsInserted} rows`
12867
+ );
12868
+ }
12869
+ const totalTime = (result.durationMs / 1e3).toFixed(1);
12870
+ console.log("");
12871
+ console.log(` Seed complete. ${result.totalRows} rows in ${totalTime}s`);
12872
+ } catch (err) {
12873
+ const msg = err instanceof Error ? err.message : String(err);
12874
+ console.error("");
12875
+ console.error(` Seed failed: ${msg}`);
12876
+ console.error(" You can retry later with: realitydb seed");
12877
+ }
12878
+ }
12879
+ wizardComplete = true;
12880
+ console.log("");
12881
+ console.log("RealityDB initialized!");
12882
+ console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
12883
+ console.log(` Config: ./${CONFIG_FILE}`);
12884
+ console.log(` Database: ${masked}`);
12885
+ if (templateName) {
12886
+ console.log(` Template: ${templateName}`);
12887
+ }
12888
+ console.log(` Records: ${records} per table`);
12889
+ console.log("");
12890
+ console.log("Next steps:");
12891
+ console.log(" realitydb scan Inspect your schema");
12892
+ console.log(" realitydb seed Generate data");
12893
+ console.log(" realitydb export Export without writing to DB");
12894
+ console.log(" realitydb analyze Generate a custom template");
12895
+ console.log(" realitydb --help See all commands");
12896
+ console.log("");
12897
+ } finally {
12898
+ rl.close();
12899
+ }
12900
+ }
12901
+ async function promptWithDefault(rl, label, defaultValue) {
12902
+ console.log(` ${label}`);
12903
+ console.log(` Default: ${defaultValue}`);
12904
+ const answer = await ask(rl, " > ");
12905
+ return answer.trim() || defaultValue;
12906
+ }
12907
+ function detectTemplate(tableNames, templates) {
12908
+ const lower = new Set(tableNames.map((t) => t.toLowerCase()));
12909
+ let bestMatch = null;
12910
+ let bestScore = 0;
12911
+ for (const template of templates) {
12912
+ let matches = 0;
12913
+ for (const target of template.targetTables) {
12914
+ if (lower.has(target.toLowerCase())) {
12915
+ matches++;
12916
+ }
12917
+ }
12918
+ if (matches >= 2 && matches > bestScore) {
12919
+ bestScore = matches;
12920
+ bestMatch = template;
12921
+ }
12922
+ }
12923
+ return bestMatch;
12924
+ }
12925
+
12926
+ // ../../packages/config/dist/loadConfig.js
12927
+ var import_promises9 = require("fs/promises");
12928
+ var import_node_path9 = require("path");
12929
+
12930
+ // ../../packages/config/dist/defaults.js
12931
+ var DEFAULT_CONFIG = {
12932
+ seed: {
12933
+ defaultRecords: 5e3,
12934
+ batchSize: 1e3,
12935
+ environment: "dev"
12936
+ },
12937
+ export: {
12938
+ defaultFormat: "json",
12939
+ outputDir: "./.databox"
12940
+ }
12941
+ };
12942
+
12943
+ // ../../packages/config/dist/loadConfig.js
12944
+ var CONFIG_FILES = ["realitydb.config.json", "seedforge.config.json", "databox.config.json"];
12945
+ async function findConfigFile(basePath) {
12946
+ for (const name of CONFIG_FILES) {
12947
+ const fullPath = (0, import_node_path9.resolve)(basePath, name);
12948
+ try {
12949
+ await (0, import_promises9.access)(fullPath);
12950
+ return fullPath;
12951
+ } catch {
12952
+ continue;
12953
+ }
12954
+ }
12955
+ return null;
12956
+ }
12957
+ async function loadConfig(filePath) {
12958
+ let resolvedPath;
12959
+ if (filePath) {
12960
+ resolvedPath = (0, import_node_path9.resolve)(filePath);
12961
+ } else {
12962
+ const found = await findConfigFile(".");
12963
+ if (!found) {
12964
+ throw new Error(`[realitydb] Config file not found.
12965
+ Create a realitydb.config.json or specify a path with --config.`);
12966
+ }
12967
+ resolvedPath = found;
12968
+ }
12969
+ let raw;
12970
+ try {
12971
+ raw = await (0, import_promises9.readFile)(resolvedPath, "utf-8");
12972
+ } catch {
12973
+ throw new Error(`[realitydb] Config file not found: ${resolvedPath}
12974
+ Create a realitydb.config.json or specify a path with --config.`);
12975
+ }
12976
+ let parsed;
12977
+ try {
12978
+ parsed = JSON.parse(raw);
12979
+ } catch {
12980
+ throw new Error(`[realitydb] Invalid JSON in config file: ${resolvedPath}`);
12981
+ }
12982
+ const config = parsed;
12983
+ const database = config["database"];
12984
+ if (!database || typeof database["connectionString"] !== "string") {
12985
+ throw new Error("[realitydb] Config validation failed: database.connectionString is required.");
12986
+ }
12987
+ return {
12988
+ database: {
12989
+ client: "postgres",
12990
+ connectionString: database["connectionString"]
12991
+ },
12992
+ seed: {
12993
+ ...DEFAULT_CONFIG.seed,
12994
+ ...config["seed"] ?? {}
12995
+ },
12996
+ template: config["template"],
12997
+ export: {
12998
+ ...DEFAULT_CONFIG.export,
12999
+ ...config["export"] ?? {}
13000
+ }
13001
+ };
13002
+ }
13003
+
12767
13004
  // src/commands/scan.ts
12768
13005
  var VERSION2 = "0.10.0";
12769
13006
  async function scanCommand(options) {
@@ -13317,7 +13554,7 @@ async function exportCommand(options) {
13317
13554
  }
13318
13555
 
13319
13556
  // src/commands/templates.ts
13320
- var import_node_fs7 = require("fs");
13557
+ var import_node_fs8 = require("fs");
13321
13558
  var VERSION6 = "0.10.0";
13322
13559
  function templatesCommand() {
13323
13560
  const registry = getDefaultRegistry();
@@ -13344,7 +13581,7 @@ function templatesCommand() {
13344
13581
  }
13345
13582
  function templatesInitCommand() {
13346
13583
  const fileName = "realitydb.template.json";
13347
- if ((0, import_node_fs7.existsSync)(fileName)) {
13584
+ if ((0, import_node_fs8.existsSync)(fileName)) {
13348
13585
  console.error(`[realitydb] ${fileName} already exists in this directory.`);
13349
13586
  process.exit(1);
13350
13587
  }
@@ -13378,7 +13615,7 @@ function templatesInitCommand() {
13378
13615
  }
13379
13616
  }
13380
13617
  };
13381
- (0, import_node_fs7.writeFileSync)(fileName, JSON.stringify(scaffold, null, 2) + "\n");
13618
+ (0, import_node_fs8.writeFileSync)(fileName, JSON.stringify(scaffold, null, 2) + "\n");
13382
13619
  console.log("");
13383
13620
  console.log(`Created ${fileName}`);
13384
13621
  console.log("Edit this file to define your custom template.");
@@ -13389,7 +13626,7 @@ function templatesInitCommand() {
13389
13626
  }
13390
13627
  function templatesValidateCommand(filePath, options) {
13391
13628
  const start = performance.now();
13392
- if (!(0, import_node_fs7.existsSync)(filePath)) {
13629
+ if (!(0, import_node_fs8.existsSync)(filePath)) {
13393
13630
  if (options.ci) {
13394
13631
  console.log(formatCIOutput({
13395
13632
  success: false,
@@ -13406,7 +13643,7 @@ function templatesValidateCommand(filePath, options) {
13406
13643
  }
13407
13644
  let json;
13408
13645
  try {
13409
- const raw = (0, import_node_fs7.readFileSync)(filePath, "utf-8");
13646
+ const raw = (0, import_node_fs8.readFileSync)(filePath, "utf-8");
13410
13647
  json = JSON.parse(raw);
13411
13648
  } catch {
13412
13649
  if (options.ci) {
@@ -13469,7 +13706,7 @@ function templatesValidateCommand(filePath, options) {
13469
13706
  }
13470
13707
 
13471
13708
  // src/commands/scenarios.ts
13472
- var import_node_fs8 = require("fs");
13709
+ var import_node_fs9 = require("fs");
13473
13710
  var import_node_path12 = require("path");
13474
13711
  function scenariosCommand() {
13475
13712
  const registry = getDefaultScenarioRegistry();
@@ -13494,12 +13731,12 @@ function scenariosCreateCommand(name) {
13494
13731
  const sanitized = name.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-");
13495
13732
  const fileName = `${sanitized}.scenario.json`;
13496
13733
  const filePath = (0, import_node_path12.resolve)(fileName);
13497
- if ((0, import_node_fs8.existsSync)(filePath)) {
13734
+ if ((0, import_node_fs9.existsSync)(filePath)) {
13498
13735
  console.error(`[realitydb] File already exists: ${fileName}`);
13499
13736
  process.exit(1);
13500
13737
  }
13501
13738
  const scaffold = scaffoldCustomScenario(sanitized);
13502
- (0, import_node_fs8.writeFileSync)(filePath, JSON.stringify(scaffold, null, 2) + "\n", "utf-8");
13739
+ (0, import_node_fs9.writeFileSync)(filePath, JSON.stringify(scaffold, null, 2) + "\n", "utf-8");
13503
13740
  console.log("");
13504
13741
  console.log(`Created custom scenario: ${fileName}`);
13505
13742
  console.log("");
@@ -14254,7 +14491,7 @@ function getDefaultSchema() {
14254
14491
  }
14255
14492
 
14256
14493
  // src/commands/analyze.ts
14257
- var import_node_fs9 = require("fs");
14494
+ var import_node_fs10 = require("fs");
14258
14495
  var import_node_path16 = require("path");
14259
14496
  var VERSION12 = "1.3.1";
14260
14497
  async function analyzeCommand(options) {
@@ -14296,14 +14533,14 @@ async function analyzeCommand(options) {
14296
14533
  }));
14297
14534
  if (result.templateJson && options.output) {
14298
14535
  const filePath = (0, import_node_path16.resolve)(options.output);
14299
- (0, import_node_fs9.writeFileSync)(filePath, result.templateJson + "\n", "utf-8");
14536
+ (0, import_node_fs10.writeFileSync)(filePath, result.templateJson + "\n", "utf-8");
14300
14537
  }
14301
14538
  return;
14302
14539
  }
14303
14540
  console.log(formatAnalysisReport(result.report));
14304
14541
  if (result.templateJson && options.output) {
14305
14542
  const filePath = (0, import_node_path16.resolve)(options.output);
14306
- (0, import_node_fs9.writeFileSync)(filePath, result.templateJson + "\n", "utf-8");
14543
+ (0, import_node_fs10.writeFileSync)(filePath, result.templateJson + "\n", "utf-8");
14307
14544
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
14308
14545
  console.log(`Template generated: ${filePath}`);
14309
14546
  console.log("");
@@ -14348,7 +14585,7 @@ async function analyzeCommand(options) {
14348
14585
  }
14349
14586
 
14350
14587
  // src/commands/mask.ts
14351
- var import_node_fs10 = require("fs");
14588
+ var import_node_fs11 = require("fs");
14352
14589
  var import_node_path17 = require("path");
14353
14590
  var VERSION13 = "1.3.1";
14354
14591
  async function maskCommand(options) {
@@ -14426,7 +14663,7 @@ async function maskCommand(options) {
14426
14663
  const durationMs = Math.round(performance.now() - start);
14427
14664
  if (options.auditLog) {
14428
14665
  const auditPath = (0, import_node_path17.resolve)(options.auditLog);
14429
- (0, import_node_fs10.writeFileSync)(auditPath, serializeAuditLog(result.auditLog) + "\n", "utf-8");
14666
+ (0, import_node_fs11.writeFileSync)(auditPath, serializeAuditLog(result.auditLog) + "\n", "utf-8");
14430
14667
  }
14431
14668
  if (options.ci) {
14432
14669
  console.log(formatCIOutput({
@@ -14501,7 +14738,7 @@ async function maskCommand(options) {
14501
14738
  }
14502
14739
 
14503
14740
  // src/commands/classroom.ts
14504
- var import_node_fs11 = require("fs");
14741
+ var import_node_fs12 = require("fs");
14505
14742
  var import_node_path18 = require("path");
14506
14743
  var VERSION14 = "1.3.1";
14507
14744
  async function classroomListCommand(options) {
@@ -14766,7 +15003,7 @@ async function classroomCreateCommand(name, options) {
14766
15003
  const content = classroomCreate(name);
14767
15004
  const filename = `${name}.course.json`;
14768
15005
  const filePath = (0, import_node_path18.resolve)(filename);
14769
- (0, import_node_fs11.writeFileSync)(filePath, content + "\n", "utf-8");
15006
+ (0, import_node_fs12.writeFileSync)(filePath, content + "\n", "utf-8");
14770
15007
  const durationMs = Math.round(performance.now() - start);
14771
15008
  if (options.ci) {
14772
15009
  console.log(formatCIOutput({
@@ -15016,10 +15253,13 @@ async function simulateWebhooksCommand(options) {
15016
15253
  }
15017
15254
 
15018
15255
  // src/cli.ts
15019
- var VERSION16 = "1.4.4";
15256
+ var VERSION16 = "1.5.0";
15020
15257
  function run(argv) {
15021
15258
  const program2 = new Command();
15022
15259
  program2.name("realitydb").description("RealityDB \u2014 Developer Reality Platform").version(VERSION16).option("--config <path>", "Path to config file").option("--ci", "CI mode: JSON output, no prompts, proper exit codes", false).option("--verbose", "Enable verbose output", false);
15260
+ program2.command("init").description("Interactive setup wizard \u2014 connect, scan, and seed in one step").action(async () => {
15261
+ await initCommand();
15262
+ });
15023
15263
  program2.command("scan").description("Scan database schema").action(async () => {
15024
15264
  const opts = program2.opts();
15025
15265
  await scanCommand({ ci: opts.ci, configPath: opts.config });
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "realitydb",
3
-
4
- "version": "1.4.4",
3
+ "version": "1.5.0",
5
4
  "description": "Developer Reality Platform - realistic database environments from your schema",
6
5
  "license": "MIT",
7
6
  "keywords": [
@@ -60,4 +59,3 @@
60
59
  "pg": "^8.20.0"
61
60
  }
62
61
  }
63
-