gjendje 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # gjendje
4
4
 
5
- Every app juggles localStorage, sessionStorage, URL params, and in-memory state — each with its own API. **gjendje** replaces it all with a single primitive. Choose where state lives. The rest is handled.
5
+ Every app juggles localStorage, sessionStorage, URL params, and in-memory state. gjendje replaces that all with a unified API. Choose where state lives. The rest is handled.
6
6
 
7
7
  ## Install
8
8
 
@@ -12,35 +12,30 @@ npm install gjendje
12
12
 
13
13
  ## Quick start
14
14
 
15
- ```ts
16
- import { local, session, url, bucket, server } from 'gjendje'
17
-
18
- // localStorage — survives refresh, works across tabs
19
- const theme = local({ theme: 'light' })
15
+ You can pass the scope as an option:
20
16
 
21
- // sessionStorage — survives refresh, gone when tab closes
22
- const draft = session({ draft: '' })
17
+ ```ts
18
+ import { state } from 'gjendje'
23
19
 
24
- // URL params shareable via address bar
25
- const filters = url({ q: '' })
20
+ const theme = state({ theme: 'light' }, { scope: 'local' })
21
+ ```
26
22
 
27
- // Storage Bucket isolated, quota-managed, expirable
28
- const cache = bucket({ cache: [] }, { bucket: { name: 'app-cache', expires: '7d' } })
23
+ Or use dot notation as a shorthand:
29
24
 
30
- // AsyncLocalStorage — server-side, session-scoped
31
- const user = server({ user: null })
25
+ ```ts
26
+ const theme = state.local({ theme: 'light' })
32
27
  ```
33
28
 
34
- For in-memory state that doesn't persist, use `state` directly:
29
+ For in-memory state that doesn't persist, call `state` without a scope:
35
30
 
36
31
  ```ts
37
- import { state } from 'gjendje'
38
-
39
32
  const counter = state({ counter: 0 })
40
33
 
41
34
  counter.set((prev) => prev + 1)
42
35
  ```
43
36
 
37
+ [See all scopes and examples](https://github.com/charliebeckstrand/gjendje/blob/main/docs/scopes.md)
38
+
44
39
  ## Configure
45
40
 
46
41
  Sets global defaults for all state instances.
@@ -64,20 +59,20 @@ theme.scope // 'local' — derived from configure
64
59
 
65
60
  ## Scopes
66
61
 
67
- | Scope | Backend | Shortcut |
68
- |----------|----------------------|-------------|
69
- | `memory` | In-memory | `state()` |
70
- | `local` | `localStorage` | `local()` |
71
- | `tab` | `sessionStorage` | `session()` |
72
- | `url` | `URLSearchParams` | `url()` |
73
- | `bucket` | Storage Buckets API | `bucket()` |
74
- | `server` | `AsyncLocalStorage` | `server()` |
62
+ | Scope | Backend | Shortcut |
63
+ |----------|----------------------|--------------------|
64
+ | `memory` | In-memory | `state()` |
65
+ | `local` | `localStorage` | `state.local()` |
66
+ | `session` | `sessionStorage` | `state.session()` |
67
+ | `url` | `URLSearchParams` | `state.url()` |
68
+ | `bucket` | Storage Buckets API | `state.bucket()` |
69
+ | `server` | `AsyncLocalStorage` | `state.server()` |
75
70
 
76
71
  [Scope decision guide](https://github.com/charliebeckstrand/gjendje/blob/main/docs/scopes.md)
77
72
 
78
73
  ## API
79
74
 
80
- Every primitive — `state`, `local`, `session`, `url`, `bucket`, and `server` — shares the same core API: `get`, `set`, `reset`, `subscribe`, `watch`, `intercept`, and more.
75
+ Every scope — `state.local`, `state.session`, `state.url`, `state.bucket`, and `state.server` — shares the same core API: `get`, `set`, `reset`, `subscribe`, `watch`, `intercept`, and more.
81
76
 
82
77
  [Full API reference](https://github.com/charliebeckstrand/gjendje/blob/main/docs/api.md) · [Persistence reference](https://github.com/charliebeckstrand/gjendje/blob/main/docs/persistence.md)
83
78
 
@@ -590,7 +590,7 @@ function createUrlAdapter(key, defaultValue, serializer, persist) {
590
590
  function isServer() {
591
591
  return typeof window === "undefined" || typeof document === "undefined";
592
592
  }
593
- var BROWSER_SCOPES = /* @__PURE__ */ new Set(["tab", "local", "url", "bucket"]);
593
+ var BROWSER_SCOPES = /* @__PURE__ */ new Set(["session", "tab", "local", "url", "bucket"]);
594
594
  function afterHydration(fn) {
595
595
  if (isServer()) return Promise.resolve();
596
596
  return new Promise((resolve) => {
@@ -615,7 +615,7 @@ var _serverAdapterFactory;
615
615
  function registerServerAdapter(factory) {
616
616
  _serverAdapterFactory = factory;
617
617
  }
618
- var PERSISTENT_SCOPES = /* @__PURE__ */ new Set(["local", "tab", "bucket"]);
618
+ var PERSISTENT_SCOPES = /* @__PURE__ */ new Set(["local", "session", "tab", "bucket"]);
619
619
  var SYNCABLE_SCOPES = /* @__PURE__ */ new Set(["local", "bucket"]);
620
620
  var RESOLVED2 = Promise.resolve();
621
621
  var RENDER_SHIM = {
@@ -636,6 +636,7 @@ function resolveAdapter(storageKey, scope, options) {
636
636
  case "memory":
637
637
  case "render":
638
638
  return createRenderAdapter(options.default);
639
+ case "session":
639
640
  case "tab":
640
641
  if (typeof sessionStorage === "undefined") {
641
642
  throw new Error(
@@ -995,7 +996,7 @@ function createBase(key, options) {
995
996
  );
996
997
  }
997
998
  const rawScope = options.scope ?? config.scope ?? "render";
998
- const scope = rawScope === "memory" ? "render" : rawScope;
999
+ const scope = rawScope === "memory" ? "render" : rawScope === "session" ? "tab" : rawScope;
999
1000
  const rKey = scopedKey(key, scope);
1000
1001
  const existing = getRegistered(rKey);
1001
1002
  if (existing && !existing.isDestroyed) return existing;
@@ -592,7 +592,7 @@ function createUrlAdapter(key, defaultValue, serializer, persist) {
592
592
  function isServer() {
593
593
  return typeof window === "undefined" || typeof document === "undefined";
594
594
  }
595
- var BROWSER_SCOPES = /* @__PURE__ */ new Set(["tab", "local", "url", "bucket"]);
595
+ var BROWSER_SCOPES = /* @__PURE__ */ new Set(["session", "tab", "local", "url", "bucket"]);
596
596
  function afterHydration(fn) {
597
597
  if (isServer()) return Promise.resolve();
598
598
  return new Promise((resolve) => {
@@ -617,7 +617,7 @@ var _serverAdapterFactory;
617
617
  function registerServerAdapter(factory) {
618
618
  _serverAdapterFactory = factory;
619
619
  }
620
- var PERSISTENT_SCOPES = /* @__PURE__ */ new Set(["local", "tab", "bucket"]);
620
+ var PERSISTENT_SCOPES = /* @__PURE__ */ new Set(["local", "session", "tab", "bucket"]);
621
621
  var SYNCABLE_SCOPES = /* @__PURE__ */ new Set(["local", "bucket"]);
622
622
  var RESOLVED2 = Promise.resolve();
623
623
  var RENDER_SHIM = {
@@ -638,6 +638,7 @@ function resolveAdapter(storageKey, scope, options) {
638
638
  case "memory":
639
639
  case "render":
640
640
  return createRenderAdapter(options.default);
641
+ case "session":
641
642
  case "tab":
642
643
  if (typeof sessionStorage === "undefined") {
643
644
  throw new Error(
@@ -997,7 +998,7 @@ function createBase(key, options) {
997
998
  );
998
999
  }
999
1000
  const rawScope = options.scope ?? config.scope ?? "render";
1000
- const scope = rawScope === "memory" ? "render" : rawScope;
1001
+ const scope = rawScope === "memory" ? "render" : rawScope === "session" ? "tab" : rawScope;
1001
1002
  const rKey = scopedKey(key, scope);
1002
1003
  const existing = getRegistered(rKey);
1003
1004
  if (existing && !existing.isDestroyed) return existing;
package/dist/index.cjs CHANGED
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var chunkIC7SQVDX_cjs = require('./chunk-IC7SQVDX.cjs');
3
+ var chunkPP6KNY6S_cjs = require('./chunk-PP6KNY6S.cjs');
4
4
 
5
5
  // src/collection.ts
6
6
  function collection(key, options) {
7
- const base = chunkIC7SQVDX_cjs.createBase(key, options);
7
+ const base = chunkPP6KNY6S_cjs.createBase(key, options);
8
8
  const watchers = /* @__PURE__ */ new Map();
9
9
  let prevItems = base.get();
10
10
  const unsubscribe = base.subscribe((next) => {
@@ -139,7 +139,7 @@ function collection(key, options) {
139
139
  // src/computed.ts
140
140
  var computedCounter = 0;
141
141
  function computed(deps, fn, options) {
142
- const listeners = chunkIC7SQVDX_cjs.createListeners();
142
+ const listeners = chunkPP6KNY6S_cjs.createListeners();
143
143
  const instanceKey = options?.key ?? `computed:${computedCounter++}`;
144
144
  let cached;
145
145
  let isDirty = true;
@@ -164,7 +164,7 @@ function computed(deps, fn, options) {
164
164
  };
165
165
  const markDirty = () => {
166
166
  isDirty = true;
167
- chunkIC7SQVDX_cjs.notify(notifyListeners);
167
+ chunkPP6KNY6S_cjs.notify(notifyListeners);
168
168
  };
169
169
  const unsubscribers = new Array(depLen);
170
170
  for (let i = 0; i < depLen; i++) {
@@ -224,7 +224,7 @@ function computed(deps, fn, options) {
224
224
 
225
225
  // src/devtools.ts
226
226
  function snapshot() {
227
- const registry = chunkIC7SQVDX_cjs.getRegistry();
227
+ const registry = chunkPP6KNY6S_cjs.getRegistry();
228
228
  const result = [];
229
229
  for (const instance of registry.values()) {
230
230
  result.push({
@@ -407,7 +407,7 @@ function withWatch(instance) {
407
407
  // src/previous.ts
408
408
  var previousCounter = 0;
409
409
  function previous(source, options) {
410
- const listeners = chunkIC7SQVDX_cjs.createListeners();
410
+ const listeners = chunkPP6KNY6S_cjs.createListeners();
411
411
  const instanceKey = options?.key ?? `previous:${previousCounter++}`;
412
412
  let prev;
413
413
  let current = source.get();
@@ -417,7 +417,7 @@ function previous(source, options) {
417
417
  prev = current;
418
418
  current = next;
419
419
  if (old !== prev) {
420
- chunkIC7SQVDX_cjs.notify(() => listeners.notify(prev));
420
+ chunkPP6KNY6S_cjs.notify(() => listeners.notify(prev));
421
421
  }
422
422
  });
423
423
  let destroyedPromise;
@@ -479,7 +479,7 @@ function readonly(instance) {
479
479
  // src/select.ts
480
480
  var selectCounter = 0;
481
481
  function select(source, fn, options) {
482
- const listeners = chunkIC7SQVDX_cjs.createListeners();
482
+ const listeners = chunkPP6KNY6S_cjs.createListeners();
483
483
  const instanceKey = options?.key ?? `select:${selectCounter++}`;
484
484
  let cached;
485
485
  let isDirty = true;
@@ -498,7 +498,7 @@ function select(source, fn, options) {
498
498
  };
499
499
  const markDirty = () => {
500
500
  isDirty = true;
501
- chunkIC7SQVDX_cjs.notify(notifyListeners);
501
+ chunkPP6KNY6S_cjs.notify(notifyListeners);
502
502
  };
503
503
  const unsubscribe = source.subscribe(markDirty);
504
504
  recompute();
@@ -553,34 +553,34 @@ function createState(key, options) {
553
553
  if (!key) {
554
554
  throw new Error("[state] key must be a non-empty string.");
555
555
  }
556
- const config = chunkIC7SQVDX_cjs.getConfig();
556
+ const config = chunkPP6KNY6S_cjs.getConfig();
557
557
  if (config.keyPattern && !config.keyPattern.test(key)) {
558
558
  throw new Error(
559
559
  `[gjendje] Key "${key}" does not match the configured keyPattern ${config.keyPattern}.`
560
560
  );
561
561
  }
562
562
  const rawScope = options.scope ?? config.scope ?? "render";
563
- const scope = rawScope === "memory" ? "render" : rawScope;
564
- const rKey = chunkIC7SQVDX_cjs.scopedKey(key, scope);
565
- const existing = chunkIC7SQVDX_cjs.getRegistered(rKey);
563
+ const scope = rawScope === "memory" ? "render" : rawScope === "session" ? "tab" : rawScope;
564
+ const rKey = chunkPP6KNY6S_cjs.scopedKey(key, scope);
565
+ const existing = chunkPP6KNY6S_cjs.getRegistered(rKey);
566
566
  if (existing && !existing.isDestroyed) {
567
567
  if (config.warnOnDuplicate) {
568
- chunkIC7SQVDX_cjs.log("warn", `Duplicate state("${key}") with scope "${scope}". Returning cached instance.`);
568
+ chunkPP6KNY6S_cjs.log("warn", `Duplicate state("${key}") with scope "${scope}". Returning cached instance.`);
569
569
  }
570
570
  return existing;
571
571
  }
572
572
  if (scope === "render" && !options.ssr && !config.ssr) {
573
573
  if (options.sync) {
574
- chunkIC7SQVDX_cjs.log(
574
+ chunkPP6KNY6S_cjs.log(
575
575
  "warn",
576
576
  `sync: true is ignored for scope "render". Only "local" and "bucket" scopes support cross-tab sync.`
577
577
  );
578
578
  }
579
- const instance = chunkIC7SQVDX_cjs.createRenderState(key, rKey, options, config);
580
- chunkIC7SQVDX_cjs.registerByKey(rKey, key, scope, instance, config);
579
+ const instance = chunkPP6KNY6S_cjs.createRenderState(key, rKey, options, config);
580
+ chunkPP6KNY6S_cjs.registerByKey(rKey, key, scope, instance, config);
581
581
  return instance;
582
582
  }
583
- return chunkIC7SQVDX_cjs.createBase(key, options);
583
+ return chunkPP6KNY6S_cjs.createBase(key, options);
584
584
  }
585
585
 
586
586
  // src/shortcuts.ts
@@ -594,7 +594,35 @@ function extractEntry(entry) {
594
594
  const key = keys[0];
595
595
  return [key, entry[key]];
596
596
  }
597
- function state(keyOrEntry, optionsOrDefault, extraOptions) {
597
+ var _deprecationWarned = /* @__PURE__ */ new Set();
598
+ function warnDeprecated(name) {
599
+ if (_deprecationWarned.has(name)) return;
600
+ _deprecationWarned.add(name);
601
+ console.warn(
602
+ `[gjendje] ${name}() is deprecated and will be removed in the next major version. Use state.${name}() instead. Example: state.${name}({ key: value })`
603
+ );
604
+ }
605
+ function _local(entry, options) {
606
+ const [key, defaultValue] = extractEntry(entry);
607
+ return createState(key, { ...options, default: defaultValue, scope: "local" });
608
+ }
609
+ function _session(entry, options) {
610
+ const [key, defaultValue] = extractEntry(entry);
611
+ return createState(key, { ...options, default: defaultValue, scope: "session" });
612
+ }
613
+ function _url(entry, options) {
614
+ const [key, defaultValue] = extractEntry(entry);
615
+ return createState(key, { ...options, default: defaultValue, scope: "url" });
616
+ }
617
+ function _server(entry, options) {
618
+ const [key, defaultValue] = extractEntry(entry);
619
+ return createState(key, { ...options, default: defaultValue, scope: "server" });
620
+ }
621
+ function _bucket(entry, options) {
622
+ const [key, defaultValue] = extractEntry(entry);
623
+ return createState(key, { ...options, default: defaultValue, scope: "bucket" });
624
+ }
625
+ function _state(keyOrEntry, optionsOrDefault, extraOptions) {
598
626
  let key;
599
627
  let options;
600
628
  if (typeof keyOrEntry === "object") {
@@ -607,38 +635,44 @@ function state(keyOrEntry, optionsOrDefault, extraOptions) {
607
635
  }
608
636
  return createState(key, options);
609
637
  }
638
+ _state.local = _local;
639
+ _state.session = _session;
640
+ _state.url = _url;
641
+ _state.bucket = _bucket;
642
+ _state.server = _server;
643
+ var state = _state;
610
644
  function local(entry, options) {
611
- const [key, defaultValue] = extractEntry(entry);
612
- return createState(key, { ...options, default: defaultValue, scope: "local" });
645
+ warnDeprecated("local");
646
+ return _local(entry, options);
613
647
  }
614
648
  function session(entry, options) {
615
- const [key, defaultValue] = extractEntry(entry);
616
- return createState(key, { ...options, default: defaultValue, scope: "tab" });
649
+ warnDeprecated("session");
650
+ return _session(entry, options);
617
651
  }
618
652
  function url(entry, options) {
619
- const [key, defaultValue] = extractEntry(entry);
620
- return createState(key, { ...options, default: defaultValue, scope: "url" });
653
+ warnDeprecated("url");
654
+ return _url(entry, options);
621
655
  }
622
656
  function server(entry, options) {
623
- const [key, defaultValue] = extractEntry(entry);
624
- return createState(key, { ...options, default: defaultValue, scope: "server" });
657
+ warnDeprecated("server");
658
+ return _server(entry, options);
625
659
  }
626
660
  function bucket(entry, options) {
627
- const [key, defaultValue] = extractEntry(entry);
628
- return createState(key, { ...options, default: defaultValue, scope: "bucket" });
661
+ warnDeprecated("bucket");
662
+ return _bucket(entry, options);
629
663
  }
630
664
 
631
665
  Object.defineProperty(exports, "batch", {
632
666
  enumerable: true,
633
- get: function () { return chunkIC7SQVDX_cjs.batch; }
667
+ get: function () { return chunkPP6KNY6S_cjs.batch; }
634
668
  });
635
669
  Object.defineProperty(exports, "configure", {
636
670
  enumerable: true,
637
- get: function () { return chunkIC7SQVDX_cjs.configure; }
671
+ get: function () { return chunkPP6KNY6S_cjs.configure; }
638
672
  });
639
673
  Object.defineProperty(exports, "shallowEqual", {
640
674
  enumerable: true,
641
- get: function () { return chunkIC7SQVDX_cjs.shallowEqual; }
675
+ get: function () { return chunkPP6KNY6S_cjs.shallowEqual; }
642
676
  });
643
677
  exports.bucket = bucket;
644
678
  exports.collection = collection;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BaseInstance, U as Unsubscribe, S as StateOptions, R as ReadonlyInstance, a as Scope, b as StateInstance } from './types-CmmPImmo.cjs';
2
- export { A as Adapter, c as BucketOptions, E as Enhancer, L as Listener, d as Serializer } from './types-CmmPImmo.cjs';
1
+ import { B as BaseInstance, U as Unsubscribe, S as StateOptions, R as ReadonlyInstance, a as Scope, b as StateInstance } from './types-DoZ6OB8U.cjs';
2
+ export { A as Adapter, c as BucketOptions, E as Enhancer, L as Listener, d as Serializer } from './types-DoZ6OB8U.cjs';
3
3
 
4
4
  /**
5
5
  * Runs all state updates inside fn as a single batch.
@@ -367,66 +367,72 @@ declare function select<TSource, TResult>(source: ReadonlyInstance<TSource>, fn:
367
367
  type Widen<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
368
368
  type ShortcutOptions<T> = Omit<StateOptions<T>, 'default' | 'scope'>;
369
369
  type BucketShortcutOptions<T> = Omit<StateOptions<T>, 'default' | 'scope' | 'bucket'> & Pick<StateOptions<T>, 'bucket'>;
370
+ /** state function with dot-notation scope shortcuts */
371
+ interface StateFunction {
372
+ /** Create in-memory state (default scope) */
373
+ <T>(entry: Record<string, T>, options?: Omit<StateOptions<T>, 'default'>): StateInstance<T>;
374
+ <T>(key: string, options: StateOptions<T>): StateInstance<T>;
375
+ <T>(key: string, defaultValue: T, options: Omit<StateOptions<T>, 'default'>): StateInstance<T>;
376
+ <T extends string | number | boolean | null | undefined>(key: string, defaultValue: T): StateInstance<Widen<T>>;
377
+ /** Create state stored in `localStorage` */
378
+ local: <T>(entry: Record<string, T>, options?: ShortcutOptions<T>) => StateInstance<T>;
379
+ /** Create state stored in `sessionStorage` */
380
+ session: <T>(entry: Record<string, T>, options?: ShortcutOptions<T>) => StateInstance<T>;
381
+ /** Create state stored in `URLSearchParams` */
382
+ url: <T>(entry: Record<string, T>, options?: ShortcutOptions<T>) => StateInstance<T>;
383
+ /** Create state stored in a Storage Bucket */
384
+ bucket: <T>(entry: Record<string, T>, options: BucketShortcutOptions<T>) => StateInstance<T>;
385
+ /** Create state stored in server-side `AsyncLocalStorage` */
386
+ server: <T>(entry: Record<string, T>, options?: ShortcutOptions<T>) => StateInstance<T>;
387
+ }
388
+ declare const state: StateFunction;
370
389
  /**
371
- * Create a stateful value.
372
- *
373
- * Preferred — entry object form (key derived from property name):
390
+ * @deprecated Use `state.local()` instead. Will be removed in the next major version.
374
391
  *
375
- * ```ts
376
- * const counter = state({ counter: 0 })
377
- * const theme = state({ theme: 'light' }, { scope: 'local' })
378
- * ```
379
- *
380
- * Alternative — string key forms:
381
- *
382
- * ```ts
383
- * const theme = state('theme', { default: 'light', scope: 'local' })
384
- * const synced = state('theme', 'light', { scope: 'local', sync: true })
385
- * const counter = state('counter', 0)
386
- * ```
387
- */
388
- declare function state<T>(entry: Record<string, T>, options?: Omit<StateOptions<T>, 'default'>): StateInstance<T>;
389
- declare function state<T>(key: string, options: StateOptions<T>): StateInstance<T>;
390
- declare function state<T>(key: string, defaultValue: T, options: Omit<StateOptions<T>, 'default'>): StateInstance<T>;
391
- declare function state<T extends string | number | boolean | null | undefined>(key: string, defaultValue: T): StateInstance<Widen<T>>;
392
- /**
393
392
  * Create state stored in `localStorage`.
394
393
  *
395
394
  * ```ts
396
- * const theme = local({ theme: 'light' })
397
- * const synced = local({ theme: 'dark' }, { sync: true })
395
+ * const theme = state.local({ theme: 'light' })
398
396
  * ```
399
397
  */
400
398
  declare function local<T>(entry: Record<string, T>, options?: ShortcutOptions<T>): StateInstance<T>;
401
399
  /**
400
+ * @deprecated Use `state.session()` instead. Will be removed in the next major version.
401
+ *
402
402
  * Create state stored in `sessionStorage`.
403
403
  *
404
404
  * ```ts
405
- * const draft = session({ draft: '' })
405
+ * const draft = state.session({ draft: '' })
406
406
  * ```
407
407
  */
408
408
  declare function session<T>(entry: Record<string, T>, options?: ShortcutOptions<T>): StateInstance<T>;
409
409
  /**
410
+ * @deprecated Use `state.url()` instead. Will be removed in the next major version.
411
+ *
410
412
  * Create state stored in `URLSearchParams`.
411
413
  *
412
414
  * ```ts
413
- * const filters = url({ filters: { q: '' } })
415
+ * const filters = state.url({ q: '' })
414
416
  * ```
415
417
  */
416
418
  declare function url<T>(entry: Record<string, T>, options?: ShortcutOptions<T>): StateInstance<T>;
417
419
  /**
420
+ * @deprecated Use `state.server()` instead. Will be removed in the next major version.
421
+ *
418
422
  * Create state stored in server-side `AsyncLocalStorage`.
419
423
  *
420
424
  * ```ts
421
- * const user = server({ user: null })
425
+ * const user = state.server({ user: null })
422
426
  * ```
423
427
  */
424
428
  declare function server<T>(entry: Record<string, T>, options?: ShortcutOptions<T>): StateInstance<T>;
425
429
  /**
430
+ * @deprecated Use `state.bucket()` instead. Will be removed in the next major version.
431
+ *
426
432
  * Create state stored in a Storage Bucket.
427
433
  *
428
434
  * ```ts
429
- * const data = bucket({ cache: [] }, { bucket: { name: 'my-bucket' } })
435
+ * const data = state.bucket({ cache: [] }, { bucket: { name: 'my-bucket' } })
430
436
  * ```
431
437
  */
432
438
  declare function bucket<T>(entry: Record<string, T>, options: BucketShortcutOptions<T>): StateInstance<T>;
@@ -437,4 +443,4 @@ declare function bucket<T>(entry: Record<string, T>, options: BucketShortcutOpti
437
443
  */
438
444
  declare function shallowEqual(a: unknown, b: unknown): boolean;
439
445
 
440
- export { BaseInstance, type CollectionInstance, type ComputedInstance, type ComputedOptions, type DestroyContext, type EffectHandle, type ErrorContext, type GjendjeConfig, type HistoryOptions, type HydrateContext, type LogLevel, type MigrateContext, type PreviousInstance, type PreviousOptions, type QuotaExceededContext, ReadonlyInstance, type RegisterContext, Scope, type SelectInstance, type SelectOptions, StateInstance, StateOptions, type StateSnapshot, type SyncContext, Unsubscribe, type WithHistoryInstance, type WithWatch, batch, bucket, collection, computed, configure, effect, local, previous, readonly, select, server, session, shallowEqual, snapshot, state, url, withHistory, withWatch };
446
+ export { BaseInstance, type CollectionInstance, type ComputedInstance, type ComputedOptions, type DestroyContext, type EffectHandle, type ErrorContext, type GjendjeConfig, type HistoryOptions, type HydrateContext, type LogLevel, type MigrateContext, type PreviousInstance, type PreviousOptions, type QuotaExceededContext, ReadonlyInstance, type RegisterContext, Scope, type SelectInstance, type SelectOptions, type StateFunction, StateInstance, StateOptions, type StateSnapshot, type SyncContext, Unsubscribe, type WithHistoryInstance, type WithWatch, batch, bucket, collection, computed, configure, effect, local, previous, readonly, select, server, session, shallowEqual, snapshot, state, url, withHistory, withWatch };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BaseInstance, U as Unsubscribe, S as StateOptions, R as ReadonlyInstance, a as Scope, b as StateInstance } from './types-CmmPImmo.js';
2
- export { A as Adapter, c as BucketOptions, E as Enhancer, L as Listener, d as Serializer } from './types-CmmPImmo.js';
1
+ import { B as BaseInstance, U as Unsubscribe, S as StateOptions, R as ReadonlyInstance, a as Scope, b as StateInstance } from './types-DoZ6OB8U.js';
2
+ export { A as Adapter, c as BucketOptions, E as Enhancer, L as Listener, d as Serializer } from './types-DoZ6OB8U.js';
3
3
 
4
4
  /**
5
5
  * Runs all state updates inside fn as a single batch.
@@ -367,66 +367,72 @@ declare function select<TSource, TResult>(source: ReadonlyInstance<TSource>, fn:
367
367
  type Widen<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
368
368
  type ShortcutOptions<T> = Omit<StateOptions<T>, 'default' | 'scope'>;
369
369
  type BucketShortcutOptions<T> = Omit<StateOptions<T>, 'default' | 'scope' | 'bucket'> & Pick<StateOptions<T>, 'bucket'>;
370
+ /** state function with dot-notation scope shortcuts */
371
+ interface StateFunction {
372
+ /** Create in-memory state (default scope) */
373
+ <T>(entry: Record<string, T>, options?: Omit<StateOptions<T>, 'default'>): StateInstance<T>;
374
+ <T>(key: string, options: StateOptions<T>): StateInstance<T>;
375
+ <T>(key: string, defaultValue: T, options: Omit<StateOptions<T>, 'default'>): StateInstance<T>;
376
+ <T extends string | number | boolean | null | undefined>(key: string, defaultValue: T): StateInstance<Widen<T>>;
377
+ /** Create state stored in `localStorage` */
378
+ local: <T>(entry: Record<string, T>, options?: ShortcutOptions<T>) => StateInstance<T>;
379
+ /** Create state stored in `sessionStorage` */
380
+ session: <T>(entry: Record<string, T>, options?: ShortcutOptions<T>) => StateInstance<T>;
381
+ /** Create state stored in `URLSearchParams` */
382
+ url: <T>(entry: Record<string, T>, options?: ShortcutOptions<T>) => StateInstance<T>;
383
+ /** Create state stored in a Storage Bucket */
384
+ bucket: <T>(entry: Record<string, T>, options: BucketShortcutOptions<T>) => StateInstance<T>;
385
+ /** Create state stored in server-side `AsyncLocalStorage` */
386
+ server: <T>(entry: Record<string, T>, options?: ShortcutOptions<T>) => StateInstance<T>;
387
+ }
388
+ declare const state: StateFunction;
370
389
  /**
371
- * Create a stateful value.
372
- *
373
- * Preferred — entry object form (key derived from property name):
390
+ * @deprecated Use `state.local()` instead. Will be removed in the next major version.
374
391
  *
375
- * ```ts
376
- * const counter = state({ counter: 0 })
377
- * const theme = state({ theme: 'light' }, { scope: 'local' })
378
- * ```
379
- *
380
- * Alternative — string key forms:
381
- *
382
- * ```ts
383
- * const theme = state('theme', { default: 'light', scope: 'local' })
384
- * const synced = state('theme', 'light', { scope: 'local', sync: true })
385
- * const counter = state('counter', 0)
386
- * ```
387
- */
388
- declare function state<T>(entry: Record<string, T>, options?: Omit<StateOptions<T>, 'default'>): StateInstance<T>;
389
- declare function state<T>(key: string, options: StateOptions<T>): StateInstance<T>;
390
- declare function state<T>(key: string, defaultValue: T, options: Omit<StateOptions<T>, 'default'>): StateInstance<T>;
391
- declare function state<T extends string | number | boolean | null | undefined>(key: string, defaultValue: T): StateInstance<Widen<T>>;
392
- /**
393
392
  * Create state stored in `localStorage`.
394
393
  *
395
394
  * ```ts
396
- * const theme = local({ theme: 'light' })
397
- * const synced = local({ theme: 'dark' }, { sync: true })
395
+ * const theme = state.local({ theme: 'light' })
398
396
  * ```
399
397
  */
400
398
  declare function local<T>(entry: Record<string, T>, options?: ShortcutOptions<T>): StateInstance<T>;
401
399
  /**
400
+ * @deprecated Use `state.session()` instead. Will be removed in the next major version.
401
+ *
402
402
  * Create state stored in `sessionStorage`.
403
403
  *
404
404
  * ```ts
405
- * const draft = session({ draft: '' })
405
+ * const draft = state.session({ draft: '' })
406
406
  * ```
407
407
  */
408
408
  declare function session<T>(entry: Record<string, T>, options?: ShortcutOptions<T>): StateInstance<T>;
409
409
  /**
410
+ * @deprecated Use `state.url()` instead. Will be removed in the next major version.
411
+ *
410
412
  * Create state stored in `URLSearchParams`.
411
413
  *
412
414
  * ```ts
413
- * const filters = url({ filters: { q: '' } })
415
+ * const filters = state.url({ q: '' })
414
416
  * ```
415
417
  */
416
418
  declare function url<T>(entry: Record<string, T>, options?: ShortcutOptions<T>): StateInstance<T>;
417
419
  /**
420
+ * @deprecated Use `state.server()` instead. Will be removed in the next major version.
421
+ *
418
422
  * Create state stored in server-side `AsyncLocalStorage`.
419
423
  *
420
424
  * ```ts
421
- * const user = server({ user: null })
425
+ * const user = state.server({ user: null })
422
426
  * ```
423
427
  */
424
428
  declare function server<T>(entry: Record<string, T>, options?: ShortcutOptions<T>): StateInstance<T>;
425
429
  /**
430
+ * @deprecated Use `state.bucket()` instead. Will be removed in the next major version.
431
+ *
426
432
  * Create state stored in a Storage Bucket.
427
433
  *
428
434
  * ```ts
429
- * const data = bucket({ cache: [] }, { bucket: { name: 'my-bucket' } })
435
+ * const data = state.bucket({ cache: [] }, { bucket: { name: 'my-bucket' } })
430
436
  * ```
431
437
  */
432
438
  declare function bucket<T>(entry: Record<string, T>, options: BucketShortcutOptions<T>): StateInstance<T>;
@@ -437,4 +443,4 @@ declare function bucket<T>(entry: Record<string, T>, options: BucketShortcutOpti
437
443
  */
438
444
  declare function shallowEqual(a: unknown, b: unknown): boolean;
439
445
 
440
- export { BaseInstance, type CollectionInstance, type ComputedInstance, type ComputedOptions, type DestroyContext, type EffectHandle, type ErrorContext, type GjendjeConfig, type HistoryOptions, type HydrateContext, type LogLevel, type MigrateContext, type PreviousInstance, type PreviousOptions, type QuotaExceededContext, ReadonlyInstance, type RegisterContext, Scope, type SelectInstance, type SelectOptions, StateInstance, StateOptions, type StateSnapshot, type SyncContext, Unsubscribe, type WithHistoryInstance, type WithWatch, batch, bucket, collection, computed, configure, effect, local, previous, readonly, select, server, session, shallowEqual, snapshot, state, url, withHistory, withWatch };
446
+ export { BaseInstance, type CollectionInstance, type ComputedInstance, type ComputedOptions, type DestroyContext, type EffectHandle, type ErrorContext, type GjendjeConfig, type HistoryOptions, type HydrateContext, type LogLevel, type MigrateContext, type PreviousInstance, type PreviousOptions, type QuotaExceededContext, ReadonlyInstance, type RegisterContext, Scope, type SelectInstance, type SelectOptions, type StateFunction, StateInstance, StateOptions, type StateSnapshot, type SyncContext, Unsubscribe, type WithHistoryInstance, type WithWatch, batch, bucket, collection, computed, configure, effect, local, previous, readonly, select, server, session, shallowEqual, snapshot, state, url, withHistory, withWatch };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createBase, createListeners, getRegistry, notify, getConfig, scopedKey, getRegistered, log, createRenderState, registerByKey } from './chunk-5J2W34MR.js';
2
- export { batch, configure, shallowEqual } from './chunk-5J2W34MR.js';
1
+ import { createBase, createListeners, getRegistry, notify, getConfig, scopedKey, getRegistered, log, createRenderState, registerByKey } from './chunk-G6M5RUNT.js';
2
+ export { batch, configure, shallowEqual } from './chunk-G6M5RUNT.js';
3
3
 
4
4
  // src/collection.ts
5
5
  function collection(key, options) {
@@ -559,7 +559,7 @@ function createState(key, options) {
559
559
  );
560
560
  }
561
561
  const rawScope = options.scope ?? config.scope ?? "render";
562
- const scope = rawScope === "memory" ? "render" : rawScope;
562
+ const scope = rawScope === "memory" ? "render" : rawScope === "session" ? "tab" : rawScope;
563
563
  const rKey = scopedKey(key, scope);
564
564
  const existing = getRegistered(rKey);
565
565
  if (existing && !existing.isDestroyed) {
@@ -593,7 +593,35 @@ function extractEntry(entry) {
593
593
  const key = keys[0];
594
594
  return [key, entry[key]];
595
595
  }
596
- function state(keyOrEntry, optionsOrDefault, extraOptions) {
596
+ var _deprecationWarned = /* @__PURE__ */ new Set();
597
+ function warnDeprecated(name) {
598
+ if (_deprecationWarned.has(name)) return;
599
+ _deprecationWarned.add(name);
600
+ console.warn(
601
+ `[gjendje] ${name}() is deprecated and will be removed in the next major version. Use state.${name}() instead. Example: state.${name}({ key: value })`
602
+ );
603
+ }
604
+ function _local(entry, options) {
605
+ const [key, defaultValue] = extractEntry(entry);
606
+ return createState(key, { ...options, default: defaultValue, scope: "local" });
607
+ }
608
+ function _session(entry, options) {
609
+ const [key, defaultValue] = extractEntry(entry);
610
+ return createState(key, { ...options, default: defaultValue, scope: "session" });
611
+ }
612
+ function _url(entry, options) {
613
+ const [key, defaultValue] = extractEntry(entry);
614
+ return createState(key, { ...options, default: defaultValue, scope: "url" });
615
+ }
616
+ function _server(entry, options) {
617
+ const [key, defaultValue] = extractEntry(entry);
618
+ return createState(key, { ...options, default: defaultValue, scope: "server" });
619
+ }
620
+ function _bucket(entry, options) {
621
+ const [key, defaultValue] = extractEntry(entry);
622
+ return createState(key, { ...options, default: defaultValue, scope: "bucket" });
623
+ }
624
+ function _state(keyOrEntry, optionsOrDefault, extraOptions) {
597
625
  let key;
598
626
  let options;
599
627
  if (typeof keyOrEntry === "object") {
@@ -606,25 +634,31 @@ function state(keyOrEntry, optionsOrDefault, extraOptions) {
606
634
  }
607
635
  return createState(key, options);
608
636
  }
637
+ _state.local = _local;
638
+ _state.session = _session;
639
+ _state.url = _url;
640
+ _state.bucket = _bucket;
641
+ _state.server = _server;
642
+ var state = _state;
609
643
  function local(entry, options) {
610
- const [key, defaultValue] = extractEntry(entry);
611
- return createState(key, { ...options, default: defaultValue, scope: "local" });
644
+ warnDeprecated("local");
645
+ return _local(entry, options);
612
646
  }
613
647
  function session(entry, options) {
614
- const [key, defaultValue] = extractEntry(entry);
615
- return createState(key, { ...options, default: defaultValue, scope: "tab" });
648
+ warnDeprecated("session");
649
+ return _session(entry, options);
616
650
  }
617
651
  function url(entry, options) {
618
- const [key, defaultValue] = extractEntry(entry);
619
- return createState(key, { ...options, default: defaultValue, scope: "url" });
652
+ warnDeprecated("url");
653
+ return _url(entry, options);
620
654
  }
621
655
  function server(entry, options) {
622
- const [key, defaultValue] = extractEntry(entry);
623
- return createState(key, { ...options, default: defaultValue, scope: "server" });
656
+ warnDeprecated("server");
657
+ return _server(entry, options);
624
658
  }
625
659
  function bucket(entry, options) {
626
- const [key, defaultValue] = extractEntry(entry);
627
- return createState(key, { ...options, default: defaultValue, scope: "bucket" });
660
+ warnDeprecated("bucket");
661
+ return _bucket(entry, options);
628
662
  }
629
663
 
630
664
  export { bucket, collection, computed, effect, local, previous, readonly, select, server, session, snapshot, state, url, withHistory, withWatch };
package/dist/server.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkIC7SQVDX_cjs = require('./chunk-IC7SQVDX.cjs');
3
+ var chunkPP6KNY6S_cjs = require('./chunk-PP6KNY6S.cjs');
4
4
  var async_hooks = require('async_hooks');
5
5
 
6
6
  var als = new async_hooks.AsyncLocalStorage();
@@ -9,7 +9,7 @@ async function withServerSession(fn) {
9
9
  return als.run(store, fn);
10
10
  }
11
11
  function createServerAdapter(key, defaultValue) {
12
- const listeners = chunkIC7SQVDX_cjs.createListeners();
12
+ const listeners = chunkPP6KNY6S_cjs.createListeners();
13
13
  function getStore() {
14
14
  return als.getStore();
15
15
  }
@@ -31,7 +31,7 @@ function createServerAdapter(key, defaultValue) {
31
31
  }
32
32
  store.set(key, value);
33
33
  lastNotifiedValue = value;
34
- chunkIC7SQVDX_cjs.notify(notifyListeners);
34
+ chunkPP6KNY6S_cjs.notify(notifyListeners);
35
35
  },
36
36
  subscribe: listeners.subscribe,
37
37
  destroy() {
@@ -39,7 +39,7 @@ function createServerAdapter(key, defaultValue) {
39
39
  }
40
40
  };
41
41
  }
42
- chunkIC7SQVDX_cjs.registerServerAdapter(createServerAdapter);
42
+ chunkPP6KNY6S_cjs.registerServerAdapter(createServerAdapter);
43
43
 
44
44
  exports.createServerAdapter = createServerAdapter;
45
45
  exports.withServerSession = withServerSession;
package/dist/server.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as Adapter } from './types-CmmPImmo.cjs';
1
+ import { A as Adapter } from './types-DoZ6OB8U.cjs';
2
2
 
3
3
  declare function withServerSession<T>(fn: () => T): Promise<T>;
4
4
  declare function createServerAdapter<T>(key: string, defaultValue: T): Adapter<T>;
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as Adapter } from './types-CmmPImmo.js';
1
+ import { A as Adapter } from './types-DoZ6OB8U.js';
2
2
 
3
3
  declare function withServerSession<T>(fn: () => T): Promise<T>;
4
4
  declare function createServerAdapter<T>(key: string, defaultValue: T): Adapter<T>;
package/dist/server.js CHANGED
@@ -1,4 +1,4 @@
1
- import { registerServerAdapter, createListeners, notify } from './chunk-5J2W34MR.js';
1
+ import { registerServerAdapter, createListeners, notify } from './chunk-G6M5RUNT.js';
2
2
  import { AsyncLocalStorage } from 'async_hooks';
3
3
 
4
4
  var als = new AsyncLocalStorage();
@@ -1,4 +1,4 @@
1
- type Scope = 'memory' | 'render' | 'tab' | 'local' | 'url' | 'server' | 'bucket';
1
+ type Scope = 'memory' | 'render' | 'session' | 'tab' | 'local' | 'url' | 'server' | 'bucket';
2
2
  interface Adapter<T> {
3
3
  get(): T;
4
4
  set(value: T): void;
@@ -95,7 +95,7 @@ interface BucketOptions {
95
95
  * Scope to use if the Storage Buckets API is not available.
96
96
  * Defaults to 'local'.
97
97
  */
98
- fallback?: 'local' | 'tab';
98
+ fallback?: 'local' | 'session' | 'tab';
99
99
  }
100
100
  interface StateOptions<T> {
101
101
  /** Initial / default value */
@@ -1,4 +1,4 @@
1
- type Scope = 'memory' | 'render' | 'tab' | 'local' | 'url' | 'server' | 'bucket';
1
+ type Scope = 'memory' | 'render' | 'session' | 'tab' | 'local' | 'url' | 'server' | 'bucket';
2
2
  interface Adapter<T> {
3
3
  get(): T;
4
4
  set(value: T): void;
@@ -95,7 +95,7 @@ interface BucketOptions {
95
95
  * Scope to use if the Storage Buckets API is not available.
96
96
  * Defaults to 'local'.
97
97
  */
98
- fallback?: 'local' | 'tab';
98
+ fallback?: 'local' | 'session' | 'tab';
99
99
  }
100
100
  interface StateOptions<T> {
101
101
  /** Initial / default value */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gjendje",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "TypeScript state management",
5
5
  "keywords": [
6
6
  "state",