@alwatr/nitrobase-engine 8.0.0 → 9.1.1
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/LICENSE +373 -661
- package/README.md +0 -6
- package/dist/alwatr-nitrobase.d.ts +1 -1
- package/dist/alwatr-nitrobase.d.ts.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/main.js +5 -0
- package/dist/main.js.map +11 -0
- package/package.json +65 -61
- package/{dist/main.mjs → src/alwatr-nitrobase.ts} +208 -135
- package/src/logger.ts +4 -0
- package/src/main.ts +1 -0
- package/CHANGELOG.md +0 -300
- package/dist/main.cjs +0 -447
- package/dist/main.cjs.map +0 -7
- package/dist/main.mjs.map +0 -7
|
@@ -1,25 +1,85 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import { exitHook } from "@alwatr/nanolib/exit-hook";
|
|
6
|
-
import { existsSync, readJson, resolve, unlink, writeJson } from "@alwatr/nanolib/node-fs";
|
|
7
|
-
import { getStoreId, getStorePath } from "@alwatr/nitrobase-helper";
|
|
8
|
-
import { CollectionReference, DocumentReference } from "@alwatr/nitrobase-reference";
|
|
1
|
+
import {delay} from '@alwatr/delay';
|
|
2
|
+
import {exitHook} from '@alwatr/exit-hook';
|
|
3
|
+
import {getStoreId, getStorePath} from '@alwatr/nitrobase-helper';
|
|
4
|
+
import {CollectionReference, DocumentReference} from '@alwatr/nitrobase-reference';
|
|
9
5
|
import {
|
|
10
6
|
StoreFileType,
|
|
11
7
|
StoreFileExtension,
|
|
12
|
-
Region
|
|
13
|
-
|
|
8
|
+
Region,
|
|
9
|
+
type StoreFileStat,
|
|
10
|
+
type StoreFileContext,
|
|
11
|
+
type CollectionContext,
|
|
12
|
+
type DocumentContext,
|
|
13
|
+
type StoreFileId,
|
|
14
|
+
type CollectionItem,
|
|
15
|
+
} from '@alwatr/nitrobase-types';
|
|
16
|
+
import {existsSync, readJson, resolve, unlink, writeJson} from '@alwatr/node-fs';
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
import {logger} from './logger.js';
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
__dev_mode__: logger.logFileModule?.('alwatr-nitrobase');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* AlwatrNitrobase configuration.
|
|
25
|
+
*/
|
|
26
|
+
export interface AlwatrNitrobaseConfig {
|
|
27
|
+
/**
|
|
28
|
+
* The root path of the storage.
|
|
29
|
+
* This is where the AlwatrNitrobase will nitrobase its data.
|
|
30
|
+
*/
|
|
31
|
+
rootPath: string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The save debounce timeout in milliseconds for minimal disk I/O usage.
|
|
35
|
+
* This is used to limit the frequency of disk writes for performance reasons.
|
|
36
|
+
* The recommended value is `40`.
|
|
37
|
+
*/
|
|
38
|
+
defaultChangeDebounce?: number;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* If true, an error will be thrown when trying to read or write to a nitrobase file that is not initialized (new storage).
|
|
42
|
+
* The default value is `false` but highly recommended to set it to `true` in production to prevent data loss.
|
|
43
|
+
*/
|
|
44
|
+
errorWhenNotInitialized?: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* AlwatrNitrobase engine.
|
|
49
|
+
*
|
|
50
|
+
* It provides methods to read, write, validate, and manage nitrobase files.
|
|
51
|
+
* It also provides methods to interact with `documents` and `collections` in the nitrobase.
|
|
52
|
+
*/
|
|
53
|
+
export class AlwatrNitrobase {
|
|
54
|
+
/**
|
|
55
|
+
* The Alwatr Nitrobase version string.
|
|
56
|
+
*
|
|
57
|
+
* Use for nitrobase file format version for check compatibility.
|
|
58
|
+
*/
|
|
59
|
+
public static readonly version = __package_version__;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The root nitrobase file stat.
|
|
63
|
+
*/
|
|
64
|
+
private static readonly rootDbStat__: StoreFileStat = {
|
|
65
|
+
name: '.nitrobase',
|
|
66
|
+
region: Region.Secret,
|
|
67
|
+
type: StoreFileType.Collection,
|
|
68
|
+
extension: StoreFileExtension.Json,
|
|
69
|
+
changeDebounce: 40,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* `collectionReference` of all `storeFileStat`s.
|
|
74
|
+
* This is the root nitrobase collection.
|
|
75
|
+
*/
|
|
76
|
+
private rootDb__;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Keep all loaded nitrobase file context loaded in memory.
|
|
80
|
+
*/
|
|
81
|
+
private cacheReferences__: DictionaryReq<DocumentReference | CollectionReference> = {};
|
|
19
82
|
|
|
20
|
-
// src/alwatr-nitrobase.ts
|
|
21
|
-
__dev_mode__: logger.logFileModule?.("alwatr-nitrobase");
|
|
22
|
-
var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
23
83
|
/**
|
|
24
84
|
* Constructs an AlwatrNitrobase instance with the provided configuration.
|
|
25
85
|
*
|
|
@@ -32,19 +92,15 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
32
92
|
* });
|
|
33
93
|
* ```
|
|
34
94
|
*/
|
|
35
|
-
constructor(config) {
|
|
36
|
-
this.config = config;
|
|
37
|
-
/**
|
|
38
|
-
* Keep all loaded nitrobase file context loaded in memory.
|
|
39
|
-
*/
|
|
40
|
-
this.cacheReferences__ = {};
|
|
41
|
-
var _a;
|
|
95
|
+
constructor(public readonly config: AlwatrNitrobaseConfig) {
|
|
42
96
|
this.storeChanged_ = this.storeChanged_.bind(this);
|
|
43
|
-
|
|
44
|
-
(
|
|
97
|
+
|
|
98
|
+
logger.logMethodArgs?.('new', config);
|
|
99
|
+
this.config.defaultChangeDebounce ??= 40;
|
|
45
100
|
this.rootDb__ = this.loadRootDb__();
|
|
46
101
|
exitHook(this.exitHook__.bind(this));
|
|
47
102
|
}
|
|
103
|
+
|
|
48
104
|
/**
|
|
49
105
|
* Checks if a nitrobase file with the given ID exists.
|
|
50
106
|
*
|
|
@@ -57,12 +113,13 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
57
113
|
* }
|
|
58
114
|
* ```
|
|
59
115
|
*/
|
|
60
|
-
hasStore(storeId) {
|
|
116
|
+
public hasStore(storeId: StoreFileId): boolean {
|
|
61
117
|
const id_ = getStoreId(storeId);
|
|
62
118
|
const exists = this.rootDb__.hasItem(id_);
|
|
63
|
-
logger.logMethodFull?.(
|
|
119
|
+
logger.logMethodFull?.('hasStore', id_, exists);
|
|
64
120
|
return exists;
|
|
65
121
|
}
|
|
122
|
+
|
|
66
123
|
/**
|
|
67
124
|
* Defines a new document with the given configuration and initial data.
|
|
68
125
|
* If a document with the same ID already exists, an error is thrown.
|
|
@@ -85,16 +142,17 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
85
142
|
* );
|
|
86
143
|
* ```
|
|
87
144
|
*/
|
|
88
|
-
newDocument(stat, data) {
|
|
89
|
-
logger.logMethodArgs?.(
|
|
90
|
-
return this.
|
|
145
|
+
public newDocument<TDoc extends JsonObject = JsonObject>(stat: Omit<StoreFileStat, 'type'>, data: TDoc): void {
|
|
146
|
+
logger.logMethodArgs?.('newDocument', stat);
|
|
147
|
+
return this.newStoreFile__(
|
|
91
148
|
{
|
|
92
149
|
...stat,
|
|
93
|
-
type: StoreFileType.Document
|
|
150
|
+
type: StoreFileType.Document,
|
|
94
151
|
},
|
|
95
|
-
data
|
|
152
|
+
data,
|
|
96
153
|
);
|
|
97
154
|
}
|
|
155
|
+
|
|
98
156
|
/**
|
|
99
157
|
* Defines a new collection with the given configuration and initial data.
|
|
100
158
|
* If a collection with the same ID already exists, an error is thrown.
|
|
@@ -111,45 +169,53 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
111
169
|
* );
|
|
112
170
|
* ```
|
|
113
171
|
*/
|
|
114
|
-
newCollection(stat) {
|
|
115
|
-
logger.logMethodArgs?.(
|
|
116
|
-
return this.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
);
|
|
172
|
+
public newCollection(stat: Omit<StoreFileStat, 'type'>): void {
|
|
173
|
+
logger.logMethodArgs?.('newCollection', stat);
|
|
174
|
+
return this.newStoreFile__({
|
|
175
|
+
...stat,
|
|
176
|
+
type: StoreFileType.Collection,
|
|
177
|
+
});
|
|
122
178
|
}
|
|
179
|
+
|
|
123
180
|
/**
|
|
124
181
|
* Defines a AlwatrNitrobaseFile with the given configuration and initial data.
|
|
125
182
|
*
|
|
126
183
|
* @param stat nitrobase file stat
|
|
127
184
|
* @param data initial data for the document
|
|
128
185
|
*/
|
|
129
|
-
|
|
130
|
-
logger.logMethodArgs?.(
|
|
131
|
-
|
|
132
|
-
|
|
186
|
+
private newStoreFile__(stat: StoreFileStat, data?: DictionaryOpt): void {
|
|
187
|
+
logger.logMethodArgs?.('newStoreFile__', stat);
|
|
188
|
+
|
|
189
|
+
(stat.changeDebounce as number | undefined) ??= this.config.defaultChangeDebounce;
|
|
190
|
+
|
|
191
|
+
let fileStoreRef: DocumentReference | CollectionReference;
|
|
133
192
|
if (stat.type === StoreFileType.Document) {
|
|
134
|
-
if (data ===
|
|
135
|
-
logger.accident(
|
|
136
|
-
throw new Error(
|
|
193
|
+
if (data === undefined) {
|
|
194
|
+
logger.accident('newStoreFile__', 'document_data_required', stat);
|
|
195
|
+
throw new Error('document_data_required', {cause: stat});
|
|
137
196
|
}
|
|
138
197
|
fileStoreRef = DocumentReference.newRefFromData(stat, data, this.storeChanged_);
|
|
139
|
-
}
|
|
198
|
+
}
|
|
199
|
+
else if (stat.type === StoreFileType.Collection) {
|
|
140
200
|
fileStoreRef = CollectionReference.newRefFromData(stat, this.storeChanged_);
|
|
141
|
-
} else {
|
|
142
|
-
logger.accident("newStoreFile_", "store_file_type_not_supported", stat);
|
|
143
|
-
throw new Error("store_file_type_not_supported", { cause: stat });
|
|
144
201
|
}
|
|
202
|
+
else {
|
|
203
|
+
logger.accident('newStoreFile__', 'store_file_type_not_supported', stat);
|
|
204
|
+
throw new Error('store_file_type_not_supported', {cause: stat});
|
|
205
|
+
}
|
|
206
|
+
|
|
145
207
|
if (this.rootDb__.hasItem(fileStoreRef.id)) {
|
|
146
|
-
logger.accident(
|
|
147
|
-
throw new Error(
|
|
208
|
+
logger.accident('newStoreFile__', 'store_file_already_defined', stat);
|
|
209
|
+
throw new Error('store_file_already_defined', {cause: stat});
|
|
148
210
|
}
|
|
211
|
+
|
|
149
212
|
this.rootDb__.addItem(fileStoreRef.id, stat);
|
|
150
213
|
this.cacheReferences__[fileStoreRef.id] = fileStoreRef;
|
|
214
|
+
|
|
215
|
+
// fileStoreRef.save();
|
|
151
216
|
this.storeChanged_(fileStoreRef);
|
|
152
217
|
}
|
|
218
|
+
|
|
153
219
|
/**
|
|
154
220
|
* Open a document with the given id and create and return a DocumentReference.
|
|
155
221
|
* If the document not exists or its not a document, an error is thrown.
|
|
@@ -167,31 +233,37 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
167
233
|
* userProfile.update({name: 'ali'});
|
|
168
234
|
* ```
|
|
169
235
|
*/
|
|
170
|
-
async openDocument(documentId) {
|
|
236
|
+
public async openDocument<TDoc extends JsonObject>(documentId: StoreFileId): Promise<DocumentReference<TDoc>> {
|
|
171
237
|
const id = getStoreId(documentId);
|
|
172
|
-
logger.logMethodArgs?.(
|
|
238
|
+
logger.logMethodArgs?.('openDocument', id);
|
|
239
|
+
|
|
173
240
|
if (Object.hasOwn(this.cacheReferences__, id)) {
|
|
174
241
|
const ref = this.cacheReferences__[id];
|
|
175
242
|
if (!(ref instanceof DocumentReference)) {
|
|
176
|
-
logger.accident(
|
|
177
|
-
throw new Error(
|
|
243
|
+
logger.accident('openDocument', 'document_wrong_type', id);
|
|
244
|
+
throw new Error('document_wrong_type', {cause: id});
|
|
178
245
|
}
|
|
179
|
-
return this.cacheReferences__[id]
|
|
246
|
+
return this.cacheReferences__[id] as unknown as DocumentReference<TDoc>;
|
|
180
247
|
}
|
|
248
|
+
|
|
181
249
|
if (!this.rootDb__.hasItem(id)) {
|
|
182
|
-
logger.accident(
|
|
183
|
-
throw new Error(
|
|
250
|
+
logger.accident('openDocument', 'document_not_found', id);
|
|
251
|
+
throw new Error('document_not_found', {cause: id});
|
|
184
252
|
}
|
|
253
|
+
|
|
185
254
|
const storeStat = this.rootDb__.getItemData(id);
|
|
255
|
+
|
|
186
256
|
if (storeStat.type != StoreFileType.Document) {
|
|
187
|
-
logger.accident(
|
|
188
|
-
throw new Error(
|
|
257
|
+
logger.accident('openDocument', 'document_wrong_type', id);
|
|
258
|
+
throw new Error('document_wrong_type', {cause: id});
|
|
189
259
|
}
|
|
190
|
-
|
|
260
|
+
|
|
261
|
+
const context = await this.readContext__<DocumentContext<TDoc>>(storeStat);
|
|
191
262
|
const docRef = DocumentReference.newRefFromContext(context, this.storeChanged_);
|
|
192
|
-
this.cacheReferences__[id] = docRef;
|
|
263
|
+
this.cacheReferences__[id] = docRef as unknown as DocumentReference;
|
|
193
264
|
return docRef;
|
|
194
265
|
}
|
|
266
|
+
|
|
195
267
|
/**
|
|
196
268
|
* Open a collection with the given id and create and return a CollectionReference.
|
|
197
269
|
* If the collection not exists or its not a collection, an error is thrown.
|
|
@@ -209,31 +281,39 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
209
281
|
* orders.append({name: 'order 1'});
|
|
210
282
|
* ```
|
|
211
283
|
*/
|
|
212
|
-
async openCollection(collectionId) {
|
|
284
|
+
public async openCollection<TItem extends JsonObject>(collectionId: StoreFileId): Promise<CollectionReference<TItem>> {
|
|
213
285
|
const id = getStoreId(collectionId);
|
|
214
|
-
logger.logMethodArgs?.(
|
|
286
|
+
logger.logMethodArgs?.('openCollection', id);
|
|
287
|
+
|
|
288
|
+
// try to get from cache
|
|
215
289
|
if (Object.hasOwn(this.cacheReferences__, id)) {
|
|
216
290
|
const ref = this.cacheReferences__[id];
|
|
217
291
|
if (!(ref instanceof CollectionReference)) {
|
|
218
|
-
logger.accident(
|
|
219
|
-
throw new Error(
|
|
292
|
+
logger.accident('openCollection', 'collection_wrong_type', id);
|
|
293
|
+
throw new Error('collection_wrong_type', {cause: id});
|
|
220
294
|
}
|
|
221
|
-
return this.cacheReferences__[id]
|
|
295
|
+
return this.cacheReferences__[id] as unknown as CollectionReference<TItem>;
|
|
222
296
|
}
|
|
297
|
+
|
|
298
|
+
// load and create new collection reference
|
|
223
299
|
if (!this.rootDb__.hasItem(id)) {
|
|
224
|
-
logger.accident(
|
|
225
|
-
throw new Error(
|
|
300
|
+
logger.accident('openCollection', 'collection_not_found', id);
|
|
301
|
+
throw new Error('collection_not_found', {cause: id});
|
|
226
302
|
}
|
|
303
|
+
|
|
227
304
|
const storeStat = this.rootDb__.getItemData(id);
|
|
305
|
+
|
|
228
306
|
if (storeStat.type != StoreFileType.Collection) {
|
|
229
|
-
logger.accident(
|
|
230
|
-
throw new Error(
|
|
307
|
+
logger.accident('openCollection', 'collection_wrong_type', id);
|
|
308
|
+
throw new Error('collection_not_found', {cause: id});
|
|
231
309
|
}
|
|
232
|
-
|
|
310
|
+
|
|
311
|
+
const context = await this.readContext__<CollectionContext<TItem>>(storeStat);
|
|
233
312
|
const colRef = CollectionReference.newRefFromContext(context, this.storeChanged_);
|
|
234
|
-
this.cacheReferences__[id] = colRef;
|
|
313
|
+
this.cacheReferences__[id] = colRef as unknown as CollectionReference;
|
|
235
314
|
return colRef;
|
|
236
315
|
}
|
|
316
|
+
|
|
237
317
|
/**
|
|
238
318
|
* Unloads the nitrobase file with the given id from memory.
|
|
239
319
|
*
|
|
@@ -244,17 +324,18 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
244
324
|
* alwatrStore.hasStore({name: 'user-list', region: Region.Secret}); // true
|
|
245
325
|
* ```
|
|
246
326
|
*/
|
|
247
|
-
unloadStore(storeId) {
|
|
327
|
+
public unloadStore(storeId: StoreFileId): void {
|
|
248
328
|
const id_ = getStoreId(storeId);
|
|
249
|
-
logger.logMethodArgs?.(
|
|
329
|
+
logger.logMethodArgs?.('unloadStore', id_);
|
|
250
330
|
const ref = this.cacheReferences__[id_];
|
|
251
|
-
if (ref ===
|
|
331
|
+
if (ref === undefined) return;
|
|
252
332
|
if (ref.hasUnprocessedChanges_ === true) {
|
|
253
333
|
ref.updateDelayed_ = false;
|
|
254
334
|
this.storeChanged_(ref);
|
|
255
335
|
}
|
|
256
336
|
delete this.cacheReferences__[id_];
|
|
257
337
|
}
|
|
338
|
+
|
|
258
339
|
/**
|
|
259
340
|
* Remove document or collection from nitrobase and delete the file from disk.
|
|
260
341
|
* If the file is not found, an error is thrown.
|
|
@@ -269,29 +350,32 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
269
350
|
* alwatrStore.hasStore({name: 'user-list', region: Region.Secret}); // false
|
|
270
351
|
* ```
|
|
271
352
|
*/
|
|
272
|
-
async removeStore(storeId) {
|
|
353
|
+
public async removeStore(storeId: StoreFileId): Promise<void> {
|
|
273
354
|
const id_ = getStoreId(storeId);
|
|
274
|
-
logger.logMethodArgs?.(
|
|
355
|
+
logger.logMethodArgs?.('removeStore', id_);
|
|
275
356
|
if (!this.rootDb__.hasItem(id_)) {
|
|
276
|
-
logger.accident(
|
|
277
|
-
throw new Error(
|
|
357
|
+
logger.accident('removeStore', 'document_not_found', id_);
|
|
358
|
+
throw new Error('document_not_found', {cause: id_});
|
|
278
359
|
}
|
|
279
360
|
const ref = this.cacheReferences__[id_];
|
|
280
|
-
if (ref !==
|
|
361
|
+
if (ref !== undefined) {
|
|
362
|
+
// direct unload to prevent save
|
|
281
363
|
ref.freeze = true;
|
|
282
364
|
ref.updateDelayed_ = false;
|
|
283
365
|
ref.hasUnprocessedChanges_ = false;
|
|
284
|
-
delete this.cacheReferences__[id_];
|
|
366
|
+
delete this.cacheReferences__[id_]; // unload
|
|
285
367
|
}
|
|
286
368
|
const path = getStorePath(this.rootDb__.getItemData(id_));
|
|
287
369
|
this.rootDb__.removeItem(id_);
|
|
288
370
|
await delay.by(0);
|
|
289
371
|
try {
|
|
290
372
|
await unlink(resolve(this.config.rootPath, path));
|
|
291
|
-
}
|
|
292
|
-
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
logger.error('removeStore', 'remove_file_failed', error, {id: storeId, path});
|
|
293
376
|
}
|
|
294
377
|
}
|
|
378
|
+
|
|
295
379
|
/**
|
|
296
380
|
* Saves all changes in the nitrobase.
|
|
297
381
|
*
|
|
@@ -301,8 +385,8 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
301
385
|
* await alwatrStore.saveAll();
|
|
302
386
|
* ```
|
|
303
387
|
*/
|
|
304
|
-
async saveAll() {
|
|
305
|
-
logger.logMethod?.(
|
|
388
|
+
public async saveAll(): Promise<void> {
|
|
389
|
+
logger.logMethod?.('saveAll');
|
|
306
390
|
for (const ref of Object.values(this.cacheReferences__)) {
|
|
307
391
|
if (ref.hasUnprocessedChanges_ === true && ref.freeze !== true) {
|
|
308
392
|
ref.updateDelayed_ = false;
|
|
@@ -310,20 +394,22 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
310
394
|
}
|
|
311
395
|
}
|
|
312
396
|
}
|
|
397
|
+
|
|
313
398
|
/**
|
|
314
399
|
* Reads the context from a given path or StoreFileStat object.
|
|
315
400
|
*
|
|
316
401
|
* @param path The path or StoreFileStat object from which to read the context.
|
|
317
402
|
* @returns A promise that resolves to the context object.
|
|
318
403
|
*/
|
|
319
|
-
async readContext__(path) {
|
|
320
|
-
if (typeof path !==
|
|
321
|
-
logger.logMethodArgs?.(
|
|
404
|
+
private async readContext__<T extends StoreFileContext>(path: string | StoreFileStat): Promise<T> {
|
|
405
|
+
if (typeof path !== 'string') path = getStorePath(path);
|
|
406
|
+
logger.logMethodArgs?.('readContext__', path);
|
|
322
407
|
logger.time?.(`readContext__time(${path})`);
|
|
323
|
-
const context = await readJson(resolve(this.config.rootPath, path));
|
|
408
|
+
const context = (await readJson(resolve(this.config.rootPath, path))) as T;
|
|
324
409
|
logger.timeEnd?.(`readContext__time(${path})`);
|
|
325
410
|
return context;
|
|
326
411
|
}
|
|
412
|
+
|
|
327
413
|
/**
|
|
328
414
|
* Writes the context to the specified path.
|
|
329
415
|
*
|
|
@@ -333,59 +419,67 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
333
419
|
* @param sync Indicates whether the write operation should be synchronous.
|
|
334
420
|
* @returns A promise that resolves when the write operation is complete.
|
|
335
421
|
*/
|
|
336
|
-
writeContext__(path, context) {
|
|
337
|
-
if (typeof path !==
|
|
338
|
-
logger.logMethodArgs?.(
|
|
422
|
+
private writeContext__<T extends StoreFileContext>(path: string | StoreFileStat, context: T): Promise<void> {
|
|
423
|
+
if (typeof path !== 'string') path = getStorePath(path);
|
|
424
|
+
logger.logMethodArgs?.('writeContext__', path);
|
|
339
425
|
return writeJson(resolve(this.config.rootPath, path), context);
|
|
340
426
|
}
|
|
427
|
+
|
|
341
428
|
/**
|
|
342
429
|
* Write nitrobase file context.
|
|
343
430
|
*
|
|
344
431
|
* @param from nitrobase file reference
|
|
345
432
|
* @returns A promise that resolves when the write operation is complete.
|
|
346
433
|
*/
|
|
347
|
-
async storeChanged_(from) {
|
|
348
|
-
logger.logMethodArgs?.(
|
|
434
|
+
protected async storeChanged_<T extends JsonObject>(from: DocumentReference<T> | CollectionReference<T>): Promise<void> {
|
|
435
|
+
logger.logMethodArgs?.('storeChanged__', from.id);
|
|
349
436
|
const rev = from.getStoreMeta().rev;
|
|
350
437
|
try {
|
|
351
438
|
await this.writeContext__(from.path, from.getFullContext_());
|
|
352
439
|
if (rev === from.getStoreMeta().rev) {
|
|
440
|
+
// Context not changed during saving
|
|
353
441
|
from.hasUnprocessedChanges_ = false;
|
|
354
442
|
}
|
|
355
|
-
}
|
|
356
|
-
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
logger.error('storeChanged__', 'write_context_failed', {id: from.id, error});
|
|
357
446
|
}
|
|
358
447
|
}
|
|
448
|
+
|
|
359
449
|
/**
|
|
360
450
|
* Load storeFilesCollection or create new one.
|
|
361
451
|
*/
|
|
362
|
-
loadRootDb__() {
|
|
363
|
-
logger.logMethod?.(
|
|
364
|
-
const fullPath = resolve(this.config.rootPath, getStorePath(
|
|
452
|
+
private loadRootDb__(): CollectionReference<StoreFileStat> {
|
|
453
|
+
logger.logMethod?.('loadRootDb__');
|
|
454
|
+
const fullPath = resolve(this.config.rootPath, getStorePath(AlwatrNitrobase.rootDbStat__));
|
|
365
455
|
if (!existsSync(fullPath)) {
|
|
366
456
|
if (this.config.errorWhenNotInitialized === true) {
|
|
367
|
-
throw new Error(
|
|
457
|
+
throw new Error('store_not_found', {cause: 'Nitrobase not initialized'});
|
|
368
458
|
}
|
|
369
|
-
|
|
370
|
-
|
|
459
|
+
|
|
460
|
+
logger.banner('Initialize new alwatr-nitrobase');
|
|
461
|
+
return CollectionReference.newRefFromData(AlwatrNitrobase.rootDbStat__, this.storeChanged_);
|
|
371
462
|
}
|
|
372
|
-
|
|
373
|
-
|
|
463
|
+
// else
|
|
464
|
+
const context = readJson<CollectionContext<StoreFileStat>>(fullPath, true);
|
|
465
|
+
return CollectionReference.newRefFromContext(context, this.storeChanged_, 'root-db');
|
|
374
466
|
}
|
|
467
|
+
|
|
375
468
|
/**
|
|
376
469
|
* Save all nitrobase files.
|
|
377
470
|
*/
|
|
378
|
-
exitHook__() {
|
|
379
|
-
logger.logMethod?.(
|
|
471
|
+
private exitHook__(): void {
|
|
472
|
+
logger.logMethod?.('exitHook__');
|
|
380
473
|
for (const ref of Object.values(this.cacheReferences__)) {
|
|
381
474
|
logger.logProperty?.(`StoreFile.${ref.id}.hasUnprocessedChanges`, ref.hasUnprocessedChanges_);
|
|
382
475
|
if (ref.hasUnprocessedChanges_ === true && ref.freeze !== true) {
|
|
383
|
-
logger.incident?.(
|
|
476
|
+
logger.incident?.('exitHook__', 'rescue_unsaved_context', {id: ref.id});
|
|
384
477
|
writeJson(resolve(this.config.rootPath, ref.path), ref.getFullContext_(), true);
|
|
385
478
|
ref.hasUnprocessedChanges_ = false;
|
|
386
479
|
}
|
|
387
480
|
}
|
|
388
481
|
}
|
|
482
|
+
|
|
389
483
|
/**
|
|
390
484
|
* Get all nitrobase files.
|
|
391
485
|
*
|
|
@@ -397,29 +491,8 @@ var _AlwatrNitrobase = class _AlwatrNitrobase {
|
|
|
397
491
|
* console.log(nitrobase.meta.id, nitrobase.data);
|
|
398
492
|
* }
|
|
399
493
|
*/
|
|
400
|
-
getStoreList() {
|
|
401
|
-
logger.logMethod?.(
|
|
494
|
+
public getStoreList(): CollectionItem<Omit<StoreFileStat, 'schemaVer'>>[] {
|
|
495
|
+
logger.logMethod?.('getStoreList');
|
|
402
496
|
return this.rootDb__.values();
|
|
403
497
|
}
|
|
404
|
-
}
|
|
405
|
-
/**
|
|
406
|
-
* The Alwatr Nitrobase version string.
|
|
407
|
-
*
|
|
408
|
-
* Use for nitrobase file format version for check compatibility.
|
|
409
|
-
*/
|
|
410
|
-
_AlwatrNitrobase.version = "8.0.0";
|
|
411
|
-
/**
|
|
412
|
-
* The root nitrobase file stat.
|
|
413
|
-
*/
|
|
414
|
-
_AlwatrNitrobase.rootDbStat__ = {
|
|
415
|
-
name: ".nitrobase",
|
|
416
|
-
region: Region.Secret,
|
|
417
|
-
type: StoreFileType.Collection,
|
|
418
|
-
extension: StoreFileExtension.Json,
|
|
419
|
-
changeDebounce: 40
|
|
420
|
-
};
|
|
421
|
-
var AlwatrNitrobase = _AlwatrNitrobase;
|
|
422
|
-
export {
|
|
423
|
-
AlwatrNitrobase
|
|
424
|
-
};
|
|
425
|
-
//# sourceMappingURL=main.mjs.map
|
|
498
|
+
}
|
package/src/logger.ts
ADDED
package/src/main.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './alwatr-nitrobase.js';
|