@nmakarov/cli-toolkit 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -1
- package/dist/{filestore.cjs → filedatabase.cjs} +191 -37
- package/dist/filedatabase.cjs.map +1 -0
- package/dist/{filestore.js → filedatabase.js} +187 -33
- package/dist/filedatabase.js.map +1 -0
- package/dist/http-client.cjs +356 -0
- package/dist/http-client.cjs.map +1 -0
- package/dist/http-client.js +318 -0
- package/dist/http-client.js.map +1 -0
- package/dist/index.cjs +186 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +186 -32
- package/dist/index.js.map +1 -1
- package/dist/mock-server.cjs +1483 -0
- package/dist/mock-server.cjs.map +1 -0
- package/dist/mock-server.js +1445 -0
- package/dist/mock-server.js.map +1 -0
- package/package.json +30 -11
- package/dist/filestore.cjs.map +0 -1
- package/dist/filestore.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,11 +4,21 @@ A comprehensive TypeScript toolkit for building professional CLI applications wi
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@nmakarov/cli-toolkit)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://github.com/nmakarov/cli-toolkit/actions)
|
|
8
|
+
[](https://codecov.io/gh/nmakarov/cli-toolkit)
|
|
9
|
+
[](https://snyk.io/test/github/nmakarov/cli-toolkit)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
[](https://nodejs.org)
|
|
12
|
+
[](https://www.npmjs.com/package/@nmakarov/cli-toolkit)
|
|
13
|
+
[](https://bundlephobia.com/package/@nmakarov/cli-toolkit)
|
|
7
14
|
|
|
8
15
|
## Features
|
|
9
16
|
|
|
10
17
|
- 🎯 **Args** - Powerful argument parser with config files, environment variables, and precedence rules
|
|
11
18
|
- ✅ **Params** - Type-safe parameter validation with Joi schemas and cross-parameter references
|
|
19
|
+
- 🌐 **HttpClient** - Resilient HTTP client with automatic retry, error classification, and unified responses
|
|
20
|
+
- 🧪 **MockServer** - HTTP mock server with FileDatabase integration for API testing
|
|
21
|
+
- 💾 **FileDatabase** - Versioned file storage with chunking, pagination, and legacy compatibility
|
|
12
22
|
- 🖥️ **Screen** - Interactive terminal UIs with React/Ink (lists, menus, grids, navigation)
|
|
13
23
|
- 📝 **Logger** - Structured logging with levels, progress tracking, and IPC routing
|
|
14
24
|
- ⚡ **Errors** - Custom error classes for framework-specific error handling
|
|
@@ -52,7 +62,7 @@ node app.js --verbose --port=8080 build deploy
|
|
|
52
62
|
|
|
53
63
|
[📖 Full Args Documentation](docs/ARGS.md)
|
|
54
64
|
|
|
55
|
-
### Params - Validate Parameters
|
|
65
|
+
### Params - Validate Parameters.
|
|
56
66
|
|
|
57
67
|
```typescript
|
|
58
68
|
import { Params } from '@nmakarov/cli-toolkit/params';
|
|
@@ -80,6 +90,107 @@ node app.js --name="My App" --port=8080 --tags="api,web" --startDate="-7d"
|
|
|
80
90
|
|
|
81
91
|
[📖 Full Params Documentation](docs/PARAMS.md)
|
|
82
92
|
|
|
93
|
+
### HttpClient - Resilient HTTP Requests
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { HttpClient } from '@nmakarov/cli-toolkit/http-client';
|
|
97
|
+
|
|
98
|
+
const client = new HttpClient({
|
|
99
|
+
timeout: 10000,
|
|
100
|
+
retryCount: 3,
|
|
101
|
+
retryDelay: 1000
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Always returns unified response - never throws!
|
|
105
|
+
const response = await client.get('https://api.example.com/users', {
|
|
106
|
+
params: { limit: 10 },
|
|
107
|
+
headers: { 'Authorization': 'Bearer token' }
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if (response.status === 'success') {
|
|
111
|
+
console.log('Users:', response.data);
|
|
112
|
+
} else {
|
|
113
|
+
console.log('Error:', response.error); // Human-readable: 'connectionFailed', 'timeout', etc.
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Features:
|
|
119
|
+
# - Automatic retry with exponential backoff
|
|
120
|
+
# - Human-readable error classification
|
|
121
|
+
# - All HTTP methods (GET, POST, PUT, DELETE, PATCH, etc.)
|
|
122
|
+
# - Per-request configuration overrides
|
|
123
|
+
# - Comprehensive logging
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
[📖 Full HttpClient Documentation](docs/HTTP_CLIENT.md)
|
|
127
|
+
|
|
128
|
+
### FileDatabase - Structured File Storage
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { FileDatabase } from '@nmakarov/cli-toolkit/filedatabase';
|
|
132
|
+
|
|
133
|
+
// Versioned mode (default) - creates timestamped folders
|
|
134
|
+
const db = new FileDatabase({
|
|
135
|
+
basePath: './data',
|
|
136
|
+
namespace: 'api',
|
|
137
|
+
tableName: 'responses'
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Non-versioned mode - for single objects
|
|
141
|
+
const db = new FileDatabase({
|
|
142
|
+
basePath: './data',
|
|
143
|
+
namespace: 'cache',
|
|
144
|
+
tableName: 'user-profile',
|
|
145
|
+
versioned: false
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
await db.write(userData);
|
|
149
|
+
const data = await db.read(); // Auto-detects latest version
|
|
150
|
+
const hasData = await db.hasData();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Features:
|
|
155
|
+
# - Versioned/non-versioned storage modes
|
|
156
|
+
# - Automatic chunking for large datasets
|
|
157
|
+
# - Pagination for efficient reading
|
|
158
|
+
# - Legacy format compatibility
|
|
159
|
+
# - Custom synopsis functions
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
[📖 Full FileDatabase Documentation](docs/FILEDATABASE.md)
|
|
163
|
+
|
|
164
|
+
### MockServer - HTTP Mock Server
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { MockServer } from '@nmakarov/cli-toolkit/mock-server';
|
|
168
|
+
|
|
169
|
+
const mockServer = new MockServer({
|
|
170
|
+
basePath: './mocks',
|
|
171
|
+
port: 5030
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
await mockServer.start();
|
|
175
|
+
|
|
176
|
+
// Capture responses
|
|
177
|
+
await mockServer.storeMock('https://api.example.com/users', null, response);
|
|
178
|
+
|
|
179
|
+
// Use with HttpClient for testing
|
|
180
|
+
const client = new HttpClient({ useTestServer: 'http://localhost:5030' });
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Features:
|
|
185
|
+
# - Express.js HTTP server with FileDatabase storage
|
|
186
|
+
# - Request/response capture and replay
|
|
187
|
+
# - Sensitive data masking
|
|
188
|
+
# - Automatic catalog management
|
|
189
|
+
# - Test server redirection support
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
[📖 Full MockServer Documentation](docs/MOCK_SERVER.md)
|
|
193
|
+
|
|
83
194
|
### Screen - Interactive Terminal UIs
|
|
84
195
|
|
|
85
196
|
```typescript
|
|
@@ -27,17 +27,17 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
));
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
|
|
30
|
-
// src/
|
|
31
|
-
var
|
|
32
|
-
__export(
|
|
30
|
+
// src/filedatabase.ts
|
|
31
|
+
var filedatabase_exports = {};
|
|
32
|
+
__export(filedatabase_exports, {
|
|
33
33
|
FileDatabase: () => FileDatabase,
|
|
34
34
|
FileDatabaseError: () => FileDatabaseError,
|
|
35
35
|
defaultFileSynopsisFunction: () => defaultFileSynopsisFunction,
|
|
36
36
|
defaultVersionSynopsisFunction: () => defaultVersionSynopsisFunction
|
|
37
37
|
});
|
|
38
|
-
module.exports = __toCommonJS(
|
|
38
|
+
module.exports = __toCommonJS(filedatabase_exports);
|
|
39
39
|
|
|
40
|
-
// src/
|
|
40
|
+
// src/filedatabase/index.ts
|
|
41
41
|
var import_fs3 = __toESM(require("fs"), 1);
|
|
42
42
|
var import_path3 = __toESM(require("path"), 1);
|
|
43
43
|
|
|
@@ -113,7 +113,7 @@ function isTimestampFolder(folderName) {
|
|
|
113
113
|
return !isNaN(date.getTime()) && date.getTime() > 0;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
// src/
|
|
116
|
+
// src/filedatabase/serializers.ts
|
|
117
117
|
function detectDataType(data) {
|
|
118
118
|
if (Array.isArray(data)) {
|
|
119
119
|
return "json-array";
|
|
@@ -159,7 +159,7 @@ var ParamError = class extends FrameworkError {
|
|
|
159
159
|
}
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
-
// src/
|
|
162
|
+
// src/filedatabase/synopsis-functions.ts
|
|
163
163
|
function defaultFileSynopsisFunction(fileEntry, data) {
|
|
164
164
|
if (!Array.isArray(data) || data.length === 0) {
|
|
165
165
|
return { ...fileEntry };
|
|
@@ -227,7 +227,7 @@ function defaultVersionSynopsisFunction(metadata) {
|
|
|
227
227
|
return result;
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
// src/
|
|
230
|
+
// src/filedatabase/index.ts
|
|
231
231
|
var FileDatabaseError = class extends Error {
|
|
232
232
|
constructor(message) {
|
|
233
233
|
super(message);
|
|
@@ -238,6 +238,7 @@ var FileDatabase = class {
|
|
|
238
238
|
basePath;
|
|
239
239
|
namespace;
|
|
240
240
|
tableName = null;
|
|
241
|
+
versioned;
|
|
241
242
|
maxVersions;
|
|
242
243
|
pageSize;
|
|
243
244
|
useMetadata;
|
|
@@ -261,6 +262,7 @@ var FileDatabase = class {
|
|
|
261
262
|
this.basePath = config.basePath;
|
|
262
263
|
this.namespace = config.namespace || "default";
|
|
263
264
|
this.tableName = config.tableName || null;
|
|
265
|
+
this.versioned = config.versioned ?? true;
|
|
264
266
|
this.maxVersions = config.maxVersions || 5;
|
|
265
267
|
this.pageSize = config.pageSize || 5e3;
|
|
266
268
|
this.useMetadata = config.useMetadata !== false;
|
|
@@ -283,14 +285,21 @@ var FileDatabase = class {
|
|
|
283
285
|
};
|
|
284
286
|
}
|
|
285
287
|
/**
|
|
286
|
-
* Get the destination path (basePath/namespace/tableName)
|
|
288
|
+
* Get the destination path (basePath/namespace/tableName[/version])
|
|
287
289
|
*/
|
|
288
|
-
getDestinationPath() {
|
|
290
|
+
getDestinationPath(version) {
|
|
289
291
|
const errors = ["basePath", "namespace", "tableName"].filter((prop) => !this[prop]).map((prop) => `${prop} is not set`);
|
|
290
292
|
if (errors.length) {
|
|
291
293
|
throw new FileDatabaseError(`[FileDatabase] ${errors.join("; ")}`);
|
|
292
294
|
}
|
|
293
|
-
|
|
295
|
+
let parts = [this.basePath, this.namespace];
|
|
296
|
+
if (this.tableName) {
|
|
297
|
+
parts.push(...this.tableName.split("/"));
|
|
298
|
+
}
|
|
299
|
+
if (this.versioned && version) {
|
|
300
|
+
parts.push(version);
|
|
301
|
+
}
|
|
302
|
+
return import_path3.default.resolve(...parts);
|
|
294
303
|
}
|
|
295
304
|
/**
|
|
296
305
|
* Set current version and version folder
|
|
@@ -301,8 +310,13 @@ var FileDatabase = class {
|
|
|
301
310
|
}
|
|
302
311
|
/**
|
|
303
312
|
* Create a new version folder with comprehensive timestamp logic
|
|
313
|
+
* Only works in versioned mode
|
|
304
314
|
*/
|
|
305
315
|
async makeNewVersion() {
|
|
316
|
+
if (!this.versioned) {
|
|
317
|
+
throw new FileDatabaseError("makeNewVersion() only works in versioned mode");
|
|
318
|
+
}
|
|
319
|
+
this.metadata = this.getDefaultMetadata();
|
|
306
320
|
const existingVersions = await this.getVersions();
|
|
307
321
|
let versionName;
|
|
308
322
|
if (existingVersions.length > 0) {
|
|
@@ -330,8 +344,12 @@ var FileDatabase = class {
|
|
|
330
344
|
}
|
|
331
345
|
/**
|
|
332
346
|
* Get list of all versions (sorted chronologically)
|
|
347
|
+
* Only works in versioned mode
|
|
333
348
|
*/
|
|
334
349
|
async getVersions() {
|
|
350
|
+
if (!this.versioned) {
|
|
351
|
+
return [];
|
|
352
|
+
}
|
|
335
353
|
const destPath = this.getDestinationPath();
|
|
336
354
|
try {
|
|
337
355
|
await ensurePath(destPath);
|
|
@@ -346,6 +364,86 @@ var FileDatabase = class {
|
|
|
346
364
|
return [];
|
|
347
365
|
}
|
|
348
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Get the latest version (most recent timestamp)
|
|
369
|
+
* Only works in versioned mode
|
|
370
|
+
* @returns Latest version string or null if no versions
|
|
371
|
+
*/
|
|
372
|
+
async getLatestVersion() {
|
|
373
|
+
if (!this.versioned) {
|
|
374
|
+
throw new FileDatabaseError("getLatestVersion() only works in versioned mode");
|
|
375
|
+
}
|
|
376
|
+
const versions = await this.getVersions();
|
|
377
|
+
if (versions.length === 0) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
return versions[versions.length - 1];
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Check if any data exists in this table
|
|
384
|
+
* Works for both versioned and non-versioned modes
|
|
385
|
+
* @returns true if data exists
|
|
386
|
+
*/
|
|
387
|
+
async hasData() {
|
|
388
|
+
const tablePath = this.getDestinationPath();
|
|
389
|
+
if (!import_fs3.default.existsSync(tablePath)) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
if (this.versioned) {
|
|
393
|
+
const versions = await this.getVersions();
|
|
394
|
+
return versions.length > 0;
|
|
395
|
+
} else {
|
|
396
|
+
const items = await import_fs3.default.promises.readdir(tablePath);
|
|
397
|
+
return items.some(
|
|
398
|
+
(item) => item === "metadata.json" || item.match(/^\d{6}\.(json|txt|xml)$/) || item.endsWith(".json")
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Auto-detect the data format in this table
|
|
404
|
+
* Used when reading existing data
|
|
405
|
+
* @returns Format detection result
|
|
406
|
+
*/
|
|
407
|
+
async detectDataFormat() {
|
|
408
|
+
const tablePath = this.getDestinationPath();
|
|
409
|
+
if (!import_fs3.default.existsSync(tablePath)) {
|
|
410
|
+
return { versioned: false, hasMetadata: false, dataType: null };
|
|
411
|
+
}
|
|
412
|
+
const items = await import_fs3.default.promises.readdir(tablePath);
|
|
413
|
+
if (items.includes("metadata.json")) {
|
|
414
|
+
const metadata = JSON.parse(
|
|
415
|
+
await import_fs3.default.promises.readFile(import_path3.default.join(tablePath, "metadata.json"), "utf8")
|
|
416
|
+
);
|
|
417
|
+
return {
|
|
418
|
+
versioned: false,
|
|
419
|
+
hasMetadata: true,
|
|
420
|
+
dataType: metadata.dataType || null
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
const versionFolders = items.filter((item) => {
|
|
424
|
+
const itemPath = import_path3.default.join(tablePath, item);
|
|
425
|
+
const stat = import_fs3.default.statSync(itemPath);
|
|
426
|
+
return stat.isDirectory() && isTimestampFolder(item);
|
|
427
|
+
});
|
|
428
|
+
if (versionFolders.length > 0) {
|
|
429
|
+
const latestVersion = versionFolders.sort().pop();
|
|
430
|
+
const versionMetadataPath = import_path3.default.join(tablePath, latestVersion, "metadata.json");
|
|
431
|
+
return {
|
|
432
|
+
versioned: true,
|
|
433
|
+
hasMetadata: import_fs3.default.existsSync(versionMetadataPath),
|
|
434
|
+
dataType: null
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
const dataFiles = items.filter((f) => f.match(/^\d{6}\.(json|txt|xml)$/));
|
|
438
|
+
if (dataFiles.length > 0) {
|
|
439
|
+
return {
|
|
440
|
+
versioned: false,
|
|
441
|
+
hasMetadata: false,
|
|
442
|
+
dataType: null
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
return { versioned: false, hasMetadata: false, dataType: null };
|
|
446
|
+
}
|
|
349
447
|
/**
|
|
350
448
|
* Load metadata from JSON file
|
|
351
449
|
*/
|
|
@@ -489,11 +587,19 @@ var FileDatabase = class {
|
|
|
489
587
|
* Save version metadata to file
|
|
490
588
|
*/
|
|
491
589
|
async saveVersionMetadata(metadata) {
|
|
492
|
-
if (!this.useMetadata
|
|
590
|
+
if (!this.useMetadata) {
|
|
493
591
|
return;
|
|
494
592
|
}
|
|
495
593
|
const metadataToSave = metadata || this.metadata;
|
|
496
|
-
|
|
594
|
+
let metadataFile;
|
|
595
|
+
if (this.versioned) {
|
|
596
|
+
if (!this.currentVersion) {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
metadataFile = import_path3.default.join(this.getDestinationPath(), this.currentVersion, "metadata.json");
|
|
600
|
+
} else {
|
|
601
|
+
metadataFile = import_path3.default.join(this.getDestinationPath(), "metadata.json");
|
|
602
|
+
}
|
|
497
603
|
await import_fs3.default.promises.writeFile(metadataFile, JSON.stringify(metadataToSave, null, 4), "utf8");
|
|
498
604
|
}
|
|
499
605
|
/**
|
|
@@ -621,31 +727,75 @@ var FileDatabase = class {
|
|
|
621
727
|
*/
|
|
622
728
|
async prepare({ write, read, version }) {
|
|
623
729
|
if (write) {
|
|
624
|
-
if (this.
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
730
|
+
if (this.versioned) {
|
|
731
|
+
if (this.currentVersion === null) {
|
|
732
|
+
await this.makeNewVersion();
|
|
733
|
+
this.metadata = this.getDefaultMetadata();
|
|
734
|
+
this.metadata.version = this.currentVersion;
|
|
735
|
+
this.makeNewFile();
|
|
736
|
+
} else {
|
|
737
|
+
if (!this.metadata.files.length) {
|
|
738
|
+
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
629
741
|
} else {
|
|
630
|
-
|
|
631
|
-
|
|
742
|
+
await ensurePath(this.getDestinationPath());
|
|
743
|
+
if (this.useMetadata === true) {
|
|
744
|
+
const metadataPath = import_path3.default.join(this.getDestinationPath(), "metadata.json");
|
|
745
|
+
if (import_fs3.default.existsSync(metadataPath)) {
|
|
746
|
+
try {
|
|
747
|
+
const rawData = await import_fs3.default.promises.readFile(metadataPath, "utf8");
|
|
748
|
+
this.metadata = JSON.parse(rawData);
|
|
749
|
+
} catch (e) {
|
|
750
|
+
this.metadata = this.getDefaultMetadata();
|
|
751
|
+
}
|
|
752
|
+
} else {
|
|
753
|
+
this.metadata = this.getDefaultMetadata();
|
|
754
|
+
this.makeNewFile();
|
|
755
|
+
}
|
|
756
|
+
} else {
|
|
757
|
+
this.metadata = this.getDefaultMetadata();
|
|
758
|
+
this.makeNewFile();
|
|
632
759
|
}
|
|
633
760
|
}
|
|
634
761
|
} else if (read) {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
if (
|
|
641
|
-
|
|
762
|
+
if (this.versioned) {
|
|
763
|
+
const versions = await this.getVersions();
|
|
764
|
+
if (versions.length === 0) {
|
|
765
|
+
throw new FileDatabaseError("[FileDatabase] No versions found, cannot read");
|
|
766
|
+
}
|
|
767
|
+
if (version) {
|
|
768
|
+
if (!versions.includes(version)) {
|
|
769
|
+
throw new FileDatabaseError(`[FileDatabase] Version "${version}" not found`);
|
|
770
|
+
}
|
|
771
|
+
await this.setCurrentVersion(version);
|
|
772
|
+
} else {
|
|
773
|
+
await this.setCurrentVersion(versions[versions.length - 1]);
|
|
774
|
+
}
|
|
775
|
+
if (!this.metadata.files.length) {
|
|
776
|
+
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
642
777
|
}
|
|
643
|
-
await this.setCurrentVersion(version);
|
|
644
778
|
} else {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
779
|
+
this.currentVersion = null;
|
|
780
|
+
if (this.useMetadata === void 0) {
|
|
781
|
+
const format = await this.detectDataFormat();
|
|
782
|
+
this.useMetadata = format.hasMetadata;
|
|
783
|
+
}
|
|
784
|
+
if (this.useMetadata) {
|
|
785
|
+
const metadataPath = import_path3.default.join(this.getDestinationPath(), "metadata.json");
|
|
786
|
+
if (import_fs3.default.existsSync(metadataPath)) {
|
|
787
|
+
try {
|
|
788
|
+
const rawData = await import_fs3.default.promises.readFile(metadataPath, "utf8");
|
|
789
|
+
this.metadata = JSON.parse(rawData);
|
|
790
|
+
} catch (e) {
|
|
791
|
+
throw new FileDatabaseError(`Failed to read metadata: ${e.message}`);
|
|
792
|
+
}
|
|
793
|
+
} else {
|
|
794
|
+
throw new FileDatabaseError("[FileDatabase] No metadata found in non-versioned mode");
|
|
795
|
+
}
|
|
796
|
+
} else {
|
|
797
|
+
this.metadata = await this.figureMetadataFromVersionFiles("");
|
|
798
|
+
}
|
|
649
799
|
}
|
|
650
800
|
}
|
|
651
801
|
}
|
|
@@ -653,6 +803,9 @@ var FileDatabase = class {
|
|
|
653
803
|
* Write data to the file database
|
|
654
804
|
*/
|
|
655
805
|
async write(data, options = {}) {
|
|
806
|
+
if (options.forceNewVersion && !this.versioned) {
|
|
807
|
+
throw new FileDatabaseError("Cannot use forceNewVersion in non-versioned mode");
|
|
808
|
+
}
|
|
656
809
|
await this.prepare({ write: true });
|
|
657
810
|
if (options.forceNewVersion) {
|
|
658
811
|
await this.makeNewVersion();
|
|
@@ -661,11 +814,12 @@ var FileDatabase = class {
|
|
|
661
814
|
this.makeNewFile();
|
|
662
815
|
}
|
|
663
816
|
let { dataToWrite, dataLeftOver, fileName } = this.figureOutDataAndFileToWrite(data);
|
|
664
|
-
|
|
817
|
+
const destPath = this.getDestinationPath(this.currentVersion || void 0);
|
|
818
|
+
await this.safeWrite(import_path3.default.join(destPath, fileName), dataToWrite);
|
|
665
819
|
this.updateMetadata(dataToWrite, fileName);
|
|
666
820
|
while (dataLeftOver && dataLeftOver.length > 0) {
|
|
667
821
|
const writeContext = this.figureOutDataAndFileToWrite(dataLeftOver);
|
|
668
|
-
await this.safeWrite(import_path3.default.join(
|
|
822
|
+
await this.safeWrite(import_path3.default.join(destPath, writeContext.fileName), writeContext.dataToWrite);
|
|
669
823
|
this.updateMetadata(writeContext.dataToWrite, writeContext.fileName);
|
|
670
824
|
dataLeftOver = writeContext.dataLeftOver;
|
|
671
825
|
}
|
|
@@ -683,7 +837,7 @@ var FileDatabase = class {
|
|
|
683
837
|
const isNonPaginatedData = this.metadata.dataType === "text" || this.metadata.dataType === "xml" || this.metadata.dataType === "json-object";
|
|
684
838
|
if (isNonPaginatedData) {
|
|
685
839
|
const file = this.metadata.files[0];
|
|
686
|
-
const filePath = import_path3.default.join(this.getDestinationPath(
|
|
840
|
+
const filePath = import_path3.default.join(this.getDestinationPath(this.currentVersion || void 0), file.fileName);
|
|
687
841
|
try {
|
|
688
842
|
const rawData = await import_fs3.default.promises.readFile(filePath, "utf8");
|
|
689
843
|
return deserializeData(rawData, this.metadata.dataType);
|
|
@@ -721,7 +875,7 @@ var FileDatabase = class {
|
|
|
721
875
|
let cumulativeRecords = currentFileOffset;
|
|
722
876
|
for (let i = currentFileIndex; i < this.metadata.files.length && recordsRead < effectivePageSize; i++) {
|
|
723
877
|
const file = this.metadata.files[i];
|
|
724
|
-
const filePath = import_path3.default.join(this.getDestinationPath(
|
|
878
|
+
const filePath = import_path3.default.join(this.getDestinationPath(this.currentVersion || void 0), file.fileName);
|
|
725
879
|
try {
|
|
726
880
|
const rawData = await import_fs3.default.promises.readFile(filePath, "utf8");
|
|
727
881
|
const fileData = deserializeData(rawData, this.metadata.dataType);
|
|
@@ -791,4 +945,4 @@ var FileDatabase = class {
|
|
|
791
945
|
defaultFileSynopsisFunction,
|
|
792
946
|
defaultVersionSynopsisFunction
|
|
793
947
|
});
|
|
794
|
-
//# sourceMappingURL=
|
|
948
|
+
//# sourceMappingURL=filedatabase.cjs.map
|