gjendje 1.3.0 → 1.3.1
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/{chunk-ARCB4TVB.cjs → chunk-3YGK3425.cjs} +22 -1
- package/dist/{chunk-KVY36YX4.cjs → chunk-TXLZGYYF.cjs} +94 -71
- package/dist/{chunk-UEEINLOF.js → chunk-UGISZQRH.js} +28 -5
- package/dist/{chunk-FAISWCIZ.js → chunk-YPT6TO4H.js} +21 -2
- package/dist/devtools.cjs +6 -6
- package/dist/devtools.d.cts +1 -1
- package/dist/devtools.d.ts +1 -1
- package/dist/devtools.js +1 -1
- package/dist/index.cjs +50 -37
- package/dist/index.d.cts +18 -4
- package/dist/index.d.ts +18 -4
- package/dist/index.js +10 -5
- package/dist/react.cjs +20 -9
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +21 -10
- package/dist/server.cjs +5 -5
- package/dist/server.d.cts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +2 -2
- package/dist/{types-DmJrN5KI.d.cts → types-DzWE2M22.d.cts} +9 -0
- package/dist/{types-DmJrN5KI.d.ts → types-DzWE2M22.d.ts} +9 -0
- package/dist/vue.d.cts +1 -1
- package/dist/vue.d.ts +1 -1
- package/package.json +3 -2
|
@@ -4,7 +4,14 @@
|
|
|
4
4
|
var globalConfig = {};
|
|
5
5
|
var PERSISTENT_SCOPES = /* @__PURE__ */ new Set(["local", "session", "bucket"]);
|
|
6
6
|
function configure(config) {
|
|
7
|
-
|
|
7
|
+
for (const key of Object.keys(config)) {
|
|
8
|
+
const value = config[key];
|
|
9
|
+
if (value === void 0) {
|
|
10
|
+
delete globalConfig[key];
|
|
11
|
+
} else {
|
|
12
|
+
globalConfig[key] = value;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
8
15
|
if (globalConfig.registry === false && globalConfig.scope && PERSISTENT_SCOPES.has(globalConfig.scope)) {
|
|
9
16
|
log(
|
|
10
17
|
"warn",
|
|
@@ -12,6 +19,9 @@ function configure(config) {
|
|
|
12
19
|
);
|
|
13
20
|
}
|
|
14
21
|
}
|
|
22
|
+
function resetConfig() {
|
|
23
|
+
globalConfig = {};
|
|
24
|
+
}
|
|
15
25
|
function getConfig() {
|
|
16
26
|
return globalConfig;
|
|
17
27
|
}
|
|
@@ -102,16 +112,27 @@ function unregisterByKey(rKey) {
|
|
|
102
112
|
function getRegistry() {
|
|
103
113
|
return registry;
|
|
104
114
|
}
|
|
115
|
+
function destroyAll() {
|
|
116
|
+
const instances = [...registry.values()];
|
|
117
|
+
for (const instance of instances) {
|
|
118
|
+
if (!instance.isDestroyed) {
|
|
119
|
+
instance.destroy();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
registry.clear();
|
|
123
|
+
}
|
|
105
124
|
|
|
106
125
|
exports.PERSISTENT_SCOPES = PERSISTENT_SCOPES;
|
|
107
126
|
exports.configure = configure;
|
|
108
127
|
exports.createListeners = createListeners;
|
|
128
|
+
exports.destroyAll = destroyAll;
|
|
109
129
|
exports.getConfig = getConfig;
|
|
110
130
|
exports.getRegistered = getRegistered;
|
|
111
131
|
exports.getRegistry = getRegistry;
|
|
112
132
|
exports.log = log;
|
|
113
133
|
exports.registerNew = registerNew;
|
|
114
134
|
exports.reportError = reportError;
|
|
135
|
+
exports.resetConfig = resetConfig;
|
|
115
136
|
exports.safeCall = safeCall;
|
|
116
137
|
exports.safeCallChange = safeCallChange;
|
|
117
138
|
exports.safeCallConfig = safeCallConfig;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk3YGK3425_cjs = require('./chunk-3YGK3425.cjs');
|
|
4
4
|
|
|
5
5
|
// src/batch.ts
|
|
6
6
|
var depth = 0;
|
|
@@ -26,8 +26,17 @@ function notify(fn) {
|
|
|
26
26
|
}
|
|
27
27
|
fn();
|
|
28
28
|
}
|
|
29
|
+
var MAX_FLUSH_ITERATIONS = 100;
|
|
29
30
|
function flush() {
|
|
31
|
+
let iterations = 0;
|
|
30
32
|
while (queue.length > 0) {
|
|
33
|
+
if (++iterations > MAX_FLUSH_ITERATIONS) {
|
|
34
|
+
console.error(
|
|
35
|
+
"[gjendje] Batch flush exceeded maximum iterations \u2014 possible infinite loop. Remaining queued notifications have been dropped."
|
|
36
|
+
);
|
|
37
|
+
queue = [];
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
31
40
|
generation++;
|
|
32
41
|
const current = queue;
|
|
33
42
|
queue = [];
|
|
@@ -203,7 +212,7 @@ function notifyWatchers(watchers, prev, next) {
|
|
|
203
212
|
const nextVal = nextObj?.[watchKey];
|
|
204
213
|
if (!Object.is(prevVal, nextVal)) {
|
|
205
214
|
for (const listener of listeners) {
|
|
206
|
-
|
|
215
|
+
chunk3YGK3425_cjs.safeCall(listener, nextVal);
|
|
207
216
|
}
|
|
208
217
|
}
|
|
209
218
|
}
|
|
@@ -230,7 +239,7 @@ function readAndMigrate(raw, options, key, scope) {
|
|
|
230
239
|
if (storedVersion < currentVersion && options.migrate) {
|
|
231
240
|
data = runMigrations(data, storedVersion, currentVersion, options.migrate, key, scope);
|
|
232
241
|
if (key && scope) {
|
|
233
|
-
|
|
242
|
+
chunk3YGK3425_cjs.safeCallConfig(chunk3YGK3425_cjs.getConfig().onMigrate, {
|
|
234
243
|
key,
|
|
235
244
|
scope,
|
|
236
245
|
fromVersion: storedVersion,
|
|
@@ -241,19 +250,19 @@ function readAndMigrate(raw, options, key, scope) {
|
|
|
241
250
|
}
|
|
242
251
|
if (options.validate && !options.validate(data)) {
|
|
243
252
|
if (key && scope) {
|
|
244
|
-
const config =
|
|
245
|
-
|
|
253
|
+
const config = chunk3YGK3425_cjs.getConfig();
|
|
254
|
+
chunk3YGK3425_cjs.safeCallConfig(config.onValidationFail, { key, scope, value: data });
|
|
246
255
|
const validationErr = new ValidationError(key, scope, data);
|
|
247
|
-
|
|
256
|
+
chunk3YGK3425_cjs.safeCallConfig(config.onError, { key, scope, error: validationErr });
|
|
248
257
|
}
|
|
249
258
|
return defaultValue;
|
|
250
259
|
}
|
|
251
260
|
return data;
|
|
252
261
|
} catch (err) {
|
|
253
|
-
|
|
262
|
+
chunk3YGK3425_cjs.log("debug", `Failed to read/migrate stored value \u2014 falling back to default.`);
|
|
254
263
|
if (key && scope) {
|
|
255
264
|
const readErr = new StorageReadError(key, scope, err);
|
|
256
|
-
|
|
265
|
+
chunk3YGK3425_cjs.safeCallConfig(chunk3YGK3425_cjs.getConfig().onError, { key, scope, error: readErr });
|
|
257
266
|
}
|
|
258
267
|
return defaultValue;
|
|
259
268
|
}
|
|
@@ -282,7 +291,7 @@ function mergeKeys(stored, defaultValue, keys) {
|
|
|
282
291
|
var MAX_MIGRATION_STEPS = 1e3;
|
|
283
292
|
function runMigrations(data, fromVersion, toVersion, migrations, key, scope) {
|
|
284
293
|
if (fromVersion < 0 || toVersion - fromVersion > MAX_MIGRATION_STEPS) {
|
|
285
|
-
|
|
294
|
+
chunk3YGK3425_cjs.log("warn", `Migration range v${fromVersion}\u2192v${toVersion} is out of bounds \u2014 skipping.`);
|
|
286
295
|
return data;
|
|
287
296
|
}
|
|
288
297
|
let current = data;
|
|
@@ -292,10 +301,10 @@ function runMigrations(data, fromVersion, toVersion, migrations, key, scope) {
|
|
|
292
301
|
try {
|
|
293
302
|
current = migrateFn(current);
|
|
294
303
|
} catch (err) {
|
|
295
|
-
|
|
304
|
+
chunk3YGK3425_cjs.log("warn", `Migration from v${v} failed \u2014 returning partially migrated value.`);
|
|
296
305
|
if (key && scope) {
|
|
297
306
|
const migrationErr = new MigrationError(key, scope, v, toVersion, err);
|
|
298
|
-
|
|
307
|
+
chunk3YGK3425_cjs.safeCallConfig(chunk3YGK3425_cjs.getConfig().onError, { key, scope, error: migrationErr });
|
|
299
308
|
}
|
|
300
309
|
return current;
|
|
301
310
|
}
|
|
@@ -307,13 +316,22 @@ function runMigrations(data, fromVersion, toVersion, migrations, key, scope) {
|
|
|
307
316
|
// src/adapters/storage.ts
|
|
308
317
|
function createStorageAdapter(storage, key, options) {
|
|
309
318
|
const { default: defaultValue, version, serialize, persist } = options;
|
|
310
|
-
const listeners =
|
|
319
|
+
const listeners = chunk3YGK3425_cjs.createListeners();
|
|
311
320
|
let cachedRaw;
|
|
312
321
|
let cachedValue;
|
|
313
322
|
let cacheValid = false;
|
|
314
323
|
function parse(raw) {
|
|
315
324
|
if (serialize) {
|
|
316
|
-
|
|
325
|
+
const value = serialize.parse(raw);
|
|
326
|
+
if (options.validate && !options.validate(value)) {
|
|
327
|
+
const scope = options.scope ?? "local";
|
|
328
|
+
const config = chunk3YGK3425_cjs.getConfig();
|
|
329
|
+
chunk3YGK3425_cjs.safeCallConfig(config.onValidationFail, { key, scope, value });
|
|
330
|
+
const validationErr = new ValidationError(key, scope, value);
|
|
331
|
+
chunk3YGK3425_cjs.safeCallConfig(config.onError, { key, scope, error: validationErr });
|
|
332
|
+
return defaultValue;
|
|
333
|
+
}
|
|
334
|
+
return value;
|
|
317
335
|
}
|
|
318
336
|
return readAndMigrate(raw, options, key, options.scope);
|
|
319
337
|
}
|
|
@@ -364,11 +382,11 @@ function createStorageAdapter(storage, key, options) {
|
|
|
364
382
|
const isQuota = e instanceof DOMException && (e.name === "QuotaExceededError" || e.code === 22);
|
|
365
383
|
const scope = options.scope ?? "local";
|
|
366
384
|
const writeErr = new StorageWriteError(key, scope, e, isQuota);
|
|
367
|
-
|
|
385
|
+
chunk3YGK3425_cjs.log("error", writeErr.message);
|
|
368
386
|
if (isQuota) {
|
|
369
|
-
|
|
387
|
+
chunk3YGK3425_cjs.safeCallConfig(chunk3YGK3425_cjs.getConfig().onQuotaExceeded, { key, scope, error: writeErr });
|
|
370
388
|
}
|
|
371
|
-
|
|
389
|
+
chunk3YGK3425_cjs.reportError(key, scope, writeErr);
|
|
372
390
|
}
|
|
373
391
|
}
|
|
374
392
|
let lastNotifiedValue = defaultValue;
|
|
@@ -445,7 +463,7 @@ function parseQuota(quota) {
|
|
|
445
463
|
function createBucketAdapter(key, bucketOptions, options) {
|
|
446
464
|
const { default: defaultValue } = options;
|
|
447
465
|
const fallbackScope = bucketOptions.fallback ?? "local";
|
|
448
|
-
const listeners =
|
|
466
|
+
const listeners = chunk3YGK3425_cjs.createListeners();
|
|
449
467
|
let lastNotifiedValue = defaultValue;
|
|
450
468
|
const notifyListeners = () => listeners.notify(lastNotifiedValue);
|
|
451
469
|
const fallbackStorage = fallbackScope === "session" ? sessionStorage : localStorage;
|
|
@@ -464,7 +482,7 @@ function createBucketAdapter(key, bucketOptions, options) {
|
|
|
464
482
|
if (parsed != null) {
|
|
465
483
|
openOptions.expires = parsed;
|
|
466
484
|
} else {
|
|
467
|
-
|
|
485
|
+
chunk3YGK3425_cjs.log(
|
|
468
486
|
"warn",
|
|
469
487
|
`Invalid bucket expires format: "${bucketOptions.expires}". Expected a number or a string like "7d", "24h", "30m".`
|
|
470
488
|
);
|
|
@@ -475,7 +493,7 @@ function createBucketAdapter(key, bucketOptions, options) {
|
|
|
475
493
|
if (parsed != null) {
|
|
476
494
|
openOptions.quota = parsed;
|
|
477
495
|
} else {
|
|
478
|
-
|
|
496
|
+
chunk3YGK3425_cjs.log(
|
|
479
497
|
"warn",
|
|
480
498
|
`Invalid bucket quota format: "${bucketOptions.quota}". Expected a number or a string like "10mb", "50kb", "1gb".`
|
|
481
499
|
);
|
|
@@ -496,17 +514,17 @@ function createBucketAdapter(key, bucketOptions, options) {
|
|
|
496
514
|
}
|
|
497
515
|
const bucketValue = delegate.get();
|
|
498
516
|
if (hadUserWrite && shallowEqual(bucketValue, defaultValue)) {
|
|
499
|
-
|
|
517
|
+
chunk3YGK3425_cjs.safeCallConfig(chunk3YGK3425_cjs.getConfig().onExpire, { key, scope: "bucket", expiredAt: Date.now() });
|
|
500
518
|
}
|
|
501
519
|
if (hadUserWrite) {
|
|
502
520
|
delegate.set(currentValue);
|
|
503
521
|
}
|
|
504
522
|
} catch (err) {
|
|
505
|
-
|
|
523
|
+
chunk3YGK3425_cjs.log(
|
|
506
524
|
"warn",
|
|
507
525
|
`Storage Bucket initialization failed for key "${key}" \u2014 using ${fallbackScope} fallback.`
|
|
508
526
|
);
|
|
509
|
-
|
|
527
|
+
chunk3YGK3425_cjs.reportError(key, "bucket", err);
|
|
510
528
|
}
|
|
511
529
|
if (isDestroyed) return;
|
|
512
530
|
const storedValue = delegate.get();
|
|
@@ -545,7 +563,7 @@ function createMemoryAdapter(defaultValue) {
|
|
|
545
563
|
const listeners = /* @__PURE__ */ new Set();
|
|
546
564
|
const notifyListeners = () => {
|
|
547
565
|
for (const listener of listeners) {
|
|
548
|
-
|
|
566
|
+
chunk3YGK3425_cjs.safeCall(listener, current);
|
|
549
567
|
}
|
|
550
568
|
};
|
|
551
569
|
return {
|
|
@@ -578,13 +596,13 @@ function withSync(adapter, key, scope) {
|
|
|
578
596
|
channel = new BroadcastChannel(channelName);
|
|
579
597
|
} catch (err) {
|
|
580
598
|
const syncErr = new SyncError(key, scope ?? "local", err);
|
|
581
|
-
|
|
599
|
+
chunk3YGK3425_cjs.log("warn", `Failed to create BroadcastChannel for key "${key}" \u2014 cross-tab sync disabled.`);
|
|
582
600
|
if (scope) {
|
|
583
|
-
|
|
601
|
+
chunk3YGK3425_cjs.reportError(key, scope, syncErr);
|
|
584
602
|
}
|
|
585
603
|
}
|
|
586
604
|
}
|
|
587
|
-
const listeners =
|
|
605
|
+
const listeners = chunk3YGK3425_cjs.createListeners();
|
|
588
606
|
let isDestroyed = false;
|
|
589
607
|
const unsubscribeAdapter = adapter.subscribe((value) => {
|
|
590
608
|
listeners.notify(value);
|
|
@@ -599,13 +617,13 @@ function withSync(adapter, key, scope) {
|
|
|
599
617
|
try {
|
|
600
618
|
adapter.set(value);
|
|
601
619
|
if (scope) {
|
|
602
|
-
|
|
620
|
+
chunk3YGK3425_cjs.safeCallConfig(chunk3YGK3425_cjs.getConfig().onSync, { key, scope, value, source: "remote" });
|
|
603
621
|
}
|
|
604
622
|
} catch (err) {
|
|
605
623
|
const syncErr = new SyncError(key, scope ?? "local", err);
|
|
606
|
-
|
|
624
|
+
chunk3YGK3425_cjs.log("error", syncErr.message);
|
|
607
625
|
if (scope) {
|
|
608
|
-
|
|
626
|
+
chunk3YGK3425_cjs.reportError(key, scope, syncErr);
|
|
609
627
|
}
|
|
610
628
|
}
|
|
611
629
|
};
|
|
@@ -624,9 +642,9 @@ function withSync(adapter, key, scope) {
|
|
|
624
642
|
channel.postMessage({ value });
|
|
625
643
|
} catch (err) {
|
|
626
644
|
const syncErr = new SyncError(key, scope ?? "local", err);
|
|
627
|
-
|
|
645
|
+
chunk3YGK3425_cjs.log("error", syncErr.message);
|
|
628
646
|
if (scope) {
|
|
629
|
-
|
|
647
|
+
chunk3YGK3425_cjs.reportError(key, scope, syncErr);
|
|
630
648
|
}
|
|
631
649
|
}
|
|
632
650
|
}
|
|
@@ -648,11 +666,11 @@ function withSync(adapter, key, scope) {
|
|
|
648
666
|
}
|
|
649
667
|
|
|
650
668
|
// src/adapters/url.ts
|
|
651
|
-
function createUrlAdapter(key, defaultValue, serializer, persist) {
|
|
669
|
+
function createUrlAdapter(key, defaultValue, serializer, persist, urlReplace) {
|
|
652
670
|
if (typeof window === "undefined") {
|
|
653
671
|
throw new Error("[gjendje] URL scope is not available in this environment.");
|
|
654
672
|
}
|
|
655
|
-
const listeners =
|
|
673
|
+
const listeners = chunk3YGK3425_cjs.createListeners();
|
|
656
674
|
const defaultSerialized = serializer.stringify(defaultValue);
|
|
657
675
|
let cachedSearch;
|
|
658
676
|
let cachedValue = defaultValue;
|
|
@@ -688,7 +706,11 @@ function createUrlAdapter(key, defaultValue, serializer, persist) {
|
|
|
688
706
|
}
|
|
689
707
|
const search = params.toString();
|
|
690
708
|
const newUrl = search ? `${window.location.pathname}?${search}${window.location.hash}` : `${window.location.pathname}${window.location.hash}`;
|
|
691
|
-
|
|
709
|
+
if (urlReplace) {
|
|
710
|
+
window.history.replaceState(null, "", newUrl);
|
|
711
|
+
} else {
|
|
712
|
+
window.history.pushState(null, "", newUrl);
|
|
713
|
+
}
|
|
692
714
|
cachedSearch = search ? `?${search}` : "";
|
|
693
715
|
cachedValue = persist ? mergeKeys(toStore, defaultValue, persist) : value;
|
|
694
716
|
} catch {
|
|
@@ -777,7 +799,8 @@ function resolveAdapter(storageKey, scope, options) {
|
|
|
777
799
|
storageKey,
|
|
778
800
|
options.default,
|
|
779
801
|
options.serialize ?? { stringify: JSON.stringify, parse: JSON.parse },
|
|
780
|
-
options.persist
|
|
802
|
+
options.persist,
|
|
803
|
+
options.urlReplace
|
|
781
804
|
);
|
|
782
805
|
case "server":
|
|
783
806
|
if (!_serverAdapterFactory) {
|
|
@@ -846,11 +869,11 @@ var StateImpl = class {
|
|
|
846
869
|
next = interceptor(next, prev);
|
|
847
870
|
}
|
|
848
871
|
} catch (err) {
|
|
849
|
-
|
|
872
|
+
chunk3YGK3425_cjs.reportError(this.key, this.scope, err);
|
|
850
873
|
throw err;
|
|
851
874
|
}
|
|
852
875
|
if (!Object.is(original, next)) {
|
|
853
|
-
|
|
876
|
+
chunk3YGK3425_cjs.safeCallConfig(this._config.onIntercept, {
|
|
854
877
|
key: this.key,
|
|
855
878
|
scope: this.scope,
|
|
856
879
|
original,
|
|
@@ -863,10 +886,10 @@ var StateImpl = class {
|
|
|
863
886
|
const s = this._s;
|
|
864
887
|
if (s.changeHandlers !== void 0 && s.changeHandlers.size > 0) {
|
|
865
888
|
for (const hook of s.changeHandlers) {
|
|
866
|
-
|
|
889
|
+
chunk3YGK3425_cjs.safeCallChange(hook, next, prev);
|
|
867
890
|
}
|
|
868
891
|
}
|
|
869
|
-
|
|
892
|
+
chunk3YGK3425_cjs.safeCallConfig(this._config.onChange, {
|
|
870
893
|
key: this.key,
|
|
871
894
|
scope: this.scope,
|
|
872
895
|
value: next,
|
|
@@ -897,7 +920,7 @@ var StateImpl = class {
|
|
|
897
920
|
s.lastValue = next;
|
|
898
921
|
this._adapter.set(next);
|
|
899
922
|
s.settled = this._adapter.ready;
|
|
900
|
-
|
|
923
|
+
chunk3YGK3425_cjs.safeCallConfig(this._config.onReset, { key: this.key, scope: this.scope, previousValue: prev });
|
|
901
924
|
this._notifyChange(next, prev);
|
|
902
925
|
}
|
|
903
926
|
get ready() {
|
|
@@ -953,7 +976,7 @@ var StateImpl = class {
|
|
|
953
976
|
if (Object.hasOwn(prevRec, key)) {
|
|
954
977
|
filtered[key] = partialRec[key];
|
|
955
978
|
} else {
|
|
956
|
-
|
|
979
|
+
chunk3YGK3425_cjs.log("warn", `patch("${this.key}") ignored unknown key "${key}" (strict mode).`);
|
|
957
980
|
}
|
|
958
981
|
}
|
|
959
982
|
return { ...prev, ...filtered };
|
|
@@ -971,8 +994,8 @@ var StateImpl = class {
|
|
|
971
994
|
s.watchers?.clear();
|
|
972
995
|
s.watchUnsub?.();
|
|
973
996
|
this._adapter.destroy?.();
|
|
974
|
-
|
|
975
|
-
|
|
997
|
+
chunk3YGK3425_cjs.unregisterByKey(this._rKey);
|
|
998
|
+
chunk3YGK3425_cjs.safeCallConfig(this._config.onDestroy, { key: this.key, scope: this.scope });
|
|
976
999
|
if (s.resolveDestroyed) {
|
|
977
1000
|
s.resolveDestroyed();
|
|
978
1001
|
} else {
|
|
@@ -1049,11 +1072,11 @@ var MemoryStateImpl = class {
|
|
|
1049
1072
|
next = interceptor(next, prev);
|
|
1050
1073
|
}
|
|
1051
1074
|
} catch (err) {
|
|
1052
|
-
|
|
1075
|
+
chunk3YGK3425_cjs.reportError(this.key, this.scope, err);
|
|
1053
1076
|
throw err;
|
|
1054
1077
|
}
|
|
1055
1078
|
if (!Object.is(original, next)) {
|
|
1056
|
-
|
|
1079
|
+
chunk3YGK3425_cjs.safeCallConfig(this._config.onIntercept, {
|
|
1057
1080
|
key: this.key,
|
|
1058
1081
|
scope: this.scope,
|
|
1059
1082
|
original,
|
|
@@ -1068,10 +1091,10 @@ var MemoryStateImpl = class {
|
|
|
1068
1091
|
}
|
|
1069
1092
|
if (ext !== void 0 && ext.changeHandlers !== void 0 && ext.changeHandlers.size > 0) {
|
|
1070
1093
|
for (const hook of ext.changeHandlers) {
|
|
1071
|
-
|
|
1094
|
+
chunk3YGK3425_cjs.safeCallChange(hook, next, prev);
|
|
1072
1095
|
}
|
|
1073
1096
|
}
|
|
1074
|
-
|
|
1097
|
+
chunk3YGK3425_cjs.safeCallConfig(this._config.onChange, {
|
|
1075
1098
|
key: this.key,
|
|
1076
1099
|
scope: this.scope,
|
|
1077
1100
|
value: next,
|
|
@@ -1085,7 +1108,7 @@ var MemoryStateImpl = class {
|
|
|
1085
1108
|
c.listeners = listeners;
|
|
1086
1109
|
c.notifyFn = () => {
|
|
1087
1110
|
for (const l of listeners) {
|
|
1088
|
-
|
|
1111
|
+
chunk3YGK3425_cjs.safeCall(l, c.current);
|
|
1089
1112
|
}
|
|
1090
1113
|
};
|
|
1091
1114
|
}
|
|
@@ -1108,11 +1131,11 @@ var MemoryStateImpl = class {
|
|
|
1108
1131
|
next = interceptor(next, prev);
|
|
1109
1132
|
}
|
|
1110
1133
|
} catch (err) {
|
|
1111
|
-
|
|
1134
|
+
chunk3YGK3425_cjs.reportError(this.key, this.scope, err);
|
|
1112
1135
|
throw err;
|
|
1113
1136
|
}
|
|
1114
1137
|
if (!Object.is(original, next)) {
|
|
1115
|
-
|
|
1138
|
+
chunk3YGK3425_cjs.safeCallConfig(this._config.onIntercept, {
|
|
1116
1139
|
key: this.key,
|
|
1117
1140
|
scope: this.scope,
|
|
1118
1141
|
original,
|
|
@@ -1127,11 +1150,11 @@ var MemoryStateImpl = class {
|
|
|
1127
1150
|
}
|
|
1128
1151
|
if (ext !== void 0 && ext.changeHandlers !== void 0 && ext.changeHandlers.size > 0) {
|
|
1129
1152
|
for (const hook of ext.changeHandlers) {
|
|
1130
|
-
|
|
1153
|
+
chunk3YGK3425_cjs.safeCallChange(hook, next, prev);
|
|
1131
1154
|
}
|
|
1132
1155
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1156
|
+
chunk3YGK3425_cjs.safeCallConfig(this._config.onReset, { key: this.key, scope: this.scope, previousValue: prev });
|
|
1157
|
+
chunk3YGK3425_cjs.safeCallConfig(this._config.onChange, {
|
|
1135
1158
|
key: this.key,
|
|
1136
1159
|
scope: this.scope,
|
|
1137
1160
|
value: next,
|
|
@@ -1192,7 +1215,7 @@ var MemoryStateImpl = class {
|
|
|
1192
1215
|
if (Object.hasOwn(prevRec, key)) {
|
|
1193
1216
|
filtered[key] = partialRec[key];
|
|
1194
1217
|
} else {
|
|
1195
|
-
|
|
1218
|
+
chunk3YGK3425_cjs.log("warn", `patch("${this.key}") ignored unknown key "${key}" (strict mode).`);
|
|
1196
1219
|
}
|
|
1197
1220
|
}
|
|
1198
1221
|
return { ...prev, ...filtered };
|
|
@@ -1227,8 +1250,8 @@ var MemoryStateImpl = class {
|
|
|
1227
1250
|
}
|
|
1228
1251
|
c.listeners?.clear();
|
|
1229
1252
|
c.notifyFn = void 0;
|
|
1230
|
-
if (this._rKey)
|
|
1231
|
-
|
|
1253
|
+
if (this._rKey) chunk3YGK3425_cjs.unregisterByKey(this._rKey);
|
|
1254
|
+
chunk3YGK3425_cjs.safeCallConfig(this._config.onDestroy, { key: this.key, scope: this.scope });
|
|
1232
1255
|
if (ext?.resolveDestroyed) {
|
|
1233
1256
|
ext.resolveDestroyed();
|
|
1234
1257
|
} else if (ext !== void 0) {
|
|
@@ -1240,7 +1263,7 @@ function createBase(key, options) {
|
|
|
1240
1263
|
if (!key) {
|
|
1241
1264
|
throw new Error("[gjendje] key must be a non-empty string.");
|
|
1242
1265
|
}
|
|
1243
|
-
const config =
|
|
1266
|
+
const config = chunk3YGK3425_cjs.getConfig();
|
|
1244
1267
|
if (config.keyPattern && !config.keyPattern.test(key)) {
|
|
1245
1268
|
throw new Error(
|
|
1246
1269
|
`[gjendje] Key "${key}" does not match the configured keyPattern ${config.keyPattern}.`
|
|
@@ -1250,7 +1273,7 @@ function createBase(key, options) {
|
|
|
1250
1273
|
const scope = rawScope === "render" ? "memory" : rawScope;
|
|
1251
1274
|
if (scope === "memory") {
|
|
1252
1275
|
if (options.sync || config.sync) {
|
|
1253
|
-
|
|
1276
|
+
chunk3YGK3425_cjs.log(
|
|
1254
1277
|
"warn",
|
|
1255
1278
|
`sync: true is ignored for scope "memory". Only "local" and "bucket" scopes support cross-tab sync.`
|
|
1256
1279
|
);
|
|
@@ -1258,27 +1281,27 @@ function createBase(key, options) {
|
|
|
1258
1281
|
if (config.registry === false) {
|
|
1259
1282
|
return new MemoryStateImpl(key, "", options, config);
|
|
1260
1283
|
}
|
|
1261
|
-
const rKey2 =
|
|
1262
|
-
const existing2 =
|
|
1284
|
+
const rKey2 = chunk3YGK3425_cjs.scopedKey(key, scope);
|
|
1285
|
+
const existing2 = chunk3YGK3425_cjs.getRegistered(rKey2);
|
|
1263
1286
|
if (existing2 && !existing2.isDestroyed) {
|
|
1264
1287
|
if (config.warnOnDuplicate) {
|
|
1265
|
-
|
|
1288
|
+
chunk3YGK3425_cjs.log("warn", `Duplicate state("${key}") with scope "${scope}". Returning cached instance.`);
|
|
1266
1289
|
}
|
|
1267
1290
|
return existing2;
|
|
1268
1291
|
}
|
|
1269
1292
|
const instance2 = new MemoryStateImpl(key, rKey2, options, config);
|
|
1270
|
-
|
|
1293
|
+
chunk3YGK3425_cjs.registerNew(rKey2, key, scope, instance2, config, existing2);
|
|
1271
1294
|
return instance2;
|
|
1272
1295
|
}
|
|
1273
|
-
const rKey =
|
|
1274
|
-
const existing =
|
|
1296
|
+
const rKey = chunk3YGK3425_cjs.scopedKey(key, scope);
|
|
1297
|
+
const existing = chunk3YGK3425_cjs.getRegistered(rKey);
|
|
1275
1298
|
if (existing && !existing.isDestroyed) {
|
|
1276
1299
|
if (config.warnOnDuplicate) {
|
|
1277
|
-
|
|
1300
|
+
chunk3YGK3425_cjs.log("warn", `Duplicate state("${key}") with scope "${scope}". Returning cached instance.`);
|
|
1278
1301
|
}
|
|
1279
1302
|
return existing;
|
|
1280
1303
|
}
|
|
1281
|
-
if (config.requireValidation &&
|
|
1304
|
+
if (config.requireValidation && chunk3YGK3425_cjs.PERSISTENT_SCOPES.has(scope) && !options.validate) {
|
|
1282
1305
|
throw new Error(
|
|
1283
1306
|
`[gjendje] A validate function is required for persisted scope "${scope}" on state("${key}"). Set requireValidation: false in configure() to disable.`
|
|
1284
1307
|
);
|
|
@@ -1287,7 +1310,7 @@ function createBase(key, options) {
|
|
|
1287
1310
|
const useMemoryFallback = isSsrMode && isServer();
|
|
1288
1311
|
const effectiveSync = options.sync ?? (config.sync && SYNCABLE_SCOPES.has(scope));
|
|
1289
1312
|
if (effectiveSync && !SYNCABLE_SCOPES.has(scope)) {
|
|
1290
|
-
|
|
1313
|
+
chunk3YGK3425_cjs.log(
|
|
1291
1314
|
"warn",
|
|
1292
1315
|
`sync: true is ignored for scope "${scope}". Only "local" and "bucket" scopes support cross-tab sync.`
|
|
1293
1316
|
);
|
|
@@ -1310,22 +1333,22 @@ function createBase(key, options) {
|
|
|
1310
1333
|
if (!shallowEqual(storedValue, options.default)) {
|
|
1311
1334
|
instance.set(storedValue);
|
|
1312
1335
|
}
|
|
1313
|
-
|
|
1336
|
+
chunk3YGK3425_cjs.safeCallConfig(config.onHydrate, {
|
|
1314
1337
|
key,
|
|
1315
1338
|
scope,
|
|
1316
1339
|
serverValue: options.default,
|
|
1317
1340
|
clientValue: storedValue
|
|
1318
1341
|
});
|
|
1319
1342
|
} catch (err) {
|
|
1320
|
-
|
|
1343
|
+
chunk3YGK3425_cjs.log("debug", `Hydration adapter unavailable for state("${key}") \u2014 using memory fallback.`);
|
|
1321
1344
|
const hydrationErr = new HydrationError(key, scope, err);
|
|
1322
|
-
|
|
1345
|
+
chunk3YGK3425_cjs.reportError(key, scope, hydrationErr);
|
|
1323
1346
|
} finally {
|
|
1324
1347
|
realAdapter?.destroy?.();
|
|
1325
1348
|
}
|
|
1326
1349
|
});
|
|
1327
1350
|
}
|
|
1328
|
-
|
|
1351
|
+
chunk3YGK3425_cjs.registerNew(rKey, key, scope, instance, config, existing);
|
|
1329
1352
|
return instance;
|
|
1330
1353
|
}
|
|
1331
1354
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { safeCall, getConfig, log, scopedKey, getRegistered, registerNew, PERSISTENT_SCOPES, reportError, safeCallConfig, safeCallChange, unregisterByKey, createListeners } from './chunk-
|
|
1
|
+
import { safeCall, getConfig, log, scopedKey, getRegistered, registerNew, PERSISTENT_SCOPES, reportError, safeCallConfig, safeCallChange, unregisterByKey, createListeners } from './chunk-YPT6TO4H.js';
|
|
2
2
|
|
|
3
3
|
// src/batch.ts
|
|
4
4
|
var depth = 0;
|
|
@@ -24,8 +24,17 @@ function notify(fn) {
|
|
|
24
24
|
}
|
|
25
25
|
fn();
|
|
26
26
|
}
|
|
27
|
+
var MAX_FLUSH_ITERATIONS = 100;
|
|
27
28
|
function flush() {
|
|
29
|
+
let iterations = 0;
|
|
28
30
|
while (queue.length > 0) {
|
|
31
|
+
if (++iterations > MAX_FLUSH_ITERATIONS) {
|
|
32
|
+
console.error(
|
|
33
|
+
"[gjendje] Batch flush exceeded maximum iterations \u2014 possible infinite loop. Remaining queued notifications have been dropped."
|
|
34
|
+
);
|
|
35
|
+
queue = [];
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
29
38
|
generation++;
|
|
30
39
|
const current = queue;
|
|
31
40
|
queue = [];
|
|
@@ -311,7 +320,16 @@ function createStorageAdapter(storage, key, options) {
|
|
|
311
320
|
let cacheValid = false;
|
|
312
321
|
function parse(raw) {
|
|
313
322
|
if (serialize) {
|
|
314
|
-
|
|
323
|
+
const value = serialize.parse(raw);
|
|
324
|
+
if (options.validate && !options.validate(value)) {
|
|
325
|
+
const scope = options.scope ?? "local";
|
|
326
|
+
const config = getConfig();
|
|
327
|
+
safeCallConfig(config.onValidationFail, { key, scope, value });
|
|
328
|
+
const validationErr = new ValidationError(key, scope, value);
|
|
329
|
+
safeCallConfig(config.onError, { key, scope, error: validationErr });
|
|
330
|
+
return defaultValue;
|
|
331
|
+
}
|
|
332
|
+
return value;
|
|
315
333
|
}
|
|
316
334
|
return readAndMigrate(raw, options, key, options.scope);
|
|
317
335
|
}
|
|
@@ -646,7 +664,7 @@ function withSync(adapter, key, scope) {
|
|
|
646
664
|
}
|
|
647
665
|
|
|
648
666
|
// src/adapters/url.ts
|
|
649
|
-
function createUrlAdapter(key, defaultValue, serializer, persist) {
|
|
667
|
+
function createUrlAdapter(key, defaultValue, serializer, persist, urlReplace) {
|
|
650
668
|
if (typeof window === "undefined") {
|
|
651
669
|
throw new Error("[gjendje] URL scope is not available in this environment.");
|
|
652
670
|
}
|
|
@@ -686,7 +704,11 @@ function createUrlAdapter(key, defaultValue, serializer, persist) {
|
|
|
686
704
|
}
|
|
687
705
|
const search = params.toString();
|
|
688
706
|
const newUrl = search ? `${window.location.pathname}?${search}${window.location.hash}` : `${window.location.pathname}${window.location.hash}`;
|
|
689
|
-
|
|
707
|
+
if (urlReplace) {
|
|
708
|
+
window.history.replaceState(null, "", newUrl);
|
|
709
|
+
} else {
|
|
710
|
+
window.history.pushState(null, "", newUrl);
|
|
711
|
+
}
|
|
690
712
|
cachedSearch = search ? `?${search}` : "";
|
|
691
713
|
cachedValue = persist ? mergeKeys(toStore, defaultValue, persist) : value;
|
|
692
714
|
} catch {
|
|
@@ -775,7 +797,8 @@ function resolveAdapter(storageKey, scope, options) {
|
|
|
775
797
|
storageKey,
|
|
776
798
|
options.default,
|
|
777
799
|
options.serialize ?? { stringify: JSON.stringify, parse: JSON.parse },
|
|
778
|
-
options.persist
|
|
800
|
+
options.persist,
|
|
801
|
+
options.urlReplace
|
|
779
802
|
);
|
|
780
803
|
case "server":
|
|
781
804
|
if (!_serverAdapterFactory) {
|
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
var globalConfig = {};
|
|
3
3
|
var PERSISTENT_SCOPES = /* @__PURE__ */ new Set(["local", "session", "bucket"]);
|
|
4
4
|
function configure(config) {
|
|
5
|
-
|
|
5
|
+
for (const key of Object.keys(config)) {
|
|
6
|
+
const value = config[key];
|
|
7
|
+
if (value === void 0) {
|
|
8
|
+
delete globalConfig[key];
|
|
9
|
+
} else {
|
|
10
|
+
globalConfig[key] = value;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
6
13
|
if (globalConfig.registry === false && globalConfig.scope && PERSISTENT_SCOPES.has(globalConfig.scope)) {
|
|
7
14
|
log(
|
|
8
15
|
"warn",
|
|
@@ -10,6 +17,9 @@ function configure(config) {
|
|
|
10
17
|
);
|
|
11
18
|
}
|
|
12
19
|
}
|
|
20
|
+
function resetConfig() {
|
|
21
|
+
globalConfig = {};
|
|
22
|
+
}
|
|
13
23
|
function getConfig() {
|
|
14
24
|
return globalConfig;
|
|
15
25
|
}
|
|
@@ -100,5 +110,14 @@ function unregisterByKey(rKey) {
|
|
|
100
110
|
function getRegistry() {
|
|
101
111
|
return registry;
|
|
102
112
|
}
|
|
113
|
+
function destroyAll() {
|
|
114
|
+
const instances = [...registry.values()];
|
|
115
|
+
for (const instance of instances) {
|
|
116
|
+
if (!instance.isDestroyed) {
|
|
117
|
+
instance.destroy();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
registry.clear();
|
|
121
|
+
}
|
|
103
122
|
|
|
104
|
-
export { PERSISTENT_SCOPES, configure, createListeners, getConfig, getRegistered, getRegistry, log, registerNew, reportError, safeCall, safeCallChange, safeCallConfig, scopedKey, unregisterByKey };
|
|
123
|
+
export { PERSISTENT_SCOPES, configure, createListeners, destroyAll, getConfig, getRegistered, getRegistry, log, registerNew, reportError, resetConfig, safeCall, safeCallChange, safeCallConfig, scopedKey, unregisterByKey };
|