taon-storage 21.0.10 → 21.0.12

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