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