realitydb 0.2.0 → 0.3.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 +619 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6150,6 +6150,13 @@ async function truncateTables(pool, tableNames, cascade) {
|
|
|
6150
6150
|
};
|
|
6151
6151
|
}
|
|
6152
6152
|
|
|
6153
|
+
// ../../packages/db/dist/readTable.js
|
|
6154
|
+
async function readTableRows(pool, tableName, columns) {
|
|
6155
|
+
const quotedColumns = columns.map((c) => `"${c}"`).join(", ");
|
|
6156
|
+
const result = await pool.query(`SELECT ${quotedColumns} FROM "${tableName}"`);
|
|
6157
|
+
return result.rows;
|
|
6158
|
+
}
|
|
6159
|
+
|
|
6153
6160
|
// ../../packages/schema/dist/normalizer.js
|
|
6154
6161
|
function normalizeSchema(raw) {
|
|
6155
6162
|
const primaryKeyMap = /* @__PURE__ */ new Map();
|
|
@@ -6340,6 +6347,85 @@ async function introspectDatabase(pool, schemaName = "public") {
|
|
|
6340
6347
|
return schema;
|
|
6341
6348
|
}
|
|
6342
6349
|
|
|
6350
|
+
// ../../packages/schema/dist/generateDDL.js
|
|
6351
|
+
function generateCreateTableDDL(schema) {
|
|
6352
|
+
const orderedNames = orderByDependency(schema.tables, schema.foreignKeys);
|
|
6353
|
+
const tableMap = /* @__PURE__ */ new Map();
|
|
6354
|
+
for (const table of schema.tables) {
|
|
6355
|
+
tableMap.set(table.name, table);
|
|
6356
|
+
}
|
|
6357
|
+
const fksBySource = /* @__PURE__ */ new Map();
|
|
6358
|
+
for (const fk of schema.foreignKeys) {
|
|
6359
|
+
const existing = fksBySource.get(fk.sourceTable) ?? [];
|
|
6360
|
+
existing.push(fk);
|
|
6361
|
+
fksBySource.set(fk.sourceTable, existing);
|
|
6362
|
+
}
|
|
6363
|
+
const statements = [];
|
|
6364
|
+
for (const tableName of orderedNames) {
|
|
6365
|
+
const table = tableMap.get(tableName);
|
|
6366
|
+
if (!table)
|
|
6367
|
+
continue;
|
|
6368
|
+
const columnDefs = table.columns.sort((a, b) => a.ordinalPosition - b.ordinalPosition).map((col) => formatColumnDef(col));
|
|
6369
|
+
if (table.primaryKey) {
|
|
6370
|
+
columnDefs.push(` PRIMARY KEY ("${table.primaryKey.columnName}")`);
|
|
6371
|
+
}
|
|
6372
|
+
const tableFks = fksBySource.get(tableName) ?? [];
|
|
6373
|
+
for (const fk of tableFks) {
|
|
6374
|
+
columnDefs.push(` FOREIGN KEY ("${fk.sourceColumn}") REFERENCES "${fk.targetTable}" ("${fk.targetColumn}")`);
|
|
6375
|
+
}
|
|
6376
|
+
statements.push(`CREATE TABLE "${tableName}" (
|
|
6377
|
+
${columnDefs.join(",\n")}
|
|
6378
|
+
);`);
|
|
6379
|
+
}
|
|
6380
|
+
return statements.join("\n\n") + "\n";
|
|
6381
|
+
}
|
|
6382
|
+
function formatColumnDef(col) {
|
|
6383
|
+
let typeName = col.dataType.toUpperCase();
|
|
6384
|
+
if (col.maxLength && (typeName === "CHARACTER VARYING" || typeName === "VARCHAR")) {
|
|
6385
|
+
typeName = `VARCHAR(${col.maxLength})`;
|
|
6386
|
+
}
|
|
6387
|
+
let def = ` "${col.name}" ${typeName}`;
|
|
6388
|
+
if (!col.isNullable) {
|
|
6389
|
+
def += " NOT NULL";
|
|
6390
|
+
}
|
|
6391
|
+
if (col.hasDefault && col.defaultValue !== null) {
|
|
6392
|
+
def += ` DEFAULT ${col.defaultValue}`;
|
|
6393
|
+
}
|
|
6394
|
+
return def;
|
|
6395
|
+
}
|
|
6396
|
+
function orderByDependency(tables, foreignKeys) {
|
|
6397
|
+
const tableNames = new Set(tables.map((t) => t.name));
|
|
6398
|
+
const deps = /* @__PURE__ */ new Map();
|
|
6399
|
+
for (const name of tableNames) {
|
|
6400
|
+
deps.set(name, /* @__PURE__ */ new Set());
|
|
6401
|
+
}
|
|
6402
|
+
for (const fk of foreignKeys) {
|
|
6403
|
+
if (fk.sourceTable !== fk.targetTable && tableNames.has(fk.targetTable)) {
|
|
6404
|
+
deps.get(fk.sourceTable).add(fk.targetTable);
|
|
6405
|
+
}
|
|
6406
|
+
}
|
|
6407
|
+
const result = [];
|
|
6408
|
+
const visited = /* @__PURE__ */ new Set();
|
|
6409
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
6410
|
+
function visit(name) {
|
|
6411
|
+
if (visited.has(name))
|
|
6412
|
+
return;
|
|
6413
|
+
if (visiting.has(name))
|
|
6414
|
+
return;
|
|
6415
|
+
visiting.add(name);
|
|
6416
|
+
for (const dep of deps.get(name) ?? []) {
|
|
6417
|
+
visit(dep);
|
|
6418
|
+
}
|
|
6419
|
+
visiting.delete(name);
|
|
6420
|
+
visited.add(name);
|
|
6421
|
+
result.push(name);
|
|
6422
|
+
}
|
|
6423
|
+
for (const name of tableNames) {
|
|
6424
|
+
visit(name);
|
|
6425
|
+
}
|
|
6426
|
+
return result;
|
|
6427
|
+
}
|
|
6428
|
+
|
|
6343
6429
|
// ../../packages/core/dist/scanPipeline.js
|
|
6344
6430
|
async function scanDatabase(config) {
|
|
6345
6431
|
const pool = createPostgresClient(config.database.connectionString);
|
|
@@ -6628,6 +6714,198 @@ function packDatasetToGenerated(pack) {
|
|
|
6628
6714
|
};
|
|
6629
6715
|
}
|
|
6630
6716
|
|
|
6717
|
+
// ../../packages/core/dist/capturePipeline.js
|
|
6718
|
+
function maskConnection(connectionString) {
|
|
6719
|
+
try {
|
|
6720
|
+
const url = new URL(connectionString);
|
|
6721
|
+
if (url.password) {
|
|
6722
|
+
url.password = "****";
|
|
6723
|
+
}
|
|
6724
|
+
return url.toString();
|
|
6725
|
+
} catch {
|
|
6726
|
+
return connectionString.replace(/:([^@/]+)@/, ":****@");
|
|
6727
|
+
}
|
|
6728
|
+
}
|
|
6729
|
+
async function captureDatabase(config, options) {
|
|
6730
|
+
const start = performance.now();
|
|
6731
|
+
const pool = createPostgresClient(config.database.connectionString);
|
|
6732
|
+
try {
|
|
6733
|
+
await testConnection(pool);
|
|
6734
|
+
const schema = await introspectDatabase(pool);
|
|
6735
|
+
const graph = buildDependencyGraph(schema.foreignKeys);
|
|
6736
|
+
const sorted = topologicalSort(graph);
|
|
6737
|
+
const graphOrder = sorted.order;
|
|
6738
|
+
const allTableNames = schema.tables.map((t) => t.name);
|
|
6739
|
+
const tableOrder = [
|
|
6740
|
+
...graphOrder,
|
|
6741
|
+
...allTableNames.filter((t) => !graphOrder.includes(t))
|
|
6742
|
+
];
|
|
6743
|
+
let tablesToCapture;
|
|
6744
|
+
if (options.tables && options.tables.length > 0) {
|
|
6745
|
+
let addDeps2 = function(tableName) {
|
|
6746
|
+
if (allDeps.has(tableName))
|
|
6747
|
+
return;
|
|
6748
|
+
allDeps.add(tableName);
|
|
6749
|
+
for (const fk of schema.foreignKeys) {
|
|
6750
|
+
if (fk.sourceTable === tableName && fk.sourceTable !== fk.targetTable) {
|
|
6751
|
+
addDeps2(fk.targetTable);
|
|
6752
|
+
}
|
|
6753
|
+
}
|
|
6754
|
+
};
|
|
6755
|
+
var addDeps = addDeps2;
|
|
6756
|
+
const requested = new Set(options.tables);
|
|
6757
|
+
const allDeps = /* @__PURE__ */ new Set();
|
|
6758
|
+
for (const t of requested) {
|
|
6759
|
+
addDeps2(t);
|
|
6760
|
+
}
|
|
6761
|
+
tablesToCapture = tableOrder.filter((t) => allDeps.has(t));
|
|
6762
|
+
} else {
|
|
6763
|
+
tablesToCapture = tableOrder;
|
|
6764
|
+
}
|
|
6765
|
+
const capturedTableSet = new Set(tablesToCapture);
|
|
6766
|
+
const filteredTables = schema.tables.filter((t) => capturedTableSet.has(t.name));
|
|
6767
|
+
const filteredFKs = schema.foreignKeys.filter((fk) => capturedTableSet.has(fk.sourceTable) && capturedTableSet.has(fk.targetTable));
|
|
6768
|
+
const filteredSchema = {
|
|
6769
|
+
...schema,
|
|
6770
|
+
tables: filteredTables,
|
|
6771
|
+
foreignKeys: filteredFKs,
|
|
6772
|
+
tableCount: filteredTables.length,
|
|
6773
|
+
foreignKeyCount: filteredFKs.length
|
|
6774
|
+
};
|
|
6775
|
+
const ddl = generateCreateTableDDL(filteredSchema);
|
|
6776
|
+
const packDataset = { tables: {} };
|
|
6777
|
+
const tableDetails = [];
|
|
6778
|
+
let totalRows = 0;
|
|
6779
|
+
for (const tableName of tablesToCapture) {
|
|
6780
|
+
const tableSchema = filteredTables.find((t) => t.name === tableName);
|
|
6781
|
+
if (!tableSchema)
|
|
6782
|
+
continue;
|
|
6783
|
+
const columns = tableSchema.columns.map((c) => c.name);
|
|
6784
|
+
const rows = await readTableRows(pool, tableName, columns);
|
|
6785
|
+
const rowCount = rows.length;
|
|
6786
|
+
packDataset.tables[tableName] = {
|
|
6787
|
+
columns,
|
|
6788
|
+
rows,
|
|
6789
|
+
rowCount
|
|
6790
|
+
};
|
|
6791
|
+
tableDetails.push({ name: tableName, rowCount });
|
|
6792
|
+
totalRows += rowCount;
|
|
6793
|
+
}
|
|
6794
|
+
const packSchema = {
|
|
6795
|
+
tables: filteredTables.map((t) => ({
|
|
6796
|
+
name: t.name,
|
|
6797
|
+
columns: t.columns.map((c) => ({
|
|
6798
|
+
name: c.name,
|
|
6799
|
+
dataType: c.dataType,
|
|
6800
|
+
nullable: c.isNullable,
|
|
6801
|
+
maxLength: c.maxLength
|
|
6802
|
+
})),
|
|
6803
|
+
primaryKey: t.primaryKey?.columnName
|
|
6804
|
+
})),
|
|
6805
|
+
foreignKeys: filteredFKs.map((fk) => ({
|
|
6806
|
+
sourceTable: fk.sourceTable,
|
|
6807
|
+
sourceColumn: fk.sourceColumn,
|
|
6808
|
+
targetTable: fk.targetTable,
|
|
6809
|
+
targetColumn: fk.targetColumn
|
|
6810
|
+
}))
|
|
6811
|
+
};
|
|
6812
|
+
const plan = {
|
|
6813
|
+
version: "1.0",
|
|
6814
|
+
planId: `capture-${options.name}-${Date.now()}`,
|
|
6815
|
+
tables: [],
|
|
6816
|
+
tableOrder: tablesToCapture,
|
|
6817
|
+
config: {
|
|
6818
|
+
targetDatabase: "postgres",
|
|
6819
|
+
defaultRowCount: 0,
|
|
6820
|
+
batchSize: config.seed?.batchSize ?? 1e3,
|
|
6821
|
+
environment: "dev"
|
|
6822
|
+
},
|
|
6823
|
+
reproducibility: {
|
|
6824
|
+
randomSeed: 0,
|
|
6825
|
+
strategyVersion: "0.3.0"
|
|
6826
|
+
}
|
|
6827
|
+
};
|
|
6828
|
+
const masked = maskConnection(config.database.connectionString);
|
|
6829
|
+
const pack = {
|
|
6830
|
+
format: "databox-reality-pack",
|
|
6831
|
+
version: "1.0",
|
|
6832
|
+
metadata: {
|
|
6833
|
+
name: options.name,
|
|
6834
|
+
description: options.description,
|
|
6835
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6836
|
+
seed: 0,
|
|
6837
|
+
totalRows,
|
|
6838
|
+
tableCount: tablesToCapture.length,
|
|
6839
|
+
ddl,
|
|
6840
|
+
capturedFrom: masked
|
|
6841
|
+
},
|
|
6842
|
+
schema: packSchema,
|
|
6843
|
+
plan,
|
|
6844
|
+
dataset: packDataset
|
|
6845
|
+
};
|
|
6846
|
+
const outputDir = options.outputDir ?? ".";
|
|
6847
|
+
const filePath = await saveRealityPack(pack, outputDir);
|
|
6848
|
+
const durationMs = Math.round(performance.now() - start);
|
|
6849
|
+
return {
|
|
6850
|
+
pack,
|
|
6851
|
+
filePath,
|
|
6852
|
+
totalRows,
|
|
6853
|
+
tableCount: tablesToCapture.length,
|
|
6854
|
+
durationMs,
|
|
6855
|
+
tableDetails
|
|
6856
|
+
};
|
|
6857
|
+
} finally {
|
|
6858
|
+
await closeConnection(pool);
|
|
6859
|
+
}
|
|
6860
|
+
}
|
|
6861
|
+
|
|
6862
|
+
// ../../packages/core/dist/sharePipeline.js
|
|
6863
|
+
var import_promises6 = require("fs/promises");
|
|
6864
|
+
function formatSize(bytes) {
|
|
6865
|
+
if (bytes < 1024)
|
|
6866
|
+
return `${bytes} B`;
|
|
6867
|
+
const kb = Math.round(bytes / 1024);
|
|
6868
|
+
if (kb < 1024)
|
|
6869
|
+
return `${kb} KB`;
|
|
6870
|
+
const mb = (bytes / (1024 * 1024)).toFixed(1);
|
|
6871
|
+
return `${mb} MB`;
|
|
6872
|
+
}
|
|
6873
|
+
async function shareRealityPack(filePath, options) {
|
|
6874
|
+
const pack = await loadRealityPack(filePath);
|
|
6875
|
+
const fileStat = await (0, import_promises6.stat)(filePath);
|
|
6876
|
+
const size = formatSize(fileStat.size);
|
|
6877
|
+
const method = options?.method ?? "file";
|
|
6878
|
+
if (method === "gist") {
|
|
6879
|
+
const token = process.env.GITHUB_TOKEN;
|
|
6880
|
+
if (!token) {
|
|
6881
|
+
return {
|
|
6882
|
+
method: "file",
|
|
6883
|
+
location: filePath,
|
|
6884
|
+
packName: pack.metadata.name,
|
|
6885
|
+
size,
|
|
6886
|
+
tableCount: pack.metadata.tableCount,
|
|
6887
|
+
totalRows: pack.metadata.totalRows
|
|
6888
|
+
};
|
|
6889
|
+
}
|
|
6890
|
+
return {
|
|
6891
|
+
method: "file",
|
|
6892
|
+
location: filePath,
|
|
6893
|
+
packName: pack.metadata.name,
|
|
6894
|
+
size,
|
|
6895
|
+
tableCount: pack.metadata.tableCount,
|
|
6896
|
+
totalRows: pack.metadata.totalRows
|
|
6897
|
+
};
|
|
6898
|
+
}
|
|
6899
|
+
return {
|
|
6900
|
+
method: "file",
|
|
6901
|
+
location: filePath,
|
|
6902
|
+
packName: pack.metadata.name,
|
|
6903
|
+
size,
|
|
6904
|
+
tableCount: pack.metadata.tableCount,
|
|
6905
|
+
totalRows: pack.metadata.totalRows
|
|
6906
|
+
};
|
|
6907
|
+
}
|
|
6908
|
+
|
|
6631
6909
|
// src/utils.ts
|
|
6632
6910
|
function maskConnectionString(connectionString) {
|
|
6633
6911
|
try {
|
|
@@ -6642,7 +6920,7 @@ function maskConnectionString(connectionString) {
|
|
|
6642
6920
|
}
|
|
6643
6921
|
|
|
6644
6922
|
// src/commands/scan.ts
|
|
6645
|
-
var VERSION2 = "0.
|
|
6923
|
+
var VERSION2 = "0.3.0";
|
|
6646
6924
|
async function scanCommand(options) {
|
|
6647
6925
|
const start = performance.now();
|
|
6648
6926
|
try {
|
|
@@ -6733,7 +7011,7 @@ async function scanCommand(options) {
|
|
|
6733
7011
|
}
|
|
6734
7012
|
|
|
6735
7013
|
// src/commands/seed.ts
|
|
6736
|
-
var VERSION3 = "0.
|
|
7014
|
+
var VERSION3 = "0.3.0";
|
|
6737
7015
|
async function seedCommand(options) {
|
|
6738
7016
|
const start = performance.now();
|
|
6739
7017
|
try {
|
|
@@ -6911,7 +7189,7 @@ async function seedCommand(options) {
|
|
|
6911
7189
|
}
|
|
6912
7190
|
|
|
6913
7191
|
// src/commands/reset.ts
|
|
6914
|
-
var VERSION4 = "0.
|
|
7192
|
+
var VERSION4 = "0.3.0";
|
|
6915
7193
|
async function resetCommand(options) {
|
|
6916
7194
|
const start = performance.now();
|
|
6917
7195
|
if (!options.ci && !options.confirm) {
|
|
@@ -6981,7 +7259,7 @@ async function resetCommand(options) {
|
|
|
6981
7259
|
}
|
|
6982
7260
|
|
|
6983
7261
|
// src/commands/export.ts
|
|
6984
|
-
var VERSION5 = "0.
|
|
7262
|
+
var VERSION5 = "0.3.0";
|
|
6985
7263
|
async function exportCommand(options) {
|
|
6986
7264
|
const start = performance.now();
|
|
6987
7265
|
try {
|
|
@@ -7174,7 +7452,7 @@ function scenariosCommand() {
|
|
|
7174
7452
|
}
|
|
7175
7453
|
|
|
7176
7454
|
// src/commands/pack.ts
|
|
7177
|
-
var
|
|
7455
|
+
var import_promises7 = require("fs/promises");
|
|
7178
7456
|
async function packExportCommand(options) {
|
|
7179
7457
|
try {
|
|
7180
7458
|
const config = await loadConfig();
|
|
@@ -7251,7 +7529,7 @@ async function packExportCommand(options) {
|
|
|
7251
7529
|
scenarios: options.scenario,
|
|
7252
7530
|
scenarioIntensity
|
|
7253
7531
|
});
|
|
7254
|
-
const fileStat = await (0,
|
|
7532
|
+
const fileStat = await (0, import_promises7.stat)(result.filePath);
|
|
7255
7533
|
const sizeKb = Math.round(fileStat.size / 1024);
|
|
7256
7534
|
console.log("");
|
|
7257
7535
|
console.log(`Tables: ${result.pack.metadata.tableCount}`);
|
|
@@ -7331,11 +7609,330 @@ async function packImportCommand(filePath, options) {
|
|
|
7331
7609
|
}
|
|
7332
7610
|
}
|
|
7333
7611
|
|
|
7612
|
+
// src/commands/capture.ts
|
|
7613
|
+
var import_promises8 = require("fs/promises");
|
|
7614
|
+
var VERSION6 = "0.3.0";
|
|
7615
|
+
async function captureCommand(options) {
|
|
7616
|
+
const start = performance.now();
|
|
7617
|
+
try {
|
|
7618
|
+
if (!options.name) {
|
|
7619
|
+
const msg = "Missing required --name flag.";
|
|
7620
|
+
if (options.ci) {
|
|
7621
|
+
console.log(formatCIOutput({
|
|
7622
|
+
success: false,
|
|
7623
|
+
command: "capture",
|
|
7624
|
+
version: VERSION6,
|
|
7625
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7626
|
+
durationMs: 0,
|
|
7627
|
+
error: msg
|
|
7628
|
+
}));
|
|
7629
|
+
process.exit(1);
|
|
7630
|
+
}
|
|
7631
|
+
console.error(`[realitydb] ${msg}`);
|
|
7632
|
+
console.error("Usage: realitydb capture --name <name>");
|
|
7633
|
+
process.exit(1);
|
|
7634
|
+
}
|
|
7635
|
+
const config = await loadConfig();
|
|
7636
|
+
const masked = maskConnectionString(config.database.connectionString);
|
|
7637
|
+
const tables = options.tables ? options.tables.split(",").map((t) => t.trim()).filter((t) => t.length > 0) : void 0;
|
|
7638
|
+
if (!options.ci) {
|
|
7639
|
+
console.log("");
|
|
7640
|
+
console.log("RealityDB Capture");
|
|
7641
|
+
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");
|
|
7642
|
+
console.log(`Database: ${masked}`);
|
|
7643
|
+
console.log(`Name: ${options.name}`);
|
|
7644
|
+
if (tables) {
|
|
7645
|
+
console.log(`Tables: ${tables.join(", ")}`);
|
|
7646
|
+
}
|
|
7647
|
+
console.log("");
|
|
7648
|
+
console.log("Capturing...");
|
|
7649
|
+
}
|
|
7650
|
+
const result = await captureDatabase(config, {
|
|
7651
|
+
name: options.name,
|
|
7652
|
+
description: options.description,
|
|
7653
|
+
tables,
|
|
7654
|
+
outputDir: options.output
|
|
7655
|
+
});
|
|
7656
|
+
const durationMs = Math.round(performance.now() - start);
|
|
7657
|
+
if (options.ci) {
|
|
7658
|
+
console.log(formatCIOutput({
|
|
7659
|
+
success: true,
|
|
7660
|
+
command: "capture",
|
|
7661
|
+
version: VERSION6,
|
|
7662
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7663
|
+
durationMs,
|
|
7664
|
+
data: {
|
|
7665
|
+
database: masked,
|
|
7666
|
+
name: options.name,
|
|
7667
|
+
filePath: result.filePath,
|
|
7668
|
+
tableCount: result.tableCount,
|
|
7669
|
+
totalRows: result.totalRows,
|
|
7670
|
+
tables: result.tableDetails.map((t) => ({
|
|
7671
|
+
name: t.name,
|
|
7672
|
+
rowCount: t.rowCount
|
|
7673
|
+
})),
|
|
7674
|
+
ddlIncluded: true
|
|
7675
|
+
}
|
|
7676
|
+
}));
|
|
7677
|
+
return;
|
|
7678
|
+
}
|
|
7679
|
+
for (const table of result.tableDetails) {
|
|
7680
|
+
console.log(` ${table.name}: ${table.rowCount} rows`);
|
|
7681
|
+
}
|
|
7682
|
+
const fileStat = await (0, import_promises8.stat)(result.filePath);
|
|
7683
|
+
const sizeKb = Math.round(fileStat.size / 1024);
|
|
7684
|
+
console.log("");
|
|
7685
|
+
console.log(`Captured: ${result.filePath} (${sizeKb} KB)`);
|
|
7686
|
+
console.log("Schema DDL included. Share this file to reproduce the environment.");
|
|
7687
|
+
console.log("");
|
|
7688
|
+
} catch (err) {
|
|
7689
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7690
|
+
if (options.ci) {
|
|
7691
|
+
console.log(formatCIOutput({
|
|
7692
|
+
success: false,
|
|
7693
|
+
command: "capture",
|
|
7694
|
+
version: VERSION6,
|
|
7695
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7696
|
+
durationMs: Math.round(performance.now() - start),
|
|
7697
|
+
error: message
|
|
7698
|
+
}));
|
|
7699
|
+
process.exit(1);
|
|
7700
|
+
}
|
|
7701
|
+
if (message.includes("Config file not found")) {
|
|
7702
|
+
console.error(`[realitydb] ${message}`);
|
|
7703
|
+
} else if (message.includes("connection") || message.includes("ECONNREFUSED")) {
|
|
7704
|
+
console.error(`[realitydb] Capture failed: ${message}`);
|
|
7705
|
+
console.error("Hint: Check that your database is running (e.g. Docker)");
|
|
7706
|
+
} else {
|
|
7707
|
+
console.error(`[realitydb] Capture failed: ${message}`);
|
|
7708
|
+
}
|
|
7709
|
+
process.exit(1);
|
|
7710
|
+
}
|
|
7711
|
+
}
|
|
7712
|
+
|
|
7713
|
+
// src/commands/share.ts
|
|
7714
|
+
var VERSION7 = "0.3.0";
|
|
7715
|
+
async function shareCommand(filePath, options) {
|
|
7716
|
+
const start = performance.now();
|
|
7717
|
+
try {
|
|
7718
|
+
if (!filePath) {
|
|
7719
|
+
const msg = "Missing file path argument.";
|
|
7720
|
+
if (options.ci) {
|
|
7721
|
+
console.log(formatCIOutput({
|
|
7722
|
+
success: false,
|
|
7723
|
+
command: "share",
|
|
7724
|
+
version: VERSION7,
|
|
7725
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7726
|
+
durationMs: 0,
|
|
7727
|
+
error: msg
|
|
7728
|
+
}));
|
|
7729
|
+
process.exit(1);
|
|
7730
|
+
}
|
|
7731
|
+
console.error(`[realitydb] ${msg}`);
|
|
7732
|
+
console.error("Usage: realitydb share <file>");
|
|
7733
|
+
process.exit(1);
|
|
7734
|
+
}
|
|
7735
|
+
const result = await shareRealityPack(filePath);
|
|
7736
|
+
const durationMs = Math.round(performance.now() - start);
|
|
7737
|
+
if (options.ci) {
|
|
7738
|
+
console.log(formatCIOutput({
|
|
7739
|
+
success: true,
|
|
7740
|
+
command: "share",
|
|
7741
|
+
version: VERSION7,
|
|
7742
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7743
|
+
durationMs,
|
|
7744
|
+
data: {
|
|
7745
|
+
method: result.method,
|
|
7746
|
+
location: result.location,
|
|
7747
|
+
packName: result.packName,
|
|
7748
|
+
size: result.size,
|
|
7749
|
+
tableCount: result.tableCount,
|
|
7750
|
+
totalRows: result.totalRows
|
|
7751
|
+
}
|
|
7752
|
+
}));
|
|
7753
|
+
return;
|
|
7754
|
+
}
|
|
7755
|
+
console.log("");
|
|
7756
|
+
console.log("RealityDB Share");
|
|
7757
|
+
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");
|
|
7758
|
+
console.log(`Pack: ${result.packName} (${result.tableCount} tables, ${result.totalRows} rows, ${result.size})`);
|
|
7759
|
+
console.log("");
|
|
7760
|
+
console.log("Share this file:");
|
|
7761
|
+
console.log(` File: ${result.location}`);
|
|
7762
|
+
console.log(` Size: ${result.size}`);
|
|
7763
|
+
console.log("");
|
|
7764
|
+
console.log("The receiver can load it with:");
|
|
7765
|
+
console.log(` realitydb load ${result.location} --confirm`);
|
|
7766
|
+
console.log("");
|
|
7767
|
+
console.log("Tip: To create the schema first, the receiver can run:");
|
|
7768
|
+
console.log(` realitydb load ${result.location} --show-ddl`);
|
|
7769
|
+
console.log("");
|
|
7770
|
+
} catch (err) {
|
|
7771
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7772
|
+
if (options.ci) {
|
|
7773
|
+
console.log(formatCIOutput({
|
|
7774
|
+
success: false,
|
|
7775
|
+
command: "share",
|
|
7776
|
+
version: VERSION7,
|
|
7777
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7778
|
+
durationMs: Math.round(performance.now() - start),
|
|
7779
|
+
error: message
|
|
7780
|
+
}));
|
|
7781
|
+
process.exit(1);
|
|
7782
|
+
}
|
|
7783
|
+
console.error(`[realitydb] Share failed: ${message}`);
|
|
7784
|
+
process.exit(1);
|
|
7785
|
+
}
|
|
7786
|
+
}
|
|
7787
|
+
|
|
7788
|
+
// src/commands/load.ts
|
|
7789
|
+
var VERSION8 = "0.3.0";
|
|
7790
|
+
async function loadCommand(filePath, options) {
|
|
7791
|
+
const start = performance.now();
|
|
7792
|
+
try {
|
|
7793
|
+
if (!filePath) {
|
|
7794
|
+
const msg = "Missing file path argument.";
|
|
7795
|
+
if (options.ci) {
|
|
7796
|
+
console.log(formatCIOutput({
|
|
7797
|
+
success: false,
|
|
7798
|
+
command: "load",
|
|
7799
|
+
version: VERSION8,
|
|
7800
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7801
|
+
durationMs: 0,
|
|
7802
|
+
error: msg
|
|
7803
|
+
}));
|
|
7804
|
+
process.exit(1);
|
|
7805
|
+
}
|
|
7806
|
+
console.error(`[realitydb] ${msg}`);
|
|
7807
|
+
console.error("Usage: realitydb load <file> --confirm");
|
|
7808
|
+
process.exit(1);
|
|
7809
|
+
}
|
|
7810
|
+
const pack = await loadRealityPack(filePath);
|
|
7811
|
+
if (options.showDdl) {
|
|
7812
|
+
const ddl = pack.metadata.ddl;
|
|
7813
|
+
if (options.ci) {
|
|
7814
|
+
console.log(formatCIOutput({
|
|
7815
|
+
success: true,
|
|
7816
|
+
command: "load",
|
|
7817
|
+
version: VERSION8,
|
|
7818
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7819
|
+
durationMs: Math.round(performance.now() - start),
|
|
7820
|
+
data: {
|
|
7821
|
+
packName: pack.metadata.name,
|
|
7822
|
+
ddlAvailable: !!ddl,
|
|
7823
|
+
ddl: ddl ?? null
|
|
7824
|
+
}
|
|
7825
|
+
}));
|
|
7826
|
+
return;
|
|
7827
|
+
}
|
|
7828
|
+
if (ddl) {
|
|
7829
|
+
console.log("");
|
|
7830
|
+
console.log("Schema DDL (run this SQL to create tables):");
|
|
7831
|
+
console.log("");
|
|
7832
|
+
console.log(ddl);
|
|
7833
|
+
} else {
|
|
7834
|
+
console.log("");
|
|
7835
|
+
console.log("No DDL available in this Reality Pack.");
|
|
7836
|
+
console.log("This pack was created with pack export (generated data), not capture.");
|
|
7837
|
+
console.log("");
|
|
7838
|
+
}
|
|
7839
|
+
return;
|
|
7840
|
+
}
|
|
7841
|
+
const config = await loadConfig();
|
|
7842
|
+
const masked = maskConnectionString(config.database.connectionString);
|
|
7843
|
+
if (!options.ci) {
|
|
7844
|
+
console.log("");
|
|
7845
|
+
console.log("RealityDB Load");
|
|
7846
|
+
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");
|
|
7847
|
+
console.log(`Database: ${masked}`);
|
|
7848
|
+
console.log(`Pack: ${pack.metadata.name} (v${pack.version})`);
|
|
7849
|
+
if (pack.metadata.templateName) {
|
|
7850
|
+
console.log(`Template: ${pack.metadata.templateName}`);
|
|
7851
|
+
}
|
|
7852
|
+
console.log(`Tables: ${pack.metadata.tableCount}`);
|
|
7853
|
+
console.log(`Total rows: ${pack.metadata.totalRows}`);
|
|
7854
|
+
const ddl = pack.metadata.ddl;
|
|
7855
|
+
if (ddl) {
|
|
7856
|
+
console.log("Schema DDL: included");
|
|
7857
|
+
}
|
|
7858
|
+
console.log("");
|
|
7859
|
+
}
|
|
7860
|
+
if (!options.ci && !options.confirm) {
|
|
7861
|
+
console.error("[realitydb] Load requires --confirm flag.");
|
|
7862
|
+
console.error("Hint: This will insert data into your database. Use --confirm to proceed.");
|
|
7863
|
+
console.error("");
|
|
7864
|
+
console.error("To view the schema DDL first:");
|
|
7865
|
+
console.error(` realitydb load ${filePath} --show-ddl`);
|
|
7866
|
+
process.exit(1);
|
|
7867
|
+
}
|
|
7868
|
+
if (!options.ci) {
|
|
7869
|
+
console.log("Loading...");
|
|
7870
|
+
}
|
|
7871
|
+
const result = await importPack(config, filePath);
|
|
7872
|
+
const durationMs = Math.round(performance.now() - start);
|
|
7873
|
+
if (options.ci) {
|
|
7874
|
+
console.log(formatCIOutput({
|
|
7875
|
+
success: true,
|
|
7876
|
+
command: "load",
|
|
7877
|
+
version: VERSION8,
|
|
7878
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7879
|
+
durationMs,
|
|
7880
|
+
data: {
|
|
7881
|
+
database: masked,
|
|
7882
|
+
packName: pack.metadata.name,
|
|
7883
|
+
totalRows: result.totalRows,
|
|
7884
|
+
tables: result.insertResult.tables.map((t) => ({
|
|
7885
|
+
name: t.tableName,
|
|
7886
|
+
rowsInserted: t.rowsInserted,
|
|
7887
|
+
durationMs: t.durationMs
|
|
7888
|
+
}))
|
|
7889
|
+
}
|
|
7890
|
+
}));
|
|
7891
|
+
return;
|
|
7892
|
+
}
|
|
7893
|
+
for (const tableResult of result.insertResult.tables) {
|
|
7894
|
+
console.log(
|
|
7895
|
+
` ${tableResult.tableName}: ${tableResult.rowsInserted} rows loaded`
|
|
7896
|
+
);
|
|
7897
|
+
}
|
|
7898
|
+
const totalTime = (result.durationMs / 1e3).toFixed(1);
|
|
7899
|
+
console.log("");
|
|
7900
|
+
console.log(`Load complete. ${result.totalRows} rows in ${totalTime}s`);
|
|
7901
|
+
console.log("");
|
|
7902
|
+
} catch (err) {
|
|
7903
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7904
|
+
if (options.ci) {
|
|
7905
|
+
console.log(formatCIOutput({
|
|
7906
|
+
success: false,
|
|
7907
|
+
command: "load",
|
|
7908
|
+
version: VERSION8,
|
|
7909
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7910
|
+
durationMs: Math.round(performance.now() - start),
|
|
7911
|
+
error: message
|
|
7912
|
+
}));
|
|
7913
|
+
process.exit(1);
|
|
7914
|
+
}
|
|
7915
|
+
if (message.includes("Config file not found")) {
|
|
7916
|
+
console.error(`[realitydb] ${message}`);
|
|
7917
|
+
} else if (message.includes("Cannot import Reality Pack")) {
|
|
7918
|
+
console.error(`[realitydb] ${message}`);
|
|
7919
|
+
const ddlHint = "Tip: Use --show-ddl to get the schema creation SQL.";
|
|
7920
|
+
console.error(ddlHint);
|
|
7921
|
+
} else if (message.includes("connection") || message.includes("ECONNREFUSED")) {
|
|
7922
|
+
console.error(`[realitydb] Load failed: ${message}`);
|
|
7923
|
+
console.error("Hint: Check that your database is running (e.g. Docker)");
|
|
7924
|
+
} else {
|
|
7925
|
+
console.error(`[realitydb] Load failed: ${message}`);
|
|
7926
|
+
}
|
|
7927
|
+
process.exit(1);
|
|
7928
|
+
}
|
|
7929
|
+
}
|
|
7930
|
+
|
|
7334
7931
|
// src/cli.ts
|
|
7335
|
-
var
|
|
7932
|
+
var VERSION9 = "0.3.0";
|
|
7336
7933
|
function run(argv) {
|
|
7337
7934
|
const program2 = new Command();
|
|
7338
|
-
program2.name("realitydb").description("RealityDB \u2014 Developer Reality Platform").version(
|
|
7935
|
+
program2.name("realitydb").description("RealityDB \u2014 Developer Reality Platform").version(VERSION9).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);
|
|
7339
7936
|
program2.command("scan").description("Scan database schema").action(async () => {
|
|
7340
7937
|
const opts = program2.opts();
|
|
7341
7938
|
await scanCommand({ ci: opts.ci });
|
|
@@ -7354,16 +7951,28 @@ function run(argv) {
|
|
|
7354
7951
|
});
|
|
7355
7952
|
program2.command("templates").description("List available domain templates").action(templatesCommand);
|
|
7356
7953
|
program2.command("scenarios").description("List available scenarios").action(scenariosCommand);
|
|
7954
|
+
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) => {
|
|
7955
|
+
const opts = program2.opts();
|
|
7956
|
+
await captureCommand({ ...cmdOpts, ci: opts.ci });
|
|
7957
|
+
});
|
|
7958
|
+
program2.command("share <file>").description("Share a Reality Pack file").action(async (filePath) => {
|
|
7959
|
+
const opts = program2.opts();
|
|
7960
|
+
await shareCommand(filePath, { ci: opts.ci });
|
|
7961
|
+
});
|
|
7962
|
+
program2.command("load <file>").description("Load a Reality Pack into the database").option("--confirm", "Confirm import operation").option("--show-ddl", "Show schema DDL without importing").action(async (filePath, cmdOpts) => {
|
|
7963
|
+
const opts = program2.opts();
|
|
7964
|
+
await loadCommand(filePath, { ...cmdOpts, ci: opts.ci });
|
|
7965
|
+
});
|
|
7357
7966
|
const pack = program2.command("pack").description("Reality Pack operations");
|
|
7358
7967
|
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").action(packExportCommand);
|
|
7359
7968
|
pack.command("import <file>").description("Import Reality Pack into database").option("--confirm", "Confirm import operation").action(packImportCommand);
|
|
7360
7969
|
program2.action(() => {
|
|
7361
7970
|
const opts = program2.opts();
|
|
7362
7971
|
if (opts.ci) {
|
|
7363
|
-
console.log(JSON.stringify({ name: "realitydb", version:
|
|
7972
|
+
console.log(JSON.stringify({ name: "realitydb", version: VERSION9 }));
|
|
7364
7973
|
} else {
|
|
7365
7974
|
console.log("");
|
|
7366
|
-
console.log(`RealityDB v${
|
|
7975
|
+
console.log(`RealityDB v${VERSION9} \u2014 Developer Reality Platform`);
|
|
7367
7976
|
console.log("Run `realitydb --help` for available commands.");
|
|
7368
7977
|
console.log("");
|
|
7369
7978
|
}
|