sqlite-hub 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +9 -0
  2. package/bin/sqlite-hub.js +555 -122
  3. package/docs/API.md +30 -0
  4. package/docs/CLI.md +22 -0
  5. package/docs/CLI_API_PARITY.md +61 -0
  6. package/docs/changelog.md +9 -1
  7. package/docs/guidelines/AGENTS.md +32 -0
  8. package/docs/{DESIGN_GUIDELINES.md → guidelines/DESIGN.md} +10 -0
  9. package/docs/todo.md +1 -13
  10. package/frontend/js/api.js +45 -0
  11. package/frontend/js/app.js +192 -2
  12. package/frontend/js/components/connectionCard.js +3 -1
  13. package/frontend/js/components/modal.js +356 -15
  14. package/frontend/js/components/sidebar.js +41 -7
  15. package/frontend/js/components/topNav.js +2 -14
  16. package/frontend/js/router.js +10 -0
  17. package/frontend/js/store.js +448 -0
  18. package/frontend/js/utils/inputClear.js +36 -0
  19. package/frontend/js/utils/syntheticData.js +240 -0
  20. package/frontend/js/views/backups.js +52 -0
  21. package/frontend/js/views/data.js +16 -0
  22. package/frontend/js/views/logs.js +339 -0
  23. package/frontend/js/views/settings.js +77 -27
  24. package/frontend/js/views/structure.js +6 -0
  25. package/frontend/js/views/tableAdvisor.js +385 -0
  26. package/frontend/js/views/tableDesigner.js +6 -0
  27. package/frontend/styles/components.css +149 -0
  28. package/frontend/styles/tailwind.generated.css +1 -1
  29. package/frontend/styles/views.css +8 -0
  30. package/package.json +1 -1
  31. package/server/routes/data.js +45 -0
  32. package/server/routes/externalApi.js +285 -2
  33. package/server/routes/logs.js +127 -0
  34. package/server/server.js +3 -0
  35. package/server/services/databaseCommandService.js +45 -0
  36. package/server/services/sqlite/dataBrowserService.js +36 -0
  37. package/server/services/sqlite/introspection.js +226 -22
  38. package/server/services/sqlite/syntheticDataGenerator.js +728 -0
  39. package/server/services/sqlite/tableAdvisor.js +790 -0
  40. package/server/services/storage/appStateStore.js +773 -169
package/bin/sqlite-hub.js CHANGED
@@ -26,6 +26,9 @@ Usage:
26
26
  sqlite-hub --database:"name" --documents
27
27
  sqlite-hub --database:"name" --documents:"Document Name"
28
28
  sqlite-hub --database:"name" --documents:"Document Name" --export
29
+ sqlite-hub --database:"name" --backups
30
+ sqlite-hub --database:"name" --backup
31
+ sqlite-hub --database:"name" --backup:"Before migration"
29
32
  sqlite-hub --database:"name" --table:"table_name"
30
33
  sqlite-hub --database:"name" --table:"table_name" --export:"primary-key"
31
34
  sqlite-hub --database:"name" --table:"table_name" --types:typescript
@@ -53,6 +56,10 @@ Options:
53
56
  --documents List Markdown documents for the selected database.
54
57
  --documents:"name" Print a document's Markdown content.
55
58
  --documents:"name" --export Export a document as a Markdown file.
59
+ --backups List managed backups for the selected database.
60
+ --backup Create and verify a managed backup.
61
+ --backup:"name" Create a backup with a custom name.
62
+ --backup-notes:"text" Add notes to a created backup.
56
63
  --table:"table" Print table metadata.
57
64
  --table:"table" --export:"pk" Export one row as JSON by primary key or rowid.
58
65
  --types:typescript|ts|rust|rs|kotlin|kt|swift
@@ -191,6 +198,10 @@ function parseCliArguments(argv) {
191
198
  documents: false,
192
199
  documentName: null,
193
200
  documentExport: false,
201
+ backups: false,
202
+ backup: false,
203
+ backupName: null,
204
+ backupNotes: null,
194
205
  tableName: null,
195
206
  typesTarget: null,
196
207
  typeName: null,
@@ -383,6 +394,39 @@ function parseCliArguments(argv) {
383
394
  continue;
384
395
  }
385
396
 
397
+ if (flag === '--backups') {
398
+ options.backups = true;
399
+ continue;
400
+ }
401
+
402
+ if (flag === '--backup') {
403
+ const parsed = takeOptionalFlagValue(value, argv, index);
404
+
405
+ options.backup = true;
406
+ if (parsed.hasValue) {
407
+ options.backupName = parsed.value;
408
+ }
409
+
410
+ index = parsed.nextIndex;
411
+ continue;
412
+ }
413
+
414
+ if (flag === '--backup-name') {
415
+ const parsed = takeFlagValue(flag, value, argv, index);
416
+ options.backup = true;
417
+ options.backupName = parsed.value;
418
+ index = parsed.nextIndex;
419
+ continue;
420
+ }
421
+
422
+ if (flag === '--backup-notes') {
423
+ const parsed = takeFlagValue(flag, value, argv, index);
424
+ options.backup = true;
425
+ options.backupNotes = parsed.value;
426
+ index = parsed.nextIndex;
427
+ continue;
428
+ }
429
+
386
430
  if (flag === '--export') {
387
431
  if (options.documents && options.documentName && value === undefined) {
388
432
  const nextValue = argv[index + 1];
@@ -506,6 +550,8 @@ function hasDatabaseOperation(options) {
506
550
  options.documents ||
507
551
  options.documentName ||
508
552
  options.documentExport ||
553
+ options.backups ||
554
+ options.backup ||
509
555
  options.exportTarget ||
510
556
  options.tableName ||
511
557
  options.typesTarget,
@@ -825,6 +871,58 @@ function exportDocumentMarkdown({ databaseService, conn, documentName }) {
825
871
  console.log(`Characters: ${result.document.contentLength}`);
826
872
  console.log(`File: ${outputPath}`);
827
873
  }
874
+
875
+ function listManagedBackups({ databaseService, conn, options }) {
876
+ const backups = databaseService.listBackups(conn.id);
877
+
878
+ if (options.jsonOutput) {
879
+ console.log(JSON.stringify({ items: backups, total: backups.length }, null, 2));
880
+ return;
881
+ }
882
+
883
+ if (backups.length === 0) {
884
+ console.log(`No backups found for ${conn.label}.`);
885
+ return;
886
+ }
887
+
888
+ console.log(`\nBackups for ${conn.label} (${backups.length}):`);
889
+ console.log('─'.repeat(60));
890
+
891
+ backups.forEach((backup, index) => {
892
+ const fileState = backup.fileExists ? 'available' : 'missing';
893
+ console.log(`${index + 1}. ${backup.name}`);
894
+ console.log(` ID: ${backup.id}`);
895
+ console.log(` Status: ${backup.status} (${fileState})`);
896
+ console.log(` Size: ${formatSize(backup.sizeBytes)}`);
897
+ console.log(` Created: ${backup.createdAt}`);
898
+ console.log(` File: ${backup.path}`);
899
+ if (backup.notes) {
900
+ console.log(` Notes: ${backup.notes}`);
901
+ }
902
+ console.log('');
903
+ });
904
+ }
905
+
906
+ async function createManagedBackup({ databaseService, conn, options }) {
907
+ const backup = await databaseService.createBackup(conn.id, {
908
+ name: options.backupName,
909
+ notes: options.backupNotes,
910
+ context: 'cli',
911
+ });
912
+
913
+ if (options.jsonOutput) {
914
+ console.log(JSON.stringify(backup, null, 2));
915
+ return;
916
+ }
917
+
918
+ console.log(`Backup created: ${backup.name}`);
919
+ console.log(`Status: ${backup.status}`);
920
+ console.log(`Database: ${conn.label}`);
921
+ console.log(`Size: ${formatSize(backup.sizeBytes)}`);
922
+ console.log(`File: ${backup.path}`);
923
+ console.log(`ID: ${backup.id}`);
924
+ }
925
+
828
926
  function exportTableRowAsJson({ databaseService, conn, tableName, exportTarget }) {
829
927
  const result = databaseService.getTableRow(conn.id, tableName, exportTarget);
830
928
  const outputPath = path.resolve(process.cwd(), result.filename);
@@ -958,191 +1056,526 @@ async function startAndOpen(port) {
958
1056
 
959
1057
  function requireDatabaseName(options) {
960
1058
  if (!options.databaseName) {
961
- console.error('Error: this command requires --database:"name".');
962
- process.exit(1);
1059
+ throw new Error('this command requires --database:"name".');
963
1060
  }
964
1061
 
965
1062
  return options.databaseName;
966
1063
  }
967
1064
 
968
- async function main(argv = process.argv.slice(2), dependencies = {}) {
969
- const options = parseCliArguments(argv);
970
- const port = options.port ?? DEFAULT_PORT;
1065
+ function readCliFlags(argv = []) {
1066
+ return argv
1067
+ .filter(argument => String(argument ?? '').startsWith('-'))
1068
+ .map(argument => splitArgument(argument).flag)
1069
+ .filter(Boolean);
1070
+ }
1071
+
1072
+ function describeCliAccess(options, argv = []) {
1073
+ const metadata = {
1074
+ flags: readCliFlags(argv),
1075
+ };
1076
+ const entry = {
1077
+ source: 'cli',
1078
+ action: 'cli.open',
1079
+ targetType: 'app',
1080
+ targetName: 'server',
1081
+ metadata,
1082
+ };
1083
+
1084
+ if (!options) {
1085
+ return {
1086
+ ...entry,
1087
+ action: 'cli.parse',
1088
+ targetType: 'command',
1089
+ targetName: 'arguments',
1090
+ };
1091
+ }
1092
+
1093
+ if (options.exportFormat) metadata.exportFormat = options.exportFormat;
1094
+ if (options.typesTarget) metadata.typesTarget = options.typesTarget;
1095
+ if (options.outputPath) metadata.hasOutputPath = true;
1096
+ if (options.jsonOutput) metadata.jsonOutput = true;
1097
+ if (options.force) metadata.force = true;
971
1098
 
972
1099
  if (options.help) {
973
- printHelp();
974
- return;
1100
+ return {
1101
+ ...entry,
1102
+ action: 'cli.help',
1103
+ targetType: 'app',
1104
+ targetName: 'help',
1105
+ };
975
1106
  }
976
1107
 
977
1108
  if (options.version) {
978
- const { version } = require('../package.json');
979
- console.log(`SQLite Hub CLI version ${version}`);
980
- return;
1109
+ return {
1110
+ ...entry,
1111
+ action: 'cli.version',
1112
+ targetType: 'app',
1113
+ targetName: 'version',
1114
+ };
981
1115
  }
982
1116
 
983
1117
  if (options.info) {
984
- await printInfo(port, dependencies);
985
- return;
1118
+ return {
1119
+ ...entry,
1120
+ action: 'cli.info',
1121
+ targetType: 'app',
1122
+ targetName: 'info',
1123
+ };
986
1124
  }
987
1125
 
988
1126
  if (options.open) {
989
- await startAndOpen(port);
990
- return;
1127
+ return entry;
1128
+ }
1129
+
1130
+ if (options.documents) {
1131
+ if (options.documentExport) {
1132
+ return {
1133
+ ...entry,
1134
+ action: 'cli.document.export',
1135
+ targetType: 'document',
1136
+ targetName: options.documentName || 'document',
1137
+ };
1138
+ }
1139
+
1140
+ if (options.documentName) {
1141
+ return {
1142
+ ...entry,
1143
+ action: 'cli.document.get',
1144
+ targetType: 'document',
1145
+ targetName: options.documentName,
1146
+ };
1147
+ }
1148
+
1149
+ return {
1150
+ ...entry,
1151
+ action: 'cli.documents.list',
1152
+ targetType: 'database',
1153
+ targetName: options.databaseName,
1154
+ };
991
1155
  }
992
1156
 
993
- if (options.storeName && !options.rawQuery) {
994
- throw new Error('--store requires --query:"sql".');
1157
+ if (options.backups) {
1158
+ return {
1159
+ ...entry,
1160
+ action: 'cli.backups.list',
1161
+ targetType: 'database',
1162
+ targetName: options.databaseName,
1163
+ };
995
1164
  }
996
1165
 
997
- const databaseService =
998
- dependencies.databaseService ??
999
- new DatabaseCommandService({
1000
- appStateStore: dependencies.appStateStore ?? createAppStateStore(),
1001
- });
1002
- const connections = databaseService.listDatabases();
1166
+ if (options.backup) {
1167
+ return {
1168
+ ...entry,
1169
+ action: 'cli.backup.create',
1170
+ targetType: 'database',
1171
+ targetName: options.databaseName,
1172
+ metadata: {
1173
+ ...metadata,
1174
+ hasBackupName: Boolean(options.backupName),
1175
+ hasBackupNotes: Boolean(options.backupNotes),
1176
+ },
1177
+ };
1178
+ }
1179
+
1180
+ if (options.tableName) {
1181
+ if (options.typesTarget) {
1182
+ return {
1183
+ ...entry,
1184
+ action: 'cli.table.types.generate',
1185
+ targetType: 'table',
1186
+ targetName: options.tableName,
1187
+ };
1188
+ }
1189
+
1190
+ if (options.exportTarget) {
1191
+ return {
1192
+ ...entry,
1193
+ action: 'cli.table.row.export',
1194
+ targetType: 'table',
1195
+ targetName: options.tableName,
1196
+ };
1197
+ }
1198
+
1199
+ return {
1200
+ ...entry,
1201
+ action: 'cli.table.get',
1202
+ targetType: 'table',
1203
+ targetName: options.tableName,
1204
+ };
1205
+ }
1206
+
1207
+ if (options.exportTarget) {
1208
+ return {
1209
+ ...entry,
1210
+ action: 'cli.query.export',
1211
+ targetType: 'query',
1212
+ targetName: options.exportTarget,
1213
+ };
1214
+ }
1215
+
1216
+ if (options.executeQuery) {
1217
+ return {
1218
+ ...entry,
1219
+ action: 'cli.query.execute.saved',
1220
+ targetType: 'query',
1221
+ targetName: options.executeQuery,
1222
+ };
1223
+ }
1224
+
1225
+ if (options.rawQuery) {
1226
+ return {
1227
+ ...entry,
1228
+ action: 'cli.query.execute',
1229
+ targetType: 'query',
1230
+ targetName: options.storeName || 'raw query',
1231
+ metadata: {
1232
+ ...metadata,
1233
+ hasStoreName: Boolean(options.storeName),
1234
+ },
1235
+ };
1236
+ }
1237
+
1238
+ if (options.showQuery) {
1239
+ return {
1240
+ ...entry,
1241
+ action: 'cli.query.get',
1242
+ targetType: 'query',
1243
+ targetName: options.showQuery,
1244
+ };
1245
+ }
1246
+
1247
+ if (options.showNotes) {
1248
+ return {
1249
+ ...entry,
1250
+ action: 'cli.query.notes.get',
1251
+ targetType: 'query',
1252
+ targetName: options.showNotes,
1253
+ };
1254
+ }
1255
+
1256
+ if (options.queries) {
1257
+ return {
1258
+ ...entry,
1259
+ action: 'cli.queries.list',
1260
+ targetType: 'database',
1261
+ targetName: options.databaseName,
1262
+ };
1263
+ }
1264
+
1265
+ if (options.tables) {
1266
+ return {
1267
+ ...entry,
1268
+ action: 'cli.tables.list',
1269
+ targetType: 'database',
1270
+ targetName: options.databaseName,
1271
+ };
1272
+ }
1273
+
1274
+ if (options.pathInfo) {
1275
+ return {
1276
+ ...entry,
1277
+ action: 'cli.database.path',
1278
+ targetType: 'database',
1279
+ targetName: options.databaseName,
1280
+ };
1281
+ }
1282
+
1283
+ if (options.sizeInfo) {
1284
+ return {
1285
+ ...entry,
1286
+ action: 'cli.database.size',
1287
+ targetType: 'database',
1288
+ targetName: options.databaseName,
1289
+ };
1290
+ }
1291
+
1292
+ if (options.lastOpenedInfo) {
1293
+ return {
1294
+ ...entry,
1295
+ action: 'cli.database.lastopened',
1296
+ targetType: 'database',
1297
+ targetName: options.databaseName,
1298
+ };
1299
+ }
1300
+
1301
+ if (options.databaseList && !options.databaseName) {
1302
+ return {
1303
+ ...entry,
1304
+ action: 'cli.databases.list',
1305
+ targetType: 'app',
1306
+ targetName: 'databases',
1307
+ };
1308
+ }
1003
1309
 
1004
- if (options.databaseList && !options.databaseName && !hasDatabaseOperation(options)) {
1005
- printDatabaseList(connections);
1310
+ if (options.databaseName) {
1311
+ return {
1312
+ ...entry,
1313
+ action: 'cli.database.get',
1314
+ targetType: 'database',
1315
+ targetName: options.databaseName,
1316
+ };
1317
+ }
1318
+
1319
+ return entry;
1320
+ }
1321
+
1322
+ function recordCliAccess({ appStateStore, entry, startedAtMs, error }) {
1323
+ if (!appStateStore?.recordAccessLog || !entry) {
1006
1324
  return;
1007
1325
  }
1008
1326
 
1009
- if (options.databaseName || hasDatabaseOperation(options)) {
1010
- const dbName = requireDatabaseName(options);
1011
- const conn = databaseService.getDatabase(dbName);
1327
+ try {
1328
+ appStateStore.recordAccessLog({
1329
+ ...entry,
1330
+ status: error ? 'error' : 'success',
1331
+ startedAt: new Date(startedAtMs).toISOString(),
1332
+ durationMs: Date.now() - startedAtMs,
1333
+ errorMessage: error ? error.message : null,
1334
+ });
1335
+ } catch {
1336
+ // Access logging must not change CLI behavior or command output.
1337
+ }
1338
+ }
1012
1339
 
1013
- if (options.documents) {
1014
- if (options.documentName) {
1015
- if (options.documentExport) {
1016
- exportDocumentMarkdown({
1017
- databaseService,
1018
- conn,
1019
- documentName: options.documentName,
1020
- });
1021
- } else {
1022
- showDocumentMarkdown({
1023
- databaseService,
1024
- conn,
1025
- documentName: options.documentName,
1026
- });
1340
+ async function main(argv = process.argv.slice(2), dependencies = {}) {
1341
+ const startedAtMs = Date.now();
1342
+ let options = null;
1343
+ let accessEntry = describeCliAccess(null, argv);
1344
+ let accessLogStore = dependencies.appStateStore ?? null;
1345
+ let databaseService = dependencies.databaseService ?? null;
1346
+ let commandError = null;
1347
+
1348
+ function getAccessLogStore() {
1349
+ if (dependencies.disableAccessLog) {
1350
+ return null;
1351
+ }
1352
+
1353
+ if (accessLogStore) {
1354
+ return accessLogStore;
1355
+ }
1356
+
1357
+ if (databaseService?.appStateStore) {
1358
+ accessLogStore = databaseService.appStateStore;
1359
+ return accessLogStore;
1360
+ }
1361
+
1362
+ if (!dependencies.databaseService) {
1363
+ accessLogStore = createAppStateStore();
1364
+ return accessLogStore;
1365
+ }
1366
+
1367
+ return null;
1368
+ }
1369
+
1370
+ try {
1371
+ options = parseCliArguments(argv);
1372
+ accessEntry = describeCliAccess(options, argv);
1373
+ const port = options.port ?? DEFAULT_PORT;
1374
+
1375
+ if (options.help) {
1376
+ printHelp();
1377
+ return;
1378
+ }
1379
+
1380
+ if (options.version) {
1381
+ const { version } = require('../package.json');
1382
+ console.log(`SQLite Hub CLI version ${version}`);
1383
+ return;
1384
+ }
1385
+
1386
+ if (options.info) {
1387
+ await printInfo(port, dependencies);
1388
+ return;
1389
+ }
1390
+
1391
+ if (options.open) {
1392
+ await startAndOpen(port);
1393
+ return;
1394
+ }
1395
+
1396
+ if (options.storeName && !options.rawQuery) {
1397
+ throw new Error('--store requires --query:"sql".');
1398
+ }
1399
+
1400
+ if (options.backup && options.backups) {
1401
+ throw new Error('--backup and --backups cannot be combined.');
1402
+ }
1403
+
1404
+ databaseService =
1405
+ databaseService ??
1406
+ new DatabaseCommandService({
1407
+ appStateStore: getAccessLogStore(),
1408
+ });
1409
+ const connections = databaseService.listDatabases();
1410
+
1411
+ if (options.databaseList && !options.databaseName && !hasDatabaseOperation(options)) {
1412
+ printDatabaseList(connections);
1413
+ return;
1414
+ }
1415
+
1416
+ if (options.databaseName || hasDatabaseOperation(options)) {
1417
+ const dbName = requireDatabaseName(options);
1418
+ const conn = databaseService.getDatabase(dbName);
1419
+ accessEntry.databaseKey = conn.id;
1420
+ accessEntry.metadata = {
1421
+ ...(accessEntry.metadata ?? {}),
1422
+ databaseLabel: conn.label ?? null,
1423
+ };
1424
+
1425
+ if (options.backups) {
1426
+ listManagedBackups({ databaseService, conn, options });
1427
+ return;
1428
+ }
1429
+
1430
+ if (options.backup) {
1431
+ await createManagedBackup({ databaseService, conn, options });
1432
+ return;
1433
+ }
1434
+
1435
+ if (options.documents) {
1436
+ if (options.documentName) {
1437
+ if (options.documentExport) {
1438
+ exportDocumentMarkdown({
1439
+ databaseService,
1440
+ conn,
1441
+ documentName: options.documentName,
1442
+ });
1443
+ } else {
1444
+ showDocumentMarkdown({
1445
+ databaseService,
1446
+ conn,
1447
+ documentName: options.documentName,
1448
+ });
1449
+ }
1450
+ return;
1027
1451
  }
1452
+
1453
+ listDocuments(databaseService, conn);
1028
1454
  return;
1029
1455
  }
1030
1456
 
1031
- listDocuments(databaseService, conn);
1032
- return;
1033
- }
1457
+ if (
1458
+ options.tableName ||
1459
+ options.tables ||
1460
+ options.queries ||
1461
+ options.executeQuery ||
1462
+ options.rawQuery ||
1463
+ options.showQuery ||
1464
+ options.showNotes ||
1465
+ options.exportTarget ||
1466
+ options.typesTarget
1467
+ ) {
1468
+ if (options.tableName) {
1469
+ if (options.typesTarget) {
1470
+ generateTypes({
1471
+ databaseService,
1472
+ conn,
1473
+ tableName: options.tableName,
1474
+ options,
1475
+ });
1476
+ return;
1477
+ }
1478
+
1479
+ if (options.exportTarget) {
1480
+ exportTableRowAsJson({
1481
+ databaseService,
1482
+ conn,
1483
+ tableName: options.tableName,
1484
+ exportTarget: options.exportTarget,
1485
+ });
1486
+ } else {
1487
+ printTableInfo(databaseService.getTable(conn.id, options.tableName));
1488
+ }
1034
1489
 
1035
- if (
1036
- options.tableName ||
1037
- options.tables ||
1038
- options.queries ||
1039
- options.executeQuery ||
1040
- options.rawQuery ||
1041
- options.showQuery ||
1042
- options.showNotes ||
1043
- options.exportTarget ||
1044
- options.typesTarget
1045
- ) {
1046
- if (options.tableName) {
1047
- if (options.typesTarget) {
1048
- generateTypes({
1490
+ return;
1491
+ }
1492
+
1493
+ if (options.exportTarget) {
1494
+ exportSavedQuery({
1049
1495
  databaseService,
1050
1496
  conn,
1051
- tableName: options.tableName,
1052
- options,
1497
+ queryName: options.exportTarget,
1498
+ format: options.exportFormat,
1053
1499
  });
1054
1500
  return;
1055
1501
  }
1056
1502
 
1057
- if (options.exportTarget) {
1058
- exportTableRowAsJson({
1503
+ if (options.executeQuery) {
1504
+ executeSavedQuery({
1059
1505
  databaseService,
1060
1506
  conn,
1061
- tableName: options.tableName,
1062
- exportTarget: options.exportTarget,
1507
+ queryName: options.executeQuery,
1063
1508
  });
1064
- } else {
1065
- printTableInfo(databaseService.getTable(conn.id, options.tableName));
1509
+ return;
1066
1510
  }
1067
1511
 
1068
- return;
1069
- }
1512
+ if (options.rawQuery) {
1513
+ executeRawQuery({
1514
+ databaseService,
1515
+ conn,
1516
+ sql: options.rawQuery,
1517
+ storeName: options.storeName,
1518
+ });
1519
+ return;
1520
+ }
1070
1521
 
1071
- if (options.exportTarget) {
1072
- exportSavedQuery({
1073
- databaseService,
1074
- conn,
1075
- queryName: options.exportTarget,
1076
- format: options.exportFormat,
1077
- });
1078
- return;
1079
- }
1522
+ if (options.showQuery) {
1523
+ showSavedQuery({ databaseService, conn, queryName: options.showQuery });
1524
+ return;
1525
+ }
1080
1526
 
1081
- if (options.executeQuery) {
1082
- executeSavedQuery({
1083
- databaseService,
1084
- conn,
1085
- queryName: options.executeQuery,
1086
- });
1087
- return;
1088
- }
1527
+ if (options.showNotes) {
1528
+ showSavedQueryNotes({ databaseService, conn, queryName: options.showNotes });
1529
+ return;
1530
+ }
1089
1531
 
1090
- if (options.rawQuery) {
1091
- executeRawQuery({
1092
- databaseService,
1093
- conn,
1094
- sql: options.rawQuery,
1095
- storeName: options.storeName,
1096
- });
1097
- return;
1098
- }
1532
+ if (options.queries) {
1533
+ listSavedQueries(databaseService, conn);
1534
+ return;
1535
+ }
1099
1536
 
1100
- if (options.showQuery) {
1101
- showSavedQuery({ databaseService, conn, queryName: options.showQuery });
1102
- return;
1537
+ if (options.tables) {
1538
+ printTables(conn, databaseService.listTables(conn.id));
1539
+ return;
1540
+ }
1103
1541
  }
1104
1542
 
1105
- if (options.showNotes) {
1106
- showSavedQueryNotes({ databaseService, conn, queryName: options.showNotes });
1543
+ if (options.pathInfo) {
1544
+ console.log(conn.path);
1107
1545
  return;
1108
1546
  }
1109
1547
 
1110
- if (options.queries) {
1111
- listSavedQueries(databaseService, conn);
1548
+ if (options.sizeInfo) {
1549
+ console.log(formatSize(conn.sizeBytes));
1112
1550
  return;
1113
1551
  }
1114
1552
 
1115
- if (options.tables) {
1116
- printTables(conn, databaseService.listTables(conn.id));
1553
+ if (options.lastOpenedInfo) {
1554
+ console.log(conn.lastOpenedAt);
1117
1555
  return;
1118
1556
  }
1119
- }
1120
-
1121
- if (options.pathInfo) {
1122
- console.log(conn.path);
1123
- return;
1124
- }
1125
1557
 
1126
- if (options.sizeInfo) {
1127
- console.log(formatSize(conn.sizeBytes));
1558
+ printSingleDatabaseInfo(conn);
1128
1559
  return;
1129
1560
  }
1130
1561
 
1131
- if (options.lastOpenedInfo) {
1132
- console.log(conn.lastOpenedAt);
1562
+ if (options.databaseList) {
1563
+ printDatabaseList(connections);
1133
1564
  return;
1134
1565
  }
1135
1566
 
1136
- printSingleDatabaseInfo(conn);
1137
- return;
1138
- }
1139
-
1140
- if (options.databaseList) {
1141
- printDatabaseList(connections);
1142
- return;
1567
+ await startAndOpen(port);
1568
+ } catch (error) {
1569
+ commandError = error;
1570
+ throw error;
1571
+ } finally {
1572
+ recordCliAccess({
1573
+ appStateStore: getAccessLogStore(),
1574
+ entry: accessEntry,
1575
+ startedAtMs,
1576
+ error: commandError,
1577
+ });
1143
1578
  }
1144
-
1145
- await startAndOpen(port);
1146
1579
  }
1147
1580
 
1148
1581
  if (require.main === module) {