@coherent.js/state 1.0.0-beta.6 → 1.0.0-beta.8
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/dist/index.js.map +7 -0
- package/dist/reactive-state.js +512 -0
- package/dist/reactive-state.js.map +7 -0
- package/dist/state-manager.js +102 -0
- package/dist/state-manager.js.map +7 -0
- package/dist/state-persistence.js +472 -0
- package/dist/state-persistence.js.map +7 -0
- package/dist/state-validation.js +621 -0
- package/dist/state-validation.js.map +7 -0
- package/package.json +13 -3
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
// src/state-persistence.js
|
|
2
|
+
var LocalStorageAdapter = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.available = typeof localStorage !== "undefined";
|
|
5
|
+
}
|
|
6
|
+
async get(key) {
|
|
7
|
+
if (!this.available) return null;
|
|
8
|
+
try {
|
|
9
|
+
return localStorage.getItem(key);
|
|
10
|
+
} catch (error) {
|
|
11
|
+
console.error("LocalStorage get error:", error);
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async set(key, value) {
|
|
16
|
+
if (!this.available) return false;
|
|
17
|
+
try {
|
|
18
|
+
localStorage.setItem(key, value);
|
|
19
|
+
return true;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error("LocalStorage set error:", error);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async remove(key) {
|
|
26
|
+
if (!this.available) return false;
|
|
27
|
+
try {
|
|
28
|
+
localStorage.removeItem(key);
|
|
29
|
+
return true;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error("LocalStorage remove error:", error);
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async clear() {
|
|
36
|
+
if (!this.available) return false;
|
|
37
|
+
try {
|
|
38
|
+
localStorage.clear();
|
|
39
|
+
return true;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error("LocalStorage clear error:", error);
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var SessionStorageAdapter = class {
|
|
47
|
+
constructor() {
|
|
48
|
+
this.available = typeof sessionStorage !== "undefined";
|
|
49
|
+
}
|
|
50
|
+
async get(key) {
|
|
51
|
+
if (!this.available) return null;
|
|
52
|
+
try {
|
|
53
|
+
return sessionStorage.getItem(key);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error("SessionStorage get error:", error);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async set(key, value) {
|
|
60
|
+
if (!this.available) return false;
|
|
61
|
+
try {
|
|
62
|
+
sessionStorage.setItem(key, value);
|
|
63
|
+
return true;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("SessionStorage set error:", error);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async remove(key) {
|
|
70
|
+
if (!this.available) return false;
|
|
71
|
+
try {
|
|
72
|
+
sessionStorage.removeItem(key);
|
|
73
|
+
return true;
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error("SessionStorage remove error:", error);
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async clear() {
|
|
80
|
+
if (!this.available) return false;
|
|
81
|
+
try {
|
|
82
|
+
sessionStorage.clear();
|
|
83
|
+
return true;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error("SessionStorage clear error:", error);
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var IndexedDBAdapter = class {
|
|
91
|
+
constructor(dbName = "coherent-db", storeName = "state") {
|
|
92
|
+
this.dbName = dbName;
|
|
93
|
+
this.storeName = storeName;
|
|
94
|
+
this.available = typeof indexedDB !== "undefined";
|
|
95
|
+
this.db = null;
|
|
96
|
+
}
|
|
97
|
+
async init() {
|
|
98
|
+
if (!this.available) return false;
|
|
99
|
+
if (this.db) return true;
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
const request = indexedDB.open(this.dbName, 1);
|
|
102
|
+
request.onerror = () => {
|
|
103
|
+
console.error("IndexedDB open error:", request.error);
|
|
104
|
+
reject(request.error);
|
|
105
|
+
};
|
|
106
|
+
request.onsuccess = () => {
|
|
107
|
+
this.db = request.result;
|
|
108
|
+
resolve(true);
|
|
109
|
+
};
|
|
110
|
+
request.onupgradeneeded = (event) => {
|
|
111
|
+
const db = event.target.result;
|
|
112
|
+
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
113
|
+
db.createObjectStore(this.storeName);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async get(key) {
|
|
119
|
+
if (!this.available) return null;
|
|
120
|
+
await this.init();
|
|
121
|
+
return new Promise((resolve, reject) => {
|
|
122
|
+
const transaction = this.db.transaction([this.storeName], "readonly");
|
|
123
|
+
const store = transaction.objectStore(this.storeName);
|
|
124
|
+
const request = store.get(key);
|
|
125
|
+
request.onerror = () => {
|
|
126
|
+
console.error("IndexedDB get error:", request.error);
|
|
127
|
+
reject(request.error);
|
|
128
|
+
};
|
|
129
|
+
request.onsuccess = () => {
|
|
130
|
+
resolve(request.result || null);
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
async set(key, value) {
|
|
135
|
+
if (!this.available) return false;
|
|
136
|
+
await this.init();
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
const transaction = this.db.transaction([this.storeName], "readwrite");
|
|
139
|
+
const store = transaction.objectStore(this.storeName);
|
|
140
|
+
const request = store.put(value, key);
|
|
141
|
+
request.onerror = () => {
|
|
142
|
+
console.error("IndexedDB set error:", request.error);
|
|
143
|
+
reject(request.error);
|
|
144
|
+
};
|
|
145
|
+
request.onsuccess = () => {
|
|
146
|
+
resolve(true);
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
async remove(key) {
|
|
151
|
+
if (!this.available) return false;
|
|
152
|
+
await this.init();
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
const transaction = this.db.transaction([this.storeName], "readwrite");
|
|
155
|
+
const store = transaction.objectStore(this.storeName);
|
|
156
|
+
const request = store.delete(key);
|
|
157
|
+
request.onerror = () => {
|
|
158
|
+
console.error("IndexedDB remove error:", request.error);
|
|
159
|
+
reject(request.error);
|
|
160
|
+
};
|
|
161
|
+
request.onsuccess = () => {
|
|
162
|
+
resolve(true);
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
async clear() {
|
|
167
|
+
if (!this.available) return false;
|
|
168
|
+
await this.init();
|
|
169
|
+
return new Promise((resolve, reject) => {
|
|
170
|
+
const transaction = this.db.transaction([this.storeName], "readwrite");
|
|
171
|
+
const store = transaction.objectStore(this.storeName);
|
|
172
|
+
const request = store.clear();
|
|
173
|
+
request.onerror = () => {
|
|
174
|
+
console.error("IndexedDB clear error:", request.error);
|
|
175
|
+
reject(request.error);
|
|
176
|
+
};
|
|
177
|
+
request.onsuccess = () => {
|
|
178
|
+
resolve(true);
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
var MemoryAdapter = class {
|
|
184
|
+
constructor() {
|
|
185
|
+
this.storage = /* @__PURE__ */ new Map();
|
|
186
|
+
this.available = true;
|
|
187
|
+
}
|
|
188
|
+
async get(key) {
|
|
189
|
+
return this.storage.get(key) || null;
|
|
190
|
+
}
|
|
191
|
+
async set(key, value) {
|
|
192
|
+
this.storage.set(key, value);
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
async remove(key) {
|
|
196
|
+
return this.storage.delete(key);
|
|
197
|
+
}
|
|
198
|
+
async clear() {
|
|
199
|
+
this.storage.clear();
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
var SimpleEncryption = class {
|
|
204
|
+
constructor(key) {
|
|
205
|
+
this.key = key || "default-key";
|
|
206
|
+
}
|
|
207
|
+
encrypt(text) {
|
|
208
|
+
let result = "";
|
|
209
|
+
for (let i = 0; i < text.length; i++) {
|
|
210
|
+
result += String.fromCharCode(
|
|
211
|
+
text.charCodeAt(i) ^ this.key.charCodeAt(i % this.key.length)
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return btoa(result);
|
|
215
|
+
}
|
|
216
|
+
decrypt(encrypted) {
|
|
217
|
+
const text = atob(encrypted);
|
|
218
|
+
let result = "";
|
|
219
|
+
for (let i = 0; i < text.length; i++) {
|
|
220
|
+
result += String.fromCharCode(
|
|
221
|
+
text.charCodeAt(i) ^ this.key.charCodeAt(i % this.key.length)
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
function createStorageAdapter(type) {
|
|
228
|
+
switch (type) {
|
|
229
|
+
case "localStorage":
|
|
230
|
+
return new LocalStorageAdapter();
|
|
231
|
+
case "sessionStorage":
|
|
232
|
+
return new SessionStorageAdapter();
|
|
233
|
+
case "indexedDB":
|
|
234
|
+
return new IndexedDBAdapter();
|
|
235
|
+
case "memory":
|
|
236
|
+
return new MemoryAdapter();
|
|
237
|
+
default:
|
|
238
|
+
return new LocalStorageAdapter();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function createPersistentState(initialState = {}, options = {}) {
|
|
242
|
+
const opts = {
|
|
243
|
+
storage: "localStorage",
|
|
244
|
+
key: "coherent-state",
|
|
245
|
+
debounce: true,
|
|
246
|
+
debounceDelay: 300,
|
|
247
|
+
serialize: JSON.stringify,
|
|
248
|
+
deserialize: JSON.parse,
|
|
249
|
+
include: null,
|
|
250
|
+
exclude: null,
|
|
251
|
+
encrypt: false,
|
|
252
|
+
encryptionKey: null,
|
|
253
|
+
onSave: null,
|
|
254
|
+
onLoad: null,
|
|
255
|
+
onError: null,
|
|
256
|
+
versioning: false,
|
|
257
|
+
version: "1.0.0",
|
|
258
|
+
migrate: null,
|
|
259
|
+
ttl: null,
|
|
260
|
+
crossTab: false,
|
|
261
|
+
...options
|
|
262
|
+
};
|
|
263
|
+
const adapter = createStorageAdapter(opts.storage);
|
|
264
|
+
const encryption = opts.encrypt ? new SimpleEncryption(opts.encryptionKey) : null;
|
|
265
|
+
let state = { ...initialState };
|
|
266
|
+
let saveTimeout = null;
|
|
267
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
268
|
+
function filterKeys(obj) {
|
|
269
|
+
if (!obj || typeof obj !== "object") return obj;
|
|
270
|
+
if (opts.include && Array.isArray(opts.include)) {
|
|
271
|
+
const filtered = {};
|
|
272
|
+
opts.include.forEach((key) => {
|
|
273
|
+
if (key in obj) {
|
|
274
|
+
filtered[key] = obj[key];
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
return filtered;
|
|
278
|
+
}
|
|
279
|
+
if (opts.exclude && Array.isArray(opts.exclude)) {
|
|
280
|
+
const filtered = { ...obj };
|
|
281
|
+
opts.exclude.forEach((key) => {
|
|
282
|
+
delete filtered[key];
|
|
283
|
+
});
|
|
284
|
+
return filtered;
|
|
285
|
+
}
|
|
286
|
+
return obj;
|
|
287
|
+
}
|
|
288
|
+
async function save(immediate = false) {
|
|
289
|
+
if (opts.debounce && !immediate) {
|
|
290
|
+
clearTimeout(saveTimeout);
|
|
291
|
+
saveTimeout = setTimeout(() => save(true), opts.debounceDelay);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
const filteredState = filterKeys(state);
|
|
296
|
+
const serialized = opts.serialize(filteredState);
|
|
297
|
+
const data = {
|
|
298
|
+
state: serialized,
|
|
299
|
+
version: opts.version,
|
|
300
|
+
timestamp: Date.now(),
|
|
301
|
+
ttl: opts.ttl
|
|
302
|
+
};
|
|
303
|
+
let dataString = JSON.stringify(data);
|
|
304
|
+
if (encryption) {
|
|
305
|
+
dataString = encryption.encrypt(dataString);
|
|
306
|
+
}
|
|
307
|
+
await adapter.set(opts.key, dataString);
|
|
308
|
+
if (opts.onSave) {
|
|
309
|
+
opts.onSave(filteredState);
|
|
310
|
+
}
|
|
311
|
+
if (opts.crossTab && typeof BroadcastChannel !== "undefined") {
|
|
312
|
+
const channel = new BroadcastChannel("coherent-state-sync");
|
|
313
|
+
channel.postMessage({ type: "state-update", state: filteredState });
|
|
314
|
+
channel.close();
|
|
315
|
+
}
|
|
316
|
+
} catch (error) {
|
|
317
|
+
console.error("State save error:", error);
|
|
318
|
+
if (opts.onError) {
|
|
319
|
+
opts.onError(error);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async function load() {
|
|
324
|
+
try {
|
|
325
|
+
let dataString = await adapter.get(opts.key);
|
|
326
|
+
if (!dataString) return null;
|
|
327
|
+
if (encryption) {
|
|
328
|
+
dataString = encryption.decrypt(dataString);
|
|
329
|
+
}
|
|
330
|
+
const data = JSON.parse(dataString);
|
|
331
|
+
if (data.ttl && data.timestamp) {
|
|
332
|
+
const age = Date.now() - data.timestamp;
|
|
333
|
+
if (age > data.ttl) {
|
|
334
|
+
await adapter.remove(opts.key);
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (opts.versioning && data.version !== opts.version) {
|
|
339
|
+
if (opts.migrate) {
|
|
340
|
+
const migrated = opts.migrate(data.state, data.version, opts.version);
|
|
341
|
+
return opts.deserialize(migrated);
|
|
342
|
+
}
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
const loadedState = opts.deserialize(data.state);
|
|
346
|
+
if (opts.onLoad) {
|
|
347
|
+
opts.onLoad(loadedState);
|
|
348
|
+
}
|
|
349
|
+
return loadedState;
|
|
350
|
+
} catch (error) {
|
|
351
|
+
console.error("State load error:", error);
|
|
352
|
+
if (opts.onError) {
|
|
353
|
+
opts.onError(error);
|
|
354
|
+
}
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function subscribe(listener) {
|
|
359
|
+
listeners.add(listener);
|
|
360
|
+
return () => listeners.delete(listener);
|
|
361
|
+
}
|
|
362
|
+
function notifyListeners(oldState, newState) {
|
|
363
|
+
listeners.forEach((listener) => {
|
|
364
|
+
try {
|
|
365
|
+
listener(newState, oldState);
|
|
366
|
+
} catch (error) {
|
|
367
|
+
console.error("Listener error:", error);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
function getState(key) {
|
|
372
|
+
return key ? state[key] : { ...state };
|
|
373
|
+
}
|
|
374
|
+
function setState(updates, persist2 = true) {
|
|
375
|
+
const oldState = { ...state };
|
|
376
|
+
if (typeof updates === "function") {
|
|
377
|
+
updates = updates(oldState);
|
|
378
|
+
}
|
|
379
|
+
state = { ...state, ...updates };
|
|
380
|
+
notifyListeners(oldState, state);
|
|
381
|
+
if (persist2) {
|
|
382
|
+
save();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function resetState(persist2 = true) {
|
|
386
|
+
const oldState = { ...state };
|
|
387
|
+
state = { ...initialState };
|
|
388
|
+
notifyListeners(oldState, state);
|
|
389
|
+
if (persist2) {
|
|
390
|
+
save(true);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async function clearStorage() {
|
|
394
|
+
await adapter.remove(opts.key);
|
|
395
|
+
}
|
|
396
|
+
async function persist() {
|
|
397
|
+
await save(true);
|
|
398
|
+
}
|
|
399
|
+
async function restore() {
|
|
400
|
+
const loaded = await load();
|
|
401
|
+
if (loaded) {
|
|
402
|
+
const oldState = { ...state };
|
|
403
|
+
state = { ...state, ...loaded };
|
|
404
|
+
notifyListeners(oldState, state);
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
if (opts.crossTab && typeof BroadcastChannel !== "undefined") {
|
|
410
|
+
const channel = new BroadcastChannel("coherent-state-sync");
|
|
411
|
+
channel.onmessage = (event) => {
|
|
412
|
+
if (event.data.type === "state-update") {
|
|
413
|
+
const oldState = { ...state };
|
|
414
|
+
state = { ...state, ...event.data.state };
|
|
415
|
+
notifyListeners(oldState, state);
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
if (opts.storage !== "memory") {
|
|
420
|
+
restore();
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
getState,
|
|
424
|
+
setState,
|
|
425
|
+
resetState,
|
|
426
|
+
subscribe,
|
|
427
|
+
persist,
|
|
428
|
+
restore,
|
|
429
|
+
clearStorage,
|
|
430
|
+
load,
|
|
431
|
+
save: () => save(true),
|
|
432
|
+
get adapter() {
|
|
433
|
+
return adapter;
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
function withLocalStorage(initialState = {}, key = "coherent-state", options = {}) {
|
|
438
|
+
return createPersistentState(initialState, {
|
|
439
|
+
...options,
|
|
440
|
+
storage: "localStorage",
|
|
441
|
+
key
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
function withSessionStorage(initialState = {}, key = "coherent-state", options = {}) {
|
|
445
|
+
return createPersistentState(initialState, {
|
|
446
|
+
...options,
|
|
447
|
+
storage: "sessionStorage",
|
|
448
|
+
key
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
function withIndexedDB(initialState = {}, key = "coherent-state", options = {}) {
|
|
452
|
+
return createPersistentState(initialState, {
|
|
453
|
+
...options,
|
|
454
|
+
storage: "indexedDB",
|
|
455
|
+
key
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
var state_persistence_default = {
|
|
459
|
+
createPersistentState,
|
|
460
|
+
withLocalStorage,
|
|
461
|
+
withSessionStorage,
|
|
462
|
+
withIndexedDB,
|
|
463
|
+
createStorageAdapter
|
|
464
|
+
};
|
|
465
|
+
export {
|
|
466
|
+
createPersistentState,
|
|
467
|
+
state_persistence_default as default,
|
|
468
|
+
withIndexedDB,
|
|
469
|
+
withLocalStorage,
|
|
470
|
+
withSessionStorage
|
|
471
|
+
};
|
|
472
|
+
//# sourceMappingURL=state-persistence.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/state-persistence.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview State Persistence for Coherent.js\n * Provides persistent state management with multiple storage backends\n * @module @coherent.js/core/state/state-persistence\n */\n\n/**\n * @typedef {'localStorage'|'sessionStorage'|'indexedDB'|'memory'} StorageType\n */\n\n/**\n * @typedef {Object} PersistenceOptions\n * @property {StorageType} [storage='localStorage'] - Storage backend to use\n * @property {string} [key='coherent-state'] - Storage key prefix\n * @property {boolean} [debounce=true] - Debounce state saves\n * @property {number} [debounceDelay=300] - Debounce delay in ms\n * @property {Function} [serialize=JSON.stringify] - Serialization function\n * @property {Function} [deserialize=JSON.parse] - Deserialization function\n * @property {Array<string>} [include] - Keys to include (whitelist)\n * @property {Array<string>} [exclude] - Keys to exclude (blacklist)\n * @property {boolean} [encrypt=false] - Encrypt stored data\n * @property {string} [encryptionKey] - Encryption key\n * @property {Function} [onSave] - Callback when state is saved\n * @property {Function} [onLoad] - Callback when state is loaded\n * @property {Function} [onError] - Error callback\n * @property {boolean} [versioning=false] - Enable versioning\n * @property {string} [version='1.0.0'] - Current version\n * @property {Function} [migrate] - Migration function for version changes\n * @property {number} [ttl] - Time to live in milliseconds\n * @property {boolean} [crossTab=false] - Enable cross-tab synchronization\n */\n\n/**\n * Storage adapter interface\n * @interface StorageAdapter\n */\n\n/**\n * LocalStorage adapter\n */\nclass LocalStorageAdapter {\n constructor() {\n this.available = typeof localStorage !== 'undefined';\n }\n\n async get(key) {\n if (!this.available) return null;\n try {\n return localStorage.getItem(key);\n } catch (error) {\n console.error('LocalStorage get error:', error);\n return null;\n }\n }\n\n async set(key, value) {\n if (!this.available) return false;\n try {\n localStorage.setItem(key, value);\n return true;\n } catch (error) {\n console.error('LocalStorage set error:', error);\n return false;\n }\n }\n\n async remove(key) {\n if (!this.available) return false;\n try {\n localStorage.removeItem(key);\n return true;\n } catch (error) {\n console.error('LocalStorage remove error:', error);\n return false;\n }\n }\n\n async clear() {\n if (!this.available) return false;\n try {\n localStorage.clear();\n return true;\n } catch (error) {\n console.error('LocalStorage clear error:', error);\n return false;\n }\n }\n}\n\n/**\n * SessionStorage adapter\n */\nclass SessionStorageAdapter {\n constructor() {\n this.available = typeof sessionStorage !== 'undefined';\n }\n\n async get(key) {\n if (!this.available) return null;\n try {\n return sessionStorage.getItem(key);\n } catch (error) {\n console.error('SessionStorage get error:', error);\n return null;\n }\n }\n\n async set(key, value) {\n if (!this.available) return false;\n try {\n sessionStorage.setItem(key, value);\n return true;\n } catch (error) {\n console.error('SessionStorage set error:', error);\n return false;\n }\n }\n\n async remove(key) {\n if (!this.available) return false;\n try {\n sessionStorage.removeItem(key);\n return true;\n } catch (error) {\n console.error('SessionStorage remove error:', error);\n return false;\n }\n }\n\n async clear() {\n if (!this.available) return false;\n try {\n sessionStorage.clear();\n return true;\n } catch (error) {\n console.error('SessionStorage clear error:', error);\n return false;\n }\n }\n}\n\n/**\n * IndexedDB adapter\n */\nclass IndexedDBAdapter {\n constructor(dbName = 'coherent-db', storeName = 'state') {\n this.dbName = dbName;\n this.storeName = storeName;\n this.available = typeof indexedDB !== 'undefined';\n this.db = null;\n }\n\n async init() {\n if (!this.available) return false;\n if (this.db) return true;\n\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, 1);\n\n request.onerror = () => {\n console.error('IndexedDB open error:', request.error);\n reject(request.error);\n };\n\n request.onsuccess = () => {\n this.db = request.result;\n resolve(true);\n };\n\n request.onupgradeneeded = (event) => {\n const db = event.target.result;\n if (!db.objectStoreNames.contains(this.storeName)) {\n db.createObjectStore(this.storeName);\n }\n };\n });\n }\n\n async get(key) {\n if (!this.available) return null;\n await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([this.storeName], 'readonly');\n const store = transaction.objectStore(this.storeName);\n const request = store.get(key);\n\n request.onerror = () => {\n console.error('IndexedDB get error:', request.error);\n reject(request.error);\n };\n\n request.onsuccess = () => {\n resolve(request.result || null);\n };\n });\n }\n\n async set(key, value) {\n if (!this.available) return false;\n await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const store = transaction.objectStore(this.storeName);\n const request = store.put(value, key);\n\n request.onerror = () => {\n console.error('IndexedDB set error:', request.error);\n reject(request.error);\n };\n\n request.onsuccess = () => {\n resolve(true);\n };\n });\n }\n\n async remove(key) {\n if (!this.available) return false;\n await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const store = transaction.objectStore(this.storeName);\n const request = store.delete(key);\n\n request.onerror = () => {\n console.error('IndexedDB remove error:', request.error);\n reject(request.error);\n };\n\n request.onsuccess = () => {\n resolve(true);\n };\n });\n }\n\n async clear() {\n if (!this.available) return false;\n await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const store = transaction.objectStore(this.storeName);\n const request = store.clear();\n\n request.onerror = () => {\n console.error('IndexedDB clear error:', request.error);\n reject(request.error);\n };\n\n request.onsuccess = () => {\n resolve(true);\n };\n });\n }\n}\n\n/**\n * Memory adapter (for testing or fallback)\n */\nclass MemoryAdapter {\n constructor() {\n this.storage = new Map();\n this.available = true;\n }\n\n async get(key) {\n return this.storage.get(key) || null;\n }\n\n async set(key, value) {\n this.storage.set(key, value);\n return true;\n }\n\n async remove(key) {\n return this.storage.delete(key);\n }\n\n async clear() {\n this.storage.clear();\n return true;\n }\n}\n\n/**\n * Simple encryption/decryption (basic XOR cipher)\n * For production, use Web Crypto API or a proper crypto library\n */\nclass SimpleEncryption {\n constructor(key) {\n this.key = key || 'default-key';\n }\n\n encrypt(text) {\n let result = '';\n for (let i = 0; i < text.length; i++) {\n result += String.fromCharCode(\n text.charCodeAt(i) ^ this.key.charCodeAt(i % this.key.length)\n );\n }\n return btoa(result);\n }\n\n decrypt(encrypted) {\n const text = atob(encrypted);\n let result = '';\n for (let i = 0; i < text.length; i++) {\n result += String.fromCharCode(\n text.charCodeAt(i) ^ this.key.charCodeAt(i % this.key.length)\n );\n }\n return result;\n }\n}\n\n/**\n * Create storage adapter\n * @param {StorageType} type - Storage type\n * @returns {StorageAdapter} Storage adapter instance\n */\nfunction createStorageAdapter(type) {\n switch (type) {\n case 'localStorage':\n return new LocalStorageAdapter();\n case 'sessionStorage':\n return new SessionStorageAdapter();\n case 'indexedDB':\n return new IndexedDBAdapter();\n case 'memory':\n return new MemoryAdapter();\n default:\n return new LocalStorageAdapter();\n }\n}\n\n/**\n * Create persistent state manager\n * @param {Object} initialState - Initial state\n * @param {PersistenceOptions} options - Persistence options\n * @returns {Object} Persistent state manager\n */\nexport function createPersistentState(initialState = {}, options = {}) {\n const opts = {\n storage: 'localStorage',\n key: 'coherent-state',\n debounce: true,\n debounceDelay: 300,\n serialize: JSON.stringify,\n deserialize: JSON.parse,\n include: null,\n exclude: null,\n encrypt: false,\n encryptionKey: null,\n onSave: null,\n onLoad: null,\n onError: null,\n versioning: false,\n version: '1.0.0',\n migrate: null,\n ttl: null,\n crossTab: false,\n ...options\n };\n\n const adapter = createStorageAdapter(opts.storage);\n const encryption = opts.encrypt ? new SimpleEncryption(opts.encryptionKey) : null;\n\n let state = { ...initialState };\n let saveTimeout = null;\n const listeners = new Set();\n\n /**\n * Filter state keys based on include/exclude options\n * @param {Object} obj - State object\n * @returns {Object} Filtered state\n */\n function filterKeys(obj) {\n if (!obj || typeof obj !== 'object') return obj;\n\n // If include list is provided, only include those keys\n if (opts.include && Array.isArray(opts.include)) {\n const filtered = {};\n opts.include.forEach(key => {\n if (key in obj) {\n filtered[key] = obj[key];\n }\n });\n return filtered;\n }\n\n // If exclude list is provided, exclude those keys\n if (opts.exclude && Array.isArray(opts.exclude)) {\n const filtered = { ...obj };\n opts.exclude.forEach(key => {\n delete filtered[key];\n });\n return filtered;\n }\n\n return obj;\n }\n\n /**\n * Save state to storage\n * @param {boolean} immediate - Save immediately without debounce\n */\n async function save(immediate = false) {\n if (opts.debounce && !immediate) {\n clearTimeout(saveTimeout);\n saveTimeout = setTimeout(() => save(true), opts.debounceDelay);\n return;\n }\n\n try {\n const filteredState = filterKeys(state);\n const serialized = opts.serialize(filteredState);\n\n // Add metadata\n const data = {\n state: serialized,\n version: opts.version,\n timestamp: Date.now(),\n ttl: opts.ttl\n };\n\n let dataString = JSON.stringify(data);\n\n // Encrypt if enabled\n if (encryption) {\n dataString = encryption.encrypt(dataString);\n }\n\n await adapter.set(opts.key, dataString);\n\n // Call onSave callback\n if (opts.onSave) {\n opts.onSave(filteredState);\n }\n\n // Broadcast to other tabs if cross-tab sync is enabled\n if (opts.crossTab && typeof BroadcastChannel !== 'undefined') {\n const channel = new BroadcastChannel('coherent-state-sync');\n channel.postMessage({ type: 'state-update', state: filteredState });\n channel.close();\n }\n } catch (error) {\n console.error('State save error:', error);\n if (opts.onError) {\n opts.onError(error);\n }\n }\n }\n\n /**\n * Load state from storage\n */\n async function load() {\n try {\n let dataString = await adapter.get(opts.key);\n if (!dataString) return null;\n\n // Decrypt if enabled\n if (encryption) {\n dataString = encryption.decrypt(dataString);\n }\n\n const data = JSON.parse(dataString);\n\n // Check TTL\n if (data.ttl && data.timestamp) {\n const age = Date.now() - data.timestamp;\n if (age > data.ttl) {\n await adapter.remove(opts.key);\n return null;\n }\n }\n\n // Check version and migrate if needed\n if (opts.versioning && data.version !== opts.version) {\n if (opts.migrate) {\n const migrated = opts.migrate(data.state, data.version, opts.version);\n return opts.deserialize(migrated);\n }\n return null;\n }\n\n const loadedState = opts.deserialize(data.state);\n\n // Call onLoad callback\n if (opts.onLoad) {\n opts.onLoad(loadedState);\n }\n\n return loadedState;\n } catch (error) {\n console.error('State load error:', error);\n if (opts.onError) {\n opts.onError(error);\n }\n return null;\n }\n }\n\n /**\n * Subscribe to state changes\n * @param {Function} listener - Change listener\n * @returns {Function} Unsubscribe function\n */\n function subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n }\n\n /**\n * Notify listeners of state changes\n * @param {Object} oldState - Previous state\n * @param {Object} newState - New state\n */\n function notifyListeners(oldState, newState) {\n listeners.forEach(listener => {\n try {\n listener(newState, oldState);\n } catch (error) {\n console.error('Listener error:', error);\n }\n });\n }\n\n /**\n * Get current state\n * @param {string} [key] - State key\n * @returns {*} State value or entire state\n */\n function getState(key) {\n return key ? state[key] : { ...state };\n }\n\n /**\n * Set state\n * @param {Object|Function} updates - State updates or updater function\n * @param {boolean} persist - Persist to storage\n */\n function setState(updates, persist = true) {\n const oldState = { ...state };\n\n if (typeof updates === 'function') {\n updates = updates(oldState);\n }\n\n state = { ...state, ...updates };\n\n notifyListeners(oldState, state);\n\n if (persist) {\n save();\n }\n }\n\n /**\n * Reset state to initial values\n * @param {boolean} persist - Persist to storage\n */\n function resetState(persist = true) {\n const oldState = { ...state };\n state = { ...initialState };\n notifyListeners(oldState, state);\n\n if (persist) {\n save(true);\n }\n }\n\n /**\n * Clear persisted state\n */\n async function clearStorage() {\n await adapter.remove(opts.key);\n }\n\n /**\n * Manually trigger persistence\n */\n async function persist() {\n await save(true);\n }\n\n /**\n * Restore state from storage\n */\n async function restore() {\n const loaded = await load();\n if (loaded) {\n const oldState = { ...state };\n state = { ...state, ...loaded };\n notifyListeners(oldState, state);\n return true;\n }\n return false;\n }\n\n // Setup cross-tab synchronization\n if (opts.crossTab && typeof BroadcastChannel !== 'undefined') {\n const channel = new BroadcastChannel('coherent-state-sync');\n channel.onmessage = (event) => {\n if (event.data.type === 'state-update') {\n const oldState = { ...state };\n state = { ...state, ...event.data.state };\n notifyListeners(oldState, state);\n }\n };\n }\n\n // Auto-restore on creation\n if (opts.storage !== 'memory') {\n restore();\n }\n\n return {\n getState,\n setState,\n resetState,\n subscribe,\n persist,\n restore,\n clearStorage,\n load,\n save: () => save(true),\n get adapter() {\n return adapter;\n }\n };\n}\n\n/**\n * Create persistent state with localStorage\n * @param {Object} initialState - Initial state\n * @param {string} key - Storage key\n * @param {Partial<PersistenceOptions>} options - Additional options\n * @returns {Object} Persistent state manager\n */\nexport function withLocalStorage(initialState = {}, key = 'coherent-state', options = {}) {\n return createPersistentState(initialState, {\n ...options,\n storage: 'localStorage',\n key\n });\n}\n\n/**\n * Create persistent state with sessionStorage\n * @param {Object} initialState - Initial state\n * @param {string} key - Storage key\n * @param {Partial<PersistenceOptions>} options - Additional options\n * @returns {Object} Persistent state manager\n */\nexport function withSessionStorage(initialState = {}, key = 'coherent-state', options = {}) {\n return createPersistentState(initialState, {\n ...options,\n storage: 'sessionStorage',\n key\n });\n}\n\n/**\n * Create persistent state with IndexedDB\n * @param {Object} initialState - Initial state\n * @param {string} key - Storage key\n * @param {Partial<PersistenceOptions>} options - Additional options\n * @returns {Object} Persistent state manager\n */\nexport function withIndexedDB(initialState = {}, key = 'coherent-state', options = {}) {\n return createPersistentState(initialState, {\n ...options,\n storage: 'indexedDB',\n key\n });\n}\n\nexport default {\n createPersistentState,\n withLocalStorage,\n withSessionStorage,\n withIndexedDB,\n createStorageAdapter\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["persist"]
|
|
7
|
+
}
|