realitydb 0.1.2 → 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 +882 -62
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -4253,6 +4253,11 @@ function createSeededRandom(seed) {
|
|
|
4253
4253
|
};
|
|
4254
4254
|
}
|
|
4255
4255
|
|
|
4256
|
+
// ../../packages/shared/dist/output.js
|
|
4257
|
+
function formatCIOutput(result) {
|
|
4258
|
+
return JSON.stringify(result, null, 2);
|
|
4259
|
+
}
|
|
4260
|
+
|
|
4256
4261
|
// ../../packages/generators/dist/foreignKeyResolver.js
|
|
4257
4262
|
function resolveForeignKey(ctx, ref) {
|
|
4258
4263
|
const referencedTable = ctx.allGeneratedTables.get(ref.referencedTable);
|
|
@@ -6145,6 +6150,13 @@ async function truncateTables(pool, tableNames, cascade) {
|
|
|
6145
6150
|
};
|
|
6146
6151
|
}
|
|
6147
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
|
+
|
|
6148
6160
|
// ../../packages/schema/dist/normalizer.js
|
|
6149
6161
|
function normalizeSchema(raw) {
|
|
6150
6162
|
const primaryKeyMap = /* @__PURE__ */ new Map();
|
|
@@ -6335,6 +6347,85 @@ async function introspectDatabase(pool, schemaName = "public") {
|
|
|
6335
6347
|
return schema;
|
|
6336
6348
|
}
|
|
6337
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
|
+
|
|
6338
6429
|
// ../../packages/core/dist/scanPipeline.js
|
|
6339
6430
|
async function scanDatabase(config) {
|
|
6340
6431
|
const pool = createPostgresClient(config.database.connectionString);
|
|
@@ -6623,6 +6714,198 @@ function packDatasetToGenerated(pack) {
|
|
|
6623
6714
|
};
|
|
6624
6715
|
}
|
|
6625
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
|
+
|
|
6626
6909
|
// src/utils.ts
|
|
6627
6910
|
function maskConnectionString(connectionString) {
|
|
6628
6911
|
try {
|
|
@@ -6637,12 +6920,40 @@ function maskConnectionString(connectionString) {
|
|
|
6637
6920
|
}
|
|
6638
6921
|
|
|
6639
6922
|
// src/commands/scan.ts
|
|
6640
|
-
|
|
6923
|
+
var VERSION2 = "0.3.0";
|
|
6924
|
+
async function scanCommand(options) {
|
|
6925
|
+
const start = performance.now();
|
|
6641
6926
|
try {
|
|
6642
6927
|
const config = await loadConfig();
|
|
6643
6928
|
const result = await scanDatabase(config);
|
|
6644
6929
|
const { schema } = result;
|
|
6645
6930
|
const masked = maskConnectionString(config.database.connectionString);
|
|
6931
|
+
const durationMs = Math.round(performance.now() - start);
|
|
6932
|
+
if (options.ci) {
|
|
6933
|
+
console.log(formatCIOutput({
|
|
6934
|
+
success: true,
|
|
6935
|
+
command: "scan",
|
|
6936
|
+
version: VERSION2,
|
|
6937
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6938
|
+
durationMs,
|
|
6939
|
+
data: {
|
|
6940
|
+
database: masked,
|
|
6941
|
+
tableCount: schema.tableCount,
|
|
6942
|
+
foreignKeyCount: schema.foreignKeyCount,
|
|
6943
|
+
tables: schema.tables.map((t) => ({
|
|
6944
|
+
name: t.name,
|
|
6945
|
+
columnCount: t.columns.length,
|
|
6946
|
+
primaryKey: t.primaryKey?.columnName ?? null
|
|
6947
|
+
})),
|
|
6948
|
+
foreignKeys: schema.foreignKeys.map((fk) => ({
|
|
6949
|
+
source: `${fk.sourceTable}.${fk.sourceColumn}`,
|
|
6950
|
+
target: `${fk.targetTable}.${fk.targetColumn}`
|
|
6951
|
+
})),
|
|
6952
|
+
insertionOrder: result.insertionOrder
|
|
6953
|
+
}
|
|
6954
|
+
}));
|
|
6955
|
+
return;
|
|
6956
|
+
}
|
|
6646
6957
|
console.log("");
|
|
6647
6958
|
console.log("RealityDB Schema Scan");
|
|
6648
6959
|
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");
|
|
@@ -6683,13 +6994,26 @@ async function scanCommand() {
|
|
|
6683
6994
|
console.log("");
|
|
6684
6995
|
} catch (err) {
|
|
6685
6996
|
const message = err instanceof Error ? err.message : String(err);
|
|
6997
|
+
if (options.ci) {
|
|
6998
|
+
console.log(formatCIOutput({
|
|
6999
|
+
success: false,
|
|
7000
|
+
command: "scan",
|
|
7001
|
+
version: VERSION2,
|
|
7002
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7003
|
+
durationMs: Math.round(performance.now() - start),
|
|
7004
|
+
error: message
|
|
7005
|
+
}));
|
|
7006
|
+
process.exit(1);
|
|
7007
|
+
}
|
|
6686
7008
|
console.error(`[realitydb] Scan failed: ${message}`);
|
|
6687
7009
|
process.exit(1);
|
|
6688
7010
|
}
|
|
6689
7011
|
}
|
|
6690
7012
|
|
|
6691
7013
|
// src/commands/seed.ts
|
|
7014
|
+
var VERSION3 = "0.3.0";
|
|
6692
7015
|
async function seedCommand(options) {
|
|
7016
|
+
const start = performance.now();
|
|
6693
7017
|
try {
|
|
6694
7018
|
const config = await loadConfig();
|
|
6695
7019
|
const records = options.records ? parseInt(options.records, 10) : void 0;
|
|
@@ -6703,6 +7027,17 @@ async function seedCommand(options) {
|
|
|
6703
7027
|
const template = registry.get(templateName);
|
|
6704
7028
|
if (!template) {
|
|
6705
7029
|
const available = registry.list();
|
|
7030
|
+
if (options.ci) {
|
|
7031
|
+
console.log(formatCIOutput({
|
|
7032
|
+
success: false,
|
|
7033
|
+
command: "seed",
|
|
7034
|
+
version: VERSION3,
|
|
7035
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7036
|
+
durationMs: Math.round(performance.now() - start),
|
|
7037
|
+
error: `Template "${templateName}" not found. Available: ${available.map((t) => t.name).join(", ")}`
|
|
7038
|
+
}));
|
|
7039
|
+
process.exit(1);
|
|
7040
|
+
}
|
|
6706
7041
|
console.error(`[realitydb] Template "${templateName}" not found.`);
|
|
6707
7042
|
console.error("");
|
|
6708
7043
|
if (available.length > 0) {
|
|
@@ -6721,6 +7056,17 @@ async function seedCommand(options) {
|
|
|
6721
7056
|
const scenarioNames = scenario.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
6722
7057
|
for (const name of scenarioNames) {
|
|
6723
7058
|
if (!scenarioRegistry.get(name)) {
|
|
7059
|
+
if (options.ci) {
|
|
7060
|
+
console.log(formatCIOutput({
|
|
7061
|
+
success: false,
|
|
7062
|
+
command: "seed",
|
|
7063
|
+
version: VERSION3,
|
|
7064
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7065
|
+
durationMs: Math.round(performance.now() - start),
|
|
7066
|
+
error: `Scenario "${name}" not found`
|
|
7067
|
+
}));
|
|
7068
|
+
process.exit(1);
|
|
7069
|
+
}
|
|
6724
7070
|
const available = scenarioRegistry.list();
|
|
6725
7071
|
console.error(`[realitydb] Scenario "${name}" not found.`);
|
|
6726
7072
|
console.error("");
|
|
@@ -6735,29 +7081,31 @@ async function seedCommand(options) {
|
|
|
6735
7081
|
const effectiveSeed = seed ?? config.seed.randomSeed ?? 42;
|
|
6736
7082
|
const effectiveRecords = records ?? config.seed.defaultRecords;
|
|
6737
7083
|
const masked = maskConnectionString(config.database.connectionString);
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
7084
|
+
if (!options.ci) {
|
|
7085
|
+
console.log("");
|
|
7086
|
+
console.log("RealityDB Seed");
|
|
7087
|
+
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");
|
|
7088
|
+
console.log(`Database: ${masked}`);
|
|
7089
|
+
if (templateName) {
|
|
7090
|
+
console.log(`Template: ${templateName}`);
|
|
7091
|
+
}
|
|
7092
|
+
if (timeline) {
|
|
7093
|
+
console.log(`Timeline: ${timeline}`);
|
|
7094
|
+
console.log(`Growth: s-curve`);
|
|
7095
|
+
}
|
|
7096
|
+
console.log(`Seed: ${effectiveSeed}`);
|
|
7097
|
+
console.log(`Records per table: ${effectiveRecords}`);
|
|
7098
|
+
if (scenario) {
|
|
7099
|
+
const scenarioNames = scenario.split(",").map((s) => s.trim());
|
|
7100
|
+
const scenarioDisplay = scenarioNames.map((s) => `${s} (${scenarioIntensity})`).join(", ");
|
|
7101
|
+
console.log(`Scenarios: ${scenarioDisplay}`);
|
|
7102
|
+
}
|
|
7103
|
+
console.log("");
|
|
7104
|
+
if (timeline) {
|
|
7105
|
+
console.log("Generating with timeline...");
|
|
7106
|
+
} else {
|
|
7107
|
+
console.log("Seeding...");
|
|
7108
|
+
}
|
|
6761
7109
|
}
|
|
6762
7110
|
const result = await seedDatabase(config, {
|
|
6763
7111
|
records,
|
|
@@ -6767,6 +7115,32 @@ async function seedCommand(options) {
|
|
|
6767
7115
|
scenarios: scenario,
|
|
6768
7116
|
scenarioIntensity
|
|
6769
7117
|
});
|
|
7118
|
+
const durationMs = Math.round(performance.now() - start);
|
|
7119
|
+
if (options.ci) {
|
|
7120
|
+
console.log(formatCIOutput({
|
|
7121
|
+
success: true,
|
|
7122
|
+
command: "seed",
|
|
7123
|
+
version: VERSION3,
|
|
7124
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7125
|
+
durationMs,
|
|
7126
|
+
data: {
|
|
7127
|
+
database: masked,
|
|
7128
|
+
template: templateName ?? null,
|
|
7129
|
+
seed: effectiveSeed,
|
|
7130
|
+
recordsPerTable: effectiveRecords,
|
|
7131
|
+
totalRows: result.totalRows,
|
|
7132
|
+
tables: result.insertResult.tables.map((t) => ({
|
|
7133
|
+
name: t.tableName,
|
|
7134
|
+
rowsInserted: t.rowsInserted,
|
|
7135
|
+
batchCount: t.batchCount,
|
|
7136
|
+
durationMs: t.durationMs
|
|
7137
|
+
})),
|
|
7138
|
+
timelineUsed: !!timeline,
|
|
7139
|
+
scenariosApplied: result.scenariosApplied ?? []
|
|
7140
|
+
}
|
|
7141
|
+
}));
|
|
7142
|
+
return;
|
|
7143
|
+
}
|
|
6770
7144
|
if (result.scenariosApplied && result.scenariosApplied.length > 0) {
|
|
6771
7145
|
console.log("");
|
|
6772
7146
|
console.log("Applying scenarios...");
|
|
@@ -6787,6 +7161,17 @@ async function seedCommand(options) {
|
|
|
6787
7161
|
console.log("");
|
|
6788
7162
|
} catch (err) {
|
|
6789
7163
|
const message = err instanceof Error ? err.message : String(err);
|
|
7164
|
+
if (options.ci) {
|
|
7165
|
+
console.log(formatCIOutput({
|
|
7166
|
+
success: false,
|
|
7167
|
+
command: "seed",
|
|
7168
|
+
version: VERSION3,
|
|
7169
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7170
|
+
durationMs: Math.round(performance.now() - start),
|
|
7171
|
+
error: message
|
|
7172
|
+
}));
|
|
7173
|
+
process.exit(1);
|
|
7174
|
+
}
|
|
6790
7175
|
if (message.includes("Config file not found")) {
|
|
6791
7176
|
console.error(`[realitydb] ${message}`);
|
|
6792
7177
|
console.error("Hint: Copy realitydb.config.json to realitydb.config.json");
|
|
@@ -6804,8 +7189,10 @@ async function seedCommand(options) {
|
|
|
6804
7189
|
}
|
|
6805
7190
|
|
|
6806
7191
|
// src/commands/reset.ts
|
|
7192
|
+
var VERSION4 = "0.3.0";
|
|
6807
7193
|
async function resetCommand(options) {
|
|
6808
|
-
|
|
7194
|
+
const start = performance.now();
|
|
7195
|
+
if (!options.ci && !options.confirm) {
|
|
6809
7196
|
console.log("");
|
|
6810
7197
|
console.log("This will delete ALL seeded data. Run with --confirm to proceed.");
|
|
6811
7198
|
console.log("");
|
|
@@ -6814,13 +7201,31 @@ async function resetCommand(options) {
|
|
|
6814
7201
|
try {
|
|
6815
7202
|
const config = await loadConfig();
|
|
6816
7203
|
const masked = maskConnectionString(config.database.connectionString);
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
7204
|
+
if (!options.ci) {
|
|
7205
|
+
console.log("");
|
|
7206
|
+
console.log("RealityDB Reset");
|
|
7207
|
+
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");
|
|
7208
|
+
console.log(`Database: ${masked}`);
|
|
7209
|
+
console.log("");
|
|
7210
|
+
console.log("Clearing tables...");
|
|
7211
|
+
}
|
|
6823
7212
|
const result = await resetDatabase(config);
|
|
7213
|
+
const durationMs = Math.round(performance.now() - start);
|
|
7214
|
+
if (options.ci) {
|
|
7215
|
+
console.log(formatCIOutput({
|
|
7216
|
+
success: true,
|
|
7217
|
+
command: "reset",
|
|
7218
|
+
version: VERSION4,
|
|
7219
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7220
|
+
durationMs,
|
|
7221
|
+
data: {
|
|
7222
|
+
database: masked,
|
|
7223
|
+
tablesCleared: result.tablesCleared,
|
|
7224
|
+
tableCount: result.tablesCleared.length
|
|
7225
|
+
}
|
|
7226
|
+
}));
|
|
7227
|
+
return;
|
|
7228
|
+
}
|
|
6824
7229
|
for (const tableName of result.tablesCleared) {
|
|
6825
7230
|
console.log(` ${tableName}: cleared`);
|
|
6826
7231
|
}
|
|
@@ -6829,6 +7234,17 @@ async function resetCommand(options) {
|
|
|
6829
7234
|
console.log("");
|
|
6830
7235
|
} catch (err) {
|
|
6831
7236
|
const message = err instanceof Error ? err.message : String(err);
|
|
7237
|
+
if (options.ci) {
|
|
7238
|
+
console.log(formatCIOutput({
|
|
7239
|
+
success: false,
|
|
7240
|
+
command: "reset",
|
|
7241
|
+
version: VERSION4,
|
|
7242
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7243
|
+
durationMs: Math.round(performance.now() - start),
|
|
7244
|
+
error: message
|
|
7245
|
+
}));
|
|
7246
|
+
process.exit(1);
|
|
7247
|
+
}
|
|
6832
7248
|
if (message.includes("Config file not found")) {
|
|
6833
7249
|
console.error(`[realitydb] ${message}`);
|
|
6834
7250
|
console.error("Hint: Copy realitydb.config.json to realitydb.config.json");
|
|
@@ -6843,7 +7259,9 @@ async function resetCommand(options) {
|
|
|
6843
7259
|
}
|
|
6844
7260
|
|
|
6845
7261
|
// src/commands/export.ts
|
|
7262
|
+
var VERSION5 = "0.3.0";
|
|
6846
7263
|
async function exportCommand(options) {
|
|
7264
|
+
const start = performance.now();
|
|
6847
7265
|
try {
|
|
6848
7266
|
const config = await loadConfig();
|
|
6849
7267
|
const format = options.format ?? config.export?.defaultFormat ?? "json";
|
|
@@ -6861,6 +7279,17 @@ async function exportCommand(options) {
|
|
|
6861
7279
|
const template = registry.get(templateName);
|
|
6862
7280
|
if (!template) {
|
|
6863
7281
|
const available = registry.list();
|
|
7282
|
+
if (options.ci) {
|
|
7283
|
+
console.log(formatCIOutput({
|
|
7284
|
+
success: false,
|
|
7285
|
+
command: "export",
|
|
7286
|
+
version: VERSION5,
|
|
7287
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7288
|
+
durationMs: Math.round(performance.now() - start),
|
|
7289
|
+
error: `Template "${templateName}" not found. Available: ${available.map((t) => t.name).join(", ")}`
|
|
7290
|
+
}));
|
|
7291
|
+
process.exit(1);
|
|
7292
|
+
}
|
|
6864
7293
|
console.error(`[realitydb] Template "${templateName}" not found.`);
|
|
6865
7294
|
console.error("");
|
|
6866
7295
|
if (available.length > 0) {
|
|
@@ -6879,6 +7308,17 @@ async function exportCommand(options) {
|
|
|
6879
7308
|
const scenarioNames = scenario.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
6880
7309
|
for (const name of scenarioNames) {
|
|
6881
7310
|
if (!scenarioRegistry.get(name)) {
|
|
7311
|
+
if (options.ci) {
|
|
7312
|
+
console.log(formatCIOutput({
|
|
7313
|
+
success: false,
|
|
7314
|
+
command: "export",
|
|
7315
|
+
version: VERSION5,
|
|
7316
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7317
|
+
durationMs: Math.round(performance.now() - start),
|
|
7318
|
+
error: `Scenario "${name}" not found`
|
|
7319
|
+
}));
|
|
7320
|
+
process.exit(1);
|
|
7321
|
+
}
|
|
6882
7322
|
const available = scenarioRegistry.list();
|
|
6883
7323
|
console.error(`[realitydb] Scenario "${name}" not found.`);
|
|
6884
7324
|
console.error("");
|
|
@@ -6890,27 +7330,29 @@ async function exportCommand(options) {
|
|
|
6890
7330
|
}
|
|
6891
7331
|
}
|
|
6892
7332
|
}
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
7333
|
+
if (!options.ci) {
|
|
7334
|
+
console.log("");
|
|
7335
|
+
console.log("RealityDB Export");
|
|
7336
|
+
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");
|
|
7337
|
+
console.log(`Database: ${masked}`);
|
|
7338
|
+
if (templateName) {
|
|
7339
|
+
console.log(`Template: ${templateName}`);
|
|
7340
|
+
}
|
|
7341
|
+
if (timeline) {
|
|
7342
|
+
console.log(`Timeline: ${timeline}`);
|
|
7343
|
+
console.log(`Growth: s-curve`);
|
|
7344
|
+
}
|
|
7345
|
+
console.log(`Format: ${format}`);
|
|
7346
|
+
console.log(`Output: ${outputDir}`);
|
|
7347
|
+
console.log(`Records per table: ${effectiveRecords}`);
|
|
7348
|
+
if (scenario) {
|
|
7349
|
+
const scenarioNames = scenario.split(",").map((s) => s.trim());
|
|
7350
|
+
const scenarioDisplay = scenarioNames.map((s) => `${s} (${scenarioIntensity})`).join(", ");
|
|
7351
|
+
console.log(`Scenarios: ${scenarioDisplay}`);
|
|
7352
|
+
}
|
|
7353
|
+
console.log("");
|
|
7354
|
+
console.log("Generating dataset...");
|
|
6911
7355
|
}
|
|
6912
|
-
console.log("");
|
|
6913
|
-
console.log("Generating dataset...");
|
|
6914
7356
|
const result = await exportDataset(config, {
|
|
6915
7357
|
format,
|
|
6916
7358
|
outputDir,
|
|
@@ -6921,6 +7363,24 @@ async function exportCommand(options) {
|
|
|
6921
7363
|
scenarios: scenario,
|
|
6922
7364
|
scenarioIntensity
|
|
6923
7365
|
});
|
|
7366
|
+
const durationMs = Math.round(performance.now() - start);
|
|
7367
|
+
if (options.ci) {
|
|
7368
|
+
console.log(formatCIOutput({
|
|
7369
|
+
success: true,
|
|
7370
|
+
command: "export",
|
|
7371
|
+
version: VERSION5,
|
|
7372
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7373
|
+
durationMs,
|
|
7374
|
+
data: {
|
|
7375
|
+
format,
|
|
7376
|
+
outputDir,
|
|
7377
|
+
files: result.files,
|
|
7378
|
+
totalRows: result.totalRows,
|
|
7379
|
+
fileCount: result.files.length
|
|
7380
|
+
}
|
|
7381
|
+
}));
|
|
7382
|
+
return;
|
|
7383
|
+
}
|
|
6924
7384
|
if (result.scenariosApplied && result.scenariosApplied.length > 0) {
|
|
6925
7385
|
console.log("Applying scenarios...");
|
|
6926
7386
|
for (const sr of result.scenariosApplied) {
|
|
@@ -6936,6 +7396,17 @@ async function exportCommand(options) {
|
|
|
6936
7396
|
console.log("");
|
|
6937
7397
|
} catch (err) {
|
|
6938
7398
|
const message = err instanceof Error ? err.message : String(err);
|
|
7399
|
+
if (options.ci) {
|
|
7400
|
+
console.log(formatCIOutput({
|
|
7401
|
+
success: false,
|
|
7402
|
+
command: "export",
|
|
7403
|
+
version: VERSION5,
|
|
7404
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7405
|
+
durationMs: Math.round(performance.now() - start),
|
|
7406
|
+
error: message
|
|
7407
|
+
}));
|
|
7408
|
+
process.exit(1);
|
|
7409
|
+
}
|
|
6939
7410
|
if (message.includes("Config file not found")) {
|
|
6940
7411
|
console.error(`[realitydb] ${message}`);
|
|
6941
7412
|
console.error("Hint: Copy realitydb.config.json to realitydb.config.json");
|
|
@@ -6981,7 +7452,7 @@ function scenariosCommand() {
|
|
|
6981
7452
|
}
|
|
6982
7453
|
|
|
6983
7454
|
// src/commands/pack.ts
|
|
6984
|
-
var
|
|
7455
|
+
var import_promises7 = require("fs/promises");
|
|
6985
7456
|
async function packExportCommand(options) {
|
|
6986
7457
|
try {
|
|
6987
7458
|
const config = await loadConfig();
|
|
@@ -7058,7 +7529,7 @@ async function packExportCommand(options) {
|
|
|
7058
7529
|
scenarios: options.scenario,
|
|
7059
7530
|
scenarioIntensity
|
|
7060
7531
|
});
|
|
7061
|
-
const fileStat = await (0,
|
|
7532
|
+
const fileStat = await (0, import_promises7.stat)(result.filePath);
|
|
7062
7533
|
const sizeKb = Math.round(fileStat.size / 1024);
|
|
7063
7534
|
console.log("");
|
|
7064
7535
|
console.log(`Tables: ${result.pack.metadata.tableCount}`);
|
|
@@ -7138,24 +7609,373 @@ async function packImportCommand(filePath, options) {
|
|
|
7138
7609
|
}
|
|
7139
7610
|
}
|
|
7140
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
|
+
|
|
7141
7931
|
// src/cli.ts
|
|
7932
|
+
var VERSION9 = "0.3.0";
|
|
7142
7933
|
function run(argv) {
|
|
7143
7934
|
const program2 = new Command();
|
|
7144
|
-
program2.name("realitydb").description("RealityDB \u2014 Developer Reality Platform").version(
|
|
7145
|
-
program2.command("scan").description("Scan database schema").action(
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
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);
|
|
7936
|
+
program2.command("scan").description("Scan database schema").action(async () => {
|
|
7937
|
+
const opts = program2.opts();
|
|
7938
|
+
await scanCommand({ ci: opts.ci });
|
|
7939
|
+
});
|
|
7940
|
+
program2.command("seed").description("Seed database with generated data").option("--records <count>", "Number of records per table").option("--template <name>", "Template to use").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").action(async (cmdOpts) => {
|
|
7941
|
+
const opts = program2.opts();
|
|
7942
|
+
await seedCommand({ ...cmdOpts, ci: opts.ci });
|
|
7943
|
+
});
|
|
7944
|
+
program2.command("reset").description("Reset seeded data").option("--confirm", "Confirm destructive operation").action(async (cmdOpts) => {
|
|
7945
|
+
const opts = program2.opts();
|
|
7946
|
+
await resetCommand({ ...cmdOpts, ci: opts.ci });
|
|
7947
|
+
});
|
|
7948
|
+
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").action(async (cmdOpts) => {
|
|
7949
|
+
const opts = program2.opts();
|
|
7950
|
+
await exportCommand({ ...cmdOpts, ci: opts.ci });
|
|
7951
|
+
});
|
|
7149
7952
|
program2.command("templates").description("List available domain templates").action(templatesCommand);
|
|
7150
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
|
+
});
|
|
7151
7966
|
const pack = program2.command("pack").description("Reality Pack operations");
|
|
7152
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);
|
|
7153
7968
|
pack.command("import <file>").description("Import Reality Pack into database").option("--confirm", "Confirm import operation").action(packImportCommand);
|
|
7154
7969
|
program2.action(() => {
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7970
|
+
const opts = program2.opts();
|
|
7971
|
+
if (opts.ci) {
|
|
7972
|
+
console.log(JSON.stringify({ name: "realitydb", version: VERSION9 }));
|
|
7973
|
+
} else {
|
|
7974
|
+
console.log("");
|
|
7975
|
+
console.log(`RealityDB v${VERSION9} \u2014 Developer Reality Platform`);
|
|
7976
|
+
console.log("Run `realitydb --help` for available commands.");
|
|
7977
|
+
console.log("");
|
|
7978
|
+
}
|
|
7159
7979
|
});
|
|
7160
7980
|
program2.parse(argv);
|
|
7161
7981
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "realitydb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Developer Reality Platform - realistic database environments from your schema",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"@databox/config": "workspace:^",
|
|
49
49
|
"@databox/core": "workspace:^",
|
|
50
50
|
"@databox/schema": "workspace:^",
|
|
51
|
+
"@databox/shared": "workspace:^",
|
|
51
52
|
"@databox/templates": "workspace:^",
|
|
52
53
|
"commander": "^14.0.3",
|
|
53
54
|
"tsup": "^8.5.1",
|