protoobject 1.1.29 → 2.0.0
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/README.md +142 -2
- package/lib/cjs/browser.js +28 -0
- package/lib/cjs/browser.js.map +1 -0
- package/lib/cjs/classes/proto-object-crypto.js +133 -0
- package/lib/cjs/classes/proto-object-crypto.js.map +1 -0
- package/lib/cjs/classes/proto-object-fs.js +395 -0
- package/lib/cjs/classes/proto-object-fs.js.map +1 -0
- package/lib/cjs/classes/proto-object-sqlite.js +331 -0
- package/lib/cjs/classes/proto-object-sqlite.js.map +1 -0
- package/lib/cjs/classes/proto-object-stream.js +148 -0
- package/lib/cjs/classes/proto-object-stream.js.map +1 -0
- package/lib/cjs/classes/proto-object-tcp.js +322 -0
- package/lib/cjs/classes/proto-object-tcp.js.map +1 -0
- package/lib/cjs/classes/proto-object.js.map +1 -0
- package/lib/cjs/decorators/static-implements.js.map +1 -0
- package/lib/cjs/index.js +41 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/cjs/package.json +1 -0
- package/lib/{types → cjs/types}/any-object.js.map +1 -1
- package/lib/cjs/types/collection-transformer.js.map +1 -0
- package/lib/cjs/types/dynamic-methods.js.map +1 -0
- package/lib/cjs/types/record-transformer.js.map +1 -0
- package/lib/cjs/types/static-methods.js.map +1 -0
- package/lib/cjs/types/unknown-object.js.map +1 -0
- package/lib/cjs/types/validator-function.js.map +1 -0
- package/lib/cjs/utils/protoobject-browser-storage.js +672 -0
- package/lib/cjs/utils/protoobject-browser-storage.js.map +1 -0
- package/lib/cjs/utils/protoobject-factory.js.map +1 -0
- package/lib/cjs/utils/protoobject-localstorage.js +188 -0
- package/lib/cjs/utils/protoobject-localstorage.js.map +1 -0
- package/lib/esm/browser.js +20 -0
- package/lib/esm/browser.js.map +1 -0
- package/lib/esm/classes/proto-object-crypto.js +129 -0
- package/lib/esm/classes/proto-object-crypto.js.map +1 -0
- package/lib/esm/classes/proto-object-fs.js +391 -0
- package/lib/esm/classes/proto-object-fs.js.map +1 -0
- package/lib/esm/classes/proto-object-sqlite.js +328 -0
- package/lib/esm/classes/proto-object-sqlite.js.map +1 -0
- package/lib/esm/classes/proto-object-stream.js +144 -0
- package/lib/esm/classes/proto-object-stream.js.map +1 -0
- package/lib/esm/classes/proto-object-tcp.js +317 -0
- package/lib/esm/classes/proto-object-tcp.js.map +1 -0
- package/lib/esm/classes/proto-object.js +264 -0
- package/lib/esm/classes/proto-object.js.map +1 -0
- package/lib/esm/decorators/static-implements.js +12 -0
- package/lib/esm/decorators/static-implements.js.map +1 -0
- package/lib/esm/index.js +22 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/package.json +1 -0
- package/lib/esm/types/any-object.js +2 -0
- package/lib/esm/types/any-object.js.map +1 -0
- package/lib/esm/types/collection-transformer.js +3 -0
- package/lib/esm/types/collection-transformer.js.map +1 -0
- package/lib/esm/types/dynamic-methods.js +3 -0
- package/lib/esm/types/dynamic-methods.js.map +1 -0
- package/lib/esm/types/record-transformer.js +3 -0
- package/lib/esm/types/record-transformer.js.map +1 -0
- package/lib/esm/types/static-methods.js +4 -0
- package/lib/esm/types/static-methods.js.map +1 -0
- package/lib/esm/types/unknown-object.js +2 -0
- package/lib/esm/types/unknown-object.js.map +1 -0
- package/lib/esm/types/validator-function.js +3 -0
- package/lib/esm/types/validator-function.js.map +1 -0
- package/lib/esm/utils/protoobject-browser-storage.js +668 -0
- package/lib/esm/utils/protoobject-browser-storage.js.map +1 -0
- package/lib/esm/utils/protoobject-factory.js +32 -0
- package/lib/esm/utils/protoobject-factory.js.map +1 -0
- package/lib/esm/utils/protoobject-localstorage.js +184 -0
- package/lib/esm/utils/protoobject-localstorage.js.map +1 -0
- package/lib/types/browser.d.ts +18 -0
- package/lib/types/browser.d.ts.map +1 -0
- package/lib/types/classes/proto-object-crypto.d.ts +99 -0
- package/lib/types/classes/proto-object-crypto.d.ts.map +1 -0
- package/lib/types/classes/proto-object-fs.d.ts +107 -0
- package/lib/types/classes/proto-object-fs.d.ts.map +1 -0
- package/lib/types/classes/proto-object-sqlite.d.ts +98 -0
- package/lib/types/classes/proto-object-sqlite.d.ts.map +1 -0
- package/lib/types/classes/proto-object-stream.d.ts +38 -0
- package/lib/types/classes/proto-object-stream.d.ts.map +1 -0
- package/lib/types/classes/proto-object-tcp.d.ts +86 -0
- package/lib/types/classes/proto-object-tcp.d.ts.map +1 -0
- package/lib/{classes → types/classes}/proto-object.d.ts +1 -0
- package/lib/types/classes/proto-object.d.ts.map +1 -0
- package/lib/{decorators → types/decorators}/static-implements.d.ts +1 -0
- package/lib/types/decorators/static-implements.d.ts.map +1 -0
- package/lib/types/index.d.ts +24 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/{any-object.d.ts → types/any-object.d.ts} +1 -0
- package/lib/types/types/any-object.d.ts.map +1 -0
- package/lib/types/{collection-transformer.d.ts → types/collection-transformer.d.ts} +1 -0
- package/lib/types/types/collection-transformer.d.ts.map +1 -0
- package/lib/types/{dynamic-methods.d.ts → types/dynamic-methods.d.ts} +1 -0
- package/lib/types/types/dynamic-methods.d.ts.map +1 -0
- package/lib/types/{record-transformer.d.ts → types/record-transformer.d.ts} +1 -0
- package/lib/types/types/record-transformer.d.ts.map +1 -0
- package/lib/types/{static-methods.d.ts → types/static-methods.d.ts} +1 -0
- package/lib/types/types/static-methods.d.ts.map +1 -0
- package/lib/types/{unknown-object.d.ts → types/unknown-object.d.ts} +1 -0
- package/lib/types/types/unknown-object.d.ts.map +1 -0
- package/lib/types/{validator-function.d.ts → types/validator-function.d.ts} +1 -0
- package/lib/types/types/validator-function.d.ts.map +1 -0
- package/lib/types/utils/protoobject-browser-storage.d.ts +118 -0
- package/lib/types/utils/protoobject-browser-storage.d.ts.map +1 -0
- package/lib/{utils → types/utils}/protoobject-factory.d.ts +1 -0
- package/lib/types/utils/protoobject-factory.d.ts.map +1 -0
- package/lib/types/utils/protoobject-localstorage.d.ts +69 -0
- package/lib/types/utils/protoobject-localstorage.d.ts.map +1 -0
- package/package.json +57 -6
- package/CHANGELOG.md +0 -186
- package/FUNDING.yml +0 -2
- package/ignoreUpdatesModules.json +0 -4
- package/lib/classes/proto-object.js.map +0 -1
- package/lib/decorators/static-implements.js.map +0 -1
- package/lib/index.d.ts +0 -14
- package/lib/index.js +0 -18
- package/lib/index.js.map +0 -1
- package/lib/types/collection-transformer.js.map +0 -1
- package/lib/types/dynamic-methods.js.map +0 -1
- package/lib/types/record-transformer.js.map +0 -1
- package/lib/types/static-methods.js.map +0 -1
- package/lib/types/unknown-object.js.map +0 -1
- package/lib/types/validator-function.js.map +0 -1
- package/lib/utils/protoobject-factory.js.map +0 -1
- /package/lib/{classes → cjs/classes}/proto-object.js +0 -0
- /package/lib/{decorators → cjs/decorators}/static-implements.js +0 -0
- /package/lib/{types → cjs/types}/any-object.js +0 -0
- /package/lib/{types → cjs/types}/collection-transformer.js +0 -0
- /package/lib/{types → cjs/types}/dynamic-methods.js +0 -0
- /package/lib/{types → cjs/types}/record-transformer.js +0 -0
- /package/lib/{types → cjs/types}/static-methods.js +0 -0
- /package/lib/{types → cjs/types}/unknown-object.js +0 -0
- /package/lib/{types → cjs/types}/validator-function.js +0 -0
- /package/lib/{utils → cjs/utils}/protoobject-factory.js +0 -0
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal ProtoObject browser storage utility
|
|
3
|
+
* Supports localStorage, sessionStorage, IndexedDB, cookies, BroadcastChannel, and Web Workers
|
|
4
|
+
*/
|
|
5
|
+
export class ProtoObjectBrowserStorage {
|
|
6
|
+
/**
|
|
7
|
+
* Save ProtoObject instance to browser storage
|
|
8
|
+
*/
|
|
9
|
+
static async save(key, obj, options = { type: "local" }) {
|
|
10
|
+
try {
|
|
11
|
+
const json = obj.toJSON();
|
|
12
|
+
const serialized = JSON.stringify(json);
|
|
13
|
+
switch (options.type) {
|
|
14
|
+
case "local":
|
|
15
|
+
return this.saveToWebStorage(key, serialized, "localStorage");
|
|
16
|
+
case "session":
|
|
17
|
+
return this.saveToWebStorage(key, serialized, "sessionStorage");
|
|
18
|
+
case "indexeddb":
|
|
19
|
+
return await this.saveToIndexedDB(key, json, options);
|
|
20
|
+
case "cookies":
|
|
21
|
+
return this.saveToCookies(key, serialized, options);
|
|
22
|
+
case "broadcast":
|
|
23
|
+
return this.saveToBroadcast(key, json, options);
|
|
24
|
+
case "worker":
|
|
25
|
+
return await this.saveToWorker(key, json, options);
|
|
26
|
+
default:
|
|
27
|
+
console.error(`Unsupported storage type: ${options.type}`);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error("ProtoObjectBrowserStorage.save error:", error);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Load ProtoObject instance from browser storage
|
|
38
|
+
*/
|
|
39
|
+
static async load(key, ClassConstructor, options = { type: "local" }) {
|
|
40
|
+
try {
|
|
41
|
+
let data;
|
|
42
|
+
switch (options.type) {
|
|
43
|
+
case "local":
|
|
44
|
+
data = this.loadFromWebStorage(key, "localStorage");
|
|
45
|
+
break;
|
|
46
|
+
case "session":
|
|
47
|
+
data = this.loadFromWebStorage(key, "sessionStorage");
|
|
48
|
+
break;
|
|
49
|
+
case "indexeddb":
|
|
50
|
+
data = await this.loadFromIndexedDB(key, options);
|
|
51
|
+
break;
|
|
52
|
+
case "cookies":
|
|
53
|
+
data = this.loadFromCookies(key);
|
|
54
|
+
break;
|
|
55
|
+
case "broadcast":
|
|
56
|
+
data = this.loadFromBroadcast(key, options);
|
|
57
|
+
break;
|
|
58
|
+
case "worker":
|
|
59
|
+
data = await this.loadFromWorker(key, options);
|
|
60
|
+
break;
|
|
61
|
+
default:
|
|
62
|
+
console.error(`Unsupported storage type: ${options.type}`);
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return data ? ClassConstructor.fromJSON(data) : undefined;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.error("ProtoObjectBrowserStorage.load error:", error);
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Remove item from browser storage
|
|
74
|
+
*/
|
|
75
|
+
static async remove(key, options = { type: "local" }) {
|
|
76
|
+
try {
|
|
77
|
+
switch (options.type) {
|
|
78
|
+
case "local":
|
|
79
|
+
return this.removeFromWebStorage(key, "localStorage");
|
|
80
|
+
case "session":
|
|
81
|
+
return this.removeFromWebStorage(key, "sessionStorage");
|
|
82
|
+
case "indexeddb":
|
|
83
|
+
return await this.removeFromIndexedDB(key, options);
|
|
84
|
+
case "cookies":
|
|
85
|
+
return this.removeFromCookies(key, options);
|
|
86
|
+
case "broadcast":
|
|
87
|
+
return this.removeFromBroadcast(key, options);
|
|
88
|
+
case "worker":
|
|
89
|
+
return await this.removeFromWorker(key, options);
|
|
90
|
+
default:
|
|
91
|
+
console.error(`Unsupported storage type: ${options.type}`);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
console.error("ProtoObjectBrowserStorage.remove error:", error);
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Check if key exists in browser storage
|
|
102
|
+
*/
|
|
103
|
+
static async exists(key, options = { type: "local" }) {
|
|
104
|
+
try {
|
|
105
|
+
switch (options.type) {
|
|
106
|
+
case "local":
|
|
107
|
+
return this.existsInWebStorage(key, "localStorage");
|
|
108
|
+
case "session":
|
|
109
|
+
return this.existsInWebStorage(key, "sessionStorage");
|
|
110
|
+
case "indexeddb":
|
|
111
|
+
return await this.existsInIndexedDB(key, options);
|
|
112
|
+
case "cookies":
|
|
113
|
+
return this.existsInCookies(key);
|
|
114
|
+
case "broadcast":
|
|
115
|
+
return this.existsInBroadcast(key, options);
|
|
116
|
+
case "worker":
|
|
117
|
+
return await this.existsInWorker(key, options);
|
|
118
|
+
default:
|
|
119
|
+
console.error(`Unsupported storage type: ${options.type}`);
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
console.error("ProtoObjectBrowserStorage.exists error:", error);
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get all keys with optional prefix filter
|
|
130
|
+
*/
|
|
131
|
+
static async getKeys(prefix, options = { type: "local" }) {
|
|
132
|
+
try {
|
|
133
|
+
switch (options.type) {
|
|
134
|
+
case "local":
|
|
135
|
+
return this.getKeysFromWebStorage(prefix, "localStorage");
|
|
136
|
+
case "session":
|
|
137
|
+
return this.getKeysFromWebStorage(prefix, "sessionStorage");
|
|
138
|
+
case "indexeddb":
|
|
139
|
+
return await this.getKeysFromIndexedDB(prefix, options);
|
|
140
|
+
case "cookies":
|
|
141
|
+
return this.getKeysFromCookies(prefix);
|
|
142
|
+
case "broadcast":
|
|
143
|
+
return this.getKeysFromBroadcast(prefix, options);
|
|
144
|
+
case "worker":
|
|
145
|
+
return await this.getKeysFromWorker(prefix, options);
|
|
146
|
+
default:
|
|
147
|
+
console.error(`Unsupported storage type: ${options.type}`);
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
console.error("ProtoObjectBrowserStorage.getKeys error:", error);
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Clear storage with optional prefix filter
|
|
158
|
+
*/
|
|
159
|
+
static async clear(prefix, options = { type: "local" }) {
|
|
160
|
+
try {
|
|
161
|
+
const keys = await this.getKeys(prefix, options);
|
|
162
|
+
let removed = 0;
|
|
163
|
+
for (const key of keys) {
|
|
164
|
+
if (await this.remove(key, options)) {
|
|
165
|
+
removed += 1;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return removed;
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
console.error("ProtoObjectBrowserStorage.clear error:", error);
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Private methods for Web Storage (localStorage/sessionStorage)
|
|
176
|
+
static saveToWebStorage(key, serialized, storageType) {
|
|
177
|
+
if (typeof window === "undefined" || !window[storageType]) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
window[storageType].setItem(key, serialized);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
static loadFromWebStorage(key, storageType) {
|
|
184
|
+
if (typeof window === "undefined" || !window[storageType]) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
const serialized = window[storageType].getItem(key);
|
|
188
|
+
return serialized ? JSON.parse(serialized) : undefined;
|
|
189
|
+
}
|
|
190
|
+
static removeFromWebStorage(key, storageType) {
|
|
191
|
+
if (typeof window === "undefined" || !window[storageType]) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
window[storageType].removeItem(key);
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
static existsInWebStorage(key, storageType) {
|
|
198
|
+
if (typeof window === "undefined" || !window[storageType]) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
return window[storageType].getItem(key) !== null;
|
|
202
|
+
}
|
|
203
|
+
static getKeysFromWebStorage(prefix, storageType) {
|
|
204
|
+
if (typeof window === "undefined" || !window[storageType]) {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
const keys = [];
|
|
208
|
+
const storage = window[storageType];
|
|
209
|
+
for (let i = 0; i < storage.length; i++) {
|
|
210
|
+
const key = storage.key(i);
|
|
211
|
+
if (key && (!prefix || key.startsWith(prefix))) {
|
|
212
|
+
keys.push(key);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return keys;
|
|
216
|
+
}
|
|
217
|
+
// Private methods for IndexedDB
|
|
218
|
+
static async getIndexedDB(options) {
|
|
219
|
+
if (typeof window === "undefined" || !window.indexedDB) {
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
const dbName = options.dbName || "ProtoObjectDB";
|
|
223
|
+
if (this.idbDatabases.has(dbName)) {
|
|
224
|
+
return this.idbDatabases.get(dbName);
|
|
225
|
+
}
|
|
226
|
+
return new Promise((resolve, reject) => {
|
|
227
|
+
const request = indexedDB.open(dbName, 1);
|
|
228
|
+
request.onerror = () => reject(request.error);
|
|
229
|
+
request.onsuccess = () => {
|
|
230
|
+
const db = request.result;
|
|
231
|
+
this.idbDatabases.set(dbName, db);
|
|
232
|
+
resolve(db);
|
|
233
|
+
};
|
|
234
|
+
request.onupgradeneeded = () => {
|
|
235
|
+
const db = request.result;
|
|
236
|
+
const storeName = options.storeName || "objects";
|
|
237
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
238
|
+
db.createObjectStore(storeName);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
static async saveToIndexedDB(key, data, options) {
|
|
244
|
+
const db = await this.getIndexedDB(options);
|
|
245
|
+
if (!db)
|
|
246
|
+
return false;
|
|
247
|
+
return new Promise((resolve) => {
|
|
248
|
+
const transaction = db.transaction([options.storeName || "objects"], "readwrite");
|
|
249
|
+
const store = transaction.objectStore(options.storeName || "objects");
|
|
250
|
+
const request = store.put(data, key);
|
|
251
|
+
request.onsuccess = () => resolve(true);
|
|
252
|
+
request.onerror = () => resolve(false);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
static async loadFromIndexedDB(key, options) {
|
|
256
|
+
const db = await this.getIndexedDB(options);
|
|
257
|
+
if (!db)
|
|
258
|
+
return undefined;
|
|
259
|
+
return new Promise((resolve) => {
|
|
260
|
+
const transaction = db.transaction([options.storeName || "objects"], "readonly");
|
|
261
|
+
const store = transaction.objectStore(options.storeName || "objects");
|
|
262
|
+
const request = store.get(key);
|
|
263
|
+
request.onsuccess = () => resolve(request.result || undefined);
|
|
264
|
+
request.onerror = () => resolve(undefined);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
static async removeFromIndexedDB(key, options) {
|
|
268
|
+
const db = await this.getIndexedDB(options);
|
|
269
|
+
if (!db)
|
|
270
|
+
return false;
|
|
271
|
+
return new Promise((resolve) => {
|
|
272
|
+
const transaction = db.transaction([options.storeName || "objects"], "readwrite");
|
|
273
|
+
const store = transaction.objectStore(options.storeName || "objects");
|
|
274
|
+
const request = store.delete(key);
|
|
275
|
+
request.onsuccess = () => resolve(true);
|
|
276
|
+
request.onerror = () => resolve(false);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
static async existsInIndexedDB(key, options) {
|
|
280
|
+
const data = await this.loadFromIndexedDB(key, options);
|
|
281
|
+
return data !== undefined;
|
|
282
|
+
}
|
|
283
|
+
static async getKeysFromIndexedDB(prefix, options) {
|
|
284
|
+
const db = await this.getIndexedDB(options);
|
|
285
|
+
if (!db)
|
|
286
|
+
return [];
|
|
287
|
+
return new Promise((resolve) => {
|
|
288
|
+
const transaction = db.transaction([options.storeName || "objects"], "readonly");
|
|
289
|
+
const store = transaction.objectStore(options.storeName || "objects");
|
|
290
|
+
const request = store.getAllKeys();
|
|
291
|
+
request.onsuccess = () => {
|
|
292
|
+
const keys = request.result
|
|
293
|
+
.map((key) => String(key))
|
|
294
|
+
.filter((key) => !prefix || key.startsWith(prefix));
|
|
295
|
+
resolve(keys);
|
|
296
|
+
};
|
|
297
|
+
request.onerror = () => resolve([]);
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
// Private methods for Cookies
|
|
301
|
+
static saveToCookies(key, serialized, options) {
|
|
302
|
+
if (typeof document === "undefined") {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
const maxAge = options.maxAge || 31536000; // 1 year default
|
|
307
|
+
const domain = options.domain ? `; domain=${options.domain}` : "";
|
|
308
|
+
const path = `; path=${options.path || "/"}`;
|
|
309
|
+
document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(serialized)}; max-age=${maxAge}${domain}${path}`;
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
static loadFromCookies(key) {
|
|
317
|
+
if (typeof document === "undefined") {
|
|
318
|
+
return undefined;
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
const encodedKey = encodeURIComponent(key);
|
|
322
|
+
const cookies = document.cookie.split(";");
|
|
323
|
+
for (const cookie of cookies) {
|
|
324
|
+
const [cookieKey, cookieValue] = cookie.trim().split("=");
|
|
325
|
+
if (cookieKey === encodedKey && cookieValue) {
|
|
326
|
+
const decoded = decodeURIComponent(cookieValue);
|
|
327
|
+
return JSON.parse(decoded);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return undefined;
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
return undefined;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
static removeFromCookies(key, options) {
|
|
337
|
+
if (typeof document === "undefined") {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
const domain = options.domain ? `; domain=${options.domain}` : "";
|
|
342
|
+
const path = `; path=${options.path || "/"}`;
|
|
343
|
+
document.cookie = `${encodeURIComponent(key)}=; expires=Thu, 01 Jan 1970 00:00:00 GMT${domain}${path}`;
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
static existsInCookies(key) {
|
|
351
|
+
return this.loadFromCookies(key) !== undefined;
|
|
352
|
+
}
|
|
353
|
+
static getKeysFromCookies(prefix) {
|
|
354
|
+
if (typeof document === "undefined") {
|
|
355
|
+
return [];
|
|
356
|
+
}
|
|
357
|
+
try {
|
|
358
|
+
const keys = [];
|
|
359
|
+
const cookies = document.cookie.split(";");
|
|
360
|
+
for (const cookie of cookies) {
|
|
361
|
+
const [cookieKey] = cookie.trim().split("=");
|
|
362
|
+
if (cookieKey) {
|
|
363
|
+
const decoded = decodeURIComponent(cookieKey);
|
|
364
|
+
if (!prefix || decoded.startsWith(prefix)) {
|
|
365
|
+
keys.push(decoded);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return keys;
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
return [];
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
// Private methods for BroadcastChannel
|
|
376
|
+
static getBroadcastChannel(options) {
|
|
377
|
+
if (typeof window === "undefined" || !window.BroadcastChannel) {
|
|
378
|
+
return undefined;
|
|
379
|
+
}
|
|
380
|
+
const channelName = options.channelName || "protoobject-channel";
|
|
381
|
+
if (!this.channels.has(channelName)) {
|
|
382
|
+
this.channels.set(channelName, new BroadcastChannel(channelName));
|
|
383
|
+
}
|
|
384
|
+
return this.channels.get(channelName);
|
|
385
|
+
}
|
|
386
|
+
static saveToBroadcast(key, data, options) {
|
|
387
|
+
const channel = this.getBroadcastChannel(options);
|
|
388
|
+
if (!channel)
|
|
389
|
+
return false;
|
|
390
|
+
try {
|
|
391
|
+
channel.postMessage({ type: "save", key, data });
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
catch {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
static loadFromBroadcast(key, options) {
|
|
399
|
+
const channel = this.getBroadcastChannel(options);
|
|
400
|
+
if (!channel)
|
|
401
|
+
return undefined;
|
|
402
|
+
// BroadcastChannel is async by nature, this is a synchronous fallback
|
|
403
|
+
// In real usage, you'd typically listen for messages
|
|
404
|
+
try {
|
|
405
|
+
channel.postMessage({ type: "load", key });
|
|
406
|
+
return undefined; // Would need async implementation for real usage
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
static removeFromBroadcast(key, options) {
|
|
413
|
+
const channel = this.getBroadcastChannel(options);
|
|
414
|
+
if (!channel)
|
|
415
|
+
return false;
|
|
416
|
+
try {
|
|
417
|
+
channel.postMessage({ type: "remove", key });
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
catch {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
static existsInBroadcast(key, options) {
|
|
425
|
+
const channel = this.getBroadcastChannel(options);
|
|
426
|
+
if (!channel)
|
|
427
|
+
return false;
|
|
428
|
+
try {
|
|
429
|
+
channel.postMessage({ type: "exists", key });
|
|
430
|
+
return false; // Would need async implementation for real usage
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
static getKeysFromBroadcast(prefix, options) {
|
|
437
|
+
const channel = this.getBroadcastChannel(options);
|
|
438
|
+
if (!channel)
|
|
439
|
+
return [];
|
|
440
|
+
try {
|
|
441
|
+
channel.postMessage({ type: "getKeys", prefix });
|
|
442
|
+
return []; // Would need async implementation for real usage
|
|
443
|
+
}
|
|
444
|
+
catch {
|
|
445
|
+
return [];
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
// Private methods for Web Worker
|
|
449
|
+
static getWorker(options) {
|
|
450
|
+
if (typeof window === "undefined" ||
|
|
451
|
+
!window.Worker ||
|
|
452
|
+
!options.workerScript) {
|
|
453
|
+
return undefined;
|
|
454
|
+
}
|
|
455
|
+
if (!this.workers.has(options.workerScript)) {
|
|
456
|
+
try {
|
|
457
|
+
const worker = new Worker(options.workerScript);
|
|
458
|
+
this.workers.set(options.workerScript, worker);
|
|
459
|
+
}
|
|
460
|
+
catch {
|
|
461
|
+
return undefined;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return this.workers.get(options.workerScript);
|
|
465
|
+
}
|
|
466
|
+
static async saveToWorker(key, data, options) {
|
|
467
|
+
const worker = this.getWorker(options);
|
|
468
|
+
if (!worker)
|
|
469
|
+
return false;
|
|
470
|
+
return new Promise((resolve) => {
|
|
471
|
+
const messageId = Date.now().toString();
|
|
472
|
+
const handleMessage = (event) => {
|
|
473
|
+
if (event.data.id === messageId) {
|
|
474
|
+
worker.removeEventListener("message", handleMessage);
|
|
475
|
+
resolve(event.data.success || false);
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
worker.addEventListener("message", handleMessage);
|
|
479
|
+
worker.postMessage({ id: messageId, type: "save", key, data });
|
|
480
|
+
// Timeout after 5 seconds
|
|
481
|
+
setTimeout(() => {
|
|
482
|
+
worker.removeEventListener("message", handleMessage);
|
|
483
|
+
resolve(false);
|
|
484
|
+
}, 5000);
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
static async loadFromWorker(key, options) {
|
|
488
|
+
const worker = this.getWorker(options);
|
|
489
|
+
if (!worker)
|
|
490
|
+
return undefined;
|
|
491
|
+
return new Promise((resolve) => {
|
|
492
|
+
const messageId = Date.now().toString();
|
|
493
|
+
const handleMessage = (event) => {
|
|
494
|
+
if (event.data.id === messageId) {
|
|
495
|
+
worker.removeEventListener("message", handleMessage);
|
|
496
|
+
resolve(event.data.data || undefined);
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
worker.addEventListener("message", handleMessage);
|
|
500
|
+
worker.postMessage({ id: messageId, type: "load", key });
|
|
501
|
+
// Timeout after 5 seconds
|
|
502
|
+
setTimeout(() => {
|
|
503
|
+
worker.removeEventListener("message", handleMessage);
|
|
504
|
+
resolve(undefined);
|
|
505
|
+
}, 5000);
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
static async removeFromWorker(key, options) {
|
|
509
|
+
const worker = this.getWorker(options);
|
|
510
|
+
if (!worker)
|
|
511
|
+
return false;
|
|
512
|
+
return new Promise((resolve) => {
|
|
513
|
+
const messageId = Date.now().toString();
|
|
514
|
+
const handleMessage = (event) => {
|
|
515
|
+
if (event.data.id === messageId) {
|
|
516
|
+
worker.removeEventListener("message", handleMessage);
|
|
517
|
+
resolve(event.data.success || false);
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
worker.addEventListener("message", handleMessage);
|
|
521
|
+
worker.postMessage({ id: messageId, type: "remove", key });
|
|
522
|
+
// Timeout after 5 seconds
|
|
523
|
+
setTimeout(() => {
|
|
524
|
+
worker.removeEventListener("message", handleMessage);
|
|
525
|
+
resolve(false);
|
|
526
|
+
}, 5000);
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
static async existsInWorker(key, options) {
|
|
530
|
+
const worker = this.getWorker(options);
|
|
531
|
+
if (!worker)
|
|
532
|
+
return false;
|
|
533
|
+
return new Promise((resolve) => {
|
|
534
|
+
const messageId = Date.now().toString();
|
|
535
|
+
const handleMessage = (event) => {
|
|
536
|
+
if (event.data.id === messageId) {
|
|
537
|
+
worker.removeEventListener("message", handleMessage);
|
|
538
|
+
resolve(event.data.exists || false);
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
worker.addEventListener("message", handleMessage);
|
|
542
|
+
worker.postMessage({ id: messageId, type: "exists", key });
|
|
543
|
+
// Timeout after 5 seconds
|
|
544
|
+
setTimeout(() => {
|
|
545
|
+
worker.removeEventListener("message", handleMessage);
|
|
546
|
+
resolve(false);
|
|
547
|
+
}, 5000);
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
static async getKeysFromWorker(prefix, options) {
|
|
551
|
+
const worker = this.getWorker(options);
|
|
552
|
+
if (!worker)
|
|
553
|
+
return [];
|
|
554
|
+
return new Promise((resolve) => {
|
|
555
|
+
const messageId = Date.now().toString();
|
|
556
|
+
const handleMessage = (event) => {
|
|
557
|
+
if (event.data.id === messageId) {
|
|
558
|
+
worker.removeEventListener("message", handleMessage);
|
|
559
|
+
resolve(event.data.keys || []);
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
worker.addEventListener("message", handleMessage);
|
|
563
|
+
worker.postMessage({ id: messageId, type: "getKeys", prefix });
|
|
564
|
+
// Timeout after 5 seconds
|
|
565
|
+
setTimeout(() => {
|
|
566
|
+
worker.removeEventListener("message", handleMessage);
|
|
567
|
+
resolve([]);
|
|
568
|
+
}, 5000);
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Array operations
|
|
573
|
+
*/
|
|
574
|
+
static async saveArray(key, objects, options = { type: "local" }) {
|
|
575
|
+
try {
|
|
576
|
+
const jsonArray = objects.map((obj) => obj.toJSON());
|
|
577
|
+
const serialized = JSON.stringify({ array: jsonArray });
|
|
578
|
+
switch (options.type) {
|
|
579
|
+
case "local":
|
|
580
|
+
return this.saveToWebStorage(key, serialized, "localStorage");
|
|
581
|
+
case "session":
|
|
582
|
+
return this.saveToWebStorage(key, serialized, "sessionStorage");
|
|
583
|
+
case "indexeddb":
|
|
584
|
+
return await this.saveToIndexedDB(key, { array: jsonArray }, options);
|
|
585
|
+
case "cookies":
|
|
586
|
+
return this.saveToCookies(key, serialized, options);
|
|
587
|
+
case "broadcast":
|
|
588
|
+
return this.saveToBroadcast(key, { array: jsonArray }, options);
|
|
589
|
+
case "worker":
|
|
590
|
+
return await this.saveToWorker(key, { array: jsonArray }, options);
|
|
591
|
+
default:
|
|
592
|
+
console.error(`Unsupported storage type: ${options.type}`);
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
catch (error) {
|
|
597
|
+
console.error("ProtoObjectBrowserStorage.saveArray error:", error);
|
|
598
|
+
return false;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
static async loadArray(key, ClassConstructor, options = { type: "local" }) {
|
|
602
|
+
try {
|
|
603
|
+
let data;
|
|
604
|
+
switch (options.type) {
|
|
605
|
+
case "local":
|
|
606
|
+
data = this.loadFromWebStorage(key, "localStorage");
|
|
607
|
+
break;
|
|
608
|
+
case "session":
|
|
609
|
+
data = this.loadFromWebStorage(key, "sessionStorage");
|
|
610
|
+
break;
|
|
611
|
+
case "indexeddb":
|
|
612
|
+
data = await this.loadFromIndexedDB(key, options);
|
|
613
|
+
break;
|
|
614
|
+
case "cookies":
|
|
615
|
+
data = this.loadFromCookies(key);
|
|
616
|
+
break;
|
|
617
|
+
case "broadcast":
|
|
618
|
+
data = this.loadFromBroadcast(key, options);
|
|
619
|
+
break;
|
|
620
|
+
case "worker":
|
|
621
|
+
data = await this.loadFromWorker(key, options);
|
|
622
|
+
break;
|
|
623
|
+
default:
|
|
624
|
+
console.error(`Unsupported storage type: ${options.type}`);
|
|
625
|
+
return undefined;
|
|
626
|
+
}
|
|
627
|
+
if (!data || !Array.isArray(data.array)) {
|
|
628
|
+
return undefined;
|
|
629
|
+
}
|
|
630
|
+
return data.array.map((json) => ClassConstructor.fromJSON(json));
|
|
631
|
+
}
|
|
632
|
+
catch (error) {
|
|
633
|
+
console.error("ProtoObjectBrowserStorage.loadArray error:", error);
|
|
634
|
+
return undefined;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Utility method to check storage support
|
|
639
|
+
*/
|
|
640
|
+
static getStorageSupport() {
|
|
641
|
+
return {
|
|
642
|
+
local: typeof window !== "undefined" && !!window.localStorage,
|
|
643
|
+
session: typeof window !== "undefined" && !!window.sessionStorage,
|
|
644
|
+
indexeddb: typeof window !== "undefined" && !!window.indexedDB,
|
|
645
|
+
cookies: typeof document !== "undefined",
|
|
646
|
+
broadcast: typeof window !== "undefined" && !!window.BroadcastChannel,
|
|
647
|
+
worker: typeof window !== "undefined" && !!window.Worker,
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Cleanup method to close connections
|
|
652
|
+
*/
|
|
653
|
+
static cleanup() {
|
|
654
|
+
// Close IndexedDB connections
|
|
655
|
+
this.idbDatabases.forEach((db) => db.close());
|
|
656
|
+
this.idbDatabases.clear();
|
|
657
|
+
// Close BroadcastChannels
|
|
658
|
+
this.channels.forEach((channel) => channel.close());
|
|
659
|
+
this.channels.clear();
|
|
660
|
+
// Terminate workers
|
|
661
|
+
this.workers.forEach((worker) => worker.terminate());
|
|
662
|
+
this.workers.clear();
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
ProtoObjectBrowserStorage.workers = new Map();
|
|
666
|
+
ProtoObjectBrowserStorage.channels = new Map();
|
|
667
|
+
ProtoObjectBrowserStorage.idbDatabases = new Map();
|
|
668
|
+
//# sourceMappingURL=protoobject-browser-storage.js.map
|