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