@nmakarov/cli-toolkit 0.14.2 → 0.18.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 (57) hide show
  1. package/dist/args.cjs +49 -9
  2. package/dist/args.cjs.map +1 -1
  3. package/dist/args.js +49 -9
  4. package/dist/args.js.map +1 -1
  5. package/dist/cli-runner.cjs +5006 -0
  6. package/dist/cli-runner.cjs.map +1 -0
  7. package/dist/cli-runner.js +4989 -0
  8. package/dist/cli-runner.js.map +1 -0
  9. package/dist/db.cjs +9 -2
  10. package/dist/db.cjs.map +1 -1
  11. package/dist/db.js +9 -2
  12. package/dist/db.js.map +1 -1
  13. package/dist/errors.cjs +17 -0
  14. package/dist/errors.cjs.map +1 -1
  15. package/dist/errors.js +15 -0
  16. package/dist/errors.js.map +1 -1
  17. package/dist/filedatabase.cjs +110 -37
  18. package/dist/filedatabase.cjs.map +1 -1
  19. package/dist/filedatabase.js +110 -36
  20. package/dist/filedatabase.js.map +1 -1
  21. package/dist/http-client.cjs +44 -34
  22. package/dist/http-client.cjs.map +1 -1
  23. package/dist/http-client.js +44 -34
  24. package/dist/http-client.js.map +1 -1
  25. package/dist/http-client2.cjs +1728 -0
  26. package/dist/http-client2.cjs.map +1 -0
  27. package/dist/http-client2.js +1690 -0
  28. package/dist/http-client2.js.map +1 -0
  29. package/dist/index.cjs +1456 -112
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.js +1436 -110
  32. package/dist/index.js.map +1 -1
  33. package/dist/init.cjs +199 -82
  34. package/dist/init.cjs.map +1 -1
  35. package/dist/init.js +199 -82
  36. package/dist/init.js.map +1 -1
  37. package/dist/logger.cjs +28 -42
  38. package/dist/logger.cjs.map +1 -1
  39. package/dist/logger.js +28 -42
  40. package/dist/logger.js.map +1 -1
  41. package/dist/mock-server.cjs +205 -359
  42. package/dist/mock-server.cjs.map +1 -1
  43. package/dist/mock-server.js +203 -359
  44. package/dist/mock-server.js.map +1 -1
  45. package/dist/params.cjs +114 -15
  46. package/dist/params.cjs.map +1 -1
  47. package/dist/params.js +114 -15
  48. package/dist/params.js.map +1 -1
  49. package/dist/tasks.cjs +2295 -0
  50. package/dist/tasks.cjs.map +1 -0
  51. package/dist/tasks.js +2240 -0
  52. package/dist/tasks.js.map +1 -0
  53. package/dist/utils.cjs +15 -2
  54. package/dist/utils.cjs.map +1 -1
  55. package/dist/utils.js +12 -1
  56. package/dist/utils.js.map +1 -1
  57. package/package.json +18 -3
@@ -119,6 +119,12 @@ var ParamError = class extends FrameworkError {
119
119
  this.name = "ParamError";
120
120
  }
121
121
  };
122
+ var FileDatabaseError = class extends FrameworkError {
123
+ constructor(message) {
124
+ super(message);
125
+ this.name = "FileDatabaseError";
126
+ }
127
+ };
122
128
 
123
129
  // src/filedatabase/synopsis-functions.ts
124
130
  function defaultFileSynopsisFunction(fileEntry, data) {
@@ -189,13 +195,7 @@ function defaultVersionSynopsisFunction(metadata) {
189
195
  }
190
196
 
191
197
  // src/filedatabase/index.ts
192
- var FileDatabaseError = class extends Error {
193
- constructor(message) {
194
- super(message);
195
- this.name = "FileDatabaseError";
196
- }
197
- };
198
- var FileDatabase = class {
198
+ var FileDatabase = class _FileDatabase {
199
199
  basePath;
200
200
  namespace;
201
201
  tableName = null;
@@ -232,18 +232,8 @@ var FileDatabase = class {
232
232
  maxVersions: "number default 5",
233
233
  pageSize: "number default 5000"
234
234
  };
235
- const paramsConfig = context.params.getAll(defs);
236
- config = {
237
- basePath: opts.basePath ?? paramsConfig.basePath,
238
- namespace: opts.namespace ?? paramsConfig.namespace,
239
- tableName: opts.tableName ?? paramsConfig.tableName ?? null,
240
- versioned: opts.versioned ?? true,
241
- maxVersions: opts.maxVersions ?? paramsConfig.maxVersions,
242
- pageSize: opts.pageSize ?? paramsConfig.pageSize,
243
- useMetadata: opts.useMetadata ?? true,
244
- freeSpaceThreshold: opts.freeSpaceThreshold ?? 100 * 1024 * 1024,
245
- logger: context.logger
246
- };
235
+ const discovered = context.params.getAllForModule(defs);
236
+ config = { ...discovered, ...opts, logger: context.logger };
247
237
  } else {
248
238
  config = contextOrConfig;
249
239
  }
@@ -261,6 +251,13 @@ var FileDatabase = class {
261
251
  this.logger = config.logger || console;
262
252
  this.metadata = this.getDefaultMetadata();
263
253
  }
254
+ /**
255
+ * Initialize FileDatabase from context and options.
256
+ * Params are read via getAllForModule("filedatabase", defs) for --showUsedParams grouping.
257
+ */
258
+ static init(context, options) {
259
+ return new _FileDatabase(context, options ?? {});
260
+ }
264
261
  /**
265
262
  * Get default metadata structure
266
263
  */
@@ -328,7 +325,7 @@ var FileDatabase = class {
328
325
  const versions = await this.getVersions();
329
326
  while (versions.length > this.maxVersions) {
330
327
  const versionToDelete = path3.resolve(this.getDestinationPath(), versions.shift());
331
- this.logger.debug?.(`[FileDatabase] Deleting old version: ${versionToDelete}`);
328
+ this.logger.silly?.(`[FileDatabase] Deleting old version: ${versionToDelete}`);
332
329
  await fs3.promises.rm(versionToDelete, { recursive: true, force: true });
333
330
  }
334
331
  return versionName;
@@ -606,7 +603,7 @@ var FileDatabase = class {
606
603
  };
607
604
  this.metadata.files.push(fileEntry);
608
605
  this.lastFileData = null;
609
- this.logger.debug?.(`[FileDatabase] Created new file: ${fileEntry.fileName}, fileNumber: ${this.currentFileNumber}`);
606
+ this.logger.silly?.(`[FileDatabase] Created new file: ${fileEntry.fileName}, fileNumber: ${this.currentFileNumber}`);
610
607
  }
611
608
  /**
612
609
  * Figure out what data to write and which file to use (for pagination)
@@ -639,7 +636,7 @@ var FileDatabase = class {
639
636
  const filesBeforeCreate = this.metadata.files.length;
640
637
  this.makeNewFile();
641
638
  newlyCreatedFileIndex = filesBeforeCreate;
642
- this.logger.debug?.(`[FileDatabase] Creating new file for unique custom metadata combination, fileNumber: ${this.currentFileNumber}`);
639
+ this.logger.silly?.(`[FileDatabase] Creating new file for unique custom metadata combination, fileNumber: ${this.currentFileNumber}`);
643
640
  } else if (this.metadata.files.length === 0) {
644
641
  this.makeNewFile();
645
642
  }
@@ -688,7 +685,7 @@ var FileDatabase = class {
688
685
  dataLeftOver = null;
689
686
  }
690
687
  const fileName = this.metadata.files[this.metadata.files.length - 1].fileName;
691
- this.logger.debug?.(
688
+ this.logger.silly?.(
692
689
  `[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, forceNewFile=${forceNewFile}, targetFileIndex=${targetFileIndex}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : "N/A"}, lastFileRecordsCount=${lastFileRecordsCount}`
693
690
  );
694
691
  return { dataToWrite, dataLeftOver, fileName };
@@ -743,7 +740,7 @@ var FileDatabase = class {
743
740
  this.metadata.modifiedAt = (/* @__PURE__ */ new Date()).toISOString();
744
741
  this.metadata.dataType = detectDataType(dataToWrite);
745
742
  this.metadata.totalRecords = this.metadata.files.reduce((sum, file) => sum + (file.recordsCount || 0), 0);
746
- this.logger.debug?.(
743
+ this.logger.silly?.(
747
744
  `[FileDatabase] Updated metadata for file ${currentFile.fileName}: recordsCount=${recordsCount}, totalRecords=${this.metadata.totalRecords}`
748
745
  );
749
746
  }
@@ -767,7 +764,7 @@ var FileDatabase = class {
767
764
  }
768
765
  try {
769
766
  await fs3.promises.writeFile(filePath, serializedData, "utf8");
770
- this.logger.debug?.(`[FileDatabase] Wrote ${bytesToHumanReadable(requiredBytes)} to ${filePath}`);
767
+ this.logger.silly?.(`[FileDatabase] Wrote ${bytesToHumanReadable(requiredBytes)} to ${filePath}`);
771
768
  } catch (error) {
772
769
  throw new FileDatabaseError(`Failed to write file ${filePath}: ${error.message}`);
773
770
  }
@@ -849,7 +846,8 @@ var FileDatabase = class {
849
846
  this.useMetadata = format.hasMetadata;
850
847
  }
851
848
  if (this.useMetadata) {
852
- const metadataPath = path3.join(this.getDestinationPath(), "metadata.json");
849
+ const destPath = this.getDestinationPath();
850
+ const metadataPath = path3.join(destPath, "metadata.json");
853
851
  if (fs3.existsSync(metadataPath)) {
854
852
  try {
855
853
  const rawData = await fs3.promises.readFile(metadataPath, "utf8");
@@ -863,7 +861,9 @@ var FileDatabase = class {
863
861
  throw new FileDatabaseError(`Failed to read metadata: ${e.message}`);
864
862
  }
865
863
  } else {
866
- throw new FileDatabaseError("[FileDatabase] No metadata found in non-versioned mode");
864
+ throw new FileDatabaseError(
865
+ `[FileDatabase] No metadata found in non-versioned mode. Looked for: ${metadataPath} (table path: ${destPath})`
866
+ );
867
867
  }
868
868
  } else {
869
869
  this.metadata = await this.figureMetadataFromVersionFiles("");
@@ -880,6 +880,13 @@ var FileDatabase = class {
880
880
  * Write data to the file database
881
881
  */
882
882
  async write(data, options = {}) {
883
+ if (options.filename) {
884
+ const destPath2 = this.getDestinationPath();
885
+ await ensurePath(destPath2);
886
+ const filePath = path3.join(destPath2, options.filename);
887
+ await this.safeWrite(filePath, data);
888
+ return;
889
+ }
883
890
  if (options.forceNewVersion && !this.versioned) {
884
891
  throw new FileDatabaseError("Cannot use forceNewVersion in non-versioned mode");
885
892
  }
@@ -903,17 +910,17 @@ var FileDatabase = class {
903
910
  });
904
911
  if (matches) {
905
912
  targetFileIndex = i;
906
- this.logger.debug?.(`[FileDatabase] Found existing file with matching custom metadata: ${fileEntry.fileName}, metadata: ${JSON.stringify(options.customMetadata)}`);
913
+ this.logger.silly?.(`[FileDatabase] Found existing file with matching custom metadata: ${fileEntry.fileName}, metadata: ${JSON.stringify(options.customMetadata)}`);
907
914
  break;
908
915
  } else {
909
- this.logger.debug?.(`[FileDatabase] File ${fileEntry.fileName} does not match custom metadata: ${JSON.stringify(options.customMetadata)}`);
916
+ this.logger.silly?.(`[FileDatabase] File ${fileEntry.fileName} does not match custom metadata: ${JSON.stringify(options.customMetadata)}`);
910
917
  }
911
918
  }
912
919
  if (targetFileIndex === null) {
913
- this.logger.debug?.(`[FileDatabase] No existing file found with custom metadata: ${JSON.stringify(options.customMetadata)}, will create new file`);
920
+ this.logger.silly?.(`[FileDatabase] No existing file found with custom metadata: ${JSON.stringify(options.customMetadata)}, will create new file`);
914
921
  }
915
922
  } else {
916
- this.logger.debug?.(`[FileDatabase] No custom metadata provided, will create new file`);
923
+ this.logger.silly?.(`[FileDatabase] No custom metadata provided, will create new file`);
917
924
  }
918
925
  if (targetFileIndex !== null) {
919
926
  const targetFile = this.metadata.files[targetFileIndex];
@@ -942,7 +949,17 @@ var FileDatabase = class {
942
949
  * Read data from the file database
943
950
  */
944
951
  async read(options = {}) {
945
- const { version, nextPage = false, pageSize } = options;
952
+ const { version, nextPage = false, pageSize, filename } = options;
953
+ if (filename) {
954
+ const destPath = this.getDestinationPath(version);
955
+ const filePath = path3.join(destPath, filename);
956
+ try {
957
+ const rawData = await fs3.promises.readFile(filePath, "utf8");
958
+ return JSON.parse(rawData);
959
+ } catch (error) {
960
+ throw new FileDatabaseError(`Failed to read file ${filename}: ${error.message}`);
961
+ }
962
+ }
946
963
  await this.prepare({ read: true, version });
947
964
  const isNonPaginatedData = this.metadata.dataType === "text" || this.metadata.dataType === "xml" || this.metadata.dataType === "json-object";
948
965
  if (isNonPaginatedData) {
@@ -1023,6 +1040,67 @@ var FileDatabase = class {
1023
1040
  this.currentRecord = 0;
1024
1041
  this.hasReadFirstPage = false;
1025
1042
  }
1043
+ /**
1044
+ * List filenames in the table directory.
1045
+ * For catalog/key-value usage (files written with { filename }).
1046
+ * Returns data file names (.json, .txt, .xml) excluding metadata.json.
1047
+ */
1048
+ async listFilenames() {
1049
+ const destPath = this.versioned && this.currentVersion ? path3.join(this.getDestinationPath(), this.currentVersion) : this.getDestinationPath();
1050
+ try {
1051
+ const entries = await fs3.promises.readdir(destPath, { withFileTypes: true });
1052
+ return entries.filter((e) => e.isFile() && e.name !== "metadata.json" && /\.(json|txt|xml)$/i.test(e.name)).map((e) => e.name);
1053
+ } catch (err) {
1054
+ if (err?.code === "ENOENT") return [];
1055
+ throw new FileDatabaseError(`Failed to list files: ${err.message}`);
1056
+ }
1057
+ }
1058
+ /**
1059
+ * Remove a file from the table directory (catalog mode).
1060
+ * Use with listFilenames() to manage individual files.
1061
+ */
1062
+ async removeFile(filename) {
1063
+ const destPath = this.versioned && this.currentVersion ? path3.join(this.getDestinationPath(), this.currentVersion) : this.getDestinationPath();
1064
+ const filePath = path3.join(destPath, filename);
1065
+ try {
1066
+ await fs3.promises.unlink(filePath);
1067
+ } catch (err) {
1068
+ if (err?.code === "ENOENT") return;
1069
+ throw new FileDatabaseError(`Failed to remove file ${filename}: ${err.message}`);
1070
+ }
1071
+ }
1072
+ /**
1073
+ * Remove a file and its metadata entry (non-versioned mode with useMetadata).
1074
+ * Use with findData() to get fileName, then call removeFileEntry to delete.
1075
+ */
1076
+ async removeFileEntry(filename) {
1077
+ if (this.versioned) {
1078
+ throw new FileDatabaseError("removeFileEntry is only supported in non-versioned mode");
1079
+ }
1080
+ await this.prepare({ read: true });
1081
+ const idx = this.metadata.files.findIndex((f) => f.fileName === filename);
1082
+ if (idx === -1) {
1083
+ throw new FileDatabaseError(`File entry ${filename} not found in metadata`);
1084
+ }
1085
+ const entry = this.metadata.files[idx];
1086
+ const recordsCount = entry.recordsCount || 0;
1087
+ this.metadata.files.splice(idx, 1);
1088
+ this.metadata.totalRecords = Math.max(0, (this.metadata.totalRecords || 0) - recordsCount);
1089
+ const destPath = this.getDestinationPath();
1090
+ const filePath = path3.join(destPath, filename);
1091
+ try {
1092
+ await fs3.promises.unlink(filePath);
1093
+ } catch (err) {
1094
+ if (err?.code === "ENOENT") {
1095
+ this.logger.warn?.(`[FileDatabase] File ${filename} already missing on disk`);
1096
+ } else {
1097
+ throw new FileDatabaseError(`Failed to remove file ${filename}: ${err.message}`);
1098
+ }
1099
+ }
1100
+ if (this.useMetadata) {
1101
+ await this.saveVersionMetadata(this.metadata);
1102
+ }
1103
+ }
1026
1104
  /**
1027
1105
  * Set file-level synopsis calculation function
1028
1106
  */
@@ -1126,15 +1204,11 @@ function listSources(basePath) {
1126
1204
  return [];
1127
1205
  }
1128
1206
  }
1129
- function fileDatabaseInit(context, options = {}) {
1130
- return new FileDatabase(context, options);
1131
- }
1132
1207
  export {
1133
1208
  FileDatabase,
1134
1209
  FileDatabaseError,
1135
1210
  defaultFileSynopsisFunction,
1136
1211
  defaultVersionSynopsisFunction,
1137
- fileDatabaseInit,
1138
1212
  listSources,
1139
1213
  listTables
1140
1214
  };