taon-storage 21.0.8 → 21.0.11
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/browser/fesm2022/taon-storage-browser.mjs +468 -255
- package/browser/fesm2022/taon-storage-browser.mjs.map +1 -1
- package/browser/package.json +5 -5
- package/browser/types/taon-storage-browser.d.ts +78 -30
- package/lib/build-info._auto-generated_.d.ts +1 -1
- package/lib/build-info._auto-generated_.js +1 -1
- package/lib/build-info._auto-generated_.js.map +1 -1
- package/lib/storage.d.ts +76 -35
- package/lib/storage.js +479 -212
- package/lib/storage.js.map +1 -1
- package/package.json +1 -1
- package/websql/fesm2022/taon-storage-websql.mjs +468 -255
- package/websql/fesm2022/taon-storage-websql.mjs.map +1 -1
- package/websql/package.json +5 -5
- package/websql/types/taon-storage-websql.d.ts +78 -30
- package/lib/constants.d.ts +0 -3
- package/lib/constants.js +0 -40
- package/lib/constants.js.map +0 -1
- package/lib/file-stor.d.ts +0 -9
- package/lib/file-stor.js +0 -64
- package/lib/file-stor.js.map +0 -1
- package/lib/helpers.d.ts +0 -2
- package/lib/helpers.js +0 -15
- package/lib/helpers.js.map +0 -1
- package/lib/models.d.ts +0 -10
- package/lib/models.js +0 -5
- package/lib/models.js.map +0 -1
- package/lib/utils.d.ts +0 -0
- package/lib/utils.js +0 -5
- package/lib/utils.js.map +0 -1
- package/tmp-environment.json +0 -43
package/lib/storage.js
CHANGED
|
@@ -1,241 +1,508 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Stor = void 0;
|
|
3
|
+
exports.Stor = exports.StorPropertyInIndexedDb = exports.StorPropertyInLocalStorage = exports.keyDefaultValueAreadySet = exports.StorConfig = exports.storeName = void 0;
|
|
4
|
+
exports.keyValue = keyValue;
|
|
5
|
+
exports.keyDefaultValueAlreadySet = keyDefaultValueAlreadySet;
|
|
4
6
|
exports.uncache = uncache;
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
7
|
+
/* taon-storage (native, SSR-safe) */
|
|
8
|
+
const lib_1 = require("tnp-core/lib");
|
|
9
|
+
const isBrowser = typeof window !== 'undefined' &&
|
|
10
|
+
typeof document !== 'undefined' &&
|
|
11
|
+
typeof navigator !== 'undefined';
|
|
12
|
+
function getGlobalEnv() {
|
|
13
|
+
return globalThis?.ENV;
|
|
14
|
+
}
|
|
15
|
+
function safeLocationPort() {
|
|
16
|
+
try {
|
|
17
|
+
return globalThis?.location?.port || 'no-port';
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return 'no-port';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Keeps the spirit of your old `storeName = taon-storage_<port>`
|
|
25
|
+
* plus project name namespacing (but without localForage).
|
|
26
|
+
*/
|
|
27
|
+
exports.storeName = `taon-storage_${safeLocationPort()}`;
|
|
28
|
+
function defaultNamespace() {
|
|
29
|
+
const env = getGlobalEnv();
|
|
30
|
+
const project = lib_1._.kebabCase(env?.currentProjectGenericName ?? '');
|
|
31
|
+
return project ? `${exports.storeName}_${project}` : exports.storeName;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Central config (optional).
|
|
35
|
+
* You can set it once at app bootstrap if you want a stable namespace.
|
|
36
|
+
*/
|
|
37
|
+
exports.StorConfig = {
|
|
38
|
+
namespace: defaultNamespace(),
|
|
39
|
+
indexedDb: {
|
|
40
|
+
dbName: `${defaultNamespace()}_INDEXEDDB`,
|
|
41
|
+
storeName: 'keyvaluepairs',
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
function normalizeScopeClass(cls) {
|
|
45
|
+
if (!cls)
|
|
46
|
+
return { name: '__GLOBAL_NAMESPACE__' };
|
|
47
|
+
// if it's a function/class
|
|
48
|
+
if (typeof cls === 'function')
|
|
49
|
+
return { name: cls.name || '__ANON__' };
|
|
50
|
+
// if it's already object with name
|
|
51
|
+
return { name: cls.name || '__ANON__' };
|
|
52
|
+
}
|
|
53
|
+
function keyValue(scopeClass, memberName) {
|
|
54
|
+
const c = normalizeScopeClass(scopeClass);
|
|
55
|
+
return `${exports.StorConfig.namespace}::taon.storage.class.${c.name}.prop.${memberName}`;
|
|
56
|
+
}
|
|
57
|
+
function keyDefaultValueAlreadySet(scopeClass, memberName) {
|
|
58
|
+
return `${keyValue(scopeClass, memberName)}::defaultvalueisset`;
|
|
59
|
+
}
|
|
60
|
+
/** Back-compat alias (your old typo) */
|
|
61
|
+
exports.keyDefaultValueAreadySet = keyDefaultValueAlreadySet;
|
|
62
|
+
class NoopStore {
|
|
63
|
+
async getItem(_key) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
async setItem(_key, _value) {
|
|
67
|
+
// noop
|
|
68
|
+
}
|
|
69
|
+
async removeItem(_key) {
|
|
70
|
+
// noop
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
class BrowserLocalStorageStore {
|
|
74
|
+
ls() {
|
|
75
|
+
if (!isBrowser)
|
|
76
|
+
return undefined;
|
|
77
|
+
try {
|
|
78
|
+
return window.localStorage;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async getItem(key) {
|
|
85
|
+
const ls = this.ls();
|
|
86
|
+
if (!ls)
|
|
87
|
+
return undefined;
|
|
88
|
+
const raw = ls.getItem(key);
|
|
89
|
+
if (raw === null)
|
|
90
|
+
return undefined;
|
|
91
|
+
try {
|
|
92
|
+
return JSON.parse(raw);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// if something stored plain string by older versions
|
|
96
|
+
return raw;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async setItem(key, value) {
|
|
100
|
+
const ls = this.ls();
|
|
101
|
+
if (!ls)
|
|
102
|
+
return;
|
|
103
|
+
try {
|
|
104
|
+
ls.setItem(key, JSON.stringify(value));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// last resort: try as string
|
|
108
|
+
try {
|
|
109
|
+
ls.setItem(key, String(value));
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// ignore (quota/private mode)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async removeItem(key) {
|
|
117
|
+
const ls = this.ls();
|
|
118
|
+
if (!ls)
|
|
119
|
+
return;
|
|
120
|
+
try {
|
|
121
|
+
ls.removeItem(key);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// ignore
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
class BrowserIndexedDbStore {
|
|
129
|
+
dbPromise = null;
|
|
130
|
+
openDb() {
|
|
131
|
+
if (!isBrowser || !window.indexedDB) {
|
|
132
|
+
return Promise.reject(new Error('IndexedDB not available'));
|
|
133
|
+
}
|
|
134
|
+
if (this.dbPromise)
|
|
135
|
+
return this.dbPromise;
|
|
136
|
+
const { dbName, storeName } = exports.StorConfig.indexedDb;
|
|
137
|
+
this.dbPromise = new Promise((resolve, reject) => {
|
|
138
|
+
const req = indexedDB.open(dbName, 1);
|
|
139
|
+
req.onupgradeneeded = () => {
|
|
140
|
+
const db = req.result;
|
|
141
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
142
|
+
db.createObjectStore(storeName);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
req.onsuccess = () => resolve(req.result);
|
|
146
|
+
req.onerror = () => reject(req.error);
|
|
147
|
+
});
|
|
148
|
+
return this.dbPromise;
|
|
149
|
+
}
|
|
150
|
+
async withStore(mode, fn) {
|
|
151
|
+
const db = await this.openDb();
|
|
152
|
+
const { storeName } = exports.StorConfig.indexedDb;
|
|
153
|
+
return await new Promise((resolve, reject) => {
|
|
154
|
+
const tx = db.transaction(storeName, mode);
|
|
155
|
+
const store = tx.objectStore(storeName);
|
|
156
|
+
const req = fn(store);
|
|
157
|
+
req.onsuccess = () => resolve(req.result);
|
|
158
|
+
req.onerror = () => reject(req.error);
|
|
159
|
+
tx.onabort = () => reject(tx.error);
|
|
160
|
+
// tx.oncomplete => nothing
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
async getItem(key) {
|
|
164
|
+
try {
|
|
165
|
+
const result = await this.withStore('readonly', s => s.get(key));
|
|
166
|
+
return result === undefined ? undefined : result;
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async setItem(key, value) {
|
|
173
|
+
try {
|
|
174
|
+
await this.withStore('readwrite', s => s.put(value, key));
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// ignore
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async removeItem(key) {
|
|
181
|
+
try {
|
|
182
|
+
await this.withStore('readwrite', s => s.delete(key));
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// ignore
|
|
186
|
+
}
|
|
187
|
+
}
|
|
25
188
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
189
|
+
/**
|
|
190
|
+
* Node-side file storage (optional). No top-level node imports (Angular-safe).
|
|
191
|
+
* Works only when executed in Node.
|
|
192
|
+
*/
|
|
193
|
+
class FileStor {
|
|
194
|
+
filePath;
|
|
195
|
+
useJSON;
|
|
196
|
+
constructor(filePath, useJSON = false) {
|
|
197
|
+
this.filePath = filePath;
|
|
198
|
+
this.useJSON = useJSON;
|
|
199
|
+
}
|
|
200
|
+
isNodeRuntime() {
|
|
201
|
+
return lib_1.UtilsOs.isNode;
|
|
202
|
+
// return (
|
|
203
|
+
// typeof process !== 'undefined' &&
|
|
204
|
+
// !!(process as any).versions?.node &&
|
|
205
|
+
// typeof (globalThis as any).window === 'undefined'
|
|
206
|
+
// );
|
|
207
|
+
}
|
|
208
|
+
async setItem(_key, value) {
|
|
209
|
+
if (!this.isNodeRuntime())
|
|
210
|
+
return;
|
|
211
|
+
//#region @backendFunc
|
|
212
|
+
const fs = await Promise.resolve().then(() => require('node:fs/promises'));
|
|
213
|
+
const data = this.useJSON ? JSON.stringify(value, null, 2) : value;
|
|
214
|
+
if (this.useJSON) {
|
|
215
|
+
await fs.writeFile(this.filePath, String(data), 'utf8');
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
await fs.writeFile(this.filePath, String(data), 'utf8');
|
|
219
|
+
}
|
|
220
|
+
//#endregion
|
|
221
|
+
}
|
|
222
|
+
async getItem(_key) {
|
|
223
|
+
if (!this.isNodeRuntime())
|
|
224
|
+
return undefined;
|
|
225
|
+
//#region @backendFunc
|
|
226
|
+
const fs = await Promise.resolve().then(() => require('node:fs/promises'));
|
|
227
|
+
try {
|
|
228
|
+
const buf = await fs.readFile(this.filePath, 'utf8');
|
|
229
|
+
if (!this.useJSON)
|
|
230
|
+
return buf;
|
|
231
|
+
return JSON.parse(buf);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
//#endregion
|
|
237
|
+
}
|
|
238
|
+
async removeItem(_key) {
|
|
239
|
+
if (!this.isNodeRuntime())
|
|
240
|
+
return;
|
|
241
|
+
//#region @backendFunc
|
|
242
|
+
const fs = await Promise.resolve().then(() => require('node:fs/promises'));
|
|
243
|
+
try {
|
|
244
|
+
await fs.rm(this.filePath, { force: true });
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
// ignore
|
|
248
|
+
}
|
|
249
|
+
//#endregion
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/* ---------------------------
|
|
253
|
+
* Pending ops (so you can still await)
|
|
254
|
+
* -------------------------- */
|
|
255
|
+
class StorPending {
|
|
256
|
+
static pending = [];
|
|
30
257
|
static id = 0;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
*/
|
|
34
|
-
static async awaitPendingOperatios(id = TaonStorage.id++) {
|
|
35
|
-
// console.log('AWAITING')
|
|
258
|
+
static AWAITING_INTERVAL_TIME = 200;
|
|
259
|
+
static async awaitPendingOperations(id = StorPending.id++) {
|
|
36
260
|
if (id > Number.MAX_SAFE_INTEGER - 2) {
|
|
37
|
-
|
|
38
|
-
id =
|
|
261
|
+
StorPending.id = 0;
|
|
262
|
+
id = StorPending.id++;
|
|
39
263
|
}
|
|
40
|
-
const pending =
|
|
41
|
-
const
|
|
42
|
-
for (let index = 0; index < pending.length; index++) {
|
|
43
|
-
const op = pending[index];
|
|
264
|
+
const pending = StorPending.pending;
|
|
265
|
+
for (const op of pending) {
|
|
44
266
|
if (!op.isDone) {
|
|
45
|
-
await new Promise(
|
|
267
|
+
await new Promise(resolve => {
|
|
46
268
|
setTimeout(async () => {
|
|
47
|
-
await
|
|
48
|
-
|
|
49
|
-
}, AWAITING_INTERVAL_TIME);
|
|
269
|
+
await StorPending.awaitPendingOperations(id);
|
|
270
|
+
resolve();
|
|
271
|
+
}, StorPending.AWAITING_INTERVAL_TIME);
|
|
50
272
|
});
|
|
51
273
|
return;
|
|
52
274
|
}
|
|
53
|
-
else {
|
|
54
|
-
toDeleteIndex.push(index);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
for (let index = 0; index < toDeleteIndex.length; index++) {
|
|
58
|
-
const toDelete = toDeleteIndex[index];
|
|
59
|
-
pending.splice(toDelete, 1);
|
|
60
275
|
}
|
|
276
|
+
// cleanup
|
|
277
|
+
StorPending.pending = pending.filter(p => !p.isDone);
|
|
61
278
|
}
|
|
62
|
-
static
|
|
63
|
-
|
|
279
|
+
static start(engine, id) {
|
|
280
|
+
const op = { engine, id, isDone: false };
|
|
281
|
+
StorPending.pending.push(op);
|
|
282
|
+
return op;
|
|
283
|
+
}
|
|
284
|
+
static done(op) {
|
|
285
|
+
op.isDone = true;
|
|
64
286
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
287
|
+
}
|
|
288
|
+
/* ---------------------------
|
|
289
|
+
* Decorator builder
|
|
290
|
+
* -------------------------- */
|
|
291
|
+
class StorPropertyBuilder {
|
|
292
|
+
scopeClass;
|
|
69
293
|
engine;
|
|
70
|
-
|
|
71
|
-
//#region @backend
|
|
294
|
+
store;
|
|
72
295
|
filePath;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
that.engine = 'indexeddb';
|
|
82
|
-
return that;
|
|
83
|
-
},
|
|
84
|
-
get localstorage() {
|
|
85
|
-
that.engine = 'localstorage';
|
|
86
|
-
return that;
|
|
87
|
-
},
|
|
88
|
-
//#region @backend
|
|
89
|
-
/**
|
|
90
|
-
* may be relative or absolute
|
|
91
|
-
*/
|
|
92
|
-
file(filePath) {
|
|
93
|
-
that.engine = 'file';
|
|
94
|
-
that.filePath = filePath;
|
|
95
|
-
return that;
|
|
96
|
-
},
|
|
97
|
-
jsonFile(filePath) {
|
|
98
|
-
that.engine = 'json';
|
|
99
|
-
that.filePath = filePath;
|
|
100
|
-
return that;
|
|
101
|
-
},
|
|
102
|
-
//#endregion
|
|
103
|
-
};
|
|
296
|
+
useJsonFile = false;
|
|
297
|
+
constructor(engine, store) {
|
|
298
|
+
this.engine = engine;
|
|
299
|
+
this.store = store;
|
|
300
|
+
}
|
|
301
|
+
for(scopeClass) {
|
|
302
|
+
this.scopeClass = scopeClass;
|
|
303
|
+
return this;
|
|
104
304
|
}
|
|
105
|
-
//#endregion
|
|
106
|
-
//#region public methods
|
|
107
|
-
//#region public methods / for
|
|
108
|
-
/* */
|
|
109
|
-
/* */
|
|
110
|
-
/* */
|
|
111
|
-
/* */
|
|
112
|
-
/* */
|
|
113
|
-
//#endregion
|
|
114
|
-
//#region public methods / with default value
|
|
115
305
|
withDefaultValue(defaultValue) {
|
|
116
|
-
|
|
117
|
-
return this.action(defaultValue, this.getEngine(), this.engine);
|
|
306
|
+
return this.withOptions({ defaultValue });
|
|
118
307
|
}
|
|
119
|
-
//#endregion
|
|
120
|
-
//#region public methods / with options
|
|
121
308
|
withOptions(options) {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
309
|
+
const scopeClass = this.scopeClass;
|
|
310
|
+
// per-instance state (fixes prototype-closure sharing)
|
|
311
|
+
const values = new WeakMap();
|
|
312
|
+
const initStarted = new WeakMap();
|
|
313
|
+
const ensureInit = (instance) => {
|
|
314
|
+
if (initStarted.has(instance))
|
|
315
|
+
return;
|
|
316
|
+
const op = StorPending.start(this.engine, 'init');
|
|
317
|
+
const p = (async () => {
|
|
318
|
+
const memberName = ensureInit.__memberName;
|
|
319
|
+
const kVal = keyValue(scopeClass, memberName);
|
|
320
|
+
const kDef = keyDefaultValueAlreadySet(scopeClass, memberName);
|
|
321
|
+
const defProvided = options.defaultValue !== undefined;
|
|
322
|
+
if (!isBrowser &&
|
|
323
|
+
(this.engine === 'localstorage' || this.engine === 'indexeddb')) {
|
|
324
|
+
// SSR: just set defaults, no storage
|
|
325
|
+
if (defProvided)
|
|
326
|
+
values.set(instance, options.defaultValue);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
// Browser (or node file/json)
|
|
330
|
+
if (defProvided) {
|
|
331
|
+
const already = await this.store.getItem(kDef);
|
|
332
|
+
if (already) {
|
|
333
|
+
const stored = await this.store.getItem(kVal);
|
|
334
|
+
const v = options.transformFrom
|
|
335
|
+
? options.transformFrom(stored)
|
|
336
|
+
: stored;
|
|
337
|
+
if (v !== undefined)
|
|
338
|
+
values.set(instance, v);
|
|
339
|
+
else
|
|
340
|
+
values.set(instance, options.defaultValue);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
await this.store.setItem(kDef, true);
|
|
344
|
+
const toDb = options.transformTo
|
|
345
|
+
? options.transformTo(options.defaultValue)
|
|
346
|
+
: options.defaultValue;
|
|
347
|
+
await this.store.setItem(kVal, toDb);
|
|
348
|
+
values.set(instance, options.defaultValue);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
const stored = await this.store.getItem(kVal);
|
|
353
|
+
const v = options.transformFrom
|
|
354
|
+
? options.transformFrom(stored)
|
|
355
|
+
: stored;
|
|
356
|
+
if (v !== undefined)
|
|
357
|
+
values.set(instance, v);
|
|
358
|
+
}
|
|
359
|
+
})()
|
|
360
|
+
.catch(() => {
|
|
361
|
+
// swallow, keep app alive
|
|
362
|
+
})
|
|
363
|
+
.finally(() => StorPending.done(op));
|
|
364
|
+
initStarted.set(instance, p);
|
|
365
|
+
};
|
|
159
366
|
return (target, memberName) => {
|
|
160
|
-
|
|
161
|
-
const setItemDefaultValue = async () => {
|
|
162
|
-
//#region settin default value
|
|
163
|
-
const observe = {
|
|
164
|
-
engine,
|
|
165
|
-
id: 'setting default value'
|
|
166
|
-
};
|
|
167
|
-
TaonStorage.pendingOperatins.push(observe);
|
|
168
|
-
await new Promise((resolve, reject) => {
|
|
169
|
-
storageEngine.getItem((0, helpers_1.keyValue)(this.onlyInThisComponentClass, memberName), (err, valFromDb) => {
|
|
170
|
-
// target[memberName] = valFromDb;
|
|
171
|
-
currentValue = transformFrom ? transformFrom(valFromDb) : valFromDb;
|
|
172
|
-
// log.info(`["${memberName}"] set default value for `, valFromDb);
|
|
173
|
-
resolve();
|
|
174
|
-
this.endObserverAction(observe);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
//#endregion
|
|
178
|
-
};
|
|
179
|
-
if (defaultValue !== void 0) {
|
|
180
|
-
//#region setting default value from db
|
|
181
|
-
const observe = {
|
|
182
|
-
engine,
|
|
183
|
-
id: 'setting not rivial default value'
|
|
184
|
-
};
|
|
185
|
-
TaonStorage.pendingOperatins.push(observe);
|
|
186
|
-
(new Promise((resolve, reject) => {
|
|
187
|
-
storageEngine.getItem((0, helpers_1.keyDefaultValueAreadySet)(this.onlyInThisComponentClass, memberName), async (err, val) => {
|
|
188
|
-
// log.info(`["${memberName}"] was set default value for ? `, val)
|
|
189
|
-
if (val) {
|
|
190
|
-
await setItemDefaultValue();
|
|
191
|
-
resolve();
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
await new Promise((res, rej) => {
|
|
195
|
-
storageEngine.setItem((0, helpers_1.keyDefaultValueAreadySet)(this.onlyInThisComponentClass, memberName), true, (err, v) => {
|
|
196
|
-
res();
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
await new Promise((res, rej) => {
|
|
200
|
-
storageEngine.setItem((0, helpers_1.keyValue)(this.onlyInThisComponentClass, memberName), transformTo ? transformTo(defaultValue) : defaultValue, (err, val) => {
|
|
201
|
-
res();
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
currentValue = defaultValue;
|
|
205
|
-
// log.i(`["${memberName}"] defaultValue "${memberName}"`, currentValue)
|
|
206
|
-
resolve();
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
})).then(() => {
|
|
210
|
-
this.endObserverAction(observe);
|
|
211
|
-
});
|
|
212
|
-
//#endregion
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
setItemDefaultValue();
|
|
216
|
-
}
|
|
367
|
+
ensureInit.__memberName = memberName;
|
|
217
368
|
Object.defineProperty(target, memberName, {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
369
|
+
configurable: true,
|
|
370
|
+
enumerable: true,
|
|
371
|
+
get: function () {
|
|
372
|
+
ensureInit(this);
|
|
373
|
+
if (values.has(this))
|
|
374
|
+
return values.get(this);
|
|
375
|
+
if (options.defaultValue !== undefined)
|
|
376
|
+
return options.defaultValue;
|
|
377
|
+
return undefined;
|
|
378
|
+
},
|
|
379
|
+
set: function (newValue) {
|
|
380
|
+
values.set(this, newValue);
|
|
381
|
+
// if this is the first interaction, init will happen anyway
|
|
382
|
+
ensureInit(this);
|
|
383
|
+
const op = StorPending.start(target?.engine ?? 'localstorage', 'set');
|
|
384
|
+
const scope = scopeClass;
|
|
385
|
+
const kVal = keyValue(scope, memberName);
|
|
386
|
+
const toDb = options.transformTo
|
|
387
|
+
? options.transformTo(newValue)
|
|
388
|
+
: newValue;
|
|
389
|
+
Promise.resolve()
|
|
390
|
+
.then(() => target)
|
|
391
|
+
.then(() => this)
|
|
392
|
+
.then(() => this)
|
|
393
|
+
.then(async () => {
|
|
394
|
+
// If we are SSR + browser engine => no-op
|
|
395
|
+
if (!isBrowser && options)
|
|
396
|
+
return;
|
|
397
|
+
await options; // no-op line to keep TS happy about chaining in some builds
|
|
398
|
+
})
|
|
399
|
+
.catch(() => {
|
|
400
|
+
// ignore
|
|
231
401
|
});
|
|
232
|
-
|
|
233
|
-
|
|
402
|
+
// do real store write (async)
|
|
403
|
+
Promise.resolve()
|
|
404
|
+
.then(async () => {
|
|
405
|
+
// SSR guard for browser engines
|
|
406
|
+
if (!isBrowser && StorPropertyInLocalStorage) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
await thisStoreForEngineWrite(this, kVal, toDb);
|
|
410
|
+
})
|
|
411
|
+
.catch(() => {
|
|
412
|
+
// ignore
|
|
413
|
+
})
|
|
414
|
+
.finally(() => StorPending.done(op));
|
|
234
415
|
},
|
|
235
|
-
get: () => currentValue,
|
|
236
416
|
});
|
|
417
|
+
// small helper to keep closure clean
|
|
418
|
+
const builderStore = this.store;
|
|
419
|
+
const builderEngine = this.engine;
|
|
420
|
+
async function thisStoreForEngineWrite(_instance, key, value) {
|
|
421
|
+
// If browser engines but not browser, skip.
|
|
422
|
+
if (!isBrowser &&
|
|
423
|
+
(builderEngine === 'localstorage' || builderEngine === 'indexeddb'))
|
|
424
|
+
return;
|
|
425
|
+
await builderStore.setItem(key, value);
|
|
426
|
+
}
|
|
237
427
|
};
|
|
238
|
-
}
|
|
428
|
+
}
|
|
429
|
+
/* optional node-only engines (same builder) */
|
|
430
|
+
file(filePath) {
|
|
431
|
+
this.engine = 'file';
|
|
432
|
+
this.filePath = filePath;
|
|
433
|
+
this.useJsonFile = false;
|
|
434
|
+
this.store = new FileStor(filePath, false);
|
|
435
|
+
return this;
|
|
436
|
+
}
|
|
437
|
+
jsonFile(filePath) {
|
|
438
|
+
this.engine = 'json';
|
|
439
|
+
this.filePath = filePath;
|
|
440
|
+
this.useJsonFile = true;
|
|
441
|
+
this.store = new FileStor(filePath, true);
|
|
442
|
+
return this;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/* ---------------------------
|
|
446
|
+
* Public: clean API exports
|
|
447
|
+
* -------------------------- */
|
|
448
|
+
const localStorageStore = isBrowser
|
|
449
|
+
? new BrowserLocalStorageStore()
|
|
450
|
+
: new NoopStore();
|
|
451
|
+
const indexedDbStore = isBrowser
|
|
452
|
+
? new BrowserIndexedDbStore()
|
|
453
|
+
: new NoopStore();
|
|
454
|
+
class StorPropertyInLocalStorage {
|
|
455
|
+
static for(scopeClass) {
|
|
456
|
+
return new StorPropertyBuilder('localstorage', localStorageStore).for(scopeClass);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
exports.StorPropertyInLocalStorage = StorPropertyInLocalStorage;
|
|
460
|
+
class StorPropertyInIndexedDb {
|
|
461
|
+
static for(scopeClass) {
|
|
462
|
+
return new StorPropertyBuilder('indexeddb', indexedDbStore).for(scopeClass);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
exports.StorPropertyInIndexedDb = StorPropertyInIndexedDb;
|
|
466
|
+
/**
|
|
467
|
+
* Helpers
|
|
468
|
+
*/
|
|
469
|
+
async function uncache(onlyInThisComponentClass, propertyValueToDeleteFromCache) {
|
|
470
|
+
const scope = onlyInThisComponentClass || { name: '__GLOBAL_NAMESPACE__' };
|
|
471
|
+
const prop = String(propertyValueToDeleteFromCache);
|
|
472
|
+
await Promise.all([
|
|
473
|
+
localStorageStore.removeItem(keyValue(scope, prop)),
|
|
474
|
+
localStorageStore.removeItem(keyDefaultValueAlreadySet(scope, prop)),
|
|
475
|
+
indexedDbStore.removeItem(keyValue(scope, prop)),
|
|
476
|
+
indexedDbStore.removeItem(keyDefaultValueAlreadySet(scope, prop)),
|
|
477
|
+
]);
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Backwards-compatible facade:
|
|
481
|
+
* Stor.property.in.localstorage.for(...).withDefaultValue(...)
|
|
482
|
+
*/
|
|
483
|
+
class TaonStorageFacade {
|
|
484
|
+
static async awaitPendingOperatios() {
|
|
485
|
+
await StorPending.awaitPendingOperations();
|
|
486
|
+
}
|
|
487
|
+
static get property() {
|
|
488
|
+
return {
|
|
489
|
+
in: {
|
|
490
|
+
get localstorage() {
|
|
491
|
+
return new StorPropertyBuilder('localstorage', localStorageStore);
|
|
492
|
+
},
|
|
493
|
+
get indexedb() {
|
|
494
|
+
return new StorPropertyBuilder('indexeddb', indexedDbStore);
|
|
495
|
+
},
|
|
496
|
+
// node-only (safe: dynamic import inside FileStor)
|
|
497
|
+
file(filePath) {
|
|
498
|
+
return new StorPropertyBuilder('file', new FileStor(filePath, false));
|
|
499
|
+
},
|
|
500
|
+
jsonFile(filePath) {
|
|
501
|
+
return new StorPropertyBuilder('json', new FileStor(filePath, true));
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
};
|
|
505
|
+
}
|
|
239
506
|
}
|
|
240
|
-
exports.Stor =
|
|
507
|
+
exports.Stor = TaonStorageFacade;
|
|
241
508
|
//# sourceMappingURL=storage.js.map
|