@c9up/aurora 0.1.21 → 0.1.22

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/browser.d.ts CHANGED
@@ -31,10 +31,14 @@ export interface WebStorageOptions {
31
31
  area?: StorageArea;
32
32
  }
33
33
  /**
34
- * Typed, SSR-safe key/value store over `localStorage` / `sessionStorage`.
34
+ * SSR-safe key/value store over `localStorage` / `sessionStorage`.
35
35
  *
36
- * - Values are JSON-serialised; reads return `null` on the server, on a missing
37
- * key, or on malformed JSON.
36
+ * - {@link get} / {@link set} are a thin pass-through raw strings, no JSON,
37
+ * exactly like the native `localStorage` API (so a token round-trips as-is,
38
+ * not double-encoded). {@link getJSON} / {@link setJSON} are the opt-in
39
+ * variants for structured values.
40
+ * - Reads return `null` on the server or a missing key (`getJSON` also on
41
+ * malformed JSON).
38
42
  * - Writes swallow quota / private-mode errors so a full store never crashes
39
43
  * the app (best-effort).
40
44
  * - `prefix` namespaces keys; {@link keys} and {@link clear} stay scoped to it,
@@ -45,13 +49,31 @@ export declare class WebStorage {
45
49
  constructor(options?: WebStorageOptions);
46
50
  /** The on-disk key for `key`, namespaced by the configured prefix. */
47
51
  fullKey(key: string): string;
48
- get<T>(key: string): T | null;
49
- set(key: string, value: unknown): void;
52
+ /**
53
+ * Read the raw string at `key` — a thin, SSR-safe pass-through over
54
+ * `localStorage.getItem` (returns `null` on the server or a missing key).
55
+ * No JSON: what you {@link set} is what you get. Use {@link getJSON} for
56
+ * structured values.
57
+ */
58
+ get(key: string): string | null;
59
+ /**
60
+ * Write the raw string `value` at `key` (SSR no-op; quota / private-mode
61
+ * errors are swallowed — best-effort). No encoding, like
62
+ * `localStorage.setItem`. Use {@link setJSON} for objects/arrays/etc.
63
+ */
64
+ set(key: string, value: string): void;
65
+ /**
66
+ * Read `key` and JSON-parse it into `T`. Returns `null` on the server, a
67
+ * missing key, or malformed JSON. Pair with {@link setJSON}.
68
+ */
69
+ getJSON<T>(key: string): T | null;
70
+ /** JSON-serialise `value` and store it at `key`. Pair with {@link getJSON}. */
71
+ setJSON(key: string, value: unknown): void;
50
72
  /** Whether `key` is present (and not the server). */
51
73
  has(key: string): boolean;
52
74
  remove(key: string): void;
53
- /** Read `key`, or compute + persist `factory()` on a miss, returning the value. */
54
- getOrSet<T>(key: string, factory: () => T): T;
75
+ /** Read `key`, or compute + persist `factory()` on a miss, returning the string. */
76
+ getOrSet(key: string, factory: () => string): string;
55
77
  /** Keys in this store, prefix stripped. Empty array during SSR. */
56
78
  keys(): string[];
57
79
  /** Remove this store's keys. With no prefix this clears the whole area. */
package/dist/browser.js CHANGED
@@ -29,10 +29,14 @@ export function reload() {
29
29
  }
30
30
  }
31
31
  /**
32
- * Typed, SSR-safe key/value store over `localStorage` / `sessionStorage`.
32
+ * SSR-safe key/value store over `localStorage` / `sessionStorage`.
33
33
  *
34
- * - Values are JSON-serialised; reads return `null` on the server, on a missing
35
- * key, or on malformed JSON.
34
+ * - {@link get} / {@link set} are a thin pass-through raw strings, no JSON,
35
+ * exactly like the native `localStorage` API (so a token round-trips as-is,
36
+ * not double-encoded). {@link getJSON} / {@link setJSON} are the opt-in
37
+ * variants for structured values.
38
+ * - Reads return `null` on the server or a missing key (`getJSON` also on
39
+ * malformed JSON).
36
40
  * - Writes swallow quota / private-mode errors so a full store never crashes
37
41
  * the app (best-effort).
38
42
  * - `prefix` namespaces keys; {@link keys} and {@link clear} stay scoped to it,
@@ -56,31 +60,53 @@ export class WebStorage {
56
60
  fullKey(key) {
57
61
  return this.#prefix + key;
58
62
  }
63
+ /**
64
+ * Read the raw string at `key` — a thin, SSR-safe pass-through over
65
+ * `localStorage.getItem` (returns `null` on the server or a missing key).
66
+ * No JSON: what you {@link set} is what you get. Use {@link getJSON} for
67
+ * structured values.
68
+ */
59
69
  get(key) {
60
70
  const backend = this.#backend();
61
71
  if (!backend)
62
72
  return null;
63
- const raw = backend.getItem(this.fullKey(key));
64
- if (raw === null)
65
- return null;
66
- try {
67
- return JSON.parse(raw);
68
- }
69
- catch {
70
- return null;
71
- }
73
+ return backend.getItem(this.fullKey(key));
72
74
  }
75
+ /**
76
+ * Write the raw string `value` at `key` (SSR no-op; quota / private-mode
77
+ * errors are swallowed — best-effort). No encoding, like
78
+ * `localStorage.setItem`. Use {@link setJSON} for objects/arrays/etc.
79
+ */
73
80
  set(key, value) {
74
81
  const backend = this.#backend();
75
82
  if (!backend)
76
83
  return;
77
84
  try {
78
- backend.setItem(this.fullKey(key), JSON.stringify(value));
85
+ backend.setItem(this.fullKey(key), value);
79
86
  }
80
87
  catch {
81
88
  // QuotaExceededError / Safari private mode — best-effort write.
82
89
  }
83
90
  }
91
+ /**
92
+ * Read `key` and JSON-parse it into `T`. Returns `null` on the server, a
93
+ * missing key, or malformed JSON. Pair with {@link setJSON}.
94
+ */
95
+ getJSON(key) {
96
+ const raw = this.get(key);
97
+ if (raw === null)
98
+ return null;
99
+ try {
100
+ return JSON.parse(raw);
101
+ }
102
+ catch {
103
+ return null;
104
+ }
105
+ }
106
+ /** JSON-serialise `value` and store it at `key`. Pair with {@link getJSON}. */
107
+ setJSON(key, value) {
108
+ this.set(key, JSON.stringify(value));
109
+ }
84
110
  /** Whether `key` is present (and not the server). */
85
111
  has(key) {
86
112
  const backend = this.#backend();
@@ -91,7 +117,7 @@ export class WebStorage {
91
117
  remove(key) {
92
118
  this.#backend()?.removeItem(this.fullKey(key));
93
119
  }
94
- /** Read `key`, or compute + persist `factory()` on a miss, returning the value. */
120
+ /** Read `key`, or compute + persist `factory()` on a miss, returning the string. */
95
121
  getOrSet(key, factory) {
96
122
  const existing = this.get(key);
97
123
  if (existing !== null)
@@ -148,11 +174,12 @@ export const session = new WebStorage({ area: "session" });
148
174
  */
149
175
  export function persistedSignal(key, initial, options = {}) {
150
176
  const store = new WebStorage(options);
151
- const stored = store.get(key);
177
+ const stored = store.getJSON(key);
152
178
  const sig = signal(stored !== null ? stored : initial);
153
179
  // Mirror every change back to storage; runs once immediately, then on change.
180
+ // JSON so any T (object, number, boolean, string) round-trips.
154
181
  effect(() => {
155
- store.set(key, sig());
182
+ store.setJSON(key, sig());
156
183
  });
157
184
  if ((options.crossTab ?? true) &&
158
185
  (options.area ?? "local") === "local" &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c9up/aurora",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "Aurora — reactive UI runtime for the Ream framework. Tagged-template DOM, signal-based state, isomorphic SSR + hydration, zero build step.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/browser.ts CHANGED
@@ -50,10 +50,14 @@ export interface WebStorageOptions {
50
50
  }
51
51
 
52
52
  /**
53
- * Typed, SSR-safe key/value store over `localStorage` / `sessionStorage`.
53
+ * SSR-safe key/value store over `localStorage` / `sessionStorage`.
54
54
  *
55
- * - Values are JSON-serialised; reads return `null` on the server, on a missing
56
- * key, or on malformed JSON.
55
+ * - {@link get} / {@link set} are a thin pass-through raw strings, no JSON,
56
+ * exactly like the native `localStorage` API (so a token round-trips as-is,
57
+ * not double-encoded). {@link getJSON} / {@link setJSON} are the opt-in
58
+ * variants for structured values.
59
+ * - Reads return `null` on the server or a missing key (`getJSON` also on
60
+ * malformed JSON).
57
61
  * - Writes swallow quota / private-mode errors so a full store never crashes
58
62
  * the app (best-effort).
59
63
  * - `prefix` namespaces keys; {@link keys} and {@link clear} stay scoped to it,
@@ -80,28 +84,52 @@ export class WebStorage {
80
84
  return this.#prefix + key;
81
85
  }
82
86
 
83
- get<T>(key: string): T | null {
87
+ /**
88
+ * Read the raw string at `key` — a thin, SSR-safe pass-through over
89
+ * `localStorage.getItem` (returns `null` on the server or a missing key).
90
+ * No JSON: what you {@link set} is what you get. Use {@link getJSON} for
91
+ * structured values.
92
+ */
93
+ get(key: string): string | null {
84
94
  const backend = this.#backend();
85
95
  if (!backend) return null;
86
- const raw = backend.getItem(this.fullKey(key));
87
- if (raw === null) return null;
88
- try {
89
- return JSON.parse(raw) as T;
90
- } catch {
91
- return null;
92
- }
96
+ return backend.getItem(this.fullKey(key));
93
97
  }
94
98
 
95
- set(key: string, value: unknown): void {
99
+ /**
100
+ * Write the raw string `value` at `key` (SSR no-op; quota / private-mode
101
+ * errors are swallowed — best-effort). No encoding, like
102
+ * `localStorage.setItem`. Use {@link setJSON} for objects/arrays/etc.
103
+ */
104
+ set(key: string, value: string): void {
96
105
  const backend = this.#backend();
97
106
  if (!backend) return;
98
107
  try {
99
- backend.setItem(this.fullKey(key), JSON.stringify(value));
108
+ backend.setItem(this.fullKey(key), value);
100
109
  } catch {
101
110
  // QuotaExceededError / Safari private mode — best-effort write.
102
111
  }
103
112
  }
104
113
 
114
+ /**
115
+ * Read `key` and JSON-parse it into `T`. Returns `null` on the server, a
116
+ * missing key, or malformed JSON. Pair with {@link setJSON}.
117
+ */
118
+ getJSON<T>(key: string): T | null {
119
+ const raw = this.get(key);
120
+ if (raw === null) return null;
121
+ try {
122
+ return JSON.parse(raw) as T;
123
+ } catch {
124
+ return null;
125
+ }
126
+ }
127
+
128
+ /** JSON-serialise `value` and store it at `key`. Pair with {@link getJSON}. */
129
+ setJSON(key: string, value: unknown): void {
130
+ this.set(key, JSON.stringify(value));
131
+ }
132
+
105
133
  /** Whether `key` is present (and not the server). */
106
134
  has(key: string): boolean {
107
135
  const backend = this.#backend();
@@ -113,9 +141,9 @@ export class WebStorage {
113
141
  this.#backend()?.removeItem(this.fullKey(key));
114
142
  }
115
143
 
116
- /** Read `key`, or compute + persist `factory()` on a miss, returning the value. */
117
- getOrSet<T>(key: string, factory: () => T): T {
118
- const existing = this.get<T>(key);
144
+ /** Read `key`, or compute + persist `factory()` on a miss, returning the string. */
145
+ getOrSet(key: string, factory: () => string): string {
146
+ const existing = this.get(key);
119
147
  if (existing !== null) return existing;
120
148
  const value = factory();
121
149
  this.set(key, value);
@@ -183,12 +211,13 @@ export function persistedSignal<T>(
183
211
  options: PersistedSignalOptions = {},
184
212
  ): Signal<T> {
185
213
  const store = new WebStorage(options);
186
- const stored = store.get<T>(key);
214
+ const stored = store.getJSON<T>(key);
187
215
  const sig = signal<T>(stored !== null ? stored : initial);
188
216
 
189
217
  // Mirror every change back to storage; runs once immediately, then on change.
218
+ // JSON so any T (object, number, boolean, string) round-trips.
190
219
  effect(() => {
191
- store.set(key, sig());
220
+ store.setJSON(key, sig());
192
221
  });
193
222
 
194
223
  if (