@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.
- package/dist/args.cjs +49 -9
- package/dist/args.cjs.map +1 -1
- package/dist/args.js +49 -9
- package/dist/args.js.map +1 -1
- package/dist/cli-runner.cjs +5006 -0
- package/dist/cli-runner.cjs.map +1 -0
- package/dist/cli-runner.js +4989 -0
- package/dist/cli-runner.js.map +1 -0
- package/dist/db.cjs +9 -2
- package/dist/db.cjs.map +1 -1
- package/dist/db.js +9 -2
- package/dist/db.js.map +1 -1
- package/dist/errors.cjs +17 -0
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -1
- package/dist/filedatabase.cjs +110 -37
- package/dist/filedatabase.cjs.map +1 -1
- package/dist/filedatabase.js +110 -36
- package/dist/filedatabase.js.map +1 -1
- package/dist/http-client.cjs +44 -34
- package/dist/http-client.cjs.map +1 -1
- package/dist/http-client.js +44 -34
- package/dist/http-client.js.map +1 -1
- package/dist/http-client2.cjs +1728 -0
- package/dist/http-client2.cjs.map +1 -0
- package/dist/http-client2.js +1690 -0
- package/dist/http-client2.js.map +1 -0
- package/dist/index.cjs +1456 -112
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1436 -110
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +199 -82
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +199 -82
- package/dist/init.js.map +1 -1
- package/dist/logger.cjs +28 -42
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.js +28 -42
- package/dist/logger.js.map +1 -1
- package/dist/mock-server.cjs +205 -359
- package/dist/mock-server.cjs.map +1 -1
- package/dist/mock-server.js +203 -359
- package/dist/mock-server.js.map +1 -1
- package/dist/params.cjs +114 -15
- package/dist/params.cjs.map +1 -1
- package/dist/params.js +114 -15
- package/dist/params.js.map +1 -1
- package/dist/tasks.cjs +2295 -0
- package/dist/tasks.cjs.map +1 -0
- package/dist/tasks.js +2240 -0
- package/dist/tasks.js.map +1 -0
- package/dist/utils.cjs +15 -2
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.js +12 -1
- package/dist/utils.js.map +1 -1
- package/package.json +18 -3
package/dist/filedatabase.js
CHANGED
|
@@ -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
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
};
|