realitydb 1.4.3 → 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.
- package/dist/index.js +479 -227
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -3476,83 +3476,10 @@ var {
|
|
|
3476
3476
|
Help
|
|
3477
3477
|
} = import_index.default;
|
|
3478
3478
|
|
|
3479
|
-
//
|
|
3480
|
-
var
|
|
3481
|
-
var
|
|
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
|
|
4394
|
-
var
|
|
4320
|
+
var import_promises = require("fs/promises");
|
|
4321
|
+
var import_node_path = require("path");
|
|
4395
4322
|
async function exportToJson(dataset, outputDir) {
|
|
4396
|
-
await (0,
|
|
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,
|
|
4326
|
+
const filePath = (0, import_node_path.join)(outputDir, `${tableName}.json`);
|
|
4400
4327
|
const content = JSON.stringify(table.rows, null, 2);
|
|
4401
|
-
await (0,
|
|
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
|
|
4409
|
-
var
|
|
4335
|
+
var import_promises2 = require("fs/promises");
|
|
4336
|
+
var import_node_path2 = require("path");
|
|
4410
4337
|
async function exportToCsv(dataset, outputDir) {
|
|
4411
|
-
await (0,
|
|
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,
|
|
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,
|
|
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
|
|
4432
|
-
var
|
|
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,
|
|
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,
|
|
4452
|
-
await (0,
|
|
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
|
|
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
|
|
5806
|
-
var
|
|
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,
|
|
5855
|
-
await (0,
|
|
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,
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
6369
|
+
var import_promises7 = require("fs/promises");
|
|
6443
6370
|
async function writeJsonHeader(filePath) {
|
|
6444
|
-
await (0,
|
|
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,
|
|
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
|
|
7239
|
+
var import_node_path6 = require("path");
|
|
7313
7240
|
var import_node_os = require("os");
|
|
7314
7241
|
function getProgressDir() {
|
|
7315
|
-
return (0,
|
|
7242
|
+
return (0, import_node_path6.join)((0, import_node_os.homedir)(), ".realitydb");
|
|
7316
7243
|
}
|
|
7317
7244
|
function getProgressPath() {
|
|
7318
|
-
return (0,
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
}
|
|
@@ -10478,27 +10405,27 @@ var saasLifecycle = {
|
|
|
10478
10405
|
{
|
|
10479
10406
|
name: "trial",
|
|
10480
10407
|
weight: 0.12,
|
|
10481
|
-
columnValues: {}
|
|
10408
|
+
columnValues: { status: "active" }
|
|
10482
10409
|
},
|
|
10483
10410
|
{
|
|
10484
10411
|
name: "active",
|
|
10485
10412
|
weight: 0.65,
|
|
10486
|
-
columnValues: {}
|
|
10413
|
+
columnValues: { status: "active" }
|
|
10487
10414
|
},
|
|
10488
10415
|
{
|
|
10489
10416
|
name: "churned",
|
|
10490
10417
|
weight: 0.1,
|
|
10491
|
-
columnValues: {}
|
|
10418
|
+
columnValues: { status: "inactive" }
|
|
10492
10419
|
},
|
|
10493
10420
|
{
|
|
10494
10421
|
name: "past_due",
|
|
10495
10422
|
weight: 0.08,
|
|
10496
|
-
columnValues: {}
|
|
10423
|
+
columnValues: { status: "active" }
|
|
10497
10424
|
},
|
|
10498
10425
|
{
|
|
10499
10426
|
name: "paused",
|
|
10500
10427
|
weight: 0.05,
|
|
10501
|
-
columnValues: {}
|
|
10428
|
+
columnValues: { status: "inactive" }
|
|
10502
10429
|
}
|
|
10503
10430
|
],
|
|
10504
10431
|
transitions: [
|
|
@@ -10510,7 +10437,7 @@ var saasLifecycle = {
|
|
|
10510
10437
|
{
|
|
10511
10438
|
table: "subscriptions",
|
|
10512
10439
|
action: "create",
|
|
10513
|
-
values: { status: "active"
|
|
10440
|
+
values: { status: "active" }
|
|
10514
10441
|
},
|
|
10515
10442
|
{
|
|
10516
10443
|
table: "payments",
|
|
@@ -10613,20 +10540,6 @@ var saasLifecycle = {
|
|
|
10613
10540
|
}
|
|
10614
10541
|
],
|
|
10615
10542
|
correlations: [
|
|
10616
|
-
{
|
|
10617
|
-
description: "Enterprise plan users have 2x more payments (longer tenure)",
|
|
10618
|
-
condition: {
|
|
10619
|
-
table: "subscriptions",
|
|
10620
|
-
column: "plan",
|
|
10621
|
-
operator: "eq",
|
|
10622
|
-
value: "Enterprise"
|
|
10623
|
-
},
|
|
10624
|
-
effect: {
|
|
10625
|
-
table: "payments",
|
|
10626
|
-
column: "amount_cents",
|
|
10627
|
-
multiplier: 2
|
|
10628
|
-
}
|
|
10629
|
-
},
|
|
10630
10543
|
{
|
|
10631
10544
|
description: "Churned users always have a failed payment before cancel",
|
|
10632
10545
|
condition: {
|
|
@@ -11731,53 +11644,13 @@ async function seedDatabase(config, options) {
|
|
|
11731
11644
|
throw new Error(`Generation plan validation failed:
|
|
11732
11645
|
${validation.errors.join("\n")}`);
|
|
11733
11646
|
}
|
|
11734
|
-
let dataset;
|
|
11735
11647
|
const lifecycleUsed = !!options?.lifecycle;
|
|
11648
|
+
let dataset = timelineConfig ? generateTimelineDataset(plan, timelineConfig) : generateDataset(plan);
|
|
11736
11649
|
if (options?.lifecycle && options?.template) {
|
|
11737
11650
|
const lifecycle = resolveLifecycle(options.template);
|
|
11738
11651
|
if (lifecycle) {
|
|
11739
|
-
|
|
11740
|
-
const entityCount = effectiveConfig.seed.defaultRecords;
|
|
11741
|
-
const simResult = simulateLifecycles(lifecycle, entityCount, random);
|
|
11742
|
-
const correlatedResult = applyCorrelations(simResult, lifecycle.correlations, random);
|
|
11743
|
-
const schemaColumnLookup = /* @__PURE__ */ new Map();
|
|
11744
|
-
for (const table of schema.tables) {
|
|
11745
|
-
schemaColumnLookup.set(table.name, new Set(table.columns.map((c) => c.name)));
|
|
11746
|
-
}
|
|
11747
|
-
const tables = /* @__PURE__ */ new Map();
|
|
11748
|
-
let totalRows = 0;
|
|
11749
|
-
for (const [tableName, rows] of correlatedResult.tables) {
|
|
11750
|
-
const validColumns = schemaColumnLookup.get(tableName);
|
|
11751
|
-
const filteredRows = validColumns ? rows.map((row) => {
|
|
11752
|
-
const filtered = {};
|
|
11753
|
-
for (const [col, val] of Object.entries(row)) {
|
|
11754
|
-
if (validColumns.has(col)) {
|
|
11755
|
-
filtered[col] = val;
|
|
11756
|
-
} else {
|
|
11757
|
-
console.warn(`[lifecycle] Skipping column '${col}' on table '${tableName}' \u2014 column does not exist`);
|
|
11758
|
-
}
|
|
11759
|
-
}
|
|
11760
|
-
return filtered;
|
|
11761
|
-
}) : rows;
|
|
11762
|
-
tables.set(tableName, {
|
|
11763
|
-
tableName,
|
|
11764
|
-
columns: filteredRows.length > 0 ? Object.keys(filteredRows[0]) : [],
|
|
11765
|
-
rows: filteredRows,
|
|
11766
|
-
rowCount: filteredRows.length
|
|
11767
|
-
});
|
|
11768
|
-
totalRows += filteredRows.length;
|
|
11769
|
-
}
|
|
11770
|
-
dataset = {
|
|
11771
|
-
tables,
|
|
11772
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11773
|
-
seed: plan.reproducibility.randomSeed,
|
|
11774
|
-
totalRows
|
|
11775
|
-
};
|
|
11776
|
-
} else {
|
|
11777
|
-
dataset = timelineConfig ? generateTimelineDataset(plan, timelineConfig) : generateDataset(plan);
|
|
11652
|
+
dataset = applyLifecycleOverlay(dataset, lifecycle, plan, schema);
|
|
11778
11653
|
}
|
|
11779
|
-
} else {
|
|
11780
|
-
dataset = timelineConfig ? generateTimelineDataset(plan, timelineConfig) : generateDataset(plan);
|
|
11781
11654
|
}
|
|
11782
11655
|
let scenariosApplied;
|
|
11783
11656
|
let scenarioReportData;
|
|
@@ -11819,6 +11692,66 @@ ${validation.errors.join("\n")}`);
|
|
|
11819
11692
|
await closeConnection(pool);
|
|
11820
11693
|
}
|
|
11821
11694
|
}
|
|
11695
|
+
function applyLifecycleOverlay(dataset, lifecycle, plan, schema) {
|
|
11696
|
+
const random = createSeededRandom(plan.reproducibility.randomSeed);
|
|
11697
|
+
const rootTable = dataset.tables.get(lifecycle.rootTable);
|
|
11698
|
+
const entityCount = rootTable?.rowCount ?? plan.tables[0]?.rowCount ?? 0;
|
|
11699
|
+
const simResult = simulateLifecycles(lifecycle, entityCount, random);
|
|
11700
|
+
const correlatedResult = applyCorrelations(simResult, lifecycle.correlations, random);
|
|
11701
|
+
const schemaColumnLookup = /* @__PURE__ */ new Map();
|
|
11702
|
+
for (const table of schema.tables) {
|
|
11703
|
+
schemaColumnLookup.set(table.name, new Set(table.columns.map((c) => c.name)));
|
|
11704
|
+
}
|
|
11705
|
+
const warnedColumns = /* @__PURE__ */ new Set();
|
|
11706
|
+
if (rootTable) {
|
|
11707
|
+
const lifecycleRootRows = correlatedResult.tables.get(lifecycle.rootTable);
|
|
11708
|
+
if (lifecycleRootRows) {
|
|
11709
|
+
const validColumns = schemaColumnLookup.get(lifecycle.rootTable);
|
|
11710
|
+
const count = Math.min(rootTable.rows.length, lifecycleRootRows.length);
|
|
11711
|
+
for (let i = 0; i < count; i++) {
|
|
11712
|
+
for (const [col, val] of Object.entries(lifecycleRootRows[i])) {
|
|
11713
|
+
if (col === "id")
|
|
11714
|
+
continue;
|
|
11715
|
+
if (validColumns && !validColumns.has(col)) {
|
|
11716
|
+
const key = `${lifecycle.rootTable}.${col}`;
|
|
11717
|
+
if (!warnedColumns.has(key)) {
|
|
11718
|
+
console.warn(`[lifecycle] Skipping column '${col}' on table '${lifecycle.rootTable}' \u2014 does not exist in schema`);
|
|
11719
|
+
warnedColumns.add(key);
|
|
11720
|
+
}
|
|
11721
|
+
continue;
|
|
11722
|
+
}
|
|
11723
|
+
rootTable.rows[i][col] = val;
|
|
11724
|
+
}
|
|
11725
|
+
}
|
|
11726
|
+
}
|
|
11727
|
+
}
|
|
11728
|
+
for (const [tableName, lifecycleRows] of correlatedResult.tables) {
|
|
11729
|
+
if (tableName === lifecycle.rootTable)
|
|
11730
|
+
continue;
|
|
11731
|
+
const existingTable = dataset.tables.get(tableName);
|
|
11732
|
+
if (!existingTable || lifecycleRows.length === 0)
|
|
11733
|
+
continue;
|
|
11734
|
+
const validColumns = schemaColumnLookup.get(tableName);
|
|
11735
|
+
const entityIdCol = `${lifecycle.entityName}_id`;
|
|
11736
|
+
const count = Math.min(lifecycleRows.length, existingTable.rows.length);
|
|
11737
|
+
for (let i = 0; i < count; i++) {
|
|
11738
|
+
for (const [col, val] of Object.entries(lifecycleRows[i])) {
|
|
11739
|
+
if (col === "id" || col === entityIdCol)
|
|
11740
|
+
continue;
|
|
11741
|
+
if (validColumns && !validColumns.has(col)) {
|
|
11742
|
+
const key = `${tableName}.${col}`;
|
|
11743
|
+
if (!warnedColumns.has(key)) {
|
|
11744
|
+
console.warn(`[lifecycle] Skipping column '${col}' on table '${tableName}' \u2014 does not exist in schema`);
|
|
11745
|
+
warnedColumns.add(key);
|
|
11746
|
+
}
|
|
11747
|
+
continue;
|
|
11748
|
+
}
|
|
11749
|
+
existingTable.rows[i][col] = val;
|
|
11750
|
+
}
|
|
11751
|
+
}
|
|
11752
|
+
}
|
|
11753
|
+
return dataset;
|
|
11754
|
+
}
|
|
11822
11755
|
function computeTotalMonths(tc) {
|
|
11823
11756
|
const start = new Date(tc.startDate);
|
|
11824
11757
|
const end = new Date(tc.endDate);
|
|
@@ -12194,7 +12127,7 @@ async function captureDatabase(config, options) {
|
|
|
12194
12127
|
}
|
|
12195
12128
|
|
|
12196
12129
|
// ../../packages/core/dist/sharePipeline.js
|
|
12197
|
-
var
|
|
12130
|
+
var import_promises8 = require("fs/promises");
|
|
12198
12131
|
|
|
12199
12132
|
// ../../packages/core/dist/sharing/gistUpload.js
|
|
12200
12133
|
var import_node_https = __toESM(require("https"), 1);
|
|
@@ -12282,11 +12215,11 @@ function formatSize(bytes) {
|
|
|
12282
12215
|
}
|
|
12283
12216
|
async function shareRealityPack(filePath, options) {
|
|
12284
12217
|
const pack = await loadRealityPack(filePath);
|
|
12285
|
-
const fileStat = await (0,
|
|
12218
|
+
const fileStat = await (0, import_promises8.stat)(filePath);
|
|
12286
12219
|
const size = formatSize(fileStat.size);
|
|
12287
12220
|
const method = options?.method ?? "file";
|
|
12288
12221
|
if (method === "gist") {
|
|
12289
|
-
const content = await (0,
|
|
12222
|
+
const content = await (0, import_promises8.readFile)(filePath, "utf-8");
|
|
12290
12223
|
const compressed = await compressPack(content);
|
|
12291
12224
|
const compressedSize = formatSize(compressed.length);
|
|
12292
12225
|
const filename = `${pack.metadata.name}.realitydb-pack.json`;
|
|
@@ -12758,12 +12691,322 @@ function maskConnectionString(connectionString) {
|
|
|
12758
12691
|
}
|
|
12759
12692
|
}
|
|
12760
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
|
+
|
|
12761
13004
|
// src/commands/scan.ts
|
|
12762
13005
|
var VERSION2 = "0.10.0";
|
|
12763
13006
|
async function scanCommand(options) {
|
|
12764
13007
|
const start = performance.now();
|
|
12765
13008
|
try {
|
|
12766
|
-
const config = await loadConfig();
|
|
13009
|
+
const config = await loadConfig(options.configPath);
|
|
12767
13010
|
const result = await scanDatabase(config);
|
|
12768
13011
|
const { schema } = result;
|
|
12769
13012
|
const masked = maskConnectionString(config.database.connectionString);
|
|
@@ -12883,7 +13126,7 @@ var VERSION3 = "1.3.1";
|
|
|
12883
13126
|
async function seedCommand(options) {
|
|
12884
13127
|
const start = performance.now();
|
|
12885
13128
|
try {
|
|
12886
|
-
const config = await loadConfig();
|
|
13129
|
+
const config = await loadConfig(options.configPath);
|
|
12887
13130
|
const records = options.records ? parseInt(options.records, 10) : void 0;
|
|
12888
13131
|
const seed = options.seed ? parseInt(options.seed, 10) : void 0;
|
|
12889
13132
|
const rawTemplateName = options.template ?? config.template;
|
|
@@ -13093,7 +13336,7 @@ async function resetCommand(options) {
|
|
|
13093
13336
|
process.exit(0);
|
|
13094
13337
|
}
|
|
13095
13338
|
try {
|
|
13096
|
-
const config = await loadConfig();
|
|
13339
|
+
const config = await loadConfig(options.configPath);
|
|
13097
13340
|
const masked = maskConnectionString(config.database.connectionString);
|
|
13098
13341
|
if (!options.ci) {
|
|
13099
13342
|
console.log("");
|
|
@@ -13158,7 +13401,7 @@ var VERSION5 = "1.3.1";
|
|
|
13158
13401
|
async function exportCommand(options) {
|
|
13159
13402
|
const start = performance.now();
|
|
13160
13403
|
try {
|
|
13161
|
-
const config = await loadConfig();
|
|
13404
|
+
const config = await loadConfig(options.configPath);
|
|
13162
13405
|
const format = options.format ?? config.export?.defaultFormat ?? "json";
|
|
13163
13406
|
const outputDir = options.output ?? config.export?.outputDir ?? "./.realitydb";
|
|
13164
13407
|
const records = options.records ? parseInt(options.records, 10) : void 0;
|
|
@@ -13311,7 +13554,7 @@ async function exportCommand(options) {
|
|
|
13311
13554
|
}
|
|
13312
13555
|
|
|
13313
13556
|
// src/commands/templates.ts
|
|
13314
|
-
var
|
|
13557
|
+
var import_node_fs8 = require("fs");
|
|
13315
13558
|
var VERSION6 = "0.10.0";
|
|
13316
13559
|
function templatesCommand() {
|
|
13317
13560
|
const registry = getDefaultRegistry();
|
|
@@ -13338,7 +13581,7 @@ function templatesCommand() {
|
|
|
13338
13581
|
}
|
|
13339
13582
|
function templatesInitCommand() {
|
|
13340
13583
|
const fileName = "realitydb.template.json";
|
|
13341
|
-
if ((0,
|
|
13584
|
+
if ((0, import_node_fs8.existsSync)(fileName)) {
|
|
13342
13585
|
console.error(`[realitydb] ${fileName} already exists in this directory.`);
|
|
13343
13586
|
process.exit(1);
|
|
13344
13587
|
}
|
|
@@ -13372,7 +13615,7 @@ function templatesInitCommand() {
|
|
|
13372
13615
|
}
|
|
13373
13616
|
}
|
|
13374
13617
|
};
|
|
13375
|
-
(0,
|
|
13618
|
+
(0, import_node_fs8.writeFileSync)(fileName, JSON.stringify(scaffold, null, 2) + "\n");
|
|
13376
13619
|
console.log("");
|
|
13377
13620
|
console.log(`Created ${fileName}`);
|
|
13378
13621
|
console.log("Edit this file to define your custom template.");
|
|
@@ -13383,7 +13626,7 @@ function templatesInitCommand() {
|
|
|
13383
13626
|
}
|
|
13384
13627
|
function templatesValidateCommand(filePath, options) {
|
|
13385
13628
|
const start = performance.now();
|
|
13386
|
-
if (!(0,
|
|
13629
|
+
if (!(0, import_node_fs8.existsSync)(filePath)) {
|
|
13387
13630
|
if (options.ci) {
|
|
13388
13631
|
console.log(formatCIOutput({
|
|
13389
13632
|
success: false,
|
|
@@ -13400,7 +13643,7 @@ function templatesValidateCommand(filePath, options) {
|
|
|
13400
13643
|
}
|
|
13401
13644
|
let json;
|
|
13402
13645
|
try {
|
|
13403
|
-
const raw = (0,
|
|
13646
|
+
const raw = (0, import_node_fs8.readFileSync)(filePath, "utf-8");
|
|
13404
13647
|
json = JSON.parse(raw);
|
|
13405
13648
|
} catch {
|
|
13406
13649
|
if (options.ci) {
|
|
@@ -13463,7 +13706,7 @@ function templatesValidateCommand(filePath, options) {
|
|
|
13463
13706
|
}
|
|
13464
13707
|
|
|
13465
13708
|
// src/commands/scenarios.ts
|
|
13466
|
-
var
|
|
13709
|
+
var import_node_fs9 = require("fs");
|
|
13467
13710
|
var import_node_path12 = require("path");
|
|
13468
13711
|
function scenariosCommand() {
|
|
13469
13712
|
const registry = getDefaultScenarioRegistry();
|
|
@@ -13488,12 +13731,12 @@ function scenariosCreateCommand(name) {
|
|
|
13488
13731
|
const sanitized = name.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
13489
13732
|
const fileName = `${sanitized}.scenario.json`;
|
|
13490
13733
|
const filePath = (0, import_node_path12.resolve)(fileName);
|
|
13491
|
-
if ((0,
|
|
13734
|
+
if ((0, import_node_fs9.existsSync)(filePath)) {
|
|
13492
13735
|
console.error(`[realitydb] File already exists: ${fileName}`);
|
|
13493
13736
|
process.exit(1);
|
|
13494
13737
|
}
|
|
13495
13738
|
const scaffold = scaffoldCustomScenario(sanitized);
|
|
13496
|
-
(0,
|
|
13739
|
+
(0, import_node_fs9.writeFileSync)(filePath, JSON.stringify(scaffold, null, 2) + "\n", "utf-8");
|
|
13497
13740
|
console.log("");
|
|
13498
13741
|
console.log(`Created custom scenario: ${fileName}`);
|
|
13499
13742
|
console.log("");
|
|
@@ -13518,7 +13761,7 @@ var import_node_path13 = require("path");
|
|
|
13518
13761
|
var import_promises10 = require("fs/promises");
|
|
13519
13762
|
async function packExportCommand(options) {
|
|
13520
13763
|
try {
|
|
13521
|
-
const config = await loadConfig();
|
|
13764
|
+
const config = await loadConfig(options.configPath);
|
|
13522
13765
|
const records = options.records ? parseInt(options.records, 10) : void 0;
|
|
13523
13766
|
const seed = options.seed ? parseInt(options.seed, 10) : void 0;
|
|
13524
13767
|
const rawTemplateName = options.template ?? config.template;
|
|
@@ -13620,7 +13863,7 @@ async function packImportCommand(filePath, options) {
|
|
|
13620
13863
|
console.error("Usage: realitydb pack import <file> --confirm");
|
|
13621
13864
|
process.exit(1);
|
|
13622
13865
|
}
|
|
13623
|
-
const config = await loadConfig();
|
|
13866
|
+
const config = await loadConfig(options.configPath);
|
|
13624
13867
|
const masked = maskConnectionString(config.database.connectionString);
|
|
13625
13868
|
const pack = await loadRealityPack(filePath);
|
|
13626
13869
|
console.log("");
|
|
@@ -13689,7 +13932,7 @@ async function captureCommand(options) {
|
|
|
13689
13932
|
console.error("Usage: realitydb capture --name <name>");
|
|
13690
13933
|
process.exit(1);
|
|
13691
13934
|
}
|
|
13692
|
-
const config = await loadConfig();
|
|
13935
|
+
const config = await loadConfig(options.configPath);
|
|
13693
13936
|
const masked = maskConnectionString(config.database.connectionString);
|
|
13694
13937
|
const tables = options.tables ? options.tables.split(",").map((t) => t.trim()).filter((t) => t.length > 0) : void 0;
|
|
13695
13938
|
if (!options.ci) {
|
|
@@ -13935,7 +14178,7 @@ async function loadCommand(filePath, options) {
|
|
|
13935
14178
|
}
|
|
13936
14179
|
return;
|
|
13937
14180
|
}
|
|
13938
|
-
const config = await loadConfig();
|
|
14181
|
+
const config = await loadConfig(options.configPath);
|
|
13939
14182
|
const masked = maskConnectionString(config.database.connectionString);
|
|
13940
14183
|
if (!options.ci) {
|
|
13941
14184
|
console.log("");
|
|
@@ -14248,13 +14491,13 @@ function getDefaultSchema() {
|
|
|
14248
14491
|
}
|
|
14249
14492
|
|
|
14250
14493
|
// src/commands/analyze.ts
|
|
14251
|
-
var
|
|
14494
|
+
var import_node_fs10 = require("fs");
|
|
14252
14495
|
var import_node_path16 = require("path");
|
|
14253
14496
|
var VERSION12 = "1.3.1";
|
|
14254
14497
|
async function analyzeCommand(options) {
|
|
14255
14498
|
const start = performance.now();
|
|
14256
14499
|
try {
|
|
14257
|
-
const config = await loadConfig();
|
|
14500
|
+
const config = await loadConfig(options.configPath);
|
|
14258
14501
|
const sampleSize = options.sampleSize ? parseInt(options.sampleSize, 10) : 1e3;
|
|
14259
14502
|
const masked = maskConnectionString(config.database.connectionString);
|
|
14260
14503
|
if (!options.ci) {
|
|
@@ -14290,14 +14533,14 @@ async function analyzeCommand(options) {
|
|
|
14290
14533
|
}));
|
|
14291
14534
|
if (result.templateJson && options.output) {
|
|
14292
14535
|
const filePath = (0, import_node_path16.resolve)(options.output);
|
|
14293
|
-
(0,
|
|
14536
|
+
(0, import_node_fs10.writeFileSync)(filePath, result.templateJson + "\n", "utf-8");
|
|
14294
14537
|
}
|
|
14295
14538
|
return;
|
|
14296
14539
|
}
|
|
14297
14540
|
console.log(formatAnalysisReport(result.report));
|
|
14298
14541
|
if (result.templateJson && options.output) {
|
|
14299
14542
|
const filePath = (0, import_node_path16.resolve)(options.output);
|
|
14300
|
-
(0,
|
|
14543
|
+
(0, import_node_fs10.writeFileSync)(filePath, result.templateJson + "\n", "utf-8");
|
|
14301
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");
|
|
14302
14545
|
console.log(`Template generated: ${filePath}`);
|
|
14303
14546
|
console.log("");
|
|
@@ -14342,13 +14585,13 @@ async function analyzeCommand(options) {
|
|
|
14342
14585
|
}
|
|
14343
14586
|
|
|
14344
14587
|
// src/commands/mask.ts
|
|
14345
|
-
var
|
|
14588
|
+
var import_node_fs11 = require("fs");
|
|
14346
14589
|
var import_node_path17 = require("path");
|
|
14347
14590
|
var VERSION13 = "1.3.1";
|
|
14348
14591
|
async function maskCommand(options) {
|
|
14349
14592
|
const start = performance.now();
|
|
14350
14593
|
try {
|
|
14351
|
-
const config = await loadConfig();
|
|
14594
|
+
const config = await loadConfig(options.configPath);
|
|
14352
14595
|
const mode = options.mode ?? "gdpr";
|
|
14353
14596
|
const seed = options.seed ? parseInt(options.seed, 10) : void 0;
|
|
14354
14597
|
const dryRun = options.dryRun ?? false;
|
|
@@ -14420,7 +14663,7 @@ async function maskCommand(options) {
|
|
|
14420
14663
|
const durationMs = Math.round(performance.now() - start);
|
|
14421
14664
|
if (options.auditLog) {
|
|
14422
14665
|
const auditPath = (0, import_node_path17.resolve)(options.auditLog);
|
|
14423
|
-
(0,
|
|
14666
|
+
(0, import_node_fs11.writeFileSync)(auditPath, serializeAuditLog(result.auditLog) + "\n", "utf-8");
|
|
14424
14667
|
}
|
|
14425
14668
|
if (options.ci) {
|
|
14426
14669
|
console.log(formatCIOutput({
|
|
@@ -14495,7 +14738,7 @@ async function maskCommand(options) {
|
|
|
14495
14738
|
}
|
|
14496
14739
|
|
|
14497
14740
|
// src/commands/classroom.ts
|
|
14498
|
-
var
|
|
14741
|
+
var import_node_fs12 = require("fs");
|
|
14499
14742
|
var import_node_path18 = require("path");
|
|
14500
14743
|
var VERSION14 = "1.3.1";
|
|
14501
14744
|
async function classroomListCommand(options) {
|
|
@@ -14557,7 +14800,7 @@ async function classroomListCommand(options) {
|
|
|
14557
14800
|
async function classroomStartCommand(courseName, options) {
|
|
14558
14801
|
const start = performance.now();
|
|
14559
14802
|
try {
|
|
14560
|
-
const config = await loadConfig();
|
|
14803
|
+
const config = await loadConfig(options.configPath);
|
|
14561
14804
|
const masked = maskConnectionString(config.database.connectionString);
|
|
14562
14805
|
if (!options.ci) {
|
|
14563
14806
|
console.log("");
|
|
@@ -14760,7 +15003,7 @@ async function classroomCreateCommand(name, options) {
|
|
|
14760
15003
|
const content = classroomCreate(name);
|
|
14761
15004
|
const filename = `${name}.course.json`;
|
|
14762
15005
|
const filePath = (0, import_node_path18.resolve)(filename);
|
|
14763
|
-
(0,
|
|
15006
|
+
(0, import_node_fs12.writeFileSync)(filePath, content + "\n", "utf-8");
|
|
14764
15007
|
const durationMs = Math.round(performance.now() - start);
|
|
14765
15008
|
if (options.ci) {
|
|
14766
15009
|
console.log(formatCIOutput({
|
|
@@ -15010,33 +15253,36 @@ async function simulateWebhooksCommand(options) {
|
|
|
15010
15253
|
}
|
|
15011
15254
|
|
|
15012
15255
|
// src/cli.ts
|
|
15013
|
-
var VERSION16 = "1.
|
|
15256
|
+
var VERSION16 = "1.5.0";
|
|
15014
15257
|
function run(argv) {
|
|
15015
15258
|
const program2 = new Command();
|
|
15016
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
|
+
});
|
|
15017
15263
|
program2.command("scan").description("Scan database schema").action(async () => {
|
|
15018
15264
|
const opts = program2.opts();
|
|
15019
|
-
await scanCommand({ ci: opts.ci });
|
|
15265
|
+
await scanCommand({ ci: opts.ci, configPath: opts.config });
|
|
15020
15266
|
});
|
|
15021
15267
|
program2.command("analyze").description("Analyze database schema and suggest column strategies").option("--output <file>", "Generate a template JSON file from analysis").option("--sample-size <count>", "Number of rows to sample per table", "1000").action(async (cmdOpts) => {
|
|
15022
15268
|
const opts = program2.opts();
|
|
15023
|
-
await analyzeCommand({ ...cmdOpts, ci: opts.ci });
|
|
15269
|
+
await analyzeCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15024
15270
|
});
|
|
15025
15271
|
program2.command("seed").description("Seed database with generated data").option("--records <count>", "Number of records per table").option("--template <name|path>", "Template name or path to custom .json file").option("--seed <number>", "Random seed for reproducibility").option("--timeline <duration>", 'Timeline duration (e.g., "12-months", "1-year")').option("--scenario <names>", "Scenarios to apply (comma-separated)").option("--scenario-intensity <level>", "Scenario intensity (low|medium|high)", "medium").option("--scenario-schedule <schedule>", 'Timeline-scheduled scenarios (e.g., "fraud-spike:month-6,churn-spike:month-9")').option("--lifecycle", "Enable lifecycle simulation for causally-connected data").action(async (cmdOpts) => {
|
|
15026
15272
|
const opts = program2.opts();
|
|
15027
|
-
await seedCommand({ ...cmdOpts, ci: opts.ci });
|
|
15273
|
+
await seedCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15028
15274
|
});
|
|
15029
15275
|
program2.command("reset").description("Reset seeded data").option("--confirm", "Confirm destructive operation").action(async (cmdOpts) => {
|
|
15030
15276
|
const opts = program2.opts();
|
|
15031
|
-
await resetCommand({ ...cmdOpts, ci: opts.ci });
|
|
15277
|
+
await resetCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15032
15278
|
});
|
|
15033
15279
|
program2.command("export").description("Export generated data").option("--format <format>", "Output format (json|csv|sql)", "json").option("--output <dir>", "Output directory", "./.realitydb").option("--records <count>", "Number of records per table").option("--seed <number>", "Random seed for reproducibility").option("--template <name>", "Template to use").option("--timeline <duration>", 'Timeline duration (e.g., "12-months", "1-year")').option("--scenario <names>", "Scenarios to apply (comma-separated)").option("--scenario-intensity <level>", "Scenario intensity (low|medium|high)", "medium").option("--scenario-schedule <schedule>", 'Timeline-scheduled scenarios (e.g., "fraud-spike:month-6,churn-spike:month-9")').action(async (cmdOpts) => {
|
|
15034
15280
|
const opts = program2.opts();
|
|
15035
|
-
await exportCommand({ ...cmdOpts, ci: opts.ci });
|
|
15281
|
+
await exportCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15036
15282
|
});
|
|
15037
15283
|
program2.command("generate").description("Generate large-scale datasets for data science (no database required)").option("--records <count>", "Number of records to generate", "1000").option("--schema <file>", "Schema definition file (.sql or .json)").option("--format <format>", "Output format (json|csv|parquet)", "json").option("--output <dir>", "Output directory", "./.realitydb/generated").option("--seed <number>", "Random seed for reproducibility").option("--table <name>", "Generate only a specific table").option("--correlations", "Enable cross-column correlations from schema").action(async (cmdOpts) => {
|
|
15038
15284
|
const opts = program2.opts();
|
|
15039
|
-
await generateCommand({ ...cmdOpts, ci: opts.ci });
|
|
15285
|
+
await generateCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15040
15286
|
});
|
|
15041
15287
|
const templates = program2.command("templates").description("Template management");
|
|
15042
15288
|
templates.command("list", { isDefault: true }).description("List available domain templates").action(templatesCommand);
|
|
@@ -15052,61 +15298,67 @@ function run(argv) {
|
|
|
15052
15298
|
});
|
|
15053
15299
|
program2.command("mask").description("Detect and mask PII in your database").option("--mode <mode>", "Compliance mode (hipaa|gdpr|strict)", "gdpr").option("--seed <number>", "Random seed for deterministic masking").option("--dry-run", "Preview PII detection without modifying data").option("--output <dir>", "Export masked data to files instead of writing to DB").option("--output-format <format>", "Output format (json|csv|sql)", "json").option("--audit-log <file>", "Write audit log to file").option("--confirm", "Confirm writing masked data back to database").action(async (cmdOpts) => {
|
|
15054
15300
|
const opts = program2.opts();
|
|
15055
|
-
await maskCommand({ ...cmdOpts, ci: opts.ci });
|
|
15301
|
+
await maskCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15056
15302
|
});
|
|
15057
15303
|
const classroom = program2.command("classroom").description("Education and classroom mode");
|
|
15058
15304
|
classroom.command("list", { isDefault: true }).description("List available courses").action(async () => {
|
|
15059
15305
|
const opts = program2.opts();
|
|
15060
|
-
await classroomListCommand({ ci: opts.ci });
|
|
15306
|
+
await classroomListCommand({ ci: opts.ci, configPath: opts.config });
|
|
15061
15307
|
});
|
|
15062
15308
|
classroom.command("start <course>").description("Load a course into your database").action(async (course) => {
|
|
15063
15309
|
const opts = program2.opts();
|
|
15064
|
-
await classroomStartCommand(course, { ci: opts.ci });
|
|
15310
|
+
await classroomStartCommand(course, { ci: opts.ci, configPath: opts.config });
|
|
15065
15311
|
});
|
|
15066
15312
|
classroom.command("status [course]").description("Show progress for all courses or a specific course").action(async (course) => {
|
|
15067
15313
|
const opts = program2.opts();
|
|
15068
|
-
await classroomStatusCommand(course, { ci: opts.ci });
|
|
15314
|
+
await classroomStatusCommand(course, { ci: opts.ci, configPath: opts.config });
|
|
15069
15315
|
});
|
|
15070
15316
|
classroom.command("complete <course> <exercise>").description("Mark an exercise as completed").action(async (course, exercise) => {
|
|
15071
15317
|
const opts = program2.opts();
|
|
15072
|
-
await classroomCompleteCommand(course, exercise, { ci: opts.ci });
|
|
15318
|
+
await classroomCompleteCommand(course, exercise, { ci: opts.ci, configPath: opts.config });
|
|
15073
15319
|
});
|
|
15074
15320
|
classroom.command("reset <course>").description("Reset progress for a course").action(async (course) => {
|
|
15075
15321
|
const opts = program2.opts();
|
|
15076
|
-
await classroomResetCommand(course, { ci: opts.ci });
|
|
15322
|
+
await classroomResetCommand(course, { ci: opts.ci, configPath: opts.config });
|
|
15077
15323
|
});
|
|
15078
15324
|
classroom.command("create <name>").description("Scaffold a custom course JSON file").action(async (name) => {
|
|
15079
15325
|
const opts = program2.opts();
|
|
15080
|
-
await classroomCreateCommand(name, { ci: opts.ci });
|
|
15326
|
+
await classroomCreateCommand(name, { ci: opts.ci, configPath: opts.config });
|
|
15081
15327
|
});
|
|
15082
15328
|
const simulate = program2.command("simulate").description("System behavior simulation");
|
|
15083
15329
|
simulate.command("run", { isDefault: true }).description("Run a simulation with a profile").option("--profile <name>", "Simulation profile (saas-startup|ecommerce-peak|api-service)", "saas-startup").option("--duration <duration>", "Override profile duration (e.g., 1-hour, 1-day, 1-week)").option("--events <count>", "Number of events to generate", "1000").option("--seed <number>", "Random seed for reproducibility").option("--output <file>", "Output file path").option("--format <format>", "Output format (json|ndjson)", "json").action(async (cmdOpts) => {
|
|
15084
15330
|
const opts = program2.opts();
|
|
15085
|
-
await simulateRunCommand({ ...cmdOpts, ci: opts.ci });
|
|
15331
|
+
await simulateRunCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15086
15332
|
});
|
|
15087
15333
|
simulate.command("profiles").description("List available simulation profiles").action(async () => {
|
|
15088
15334
|
const opts = program2.opts();
|
|
15089
|
-
await simulateProfilesCommand({ ci: opts.ci });
|
|
15335
|
+
await simulateProfilesCommand({ ci: opts.ci, configPath: opts.config });
|
|
15090
15336
|
});
|
|
15091
15337
|
simulate.command("webhooks").description("Generate webhook events from a specific source").option("--source <source>", "Webhook source (stripe|github)", "stripe").option("--events <count>", "Number of events to generate", "100").option("--seed <number>", "Random seed for reproducibility").option("--output <file>", "Output file path").option("--format <format>", "Output format (json|ndjson)", "json").action(async (cmdOpts) => {
|
|
15092
15338
|
const opts = program2.opts();
|
|
15093
|
-
await simulateWebhooksCommand({ ...cmdOpts, ci: opts.ci });
|
|
15339
|
+
await simulateWebhooksCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15094
15340
|
});
|
|
15095
15341
|
program2.command("capture").description("Capture live database state into a Reality Pack").requiredOption("--name <name>", "Name for the captured pack").option("--description <desc>", "Pack description").option("--tables <tables>", "Comma-separated list of tables to capture").option("--output <dir>", "Output directory", ".").action(async (cmdOpts) => {
|
|
15096
15342
|
const opts = program2.opts();
|
|
15097
|
-
await captureCommand({ ...cmdOpts, ci: opts.ci });
|
|
15343
|
+
await captureCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15098
15344
|
});
|
|
15099
15345
|
program2.command("share <file>").description("Share a Reality Pack file").option("--gist", "Upload to GitHub Gist").option("--description <desc>", "Gist description").action(async (filePath, cmdOpts) => {
|
|
15100
15346
|
const opts = program2.opts();
|
|
15101
|
-
await shareCommand(filePath, { ...cmdOpts, ci: opts.ci });
|
|
15347
|
+
await shareCommand(filePath, { ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15102
15348
|
});
|
|
15103
15349
|
program2.command("load <file>").description("Load a Reality Pack into the database (file path or URL)").option("--confirm", "Confirm import operation").option("--show-ddl", "Show schema DDL without importing").action(async (filePath, cmdOpts) => {
|
|
15104
15350
|
const opts = program2.opts();
|
|
15105
|
-
await loadCommand(filePath, { ...cmdOpts, ci: opts.ci });
|
|
15351
|
+
await loadCommand(filePath, { ...cmdOpts, ci: opts.ci, configPath: opts.config });
|
|
15106
15352
|
});
|
|
15107
15353
|
const pack = program2.command("pack").description("Reality Pack operations");
|
|
15108
|
-
pack.command("export").description("Export environment as Reality Pack").option("--name <name>", "Pack name").option("--description <desc>", "Pack description").option("--output <dir>", "Output directory", ".").option("--records <count>", "Number of records per table").option("--seed <number>", "Random seed for reproducibility").option("--template <name>", "Template to use").option("--timeline <duration>", 'Timeline duration (e.g., "12-months", "1-year")').option("--scenario <names>", "Scenarios to apply (comma-separated)").option("--scenario-intensity <level>", "Scenario intensity (low|medium|high)", "medium").option("--scenario-schedule <schedule>", 'Timeline-scheduled scenarios (e.g., "fraud-spike:month-6,churn-spike:month-9")').action(
|
|
15109
|
-
|
|
15354
|
+
pack.command("export").description("Export environment as Reality Pack").option("--name <name>", "Pack name").option("--description <desc>", "Pack description").option("--output <dir>", "Output directory", ".").option("--records <count>", "Number of records per table").option("--seed <number>", "Random seed for reproducibility").option("--template <name>", "Template to use").option("--timeline <duration>", 'Timeline duration (e.g., "12-months", "1-year")').option("--scenario <names>", "Scenarios to apply (comma-separated)").option("--scenario-intensity <level>", "Scenario intensity (low|medium|high)", "medium").option("--scenario-schedule <schedule>", 'Timeline-scheduled scenarios (e.g., "fraud-spike:month-6,churn-spike:month-9")').action(async (cmdOpts) => {
|
|
15355
|
+
const opts = program2.opts();
|
|
15356
|
+
await packExportCommand({ ...cmdOpts, configPath: opts.config });
|
|
15357
|
+
});
|
|
15358
|
+
pack.command("import <file>").description("Import Reality Pack into database").option("--confirm", "Confirm import operation").action(async (filePath, cmdOpts) => {
|
|
15359
|
+
const opts = program2.opts();
|
|
15360
|
+
await packImportCommand(filePath, { ...cmdOpts, configPath: opts.config });
|
|
15361
|
+
});
|
|
15110
15362
|
const packs = program2.command("packs").description("Browse available Reality Packs");
|
|
15111
15363
|
packs.command("list", { isDefault: true }).description("List available demo packs").action(() => {
|
|
15112
15364
|
const opts = program2.opts();
|
package/package.json
CHANGED