gjendje 1.2.0 → 1.2.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/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  # gjendje
4
4
 
5
- ![NPM Last Update](https://img.shields.io/npm/last-update/gjendje)
6
5
  ![NPM Version](https://img.shields.io/npm/v/gjendje)
6
+ ![NPM Last Update](https://img.shields.io/npm/last-update/gjendje)
7
7
  ![GitHub License](https://img.shields.io/github/license/charliebeckstrand/gjendje)
8
8
 
9
9
  gjendje is a storage-agnostic state management library for TypeScript and JavaScript. It gives you a single, unified API for reactive state — regardless of where that state lives.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkPEC73EEB_cjs = require('./chunk-PEC73EEB.cjs');
3
+ var chunk7LC5PRFD_cjs = require('./chunk-7LC5PRFD.cjs');
4
4
 
5
5
  // src/batch.ts
6
6
  var depth = 0;
@@ -184,7 +184,7 @@ function readAndMigrate(raw, options, key, scope) {
184
184
  if (storedVersion < currentVersion && options.migrate) {
185
185
  data = runMigrations(data, storedVersion, currentVersion, options.migrate);
186
186
  if (key && scope) {
187
- chunkPEC73EEB_cjs.getConfig().onMigrate?.({
187
+ chunk7LC5PRFD_cjs.getConfig().onMigrate?.({
188
188
  key,
189
189
  scope,
190
190
  fromVersion: storedVersion,
@@ -195,13 +195,13 @@ function readAndMigrate(raw, options, key, scope) {
195
195
  }
196
196
  if (options.validate && !options.validate(data)) {
197
197
  if (key && scope) {
198
- chunkPEC73EEB_cjs.getConfig().onValidationFail?.({ key, scope, value: data });
198
+ chunk7LC5PRFD_cjs.getConfig().onValidationFail?.({ key, scope, value: data });
199
199
  }
200
200
  return defaultValue;
201
201
  }
202
202
  return data;
203
203
  } catch {
204
- chunkPEC73EEB_cjs.log("debug", `Failed to read/migrate stored value \u2014 falling back to default.`);
204
+ chunk7LC5PRFD_cjs.log("debug", `Failed to read/migrate stored value \u2014 falling back to default.`);
205
205
  return defaultValue;
206
206
  }
207
207
  }
@@ -229,7 +229,7 @@ function mergeKeys(stored, defaultValue, keys) {
229
229
  var MAX_MIGRATION_STEPS = 1e3;
230
230
  function runMigrations(data, fromVersion, toVersion, migrations) {
231
231
  if (fromVersion < 0 || toVersion - fromVersion > MAX_MIGRATION_STEPS) {
232
- chunkPEC73EEB_cjs.log("warn", `Migration range v${fromVersion}\u2192v${toVersion} is out of bounds \u2014 skipping.`);
232
+ chunk7LC5PRFD_cjs.log("warn", `Migration range v${fromVersion}\u2192v${toVersion} is out of bounds \u2014 skipping.`);
233
233
  return data;
234
234
  }
235
235
  let current = data;
@@ -239,7 +239,7 @@ function runMigrations(data, fromVersion, toVersion, migrations) {
239
239
  try {
240
240
  current = migrateFn(current);
241
241
  } catch {
242
- chunkPEC73EEB_cjs.log("warn", `Migration from v${v} failed \u2014 returning partially migrated value.`);
242
+ chunk7LC5PRFD_cjs.log("warn", `Migration from v${v} failed \u2014 returning partially migrated value.`);
243
243
  return current;
244
244
  }
245
245
  }
@@ -253,6 +253,7 @@ function createStorageAdapter(storage, key, options) {
253
253
  const listeners = createListeners();
254
254
  let cachedRaw;
255
255
  let cachedValue;
256
+ let cacheValid = false;
256
257
  function parse(raw) {
257
258
  if (serialize) {
258
259
  return serialize.parse(raw);
@@ -260,25 +261,32 @@ function createStorageAdapter(storage, key, options) {
260
261
  return readAndMigrate(raw, options, key, options.scope);
261
262
  }
262
263
  function read() {
264
+ if (cacheValid) return cachedValue;
263
265
  try {
264
266
  const raw = storage.getItem(key);
265
267
  if (raw === null) {
266
268
  cachedRaw = null;
267
- cachedValue = void 0;
269
+ cachedValue = defaultValue;
270
+ cacheValid = true;
268
271
  return defaultValue;
269
272
  }
270
- if (raw === cachedRaw) return cachedValue;
273
+ if (raw === cachedRaw) {
274
+ cacheValid = true;
275
+ return cachedValue;
276
+ }
271
277
  let value;
272
278
  try {
273
279
  value = parse(raw);
274
280
  } catch {
275
281
  cachedRaw = void 0;
276
282
  cachedValue = void 0;
283
+ cacheValid = false;
277
284
  return defaultValue;
278
285
  }
279
286
  value = mergeKeys(value, defaultValue, persist);
280
287
  cachedRaw = raw;
281
288
  cachedValue = value;
289
+ cacheValid = true;
282
290
  return value;
283
291
  } catch {
284
292
  return defaultValue;
@@ -291,16 +299,18 @@ function createStorageAdapter(storage, key, options) {
291
299
  storage.setItem(key, raw);
292
300
  cachedRaw = raw;
293
301
  cachedValue = persist ? mergeKeys(toStore, defaultValue, persist) : value;
302
+ cacheValid = true;
294
303
  } catch (e) {
295
304
  cachedRaw = void 0;
296
305
  cachedValue = void 0;
297
- chunkPEC73EEB_cjs.log(
306
+ cacheValid = false;
307
+ chunk7LC5PRFD_cjs.log(
298
308
  "error",
299
309
  `Failed to write key "${key}" to storage: ${e instanceof Error ? e.message : String(e)}`
300
310
  );
301
311
  const isQuotaError = e instanceof DOMException && (e.name === "QuotaExceededError" || e.code === 22);
302
312
  if (isQuotaError && options.scope) {
303
- chunkPEC73EEB_cjs.getConfig().onQuotaExceeded?.({ key, scope: options.scope, error: e });
313
+ chunk7LC5PRFD_cjs.getConfig().onQuotaExceeded?.({ key, scope: options.scope, error: e });
304
314
  }
305
315
  }
306
316
  }
@@ -310,6 +320,7 @@ function createStorageAdapter(storage, key, options) {
310
320
  if (event.storageArea !== storage || event.key !== key) return;
311
321
  cachedRaw = void 0;
312
322
  cachedValue = void 0;
323
+ cacheValid = false;
313
324
  lastNotifiedValue = read();
314
325
  notify(notifyListeners);
315
326
  }
@@ -330,6 +341,7 @@ function createStorageAdapter(storage, key, options) {
330
341
  destroy() {
331
342
  cachedRaw = void 0;
332
343
  cachedValue = void 0;
344
+ cacheValid = false;
333
345
  listeners.clear();
334
346
  if (typeof window !== "undefined") {
335
347
  window.removeEventListener("storage", onStorageEvent);
@@ -395,7 +407,7 @@ function createBucketAdapter(key, bucketOptions, options) {
395
407
  if (parsed != null) {
396
408
  openOptions.expires = parsed;
397
409
  } else {
398
- chunkPEC73EEB_cjs.log(
410
+ chunk7LC5PRFD_cjs.log(
399
411
  "warn",
400
412
  `Invalid bucket expires format: "${bucketOptions.expires}". Expected a number or a string like "7d", "24h", "30m".`
401
413
  );
@@ -406,7 +418,7 @@ function createBucketAdapter(key, bucketOptions, options) {
406
418
  if (parsed != null) {
407
419
  openOptions.quota = parsed;
408
420
  } else {
409
- chunkPEC73EEB_cjs.log(
421
+ chunk7LC5PRFD_cjs.log(
410
422
  "warn",
411
423
  `Invalid bucket quota format: "${bucketOptions.quota}". Expected a number or a string like "10mb", "50kb", "1gb".`
412
424
  );
@@ -427,7 +439,7 @@ function createBucketAdapter(key, bucketOptions, options) {
427
439
  }
428
440
  const bucketValue = delegate.get();
429
441
  if (hadUserWrite && shallowEqual(bucketValue, defaultValue)) {
430
- chunkPEC73EEB_cjs.getConfig().onExpire?.({ key, scope: "bucket", expiredAt: Date.now() });
442
+ chunk7LC5PRFD_cjs.getConfig().onExpire?.({ key, scope: "bucket", expiredAt: Date.now() });
431
443
  }
432
444
  if (hadUserWrite) {
433
445
  delegate.set(currentValue);
@@ -514,15 +526,15 @@ function withSync(adapter, key, scope) {
514
526
  try {
515
527
  adapter.set(value);
516
528
  if (scope) {
517
- chunkPEC73EEB_cjs.getConfig().onSync?.({ key, scope, value, source: "remote" });
529
+ chunk7LC5PRFD_cjs.getConfig().onSync?.({ key, scope, value, source: "remote" });
518
530
  }
519
531
  } catch (err) {
520
- chunkPEC73EEB_cjs.log(
532
+ chunk7LC5PRFD_cjs.log(
521
533
  "error",
522
534
  `Sync failed for key "${key}": ${err instanceof Error ? err.message : String(err)}`
523
535
  );
524
536
  if (scope) {
525
- chunkPEC73EEB_cjs.reportError(key, scope, err);
537
+ chunk7LC5PRFD_cjs.reportError(key, scope, err);
526
538
  }
527
539
  }
528
540
  };
@@ -654,16 +666,7 @@ var _serverAdapterFactory;
654
666
  function registerServerAdapter(factory) {
655
667
  _serverAdapterFactory = factory;
656
668
  }
657
- var PERSISTENT_SCOPES = /* @__PURE__ */ new Set(["local", "session", "bucket"]);
658
669
  var SYNCABLE_SCOPES = /* @__PURE__ */ new Set(["local", "bucket"]);
659
- var MEMORY_SHIM = {
660
- ready: RESOLVED,
661
- get: () => void 0,
662
- set: () => {
663
- },
664
- subscribe: () => () => {
665
- }
666
- };
667
670
  function resolveStorageKey(key, options, configPrefix) {
668
671
  if (options.prefix === false) return key;
669
672
  const prefix = options.prefix ?? configPrefix;
@@ -671,9 +674,6 @@ function resolveStorageKey(key, options, configPrefix) {
671
674
  }
672
675
  function resolveAdapter(storageKey, scope, options) {
673
676
  switch (scope) {
674
- case "memory":
675
- case "render":
676
- return createMemoryAdapter(options.default);
677
677
  case "session":
678
678
  if (typeof sessionStorage === "undefined") {
679
679
  throw new Error(
@@ -859,7 +859,7 @@ var StateImpl = class {
859
859
  if (Object.hasOwn(prevRec, key)) {
860
860
  filtered[key] = partialRec[key];
861
861
  } else {
862
- chunkPEC73EEB_cjs.log("warn", `patch("${this.key}") ignored unknown key "${key}" (strict mode).`);
862
+ chunk7LC5PRFD_cjs.log("warn", `patch("${this.key}") ignored unknown key "${key}" (strict mode).`);
863
863
  }
864
864
  }
865
865
  return { ...prev, ...filtered };
@@ -877,7 +877,7 @@ var StateImpl = class {
877
877
  s.watchers?.clear();
878
878
  s.watchUnsub?.();
879
879
  this._adapter.destroy?.();
880
- chunkPEC73EEB_cjs.unregisterByKey(this._rKey);
880
+ chunk7LC5PRFD_cjs.unregisterByKey(this._rKey);
881
881
  this._config.onDestroy?.({ key: this.key, scope: this.scope });
882
882
  if (s.resolveDestroyed) {
883
883
  s.resolveDestroyed();
@@ -914,31 +914,20 @@ function getExt(c) {
914
914
  }
915
915
  return c.ext;
916
916
  }
917
- var MEMORY_MUTABLE_SHIM = {
918
- lastValue: void 0,
919
- isDestroyed: false,
920
- interceptors: void 0,
921
- changeHandlers: void 0,
922
- settled: RESOLVED,
923
- resolveDestroyed: void 0,
924
- destroyed: void 0,
925
- hydrated: void 0,
926
- watchers: void 0,
927
- watchUnsub: void 0,
928
- watchPrev: void 0
929
- };
930
- var MemoryStateImpl = class extends StateImpl {
917
+ var MemoryStateImpl = class {
918
+ key;
919
+ scope = "memory";
931
920
  _c;
921
+ _defaultValue;
922
+ _options;
923
+ _config;
924
+ _rKey;
932
925
  constructor(key, rKey, options, config) {
933
- super(
934
- key,
935
- "memory",
936
- rKey,
937
- MEMORY_SHIM,
938
- options,
939
- config,
940
- MEMORY_MUTABLE_SHIM
941
- );
926
+ this.key = key;
927
+ this._rKey = rKey;
928
+ this._defaultValue = options.default;
929
+ this._options = options;
930
+ this._config = config;
942
931
  this._c = {
943
932
  current: options.default,
944
933
  isDestroyed: false,
@@ -1079,6 +1068,24 @@ var MemoryStateImpl = class extends StateImpl {
1079
1068
  this._ensureWatchSubscription();
1080
1069
  return addWatcher(ext.watchers, watchKey, listener);
1081
1070
  }
1071
+ patch(partial, options) {
1072
+ this.set((prev) => {
1073
+ if (options?.strict) {
1074
+ const prevRec = prev;
1075
+ const partialRec = partial;
1076
+ const filtered = {};
1077
+ for (const key of Object.keys(partialRec)) {
1078
+ if (Object.hasOwn(prevRec, key)) {
1079
+ filtered[key] = partialRec[key];
1080
+ } else {
1081
+ chunk7LC5PRFD_cjs.log("warn", `patch("${this.key}") ignored unknown key "${key}" (strict mode).`);
1082
+ }
1083
+ }
1084
+ return { ...prev, ...filtered };
1085
+ }
1086
+ return { ...prev, ...partial };
1087
+ });
1088
+ }
1082
1089
  _ensureWatchSubscription() {
1083
1090
  const ext = getExt(this._c);
1084
1091
  if (ext.watchUnsub) return;
@@ -1106,7 +1113,7 @@ var MemoryStateImpl = class extends StateImpl {
1106
1113
  }
1107
1114
  c.listeners?.clear();
1108
1115
  c.notifyFn = void 0;
1109
- if (this._rKey) chunkPEC73EEB_cjs.unregisterByKey(this._rKey);
1116
+ if (this._rKey) chunk7LC5PRFD_cjs.unregisterByKey(this._rKey);
1110
1117
  this._config.onDestroy?.({ key: this.key, scope: this.scope });
1111
1118
  if (ext?.resolveDestroyed) {
1112
1119
  ext.resolveDestroyed();
@@ -1119,7 +1126,7 @@ function createBase(key, options) {
1119
1126
  if (!key) {
1120
1127
  throw new Error("[gjendje] key must be a non-empty string.");
1121
1128
  }
1122
- const config = chunkPEC73EEB_cjs.getConfig();
1129
+ const config = chunk7LC5PRFD_cjs.getConfig();
1123
1130
  if (config.keyPattern && !config.keyPattern.test(key)) {
1124
1131
  throw new Error(
1125
1132
  `[gjendje] Key "${key}" does not match the configured keyPattern ${config.keyPattern}.`
@@ -1129,7 +1136,7 @@ function createBase(key, options) {
1129
1136
  const scope = rawScope === "render" ? "memory" : rawScope;
1130
1137
  if (scope === "memory") {
1131
1138
  if (options.sync || config.sync) {
1132
- chunkPEC73EEB_cjs.log(
1139
+ chunk7LC5PRFD_cjs.log(
1133
1140
  "warn",
1134
1141
  `sync: true is ignored for scope "memory". Only "local" and "bucket" scopes support cross-tab sync.`
1135
1142
  );
@@ -1137,27 +1144,27 @@ function createBase(key, options) {
1137
1144
  if (config.registry === false) {
1138
1145
  return new MemoryStateImpl(key, "", options, config);
1139
1146
  }
1140
- const rKey2 = chunkPEC73EEB_cjs.scopedKey(key, scope);
1141
- const existing2 = chunkPEC73EEB_cjs.getRegistered(rKey2);
1147
+ const rKey2 = chunk7LC5PRFD_cjs.scopedKey(key, scope);
1148
+ const existing2 = chunk7LC5PRFD_cjs.getRegistered(rKey2);
1142
1149
  if (existing2 && !existing2.isDestroyed) {
1143
1150
  if (config.warnOnDuplicate) {
1144
- chunkPEC73EEB_cjs.log("warn", `Duplicate state("${key}") with scope "${scope}". Returning cached instance.`);
1151
+ chunk7LC5PRFD_cjs.log("warn", `Duplicate state("${key}") with scope "${scope}". Returning cached instance.`);
1145
1152
  }
1146
1153
  return existing2;
1147
1154
  }
1148
1155
  const instance2 = new MemoryStateImpl(key, rKey2, options, config);
1149
- chunkPEC73EEB_cjs.registerNew(rKey2, key, scope, instance2, config, existing2);
1156
+ chunk7LC5PRFD_cjs.registerNew(rKey2, key, scope, instance2, config, existing2);
1150
1157
  return instance2;
1151
1158
  }
1152
- const rKey = chunkPEC73EEB_cjs.scopedKey(key, scope);
1153
- const existing = chunkPEC73EEB_cjs.getRegistered(rKey);
1159
+ const rKey = chunk7LC5PRFD_cjs.scopedKey(key, scope);
1160
+ const existing = chunk7LC5PRFD_cjs.getRegistered(rKey);
1154
1161
  if (existing && !existing.isDestroyed) {
1155
1162
  if (config.warnOnDuplicate) {
1156
- chunkPEC73EEB_cjs.log("warn", `Duplicate state("${key}") with scope "${scope}". Returning cached instance.`);
1163
+ chunk7LC5PRFD_cjs.log("warn", `Duplicate state("${key}") with scope "${scope}". Returning cached instance.`);
1157
1164
  }
1158
1165
  return existing;
1159
1166
  }
1160
- if (config.requireValidation && PERSISTENT_SCOPES.has(scope) && !options.validate) {
1167
+ if (config.requireValidation && chunk7LC5PRFD_cjs.PERSISTENT_SCOPES.has(scope) && !options.validate) {
1161
1168
  throw new Error(
1162
1169
  `[gjendje] A validate function is required for persisted scope "${scope}" on state("${key}"). Set requireValidation: false in configure() to disable.`
1163
1170
  );
@@ -1166,13 +1173,14 @@ function createBase(key, options) {
1166
1173
  const useMemoryFallback = isSsrMode && isServer();
1167
1174
  const effectiveSync = options.sync ?? (config.sync && SYNCABLE_SCOPES.has(scope));
1168
1175
  if (effectiveSync && !SYNCABLE_SCOPES.has(scope)) {
1169
- chunkPEC73EEB_cjs.log(
1176
+ chunk7LC5PRFD_cjs.log(
1170
1177
  "warn",
1171
1178
  `sync: true is ignored for scope "${scope}". Only "local" and "bucket" scopes support cross-tab sync.`
1172
1179
  );
1173
1180
  }
1174
1181
  const storageKey = resolveStorageKey(key, options, config.prefix);
1175
- const baseAdapter = useMemoryFallback ? createMemoryAdapter(options.default) : resolveAdapter(storageKey, scope, options);
1182
+ const nonMemoryScope = scope;
1183
+ const baseAdapter = useMemoryFallback ? createMemoryAdapter(options.default) : resolveAdapter(storageKey, nonMemoryScope, options);
1176
1184
  const shouldSync = effectiveSync && SYNCABLE_SCOPES.has(scope) && !useMemoryFallback;
1177
1185
  const adapter = shouldSync ? withSync(baseAdapter, storageKey, scope) : baseAdapter;
1178
1186
  const instance = new StateImpl(key, scope, rKey, adapter, options, config);
@@ -1183,7 +1191,7 @@ function createBase(key, options) {
1183
1191
  if (!shallowEqual(currentValue, options.default)) return;
1184
1192
  let realAdapter;
1185
1193
  try {
1186
- realAdapter = resolveAdapter(storageKey, scope, options);
1194
+ realAdapter = resolveAdapter(storageKey, nonMemoryScope, options);
1187
1195
  const storedValue = realAdapter.get();
1188
1196
  if (!shallowEqual(storedValue, options.default)) {
1189
1197
  instance.set(storedValue);
@@ -1195,14 +1203,14 @@ function createBase(key, options) {
1195
1203
  clientValue: storedValue
1196
1204
  });
1197
1205
  } catch (err) {
1198
- chunkPEC73EEB_cjs.log("debug", `Hydration adapter unavailable for state("${key}") \u2014 using memory fallback.`);
1199
- chunkPEC73EEB_cjs.reportError(key, scope, err);
1206
+ chunk7LC5PRFD_cjs.log("debug", `Hydration adapter unavailable for state("${key}") \u2014 using memory fallback.`);
1207
+ chunk7LC5PRFD_cjs.reportError(key, scope, err);
1200
1208
  } finally {
1201
1209
  realAdapter?.destroy?.();
1202
1210
  }
1203
1211
  });
1204
1212
  }
1205
- chunkPEC73EEB_cjs.registerNew(rKey, key, scope, instance, config, existing);
1213
+ chunk7LC5PRFD_cjs.registerNew(rKey, key, scope, instance, config, existing);
1206
1214
  return instance;
1207
1215
  }
1208
1216
 
@@ -55,6 +55,7 @@ function getRegistry() {
55
55
  return registry;
56
56
  }
57
57
 
58
+ exports.PERSISTENT_SCOPES = PERSISTENT_SCOPES;
58
59
  exports.configure = configure;
59
60
  exports.getConfig = getConfig;
60
61
  exports.getRegistered = getRegistered;
@@ -53,4 +53,4 @@ function getRegistry() {
53
53
  return registry;
54
54
  }
55
55
 
56
- export { configure, getConfig, getRegistered, getRegistry, log, registerNew, reportError, scopedKey, unregisterByKey };
56
+ export { PERSISTENT_SCOPES, configure, getConfig, getRegistered, getRegistry, log, registerNew, reportError, scopedKey, unregisterByKey };
@@ -1,4 +1,4 @@
1
- import { getConfig, log, scopedKey, getRegistered, registerNew, unregisterByKey, reportError } from './chunk-4IXO3W5U.js';
1
+ import { getConfig, log, scopedKey, getRegistered, registerNew, PERSISTENT_SCOPES, unregisterByKey, reportError } from './chunk-T6S7QGUQ.js';
2
2
 
3
3
  // src/batch.ts
4
4
  var depth = 0;
@@ -251,6 +251,7 @@ function createStorageAdapter(storage, key, options) {
251
251
  const listeners = createListeners();
252
252
  let cachedRaw;
253
253
  let cachedValue;
254
+ let cacheValid = false;
254
255
  function parse(raw) {
255
256
  if (serialize) {
256
257
  return serialize.parse(raw);
@@ -258,25 +259,32 @@ function createStorageAdapter(storage, key, options) {
258
259
  return readAndMigrate(raw, options, key, options.scope);
259
260
  }
260
261
  function read() {
262
+ if (cacheValid) return cachedValue;
261
263
  try {
262
264
  const raw = storage.getItem(key);
263
265
  if (raw === null) {
264
266
  cachedRaw = null;
265
- cachedValue = void 0;
267
+ cachedValue = defaultValue;
268
+ cacheValid = true;
266
269
  return defaultValue;
267
270
  }
268
- if (raw === cachedRaw) return cachedValue;
271
+ if (raw === cachedRaw) {
272
+ cacheValid = true;
273
+ return cachedValue;
274
+ }
269
275
  let value;
270
276
  try {
271
277
  value = parse(raw);
272
278
  } catch {
273
279
  cachedRaw = void 0;
274
280
  cachedValue = void 0;
281
+ cacheValid = false;
275
282
  return defaultValue;
276
283
  }
277
284
  value = mergeKeys(value, defaultValue, persist);
278
285
  cachedRaw = raw;
279
286
  cachedValue = value;
287
+ cacheValid = true;
280
288
  return value;
281
289
  } catch {
282
290
  return defaultValue;
@@ -289,9 +297,11 @@ function createStorageAdapter(storage, key, options) {
289
297
  storage.setItem(key, raw);
290
298
  cachedRaw = raw;
291
299
  cachedValue = persist ? mergeKeys(toStore, defaultValue, persist) : value;
300
+ cacheValid = true;
292
301
  } catch (e) {
293
302
  cachedRaw = void 0;
294
303
  cachedValue = void 0;
304
+ cacheValid = false;
295
305
  log(
296
306
  "error",
297
307
  `Failed to write key "${key}" to storage: ${e instanceof Error ? e.message : String(e)}`
@@ -308,6 +318,7 @@ function createStorageAdapter(storage, key, options) {
308
318
  if (event.storageArea !== storage || event.key !== key) return;
309
319
  cachedRaw = void 0;
310
320
  cachedValue = void 0;
321
+ cacheValid = false;
311
322
  lastNotifiedValue = read();
312
323
  notify(notifyListeners);
313
324
  }
@@ -328,6 +339,7 @@ function createStorageAdapter(storage, key, options) {
328
339
  destroy() {
329
340
  cachedRaw = void 0;
330
341
  cachedValue = void 0;
342
+ cacheValid = false;
331
343
  listeners.clear();
332
344
  if (typeof window !== "undefined") {
333
345
  window.removeEventListener("storage", onStorageEvent);
@@ -652,16 +664,7 @@ var _serverAdapterFactory;
652
664
  function registerServerAdapter(factory) {
653
665
  _serverAdapterFactory = factory;
654
666
  }
655
- var PERSISTENT_SCOPES = /* @__PURE__ */ new Set(["local", "session", "bucket"]);
656
667
  var SYNCABLE_SCOPES = /* @__PURE__ */ new Set(["local", "bucket"]);
657
- var MEMORY_SHIM = {
658
- ready: RESOLVED,
659
- get: () => void 0,
660
- set: () => {
661
- },
662
- subscribe: () => () => {
663
- }
664
- };
665
668
  function resolveStorageKey(key, options, configPrefix) {
666
669
  if (options.prefix === false) return key;
667
670
  const prefix = options.prefix ?? configPrefix;
@@ -669,9 +672,6 @@ function resolveStorageKey(key, options, configPrefix) {
669
672
  }
670
673
  function resolveAdapter(storageKey, scope, options) {
671
674
  switch (scope) {
672
- case "memory":
673
- case "render":
674
- return createMemoryAdapter(options.default);
675
675
  case "session":
676
676
  if (typeof sessionStorage === "undefined") {
677
677
  throw new Error(
@@ -912,31 +912,20 @@ function getExt(c) {
912
912
  }
913
913
  return c.ext;
914
914
  }
915
- var MEMORY_MUTABLE_SHIM = {
916
- lastValue: void 0,
917
- isDestroyed: false,
918
- interceptors: void 0,
919
- changeHandlers: void 0,
920
- settled: RESOLVED,
921
- resolveDestroyed: void 0,
922
- destroyed: void 0,
923
- hydrated: void 0,
924
- watchers: void 0,
925
- watchUnsub: void 0,
926
- watchPrev: void 0
927
- };
928
- var MemoryStateImpl = class extends StateImpl {
915
+ var MemoryStateImpl = class {
916
+ key;
917
+ scope = "memory";
929
918
  _c;
919
+ _defaultValue;
920
+ _options;
921
+ _config;
922
+ _rKey;
930
923
  constructor(key, rKey, options, config) {
931
- super(
932
- key,
933
- "memory",
934
- rKey,
935
- MEMORY_SHIM,
936
- options,
937
- config,
938
- MEMORY_MUTABLE_SHIM
939
- );
924
+ this.key = key;
925
+ this._rKey = rKey;
926
+ this._defaultValue = options.default;
927
+ this._options = options;
928
+ this._config = config;
940
929
  this._c = {
941
930
  current: options.default,
942
931
  isDestroyed: false,
@@ -1077,6 +1066,24 @@ var MemoryStateImpl = class extends StateImpl {
1077
1066
  this._ensureWatchSubscription();
1078
1067
  return addWatcher(ext.watchers, watchKey, listener);
1079
1068
  }
1069
+ patch(partial, options) {
1070
+ this.set((prev) => {
1071
+ if (options?.strict) {
1072
+ const prevRec = prev;
1073
+ const partialRec = partial;
1074
+ const filtered = {};
1075
+ for (const key of Object.keys(partialRec)) {
1076
+ if (Object.hasOwn(prevRec, key)) {
1077
+ filtered[key] = partialRec[key];
1078
+ } else {
1079
+ log("warn", `patch("${this.key}") ignored unknown key "${key}" (strict mode).`);
1080
+ }
1081
+ }
1082
+ return { ...prev, ...filtered };
1083
+ }
1084
+ return { ...prev, ...partial };
1085
+ });
1086
+ }
1080
1087
  _ensureWatchSubscription() {
1081
1088
  const ext = getExt(this._c);
1082
1089
  if (ext.watchUnsub) return;
@@ -1170,7 +1177,8 @@ function createBase(key, options) {
1170
1177
  );
1171
1178
  }
1172
1179
  const storageKey = resolveStorageKey(key, options, config.prefix);
1173
- const baseAdapter = useMemoryFallback ? createMemoryAdapter(options.default) : resolveAdapter(storageKey, scope, options);
1180
+ const nonMemoryScope = scope;
1181
+ const baseAdapter = useMemoryFallback ? createMemoryAdapter(options.default) : resolveAdapter(storageKey, nonMemoryScope, options);
1174
1182
  const shouldSync = effectiveSync && SYNCABLE_SCOPES.has(scope) && !useMemoryFallback;
1175
1183
  const adapter = shouldSync ? withSync(baseAdapter, storageKey, scope) : baseAdapter;
1176
1184
  const instance = new StateImpl(key, scope, rKey, adapter, options, config);
@@ -1181,7 +1189,7 @@ function createBase(key, options) {
1181
1189
  if (!shallowEqual(currentValue, options.default)) return;
1182
1190
  let realAdapter;
1183
1191
  try {
1184
- realAdapter = resolveAdapter(storageKey, scope, options);
1192
+ realAdapter = resolveAdapter(storageKey, nonMemoryScope, options);
1185
1193
  const storedValue = realAdapter.get();
1186
1194
  if (!shallowEqual(storedValue, options.default)) {
1187
1195
  instance.set(storedValue);
package/dist/devtools.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkPEC73EEB_cjs = require('./chunk-PEC73EEB.cjs');
3
+ var chunk7LC5PRFD_cjs = require('./chunk-7LC5PRFD.cjs');
4
4
 
5
5
  // src/devtools/logger.ts
6
6
  var loggerOptions;
@@ -82,7 +82,7 @@ var unsubscribeDevTools;
82
82
  var connected = false;
83
83
  function getGlobalState() {
84
84
  const result = {};
85
- for (const instance of chunkPEC73EEB_cjs.getRegistry().values()) {
85
+ for (const instance of chunk7LC5PRFD_cjs.getRegistry().values()) {
86
86
  if (!instance.isDestroyed) {
87
87
  result[instance.key] = instance.get();
88
88
  }
@@ -106,7 +106,7 @@ function handleDevToolsMessage(message) {
106
106
  } catch {
107
107
  return;
108
108
  }
109
- const registry = chunkPEC73EEB_cjs.getRegistry();
109
+ const registry = chunk7LC5PRFD_cjs.getRegistry();
110
110
  for (const instance of registry.values()) {
111
111
  if (instance.isDestroyed) continue;
112
112
  const key = instance.key;
@@ -188,12 +188,12 @@ function enableDevTools(options) {
188
188
  if (devToolsEnabled) {
189
189
  return disableDevTools;
190
190
  }
191
- const config = chunkPEC73EEB_cjs.getConfig();
191
+ const config = chunk7LC5PRFD_cjs.getConfig();
192
192
  originalOnChange = config.onChange;
193
193
  originalOnReset = config.onReset;
194
194
  originalOnRegister = config.onRegister;
195
195
  originalOnDestroy = config.onDestroy;
196
- chunkPEC73EEB_cjs.configure({
196
+ chunk7LC5PRFD_cjs.configure({
197
197
  onChange: onChangeHandler,
198
198
  onReset: onResetHandler,
199
199
  onRegister: onRegisterHandler,
@@ -210,7 +210,7 @@ function enableDevTools(options) {
210
210
  }
211
211
  function disableDevTools() {
212
212
  if (!devToolsEnabled) return;
213
- chunkPEC73EEB_cjs.configure({
213
+ chunk7LC5PRFD_cjs.configure({
214
214
  onChange: originalOnChange,
215
215
  onReset: originalOnReset,
216
216
  onRegister: originalOnRegister,
package/dist/devtools.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getConfig, configure, getRegistry } from './chunk-4IXO3W5U.js';
1
+ import { getConfig, configure, getRegistry } from './chunk-T6S7QGUQ.js';
2
2
 
3
3
  // src/devtools/logger.ts
4
4
  var loggerOptions;
package/dist/index.cjs CHANGED
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var chunkZOVUXRDH_cjs = require('./chunk-ZOVUXRDH.cjs');
4
- var chunkPEC73EEB_cjs = require('./chunk-PEC73EEB.cjs');
3
+ var chunk6NYUDOPO_cjs = require('./chunk-6NYUDOPO.cjs');
4
+ var chunk7LC5PRFD_cjs = require('./chunk-7LC5PRFD.cjs');
5
5
 
6
6
  // src/collection.ts
7
7
  function collection(key, options) {
8
- const base = chunkZOVUXRDH_cjs.createBase(key, options);
8
+ const base = chunk6NYUDOPO_cjs.createBase(key, options);
9
9
  let watchers;
10
10
  let prevItems;
11
11
  let unsubscribe;
@@ -23,7 +23,7 @@ function collection(key, options) {
23
23
  if (lengthChanged) {
24
24
  for (const [, listeners] of w) {
25
25
  for (const listener of listeners) {
26
- chunkZOVUXRDH_cjs.safeCall(listener, next);
26
+ chunk6NYUDOPO_cjs.safeCall(listener, next);
27
27
  }
28
28
  }
29
29
  prevItems = next;
@@ -35,12 +35,12 @@ function collection(key, options) {
35
35
  const prev = prevItems[i];
36
36
  const curr = next[i];
37
37
  if (prev === curr) continue;
38
- const p = chunkZOVUXRDH_cjs.isRecord(prev) ? prev : void 0;
39
- const n = chunkZOVUXRDH_cjs.isRecord(curr) ? curr : void 0;
38
+ const p = chunk6NYUDOPO_cjs.isRecord(prev) ? prev : void 0;
39
+ const n = chunk6NYUDOPO_cjs.isRecord(curr) ? curr : void 0;
40
40
  if (!p || !n) {
41
41
  for (const [, listeners] of w) {
42
42
  for (const listener of listeners) {
43
- chunkZOVUXRDH_cjs.safeCall(listener, next);
43
+ chunk6NYUDOPO_cjs.safeCall(listener, next);
44
44
  }
45
45
  }
46
46
  prevItems = next;
@@ -60,7 +60,7 @@ function collection(key, options) {
60
60
  const listeners = w.get(watchKey);
61
61
  if (listeners) {
62
62
  for (const listener of listeners) {
63
- chunkZOVUXRDH_cjs.safeCall(listener, next);
63
+ chunk6NYUDOPO_cjs.safeCall(listener, next);
64
64
  }
65
65
  }
66
66
  }
@@ -69,9 +69,10 @@ function collection(key, options) {
69
69
  });
70
70
  return w;
71
71
  }
72
- const col = Object.create(base);
72
+ const baseDestroy = base.destroy;
73
+ const col = base;
73
74
  col.watch = (watchKey, listener) => {
74
- return chunkZOVUXRDH_cjs.addWatcher(ensureWatchers(), watchKey, listener);
75
+ return chunk6NYUDOPO_cjs.addWatcher(ensureWatchers(), watchKey, listener);
75
76
  };
76
77
  col.add = (...items) => {
77
78
  base.set(base.get().concat(items));
@@ -135,7 +136,7 @@ function collection(key, options) {
135
136
  col.destroy = () => {
136
137
  watchers?.clear();
137
138
  unsubscribe?.();
138
- base.destroy();
139
+ baseDestroy.call(col);
139
140
  };
140
141
  return col;
141
142
  }
@@ -143,7 +144,6 @@ function collection(key, options) {
143
144
  // src/computed.ts
144
145
  var NOOP = () => {
145
146
  };
146
- var TO_VOID = () => void 0;
147
147
  var computedCounter = 0;
148
148
  function computed(deps, fn, options) {
149
149
  const listenerSet = /* @__PURE__ */ new Set();
@@ -153,7 +153,7 @@ function computed(deps, fn, options) {
153
153
  let cached;
154
154
  let isDirty = true;
155
155
  let isDestroyed = false;
156
- const lazyDestroyed = chunkZOVUXRDH_cjs.createLazyDestroyed();
156
+ const lazyDestroyed = chunk6NYUDOPO_cjs.createLazyDestroyed();
157
157
  const depValues = new Array(deps.length);
158
158
  const depLen = deps.length;
159
159
  function recompute() {
@@ -171,16 +171,16 @@ function computed(deps, fn, options) {
171
171
  const value = recompute();
172
172
  if (value === prev) return;
173
173
  if (singleListener !== void 0) {
174
- chunkZOVUXRDH_cjs.safeCall(singleListener, value);
174
+ chunk6NYUDOPO_cjs.safeCall(singleListener, value);
175
175
  return;
176
176
  }
177
177
  for (const l of listenerSet) {
178
- chunkZOVUXRDH_cjs.safeCall(l, value);
178
+ chunk6NYUDOPO_cjs.safeCall(l, value);
179
179
  }
180
180
  };
181
181
  const markDirty = () => {
182
182
  isDirty = true;
183
- chunkZOVUXRDH_cjs.notify(notifyListeners);
183
+ chunk6NYUDOPO_cjs.notify(notifyListeners);
184
184
  };
185
185
  const unsubscribers = new Array(depLen);
186
186
  for (let i = 0; i < depLen; i++) {
@@ -188,12 +188,12 @@ function computed(deps, fn, options) {
188
188
  unsubscribers[i] = dep.subscribe(markDirty);
189
189
  }
190
190
  recompute();
191
- let readyPromise = chunkZOVUXRDH_cjs.RESOLVED;
192
- let hydratedPromise = chunkZOVUXRDH_cjs.RESOLVED;
193
- let settledPromise = chunkZOVUXRDH_cjs.RESOLVED;
191
+ let readyPromise = chunk6NYUDOPO_cjs.RESOLVED;
192
+ let hydratedPromise = chunk6NYUDOPO_cjs.RESOLVED;
193
+ let settledPromise = chunk6NYUDOPO_cjs.RESOLVED;
194
194
  let hasAsyncDep = false;
195
195
  for (let i = 0; i < depLen; i++) {
196
- if (deps[i].ready !== chunkZOVUXRDH_cjs.RESOLVED) {
196
+ if (deps[i].ready !== chunk6NYUDOPO_cjs.RESOLVED) {
197
197
  hasAsyncDep = true;
198
198
  break;
199
199
  }
@@ -208,9 +208,9 @@ function computed(deps, fn, options) {
208
208
  hydratedArr[i] = dep.hydrated;
209
209
  settledArr[i] = dep.settled;
210
210
  }
211
- readyPromise = Promise.all(readyArr).then(TO_VOID);
212
- hydratedPromise = Promise.all(hydratedArr).then(TO_VOID);
213
- settledPromise = Promise.all(settledArr).then(TO_VOID);
211
+ readyPromise = Promise.all(readyArr).then(NOOP);
212
+ hydratedPromise = Promise.all(hydratedArr).then(NOOP);
213
+ settledPromise = Promise.all(settledArr).then(NOOP);
214
214
  }
215
215
  return {
216
216
  key: instanceKey,
@@ -225,7 +225,7 @@ function computed(deps, fn, options) {
225
225
  return hydratedPromise;
226
226
  },
227
227
  get destroyed() {
228
- if (isDestroyed) return chunkZOVUXRDH_cjs.RESOLVED;
228
+ if (isDestroyed) return chunk6NYUDOPO_cjs.RESOLVED;
229
229
  return lazyDestroyed.promise;
230
230
  },
231
231
  get isDestroyed() {
@@ -268,7 +268,7 @@ function computed(deps, fn, options) {
268
268
 
269
269
  // src/devtools.ts
270
270
  function snapshot() {
271
- return Array.from(chunkPEC73EEB_cjs.getRegistry().values(), (instance) => ({
271
+ return Array.from(chunk7LC5PRFD_cjs.getRegistry().values(), (instance) => ({
272
272
  key: instance.key,
273
273
  scope: instance.scope,
274
274
  value: instance.isDestroyed ? void 0 : instance.get(),
@@ -396,7 +396,7 @@ function withWatch(instance) {
396
396
  unsubscribe = instance.subscribe((next) => {
397
397
  try {
398
398
  if (watchers && watchers.size > 0) {
399
- chunkZOVUXRDH_cjs.notifyWatchers(watchers, prev, next);
399
+ chunk6NYUDOPO_cjs.notifyWatchers(watchers, prev, next);
400
400
  }
401
401
  } finally {
402
402
  prev = next;
@@ -407,7 +407,7 @@ function withWatch(instance) {
407
407
  result.watch = (watchKey, listener) => {
408
408
  if (!watchers) watchers = /* @__PURE__ */ new Map();
409
409
  ensureSubscription();
410
- return chunkZOVUXRDH_cjs.addWatcher(watchers, watchKey, listener);
410
+ return chunk6NYUDOPO_cjs.addWatcher(watchers, watchKey, listener);
411
411
  };
412
412
  result.destroy = () => {
413
413
  watchers?.clear();
@@ -424,7 +424,7 @@ function withWatch(instance) {
424
424
  // src/previous.ts
425
425
  var previousCounter = 0;
426
426
  function previous(source, options) {
427
- const listeners = chunkZOVUXRDH_cjs.createListeners();
427
+ const listeners = chunk6NYUDOPO_cjs.createListeners();
428
428
  const instanceKey = options?.key ?? `previous:${previousCounter++}`;
429
429
  let prev;
430
430
  let current = source.get();
@@ -437,10 +437,10 @@ function previous(source, options) {
437
437
  prev = current;
438
438
  current = next;
439
439
  if (old !== prev) {
440
- chunkZOVUXRDH_cjs.notify(notifyListeners);
440
+ chunk6NYUDOPO_cjs.notify(notifyListeners);
441
441
  }
442
442
  });
443
- const lazyDestroyed = chunkZOVUXRDH_cjs.createLazyDestroyed();
443
+ const lazyDestroyed = chunk6NYUDOPO_cjs.createLazyDestroyed();
444
444
  return {
445
445
  key: instanceKey,
446
446
  scope: "memory",
@@ -487,92 +487,11 @@ function readonly(instance) {
487
487
  }
488
488
 
489
489
  // src/select.ts
490
- var NOOP2 = () => {
491
- };
492
490
  var selectCounter = 0;
493
491
  function select(source, fn, options) {
494
- const listenerSet = /* @__PURE__ */ new Set();
495
- let singleListener;
496
- let listenerCount = 0;
497
- const instanceKey = options?.key ?? `select:${selectCounter++}`;
498
- let cached;
499
- let isDirty = true;
500
- let isDestroyed = false;
501
- const lazyDestroyed = chunkZOVUXRDH_cjs.createLazyDestroyed();
502
- function recompute() {
503
- if (!isDirty) return cached;
504
- cached = fn(source.get());
505
- isDirty = false;
506
- return cached;
507
- }
508
- const notifyListeners = () => {
509
- const prev = cached;
510
- const value = recompute();
511
- if (value === prev) return;
512
- if (singleListener !== void 0) {
513
- chunkZOVUXRDH_cjs.safeCall(singleListener, value);
514
- return;
515
- }
516
- for (const l of listenerSet) {
517
- chunkZOVUXRDH_cjs.safeCall(l, value);
518
- }
519
- };
520
- const markDirty = () => {
521
- isDirty = true;
522
- chunkZOVUXRDH_cjs.notify(notifyListeners);
523
- };
524
- const unsubscribe = source.subscribe(markDirty);
525
- recompute();
526
- return {
527
- key: instanceKey,
528
- scope: "memory",
529
- get ready() {
530
- return source.ready;
531
- },
532
- get settled() {
533
- return source.settled;
534
- },
535
- get hydrated() {
536
- return source.hydrated;
537
- },
538
- get destroyed() {
539
- if (isDestroyed) return chunkZOVUXRDH_cjs.RESOLVED;
540
- return lazyDestroyed.promise;
541
- },
542
- get isDestroyed() {
543
- return isDestroyed;
544
- },
545
- get() {
546
- return recompute();
547
- },
548
- peek() {
549
- return cached;
550
- },
551
- subscribe(listener) {
552
- if (isDestroyed) return NOOP2;
553
- listenerSet.add(listener);
554
- listenerCount++;
555
- singleListener = listenerCount === 1 ? listener : void 0;
556
- return () => {
557
- listenerSet.delete(listener);
558
- listenerCount--;
559
- if (listenerCount === 1) {
560
- singleListener = listenerSet.values().next().value;
561
- } else {
562
- singleListener = void 0;
563
- }
564
- };
565
- },
566
- destroy() {
567
- if (isDestroyed) return;
568
- isDestroyed = true;
569
- unsubscribe();
570
- listenerSet.clear();
571
- listenerCount = 0;
572
- singleListener = void 0;
573
- lazyDestroyed.resolve();
574
- }
575
- };
492
+ return computed([source], (values) => fn(values[0]), {
493
+ key: options?.key ?? `select:${selectCounter++}`
494
+ });
576
495
  }
577
496
 
578
497
  // src/shortcuts.ts
@@ -588,7 +507,7 @@ function extractEntry(entry) {
588
507
  }
589
508
  function scopeShortcut(scope, entry, options) {
590
509
  const [key, defaultValue] = extractEntry(entry);
591
- return chunkZOVUXRDH_cjs.createBase(key, { ...options, default: defaultValue, scope });
510
+ return chunk6NYUDOPO_cjs.createBase(key, { ...options, default: defaultValue, scope });
592
511
  }
593
512
  function _state(keyOrEntry, optionsOrDefault, extraOptions) {
594
513
  let key;
@@ -601,7 +520,7 @@ function _state(keyOrEntry, optionsOrDefault, extraOptions) {
601
520
  key = keyOrEntry;
602
521
  options = extraOptions ? { ...extraOptions, default: optionsOrDefault } : optionsOrDefault !== null && typeof optionsOrDefault === "object" && "default" in optionsOrDefault ? optionsOrDefault : { default: optionsOrDefault };
603
522
  }
604
- return chunkZOVUXRDH_cjs.createBase(key, options);
523
+ return chunk6NYUDOPO_cjs.createBase(key, options);
605
524
  }
606
525
  _state.local = (e, o) => scopeShortcut("local", e, o);
607
526
  _state.session = (e, o) => scopeShortcut("session", e, o);
@@ -612,15 +531,15 @@ var state = _state;
612
531
 
613
532
  Object.defineProperty(exports, "batch", {
614
533
  enumerable: true,
615
- get: function () { return chunkZOVUXRDH_cjs.batch; }
534
+ get: function () { return chunk6NYUDOPO_cjs.batch; }
616
535
  });
617
536
  Object.defineProperty(exports, "shallowEqual", {
618
537
  enumerable: true,
619
- get: function () { return chunkZOVUXRDH_cjs.shallowEqual; }
538
+ get: function () { return chunk6NYUDOPO_cjs.shallowEqual; }
620
539
  });
621
540
  Object.defineProperty(exports, "configure", {
622
541
  enumerable: true,
623
- get: function () { return chunkPEC73EEB_cjs.configure; }
542
+ get: function () { return chunk7LC5PRFD_cjs.configure; }
624
543
  });
625
544
  exports.collection = collection;
626
545
  exports.computed = computed;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { createBase, addWatcher, createLazyDestroyed, RESOLVED, createListeners, notify, safeCall, isRecord, notifyWatchers } from './chunk-664AIFB3.js';
2
- export { batch, shallowEqual } from './chunk-664AIFB3.js';
3
- import { getRegistry } from './chunk-4IXO3W5U.js';
4
- export { configure } from './chunk-4IXO3W5U.js';
1
+ import { createBase, addWatcher, createLazyDestroyed, RESOLVED, createListeners, notify, safeCall, isRecord, notifyWatchers } from './chunk-V7QPAQ6F.js';
2
+ export { batch, shallowEqual } from './chunk-V7QPAQ6F.js';
3
+ import { getRegistry } from './chunk-T6S7QGUQ.js';
4
+ export { configure } from './chunk-T6S7QGUQ.js';
5
5
 
6
6
  // src/collection.ts
7
7
  function collection(key, options) {
@@ -69,7 +69,8 @@ function collection(key, options) {
69
69
  });
70
70
  return w;
71
71
  }
72
- const col = Object.create(base);
72
+ const baseDestroy = base.destroy;
73
+ const col = base;
73
74
  col.watch = (watchKey, listener) => {
74
75
  return addWatcher(ensureWatchers(), watchKey, listener);
75
76
  };
@@ -135,7 +136,7 @@ function collection(key, options) {
135
136
  col.destroy = () => {
136
137
  watchers?.clear();
137
138
  unsubscribe?.();
138
- base.destroy();
139
+ baseDestroy.call(col);
139
140
  };
140
141
  return col;
141
142
  }
@@ -143,7 +144,6 @@ function collection(key, options) {
143
144
  // src/computed.ts
144
145
  var NOOP = () => {
145
146
  };
146
- var TO_VOID = () => void 0;
147
147
  var computedCounter = 0;
148
148
  function computed(deps, fn, options) {
149
149
  const listenerSet = /* @__PURE__ */ new Set();
@@ -208,9 +208,9 @@ function computed(deps, fn, options) {
208
208
  hydratedArr[i] = dep.hydrated;
209
209
  settledArr[i] = dep.settled;
210
210
  }
211
- readyPromise = Promise.all(readyArr).then(TO_VOID);
212
- hydratedPromise = Promise.all(hydratedArr).then(TO_VOID);
213
- settledPromise = Promise.all(settledArr).then(TO_VOID);
211
+ readyPromise = Promise.all(readyArr).then(NOOP);
212
+ hydratedPromise = Promise.all(hydratedArr).then(NOOP);
213
+ settledPromise = Promise.all(settledArr).then(NOOP);
214
214
  }
215
215
  return {
216
216
  key: instanceKey,
@@ -487,92 +487,11 @@ function readonly(instance) {
487
487
  }
488
488
 
489
489
  // src/select.ts
490
- var NOOP2 = () => {
491
- };
492
490
  var selectCounter = 0;
493
491
  function select(source, fn, options) {
494
- const listenerSet = /* @__PURE__ */ new Set();
495
- let singleListener;
496
- let listenerCount = 0;
497
- const instanceKey = options?.key ?? `select:${selectCounter++}`;
498
- let cached;
499
- let isDirty = true;
500
- let isDestroyed = false;
501
- const lazyDestroyed = createLazyDestroyed();
502
- function recompute() {
503
- if (!isDirty) return cached;
504
- cached = fn(source.get());
505
- isDirty = false;
506
- return cached;
507
- }
508
- const notifyListeners = () => {
509
- const prev = cached;
510
- const value = recompute();
511
- if (value === prev) return;
512
- if (singleListener !== void 0) {
513
- safeCall(singleListener, value);
514
- return;
515
- }
516
- for (const l of listenerSet) {
517
- safeCall(l, value);
518
- }
519
- };
520
- const markDirty = () => {
521
- isDirty = true;
522
- notify(notifyListeners);
523
- };
524
- const unsubscribe = source.subscribe(markDirty);
525
- recompute();
526
- return {
527
- key: instanceKey,
528
- scope: "memory",
529
- get ready() {
530
- return source.ready;
531
- },
532
- get settled() {
533
- return source.settled;
534
- },
535
- get hydrated() {
536
- return source.hydrated;
537
- },
538
- get destroyed() {
539
- if (isDestroyed) return RESOLVED;
540
- return lazyDestroyed.promise;
541
- },
542
- get isDestroyed() {
543
- return isDestroyed;
544
- },
545
- get() {
546
- return recompute();
547
- },
548
- peek() {
549
- return cached;
550
- },
551
- subscribe(listener) {
552
- if (isDestroyed) return NOOP2;
553
- listenerSet.add(listener);
554
- listenerCount++;
555
- singleListener = listenerCount === 1 ? listener : void 0;
556
- return () => {
557
- listenerSet.delete(listener);
558
- listenerCount--;
559
- if (listenerCount === 1) {
560
- singleListener = listenerSet.values().next().value;
561
- } else {
562
- singleListener = void 0;
563
- }
564
- };
565
- },
566
- destroy() {
567
- if (isDestroyed) return;
568
- isDestroyed = true;
569
- unsubscribe();
570
- listenerSet.clear();
571
- listenerCount = 0;
572
- singleListener = void 0;
573
- lazyDestroyed.resolve();
574
- }
575
- };
492
+ return computed([source], (values) => fn(values[0]), {
493
+ key: options?.key ?? `select:${selectCounter++}`
494
+ });
576
495
  }
577
496
 
578
497
  // src/shortcuts.ts
package/dist/server.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkZOVUXRDH_cjs = require('./chunk-ZOVUXRDH.cjs');
4
- require('./chunk-PEC73EEB.cjs');
3
+ var chunk6NYUDOPO_cjs = require('./chunk-6NYUDOPO.cjs');
4
+ require('./chunk-7LC5PRFD.cjs');
5
5
  var async_hooks = require('async_hooks');
6
6
 
7
7
  var als = new async_hooks.AsyncLocalStorage();
@@ -10,7 +10,7 @@ async function withServerSession(fn) {
10
10
  return als.run(store, fn);
11
11
  }
12
12
  function createServerAdapter(key, defaultValue) {
13
- const listeners = chunkZOVUXRDH_cjs.createListeners();
13
+ const listeners = chunk6NYUDOPO_cjs.createListeners();
14
14
  function getStore() {
15
15
  return als.getStore();
16
16
  }
@@ -32,7 +32,7 @@ function createServerAdapter(key, defaultValue) {
32
32
  }
33
33
  store.set(key, value);
34
34
  lastNotifiedValue = value;
35
- chunkZOVUXRDH_cjs.notify(notifyListeners);
35
+ chunk6NYUDOPO_cjs.notify(notifyListeners);
36
36
  },
37
37
  subscribe: listeners.subscribe,
38
38
  destroy() {
@@ -40,7 +40,7 @@ function createServerAdapter(key, defaultValue) {
40
40
  }
41
41
  };
42
42
  }
43
- chunkZOVUXRDH_cjs.registerServerAdapter(createServerAdapter);
43
+ chunk6NYUDOPO_cjs.registerServerAdapter(createServerAdapter);
44
44
 
45
45
  exports.createServerAdapter = createServerAdapter;
46
46
  exports.withServerSession = withServerSession;
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { registerServerAdapter, createListeners, notify } from './chunk-664AIFB3.js';
2
- import './chunk-4IXO3W5U.js';
1
+ import { registerServerAdapter, createListeners, notify } from './chunk-V7QPAQ6F.js';
2
+ import './chunk-T6S7QGUQ.js';
3
3
  import { AsyncLocalStorage } from 'async_hooks';
4
4
 
5
5
  var als = new AsyncLocalStorage();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gjendje",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Storage-agnostic state management for TypeScript",
5
5
  "keywords": [
6
6
  "state",