@thalesfp/snapstate 0.1.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/dist/index.js ADDED
@@ -0,0 +1,498 @@
1
+ // src/core/types.ts
2
+ var _statuses = {
3
+ idle: Object.freeze({ value: "idle", isIdle: true, isLoading: false, isReady: false, isError: false }),
4
+ loading: Object.freeze({ value: "loading", isIdle: false, isLoading: true, isReady: false, isError: false }),
5
+ ready: Object.freeze({ value: "ready", isIdle: false, isLoading: false, isReady: true, isError: false }),
6
+ error: Object.freeze({ value: "error", isIdle: false, isLoading: false, isReady: false, isError: true })
7
+ };
8
+ function asyncStatus(value) {
9
+ return _statuses[value];
10
+ }
11
+
12
+ // src/core/trie.ts
13
+ function invokeAll(listeners) {
14
+ let firstError;
15
+ for (const l of listeners) {
16
+ try {
17
+ l();
18
+ } catch (e) {
19
+ firstError ??= e;
20
+ }
21
+ }
22
+ if (firstError !== void 0) {
23
+ throw firstError;
24
+ }
25
+ }
26
+ function createNode() {
27
+ return { listeners: /* @__PURE__ */ new Set(), children: /* @__PURE__ */ new Map() };
28
+ }
29
+ function parsePath(path) {
30
+ if (path === "") {
31
+ return [];
32
+ }
33
+ return path.split(".");
34
+ }
35
+ var SubscriptionTrie = class {
36
+ root = createNode();
37
+ globalListeners = /* @__PURE__ */ new Set();
38
+ /** Subscribe to a specific path. Returns unsubscribe function. */
39
+ add(path, listener) {
40
+ const segments = parsePath(path);
41
+ const parents = [];
42
+ let node = this.root;
43
+ for (const seg of segments) {
44
+ if (!node.children.has(seg)) {
45
+ node.children.set(seg, createNode());
46
+ }
47
+ parents.push({ parent: node, segment: seg });
48
+ node = node.children.get(seg);
49
+ }
50
+ node.listeners.add(listener);
51
+ return () => {
52
+ node.listeners.delete(listener);
53
+ for (let i = parents.length - 1; i >= 0; i--) {
54
+ const { parent, segment } = parents[i];
55
+ const child = parent.children.get(segment);
56
+ if (child.listeners.size === 0 && child.children.size === 0) {
57
+ parent.children.delete(segment);
58
+ } else {
59
+ break;
60
+ }
61
+ }
62
+ };
63
+ }
64
+ /** Subscribe to all changes (no path filter). */
65
+ addGlobal(listener) {
66
+ this.globalListeners.add(listener);
67
+ return () => {
68
+ this.globalListeners.delete(listener);
69
+ };
70
+ }
71
+ /** Notify listeners for exact path, all ancestors, and all descendants. */
72
+ notify(path) {
73
+ const segments = parsePath(path);
74
+ const collected = /* @__PURE__ */ new Set();
75
+ for (const l of this.globalListeners) collected.add(l);
76
+ let node = this.root;
77
+ for (const l of node.listeners) collected.add(l);
78
+ let matched = true;
79
+ for (const seg of segments) {
80
+ const wildcard = node.children.get("*");
81
+ if (wildcard) {
82
+ for (const l of wildcard.listeners) collected.add(l);
83
+ this.collectDescendants(wildcard, collected);
84
+ }
85
+ const child = node.children.get(seg);
86
+ if (!child) {
87
+ matched = false;
88
+ break;
89
+ }
90
+ node = child;
91
+ for (const l of node.listeners) collected.add(l);
92
+ }
93
+ if (matched) {
94
+ this.collectDescendants(node, collected);
95
+ }
96
+ invokeAll(collected);
97
+ }
98
+ /** Notify all listeners in the trie. */
99
+ notifyAll() {
100
+ const collected = /* @__PURE__ */ new Set();
101
+ for (const l of this.globalListeners) collected.add(l);
102
+ this.collectDescendants(this.root, collected);
103
+ for (const l of this.root.listeners) collected.add(l);
104
+ invokeAll(collected);
105
+ }
106
+ collectDescendants(node, out) {
107
+ for (const child of node.children.values()) {
108
+ for (const l of child.listeners) out.add(l);
109
+ this.collectDescendants(child, out);
110
+ }
111
+ }
112
+ clear() {
113
+ this.root = createNode();
114
+ this.globalListeners.clear();
115
+ }
116
+ };
117
+
118
+ // src/core/structural.ts
119
+ function applyUpdate(state, path, value) {
120
+ const segments = path.split(".");
121
+ return updateAtPath(state, segments, 0, value);
122
+ }
123
+ function updateAtPath(current, segments, index, value) {
124
+ if (index === segments.length) {
125
+ if (typeof value === "function") {
126
+ return value(current);
127
+ }
128
+ return value;
129
+ }
130
+ const key = segments[index];
131
+ if (Array.isArray(current)) {
132
+ const i = Number(key);
133
+ const next2 = updateAtPath(current[i], segments, index + 1, value);
134
+ if (Object.is(next2, current[i])) {
135
+ return current;
136
+ }
137
+ const copy = current.slice();
138
+ copy[i] = next2;
139
+ return copy;
140
+ }
141
+ if (current !== null && typeof current === "object") {
142
+ const obj = current;
143
+ const next2 = updateAtPath(obj[key], segments, index + 1, value);
144
+ if (Object.is(next2, obj[key])) {
145
+ return current;
146
+ }
147
+ return { ...obj, [key]: next2 };
148
+ }
149
+ const next = updateAtPath(void 0, segments, index + 1, value);
150
+ return { [key]: next };
151
+ }
152
+ function getAtPath(state, path) {
153
+ if (path === "") {
154
+ return state;
155
+ }
156
+ const segments = path.split(".");
157
+ let current = state;
158
+ for (const seg of segments) {
159
+ if (current === null || current === void 0) {
160
+ return void 0;
161
+ }
162
+ current = current[seg];
163
+ }
164
+ return current;
165
+ }
166
+
167
+ // src/core/computed.ts
168
+ function createComputed(host, deps, fn) {
169
+ let cachedValue;
170
+ let dirty = true;
171
+ const unsubs = [];
172
+ const markDirty = () => {
173
+ dirty = true;
174
+ };
175
+ for (const dep of deps) {
176
+ unsubs.push(host.subscribe(dep, markDirty));
177
+ }
178
+ try {
179
+ cachedValue = fn(host.getSnapshot());
180
+ } catch (e) {
181
+ for (const unsub of unsubs) unsub();
182
+ unsubs.length = 0;
183
+ throw e;
184
+ }
185
+ dirty = false;
186
+ return {
187
+ get() {
188
+ if (dirty) {
189
+ cachedValue = fn(host.getSnapshot());
190
+ dirty = false;
191
+ }
192
+ return cachedValue;
193
+ },
194
+ destroy() {
195
+ for (const unsub of unsubs) unsub();
196
+ unsubs.length = 0;
197
+ }
198
+ };
199
+ }
200
+
201
+ // src/core/store.ts
202
+ function createStore(initialState, options = {}) {
203
+ const { autoBatch = true } = options;
204
+ let state = initialState;
205
+ const trie = new SubscriptionTrie();
206
+ let batchDepth = 0;
207
+ let pendingPaths = /* @__PURE__ */ new Set();
208
+ let microtaskScheduled = false;
209
+ function flushNotifications() {
210
+ const paths = pendingPaths;
211
+ pendingPaths = /* @__PURE__ */ new Set();
212
+ microtaskScheduled = false;
213
+ if (paths.size === 0) {
214
+ return;
215
+ }
216
+ const sorted = [...paths].sort();
217
+ const deduped = [];
218
+ for (const p of sorted) {
219
+ const last = deduped[deduped.length - 1];
220
+ if (last !== void 0 && p.startsWith(last + ".")) {
221
+ continue;
222
+ }
223
+ deduped.push(p);
224
+ }
225
+ for (const path of deduped) {
226
+ trie.notify(path);
227
+ }
228
+ }
229
+ function scheduleFlush() {
230
+ if (batchDepth > 0) {
231
+ return;
232
+ }
233
+ if (autoBatch && !microtaskScheduled) {
234
+ microtaskScheduled = true;
235
+ queueMicrotask(flushNotifications);
236
+ } else if (!autoBatch) {
237
+ flushNotifications();
238
+ }
239
+ }
240
+ function get(path) {
241
+ if (path === void 0 || path === "") {
242
+ return state;
243
+ }
244
+ return getAtPath(state, path);
245
+ }
246
+ function set(path, value) {
247
+ if (path === "") {
248
+ throw new Error("Cannot set with an empty path. Use a specific path to update state.");
249
+ }
250
+ const prev = state;
251
+ state = applyUpdate(state, path, value);
252
+ if (state !== prev) {
253
+ pendingPaths.add(path);
254
+ scheduleFlush();
255
+ }
256
+ }
257
+ function batch(fn) {
258
+ batchDepth++;
259
+ try {
260
+ fn();
261
+ } finally {
262
+ batchDepth--;
263
+ if (batchDepth === 0) {
264
+ flushNotifications();
265
+ }
266
+ }
267
+ }
268
+ function subscribe(pathOrCallback, callback) {
269
+ if (typeof pathOrCallback === "function") {
270
+ return trie.addGlobal(pathOrCallback);
271
+ }
272
+ return trie.add(pathOrCallback, callback);
273
+ }
274
+ function getSnapshot() {
275
+ return state;
276
+ }
277
+ function computed(deps, fn) {
278
+ return createComputed({ getSnapshot, subscribe }, deps, fn);
279
+ }
280
+ function notify() {
281
+ trie.notifyAll();
282
+ }
283
+ function destroy() {
284
+ trie.clear();
285
+ pendingPaths.clear();
286
+ }
287
+ return {
288
+ get,
289
+ set,
290
+ batch,
291
+ subscribe,
292
+ getSnapshot,
293
+ computed,
294
+ notify,
295
+ destroy
296
+ };
297
+ }
298
+
299
+ // src/core/base.ts
300
+ var IDLE_STATE = { status: asyncStatus("idle"), error: null };
301
+ var defaultHttpClient = {
302
+ async request(url, init) {
303
+ const fetchInit = { method: init?.method ?? "GET" };
304
+ const merged = { ...defaultHeaders, ...init?.headers };
305
+ if (Object.keys(merged).length) {
306
+ fetchInit.headers = merged;
307
+ }
308
+ if (init?.body !== void 0) {
309
+ fetchInit.body = JSON.stringify(init.body);
310
+ fetchInit.headers = { "Content-Type": "application/json", ...merged };
311
+ }
312
+ const res = await fetch(url, fetchInit);
313
+ if (!res.ok) {
314
+ let message = `HTTP ${res.status}`;
315
+ try {
316
+ const text2 = await res.text();
317
+ if (text2) {
318
+ const json = JSON.parse(text2);
319
+ message = json.error ?? json.message ?? message;
320
+ }
321
+ } catch {
322
+ }
323
+ throw new Error(message);
324
+ }
325
+ const text = await res.text();
326
+ return text ? JSON.parse(text) : void 0;
327
+ }
328
+ };
329
+ var httpClient = defaultHttpClient;
330
+ var defaultHeaders = {};
331
+ function setHttpClient(client) {
332
+ httpClient = client;
333
+ }
334
+ function setDefaultHeaders(headers) {
335
+ defaultHeaders = headers;
336
+ }
337
+ var SnapStore = class {
338
+ _store;
339
+ _operations = /* @__PURE__ */ new Map();
340
+ _generations = /* @__PURE__ */ new Map();
341
+ state;
342
+ api;
343
+ constructor(initialState, options) {
344
+ this._store = createStore(initialState, options);
345
+ const store = this._store;
346
+ const operations = this._operations;
347
+ const generations = this._generations;
348
+ const doFetch = async (key, fn) => {
349
+ const gen = (generations.get(key) ?? 0) + 1;
350
+ generations.set(key, gen);
351
+ operations.set(key, { status: asyncStatus("loading"), error: null });
352
+ store.notify();
353
+ try {
354
+ await fn();
355
+ if (generations.get(key) !== gen) {
356
+ return;
357
+ }
358
+ operations.set(key, { status: asyncStatus("ready"), error: null });
359
+ } catch (e) {
360
+ if (generations.get(key) !== gen) {
361
+ return;
362
+ }
363
+ operations.set(key, {
364
+ status: asyncStatus("error"),
365
+ error: e instanceof Error ? e.message : "Unknown error"
366
+ });
367
+ store.notify();
368
+ throw e;
369
+ }
370
+ store.notify();
371
+ };
372
+ const doSend = async (key, method, url, options2) => {
373
+ await doFetch(key, async () => {
374
+ try {
375
+ const data = await httpClient.request(url, {
376
+ method,
377
+ body: options2?.body,
378
+ headers: options2?.headers
379
+ });
380
+ options2?.onSuccess?.(data);
381
+ } catch (e) {
382
+ options2?.onError?.(e instanceof Error ? e : new Error("Unknown error"));
383
+ throw e;
384
+ }
385
+ });
386
+ };
387
+ this.state = {
388
+ get: ((path) => {
389
+ if (path === void 0) {
390
+ return store.get();
391
+ }
392
+ return store.get(path);
393
+ }),
394
+ set: (path, value) => store.set(path, value),
395
+ batch: (fn) => store.batch(fn),
396
+ computed: (deps, fn) => store.computed(deps, fn),
397
+ append: (path, ...items) => {
398
+ store.set(path, ((prev) => [...prev, ...items]));
399
+ },
400
+ prepend: (path, ...items) => {
401
+ store.set(path, ((prev) => [...items, ...prev]));
402
+ },
403
+ insertAt: (path, index, ...items) => {
404
+ store.set(path, ((prev) => {
405
+ const arr = prev;
406
+ return [...arr.slice(0, index), ...items, ...arr.slice(index)];
407
+ }));
408
+ },
409
+ patch: (path, predicate, updates) => {
410
+ store.set(path, ((prev) => {
411
+ const arr = prev;
412
+ let changed = false;
413
+ const result = arr.map((item) => {
414
+ if (item == null) {
415
+ return item;
416
+ }
417
+ if (predicate(item)) {
418
+ changed = true;
419
+ return Object.assign(Object.create(Object.getPrototypeOf(item)), item, updates);
420
+ }
421
+ return item;
422
+ });
423
+ return changed ? result : arr;
424
+ }));
425
+ },
426
+ remove: (path, predicate) => {
427
+ store.set(path, ((prev) => {
428
+ const arr = prev;
429
+ const result = arr.filter((item) => !predicate(item));
430
+ return result.length === arr.length ? arr : result;
431
+ }));
432
+ },
433
+ removeAt: (path, index) => {
434
+ store.set(path, ((prev) => {
435
+ const arr = prev;
436
+ const i = index < 0 ? arr.length + index : index;
437
+ if (i < 0 || i >= arr.length) {
438
+ throw new RangeError(`Index ${index} out of bounds for array of length ${arr.length}`);
439
+ }
440
+ return [...arr.slice(0, i), ...arr.slice(i + 1)];
441
+ }));
442
+ },
443
+ at: (path, index) => {
444
+ return store.get(path).at(index);
445
+ },
446
+ filter: (path, predicate) => {
447
+ return store.get(path).filter(predicate);
448
+ },
449
+ find: (path, predicate) => {
450
+ return store.get(path).find(predicate);
451
+ },
452
+ findIndexOf: (path, predicate) => {
453
+ return store.get(path).findIndex(predicate);
454
+ },
455
+ count: (path, predicate) => {
456
+ return store.get(path).filter(predicate).length;
457
+ }
458
+ };
459
+ this.api = {
460
+ fetch: doFetch,
461
+ get: async (key, url, onSuccess) => {
462
+ await doFetch(key, async () => {
463
+ const data = await httpClient.request(url);
464
+ onSuccess?.(data);
465
+ });
466
+ },
467
+ post: (key, url, options2) => doSend(key, "POST", url, options2),
468
+ put: (key, url, options2) => doSend(key, "PUT", url, options2),
469
+ patch: (key, url, options2) => doSend(key, "PATCH", url, options2),
470
+ delete: (key, url, options2) => doSend(key, "DELETE", url, options2)
471
+ };
472
+ }
473
+ subscribe(pathOrCallback, callback) {
474
+ if (typeof pathOrCallback === "function") {
475
+ return this._store.subscribe(pathOrCallback);
476
+ }
477
+ return this._store.subscribe(pathOrCallback, callback);
478
+ }
479
+ /** Return a snapshot of the current state. Compatible with React's `useSyncExternalStore`. */
480
+ getSnapshot = () => {
481
+ return this._store.getSnapshot();
482
+ };
483
+ /** Get the async status of an operation by key. Returns `idle` if never started. */
484
+ getStatus(key) {
485
+ return { ...this._operations.get(key) ?? IDLE_STATE };
486
+ }
487
+ /** Tear down subscriptions and cleanup. */
488
+ destroy() {
489
+ this._store.destroy();
490
+ }
491
+ };
492
+ export {
493
+ SnapStore,
494
+ asyncStatus,
495
+ setDefaultHeaders,
496
+ setHttpClient
497
+ };
498
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/types.ts","../src/core/trie.ts","../src/core/structural.ts","../src/core/computed.ts","../src/core/store.ts","../src/core/base.ts"],"sourcesContent":["export type AsyncStatusValue = \"idle\" | \"loading\" | \"ready\" | \"error\";\n\nexport interface AsyncStatus {\n readonly value: AsyncStatusValue;\n readonly isIdle: boolean;\n readonly isLoading: boolean;\n readonly isReady: boolean;\n readonly isError: boolean;\n}\n\nconst _statuses: Record<AsyncStatusValue, AsyncStatus> = {\n idle: Object.freeze({ value: \"idle\", isIdle: true, isLoading: false, isReady: false, isError: false }),\n loading: Object.freeze({ value: \"loading\", isIdle: false, isLoading: true, isReady: false, isError: false }),\n ready: Object.freeze({ value: \"ready\", isIdle: false, isLoading: false, isReady: true, isError: false }),\n error: Object.freeze({ value: \"error\", isIdle: false, isLoading: false, isReady: false, isError: true }),\n};\n\nexport function asyncStatus(value: AsyncStatusValue): AsyncStatus {\n return _statuses[value];\n}\n\n/** Async operation status and error. Tracks the lifecycle of an `api.fetch`/`api.get`/`api.post` call. */\nexport interface OperationState {\n status: AsyncStatus;\n error: string | null;\n}\n\nexport type Path = string & { readonly __brand?: \"Path\" };\n\nexport type Listener = () => void;\n\nexport type Unsubscribe = () => void;\n\n// Union of all valid dot-separated paths into T (for autocomplete)\nexport type DotPaths<T, Prefix extends string = \"\"> = T extends object\n ? { [K in keyof T & string]:\n | `${Prefix}${K}`\n | DotPaths<T[K], `${Prefix}${K}.`>\n }[keyof T & string]\n : never;\n\n// Extract a deeply nested type by dot-separated path\nexport type GetByPath<T, P extends string> = P extends \"\"\n ? T\n : P extends `${infer K}.${infer Rest}`\n ? K extends keyof T\n ? GetByPath<T[K], Rest>\n : never\n : P extends keyof T\n ? T[P]\n : never;\n\nexport type DeepPartial<T> = T extends object\n ? { [K in keyof T]?: DeepPartial<T[K]> }\n : T;\n\nexport type ArrayPaths<T> = {\n [K in keyof T & string]: T[K] extends any[] ? K : never;\n}[keyof T & string];\n\nexport type ObjectArrayPaths<T> = {\n [K in keyof T & string]: T[K] extends (infer V)[]\n ? V extends Date | RegExp | Map<any, any> | Set<any> | Function | any[]\n ? never\n : V extends Record<string, any> ? K : never\n : never;\n}[keyof T & string];\n\nexport type ElementOf<A> = A extends (infer V)[] ? V : never;\n\nexport type Updater<V> = V | ((prev: V) => V);\n\nexport interface StoreOptions {\n /** Auto-batch synchronous sets via microtask (default: true) */\n autoBatch?: boolean;\n}\n\n/** Handle to a computed (derived) value. Call `get()` to read, `destroy()` to stop tracking. */\nexport interface ComputedRef<V> {\n get(): V;\n destroy(): void;\n}\n\n/** Options for an HTTP request (method, body, headers). */\nexport interface HttpRequestInit {\n method?: string;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\n/** Interface for the HTTP layer used by `api.get` and `api.post/put/patch/delete`. */\nexport interface HttpClient {\n request<R = unknown>(url: string, init?: HttpRequestInit): Promise<R>;\n}\n\n/** Options for HTTP verb methods (`api.post`, `api.put`, etc.). */\nexport interface ApiRequestOptions<R = unknown> {\n body?: unknown;\n headers?: Record<string, string>;\n onSuccess?: (data: R) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface Subscribable<T extends object> {\n subscribe(callback: Listener): Unsubscribe;\n getSnapshot(): T;\n}\n\nexport interface StateAccessor<T extends object> {\n get(): T;\n get<P extends DotPaths<T>>(path: P): GetByPath<T, P>;\n set<P extends DotPaths<T>>(path: P, value: Updater<GetByPath<T, P>>): void;\n batch(fn: () => void): void;\n computed<V>(deps: (keyof T & string)[], fn: (state: T) => V): ComputedRef<V>;\n append<P extends ArrayPaths<T>>(path: P, ...items: ElementOf<T[P]>[]): void;\n prepend<P extends ArrayPaths<T>>(path: P, ...items: ElementOf<T[P]>[]): void;\n insertAt<P extends ArrayPaths<T>>(path: P, index: number, ...items: ElementOf<T[P]>[]): void;\n patch<P extends ObjectArrayPaths<T>>(path: P, predicate: (item: ElementOf<T[P]>) => boolean, updates: Partial<ElementOf<T[P]>>): void;\n remove<P extends ArrayPaths<T>>(path: P, predicate: (item: ElementOf<T[P]>) => boolean): void;\n removeAt<P extends ArrayPaths<T>>(path: P, index: number): void;\n at<P extends ArrayPaths<T>>(path: P, index: number): ElementOf<T[P]> | undefined;\n filter<P extends ArrayPaths<T>>(path: P, predicate: (item: ElementOf<T[P]>) => boolean): ElementOf<T[P]>[];\n find<P extends ArrayPaths<T>>(path: P, predicate: (item: ElementOf<T[P]>) => boolean): ElementOf<T[P]> | undefined;\n findIndexOf<P extends ArrayPaths<T>>(path: P, predicate: (item: ElementOf<T[P]>) => boolean): number;\n count<P extends ArrayPaths<T>>(path: P, predicate: (item: ElementOf<T[P]>) => boolean): number;\n}\n\nexport interface ApiAccessor<K extends string> {\n fetch(key: K, fn: () => Promise<void>): Promise<void>;\n get<R = unknown>(key: K, url: string, onSuccess?: (data: R) => void): Promise<void>;\n post<R = unknown>(key: K, url: string, options?: ApiRequestOptions<R>): Promise<void>;\n put<R = unknown>(key: K, url: string, options?: ApiRequestOptions<R>): Promise<void>;\n patch<R = unknown>(key: K, url: string, options?: ApiRequestOptions<R>): Promise<void>;\n delete<R = unknown>(key: K, url: string, options?: ApiRequestOptions<R>): Promise<void>;\n}\n\nexport interface RawStore<T extends object> extends Subscribable<T> {\n get(): T;\n get<P extends DotPaths<T>>(path: P): GetByPath<T, P>;\n\n set<P extends DotPaths<T>>(path: P, value: Updater<GetByPath<T, P>>): void;\n\n batch(fn: () => void): void;\n\n subscribe(callback: Listener): Unsubscribe;\n subscribe(path: string, callback: Listener): Unsubscribe;\n\n getSnapshot(): T;\n\n computed<V>(deps: (keyof T & string)[], fn: (state: T) => V): ComputedRef<V>;\n\n notify(): void;\n\n destroy(): void;\n}\n","import type { Listener, Unsubscribe } from \"./types.js\";\n\nfunction invokeAll(listeners: Set<Listener>): void {\n let firstError: unknown;\n for (const l of listeners) {\n try { l(); } catch (e) { firstError ??= e; }\n }\n if (firstError !== undefined) { throw firstError; }\n}\n\ninterface TrieNode {\n listeners: Set<Listener>;\n children: Map<string, TrieNode>;\n}\n\nfunction createNode(): TrieNode {\n return { listeners: new Set(), children: new Map() };\n}\n\nfunction parsePath(path: string): string[] {\n if (path === \"\") { return []; }\n return path.split(\".\");\n}\n\nexport class SubscriptionTrie {\n private root = createNode();\n private globalListeners = new Set<Listener>();\n\n /** Subscribe to a specific path. Returns unsubscribe function. */\n add(path: string, listener: Listener): Unsubscribe {\n const segments = parsePath(path);\n const parents: { parent: TrieNode; segment: string }[] = [];\n let node = this.root;\n for (const seg of segments) {\n if (!node.children.has(seg)) {\n node.children.set(seg, createNode());\n }\n parents.push({ parent: node, segment: seg });\n node = node.children.get(seg)!;\n }\n node.listeners.add(listener);\n return () => {\n node.listeners.delete(listener);\n for (let i = parents.length - 1; i >= 0; i--) {\n const { parent, segment } = parents[i];\n const child = parent.children.get(segment)!;\n if (child.listeners.size === 0 && child.children.size === 0) {\n parent.children.delete(segment);\n } else {\n break;\n }\n }\n };\n }\n\n /** Subscribe to all changes (no path filter). */\n addGlobal(listener: Listener): Unsubscribe {\n this.globalListeners.add(listener);\n return () => {\n this.globalListeners.delete(listener);\n };\n }\n\n /** Notify listeners for exact path, all ancestors, and all descendants. */\n notify(path: string): void {\n const segments = parsePath(path);\n const collected = new Set<Listener>();\n\n // Collect global listeners\n for (const l of this.globalListeners) collected.add(l);\n\n // Walk down to the target, collecting ancestor listeners\n let node = this.root;\n // Root-level listeners (subscribe to \"\")\n for (const l of node.listeners) collected.add(l);\n\n let matched = true;\n for (const seg of segments) {\n // Check wildcard sibling at this level\n const wildcard = node.children.get(\"*\");\n if (wildcard) {\n for (const l of wildcard.listeners) collected.add(l);\n this.collectDescendants(wildcard, collected);\n }\n\n const child = node.children.get(seg);\n if (!child) {\n matched = false;\n break;\n }\n node = child;\n for (const l of node.listeners) collected.add(l);\n }\n\n // Only collect descendants if we matched the full path\n if (matched) {\n this.collectDescendants(node, collected);\n }\n\n invokeAll(collected);\n }\n\n /** Notify all listeners in the trie. */\n notifyAll(): void {\n const collected = new Set<Listener>();\n for (const l of this.globalListeners) collected.add(l);\n this.collectDescendants(this.root, collected);\n for (const l of this.root.listeners) collected.add(l);\n invokeAll(collected);\n }\n\n private collectDescendants(node: TrieNode, out: Set<Listener>): void {\n for (const child of node.children.values()) {\n for (const l of child.listeners) out.add(l);\n this.collectDescendants(child, out);\n }\n }\n\n clear(): void {\n this.root = createNode();\n this.globalListeners.clear();\n }\n}\n","/**\n * Immutable update with structural sharing.\n * Only clones objects along the changed path; unchanged subtrees keep their references.\n */\nexport function applyUpdate<T extends object>(\n state: T,\n path: string,\n value: unknown,\n): T {\n const segments = path.split(\".\");\n return updateAtPath(state, segments, 0, value) as T;\n}\n\nfunction updateAtPath(\n current: unknown,\n segments: string[],\n index: number,\n value: unknown,\n): unknown {\n if (index === segments.length) {\n // Functional updater support\n if (typeof value === \"function\") {\n return (value as (prev: unknown) => unknown)(current);\n }\n return value;\n }\n\n const key = segments[index];\n\n if (Array.isArray(current)) {\n const i = Number(key);\n const next = updateAtPath(current[i], segments, index + 1, value);\n if (Object.is(next, current[i])) { return current; }\n const copy = current.slice();\n copy[i] = next;\n return copy;\n }\n\n if (current !== null && typeof current === \"object\") {\n const obj = current as Record<string, unknown>;\n const next = updateAtPath(obj[key], segments, index + 1, value);\n if (Object.is(next, obj[key])) { return current; }\n return { ...obj, [key]: next };\n }\n\n // Path doesn't exist yet — create nested objects\n const next = updateAtPath(undefined, segments, index + 1, value);\n return { [key]: next };\n}\n\n/** Read a value at a dot-separated path. */\nexport function getAtPath(state: unknown, path: string): unknown {\n if (path === \"\") { return state; }\n const segments = path.split(\".\");\n let current = state;\n for (const seg of segments) {\n if (current === null || current === undefined) { return undefined; }\n current = (current as Record<string, unknown>)[seg];\n }\n return current;\n}\n","import type { ComputedRef, Listener, Unsubscribe } from \"./types.js\";\n\ninterface ComputedHost {\n getSnapshot(): object;\n subscribe(path: string, callback: Listener): Unsubscribe;\n}\n\nexport function createComputed<T extends object, V>(\n host: ComputedHost,\n deps: string[],\n fn: (state: T) => V,\n): ComputedRef<V> {\n let cachedValue: V;\n let dirty = true;\n const unsubs: Unsubscribe[] = [];\n\n const markDirty = () => {\n dirty = true;\n };\n\n for (const dep of deps) {\n unsubs.push(host.subscribe(dep, markDirty));\n }\n\n // Compute initial value; clean up subscriptions if it throws\n try {\n cachedValue = fn(host.getSnapshot() as T);\n } catch (e) {\n for (const unsub of unsubs) unsub();\n unsubs.length = 0;\n throw e;\n }\n dirty = false;\n\n return {\n get(): V {\n if (dirty) {\n cachedValue = fn(host.getSnapshot() as T);\n dirty = false;\n }\n return cachedValue;\n },\n destroy(): void {\n for (const unsub of unsubs) unsub();\n unsubs.length = 0;\n },\n };\n}\n","import type {\n RawStore,\n StoreOptions,\n Listener,\n Unsubscribe,\n Updater,\n ComputedRef,\n GetByPath,\n} from \"./types.js\";\nimport { SubscriptionTrie } from \"./trie.js\";\nimport { applyUpdate, getAtPath } from \"./structural.js\";\nimport { createComputed } from \"./computed.js\";\n\nexport function createStore<T extends object>(\n initialState: T,\n options: StoreOptions = {},\n): RawStore<T> {\n const { autoBatch = true } = options;\n\n let state: T = initialState;\n const trie = new SubscriptionTrie();\n\n // Batching\n let batchDepth = 0;\n let pendingPaths = new Set<string>();\n let microtaskScheduled = false;\n\n function flushNotifications(): void {\n const paths = pendingPaths;\n pendingPaths = new Set();\n microtaskScheduled = false;\n\n if (paths.size === 0) { return; }\n\n // Deduplicate: if a parent path is present, skip its children\n const sorted = [...paths].sort();\n const deduped: string[] = [];\n for (const p of sorted) {\n const last = deduped[deduped.length - 1];\n if (last !== undefined && p.startsWith(last + \".\")) { continue; }\n deduped.push(p);\n }\n\n for (const path of deduped) {\n trie.notify(path);\n }\n }\n\n function scheduleFlush(): void {\n if (batchDepth > 0) { return; }\n if (autoBatch && !microtaskScheduled) {\n microtaskScheduled = true;\n queueMicrotask(flushNotifications);\n } else if (!autoBatch) {\n flushNotifications();\n }\n }\n\n function get(): T;\n function get<P extends string>(path: P): GetByPath<T, P>;\n function get(path?: string): unknown {\n if (path === undefined || path === \"\") { return state; }\n return getAtPath(state, path);\n }\n\n function set<P extends string>(\n path: P,\n value: Updater<GetByPath<T, P>>,\n ): void {\n if (path === \"\") {\n throw new Error(\"Cannot set with an empty path. Use a specific path to update state.\");\n }\n const prev = state;\n state = applyUpdate(state, path, value);\n if (state !== prev) {\n pendingPaths.add(path);\n scheduleFlush();\n }\n }\n\n function batch(fn: () => void): void {\n batchDepth++;\n try {\n fn();\n } finally {\n batchDepth--;\n if (batchDepth === 0) {\n flushNotifications();\n }\n }\n }\n\n function subscribe(callback: Listener): Unsubscribe;\n function subscribe(path: string, callback: Listener): Unsubscribe;\n function subscribe(\n pathOrCallback: string | Listener,\n callback?: Listener,\n ): Unsubscribe {\n if (typeof pathOrCallback === \"function\") {\n return trie.addGlobal(pathOrCallback);\n }\n return trie.add(pathOrCallback, callback!);\n }\n\n function getSnapshot(): T {\n return state;\n }\n\n function computed<V>(deps: (keyof T & string)[], fn: (state: T) => V): ComputedRef<V> {\n return createComputed<T, V>({ getSnapshot, subscribe }, deps, fn);\n }\n\n function notify(): void {\n trie.notifyAll();\n }\n\n function destroy(): void {\n trie.clear();\n pendingPaths.clear();\n }\n\n return {\n get,\n set,\n batch,\n subscribe,\n getSnapshot,\n computed,\n notify,\n destroy,\n } as RawStore<T>;\n}\n","import type {\n RawStore,\n StoreOptions,\n Listener,\n Unsubscribe,\n OperationState,\n HttpClient,\n StateAccessor,\n ApiAccessor,\n ApiRequestOptions,\n} from \"./types.js\";\nimport { asyncStatus } from \"./types.js\";\nimport { createStore } from \"./store.js\";\n\nconst IDLE_STATE: OperationState = { status: asyncStatus(\"idle\"), error: null };\n\nconst defaultHttpClient: HttpClient = {\n async request(url, init) {\n const fetchInit: RequestInit = { method: init?.method ?? \"GET\" };\n const merged = { ...defaultHeaders, ...init?.headers };\n if (Object.keys(merged).length) { fetchInit.headers = merged; }\n if (init?.body !== undefined) {\n fetchInit.body = JSON.stringify(init.body);\n fetchInit.headers = { \"Content-Type\": \"application/json\", ...merged };\n }\n const res = await fetch(url, fetchInit);\n if (!res.ok) {\n let message = `HTTP ${res.status}`;\n try {\n const text = await res.text();\n if (text) {\n const json = JSON.parse(text);\n message = json.error ?? json.message ?? message;\n }\n } catch {}\n throw new Error(message);\n }\n const text = await res.text();\n return text ? JSON.parse(text) : undefined;\n },\n};\n\nlet httpClient: HttpClient = defaultHttpClient;\nlet defaultHeaders: Record<string, string> = {};\n\n/** Replace the global HTTP client used by `api.get` and `api.post/put/patch/delete`. */\nexport function setHttpClient(client: HttpClient): void {\n httpClient = client;\n}\n\n/** Set default headers merged into every HTTP request. Per-request headers override defaults. */\nexport function setDefaultHeaders(headers: Record<string, string>): void {\n defaultHeaders = headers;\n}\n\nexport class SnapStore<T extends object, K extends string = string> {\n private _store: RawStore<T>;\n private _operations = new Map<K, OperationState>();\n private _generations = new Map<K, number>();\n\n protected readonly state: StateAccessor<T>;\n protected readonly api: ApiAccessor<K>;\n\n constructor(initialState: T, options?: StoreOptions) {\n this._store = createStore(initialState, options);\n\n const store = this._store;\n const operations = this._operations;\n const generations = this._generations;\n\n // takeLatest semantic: if a newer call starts for the same key, the older\n // call's promise resolves silently (no reject, no state update).\n const doFetch = async (key: K, fn: () => Promise<void>): Promise<void> => {\n const gen = (generations.get(key) ?? 0) + 1;\n generations.set(key, gen);\n operations.set(key, { status: asyncStatus(\"loading\"), error: null });\n store.notify();\n try {\n await fn();\n if (generations.get(key) !== gen) { return; }\n operations.set(key, { status: asyncStatus(\"ready\"), error: null });\n } catch (e) {\n if (generations.get(key) !== gen) { return; }\n operations.set(key, {\n status: asyncStatus(\"error\"),\n error: e instanceof Error ? e.message : \"Unknown error\",\n });\n store.notify();\n throw e;\n }\n store.notify();\n };\n\n const doSend = async <R>(key: K, method: string, url: string, options?: ApiRequestOptions<R>): Promise<void> => {\n await doFetch(key, async () => {\n try {\n const data = await httpClient.request<R>(url, {\n method,\n body: options?.body,\n headers: options?.headers,\n });\n options?.onSuccess?.(data);\n } catch (e) {\n options?.onError?.(e instanceof Error ? e : new Error(\"Unknown error\"));\n throw e;\n }\n });\n };\n\n this.state = {\n get: ((path?: string): unknown => {\n if (path === undefined) { return store.get(); }\n return (store.get as (p: string) => unknown)(path);\n }) as StateAccessor<T>[\"get\"],\n\n set: (path, value) => store.set(path, value),\n batch: (fn) => store.batch(fn),\n computed: (deps, fn) => store.computed(deps, fn),\n\n append: (path, ...items) => {\n store.set(path as any, ((prev: any) => [...(prev as any[]), ...items]) as any);\n },\n prepend: (path, ...items) => {\n store.set(path as any, ((prev: any) => [...items, ...(prev as any[])]) as any);\n },\n insertAt: (path, index, ...items) => {\n store.set(path as any, ((prev: any) => {\n const arr = prev as any[];\n return [...arr.slice(0, index), ...items, ...arr.slice(index)];\n }) as any);\n },\n patch: (path, predicate, updates) => {\n store.set(path as any, ((prev: any) => {\n const arr = prev as any[];\n let changed = false;\n const result = arr.map((item: any) => {\n if (item == null) { return item; }\n if (predicate(item)) {\n changed = true;\n return Object.assign(Object.create(Object.getPrototypeOf(item)), item, updates);\n }\n return item;\n });\n return changed ? result : arr;\n }) as any);\n },\n remove: (path, predicate) => {\n store.set(path as any, ((prev: any) => {\n const arr = prev as any[];\n const result = arr.filter((item: any) => !predicate(item));\n return result.length === arr.length ? arr : result;\n }) as any);\n },\n removeAt: (path, index) => {\n store.set(path as any, ((prev: any) => {\n const arr = prev as any[];\n const i = index < 0 ? arr.length + index : index;\n if (i < 0 || i >= arr.length) {\n throw new RangeError(`Index ${index} out of bounds for array of length ${arr.length}`);\n }\n return [...arr.slice(0, i), ...arr.slice(i + 1)];\n }) as any);\n },\n at: (path, index) => {\n return (store.get(path as any) as any[]).at(index);\n },\n filter: (path, predicate) => {\n return (store.get(path as any) as any[]).filter(predicate);\n },\n find: (path, predicate) => {\n return (store.get(path as any) as any[]).find(predicate);\n },\n findIndexOf: (path, predicate) => {\n return (store.get(path as any) as any[]).findIndex(predicate);\n },\n count: (path, predicate) => {\n return (store.get(path as any) as any[]).filter(predicate).length;\n },\n };\n\n this.api = {\n fetch: doFetch,\n get: async <R>(key: K, url: string, onSuccess?: (data: R) => void): Promise<void> => {\n await doFetch(key, async () => {\n const data = await httpClient.request<R>(url);\n onSuccess?.(data);\n });\n },\n post: (key, url, options?) => doSend(key, \"POST\", url, options),\n put: (key, url, options?) => doSend(key, \"PUT\", url, options),\n patch: (key, url, options?) => doSend(key, \"PATCH\", url, options),\n delete: (key, url, options?) => doSend(key, \"DELETE\", url, options),\n };\n }\n\n /** Subscribe to all state changes. Returns an unsubscribe function. */\n subscribe(callback: Listener): Unsubscribe;\n /** Subscribe to changes at a specific dot-separated path. */\n subscribe(path: string, callback: Listener): Unsubscribe;\n subscribe(pathOrCallback: string | Listener, callback?: Listener): Unsubscribe {\n if (typeof pathOrCallback === \"function\") {\n return this._store.subscribe(pathOrCallback);\n }\n return this._store.subscribe(pathOrCallback, callback!);\n }\n\n /** Return a snapshot of the current state. Compatible with React's `useSyncExternalStore`. */\n getSnapshot = (): T => {\n return this._store.getSnapshot();\n };\n\n /** Get the async status of an operation by key. Returns `idle` if never started. */\n getStatus(key: K): OperationState {\n return { ...(this._operations.get(key) ?? IDLE_STATE) };\n }\n\n /** Tear down subscriptions and cleanup. */\n destroy(): void {\n this._store.destroy();\n }\n}\n"],"mappings":"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","names":["next","text","options"]}