@oddkin/state 0.0.0-stage → 1.0.0-beta.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -2
  3. package/dist/context/context.d.ts +77 -0
  4. package/dist/context/context.d.ts.map +1 -0
  5. package/dist/context/context.js +335 -0
  6. package/dist/context/context.js.map +1 -0
  7. package/dist/context/index.d.ts +8 -0
  8. package/dist/context/index.d.ts.map +1 -0
  9. package/dist/context/index.js +7 -0
  10. package/dist/context/index.js.map +1 -0
  11. package/dist/index.d.ts +15 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +15 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/inspect/index.d.ts +33 -0
  16. package/dist/inspect/index.d.ts.map +1 -0
  17. package/dist/inspect/index.js +63 -0
  18. package/dist/inspect/index.js.map +1 -0
  19. package/dist/internal/dev.d.ts +6 -0
  20. package/dist/internal/dev.d.ts.map +1 -0
  21. package/dist/internal/dev.js +6 -0
  22. package/dist/internal/dev.js.map +1 -0
  23. package/dist/persist/index.d.ts +74 -0
  24. package/dist/persist/index.d.ts.map +1 -0
  25. package/dist/persist/index.js +228 -0
  26. package/dist/persist/index.js.map +1 -0
  27. package/dist/prod/context/context.js +222 -0
  28. package/dist/prod/context/index.js +8 -0
  29. package/dist/prod/index.js +7 -0
  30. package/dist/prod/inspect/index.js +45 -0
  31. package/dist/prod/internal/dev.js +4 -0
  32. package/dist/prod/persist/index.js +140 -0
  33. package/dist/prod/store/index.js +6 -0
  34. package/dist/prod/store/store.js +167 -0
  35. package/dist/store/index.d.ts +7 -0
  36. package/dist/store/index.d.ts.map +1 -0
  37. package/dist/store/index.js +6 -0
  38. package/dist/store/index.js.map +1 -0
  39. package/dist/store/store.d.ts +83 -0
  40. package/dist/store/store.d.ts.map +1 -0
  41. package/dist/store/store.js +235 -0
  42. package/dist/store/store.js.map +1 -0
  43. package/package.json +50 -4
@@ -0,0 +1,45 @@
1
+ import { OddkinError } from "@oddkin/core/diagnostics";
2
+ import { INTERNALS, liveCounts } from "../store/store.js";
3
+ function storeStats() {
4
+ return liveCounts();
5
+ }
6
+ function inspect(store, options) {
7
+ const internals = store[INTERNALS];
8
+ if (!internals)
9
+ throw new OddkinError("state.inspect.unsupported", "");
10
+ const limit = options?.limit ?? 50;
11
+ if (!Number.isInteger(limit) || limit < 0)
12
+ throw new OddkinError("state.inspect.limit", "");
13
+ const updates = [];
14
+ let recorded = 0, stopped = !1;
15
+ const stop = internals.observe({
16
+ update(record) {
17
+ recorded++, limit !== 0 && (updates.length === limit && updates.shift(), updates.push({ previous: record.previous, next: record.next, actions: record.actions }));
18
+ },
19
+ dispose() {
20
+ stopped = !0;
21
+ }
22
+ });
23
+ return {
24
+ store,
25
+ get updates() {
26
+ return [...updates];
27
+ },
28
+ get recorded() {
29
+ return recorded;
30
+ },
31
+ get subscribers() {
32
+ return internals.subscribers;
33
+ },
34
+ get stopped() {
35
+ return stopped || store.disposed;
36
+ },
37
+ dispose() {
38
+ stopped || (stopped = !0, stop());
39
+ }
40
+ };
41
+ }
42
+ export {
43
+ inspect,
44
+ storeStats
45
+ };
@@ -0,0 +1,4 @@
1
+ const DEV = !1;
2
+ export {
3
+ DEV
4
+ };
@@ -0,0 +1,140 @@
1
+ import { OddkinError, reportOddkinError } from "@oddkin/core/diagnostics";
2
+ import { computed, signal } from "@oddkin/core/reactive";
3
+ import { action } from "../store/store.js";
4
+ const NOTHING = /* @__PURE__ */ Symbol("nothing written");
5
+ function isEnvelope(value) {
6
+ if (typeof value != "object" || value === null || !("data" in value))
7
+ return !1;
8
+ const version = value.version;
9
+ return typeof version == "number" && Number.isInteger(version) && version >= 1;
10
+ }
11
+ function persist(store, options) {
12
+ const { key, version } = options;
13
+ if (typeof key != "string" || key === "" || !Number.isInteger(version) || version < 1)
14
+ throw new OddkinError("state.persist.options", "");
15
+ if (store.disposed)
16
+ throw new OddkinError("state.store.disposed", "");
17
+ const select = options.select ?? ((state) => state), restore = options.restore ?? ((_state, saved) => saved), equals = options.equals ?? Object.is, serialize = options.serialize ?? JSON.stringify, deserialize = options.deserialize ?? JSON.parse, status = signal("empty"), fail = (code, message, cause) => {
18
+ const error = new OddkinError(code, message, cause === void 0 ? void 0 : { cause });
19
+ if (!options.onError)
20
+ return reportOddkinError(error, { code, origin: key });
21
+ try {
22
+ options.onError(error);
23
+ } catch (handlerError) {
24
+ reportOddkinError(handlerError, { code, origin: key });
25
+ }
26
+ }, reject = (code, message, cause) => {
27
+ status.value = "rejected", fail(code, message, cause);
28
+ };
29
+ let storage;
30
+ try {
31
+ const source = options.storage ?? (() => globalThis.localStorage);
32
+ storage = (typeof source == "function" ? source() : source) ?? void 0, storage || fail("state.persist.unavailable", "");
33
+ } catch (error) {
34
+ storage = void 0, fail("state.persist.unavailable", "", error);
35
+ }
36
+ let text = null;
37
+ if (storage)
38
+ try {
39
+ text = storage.getItem(key);
40
+ } catch (error) {
41
+ storage = void 0, fail("state.persist.read", "", error);
42
+ }
43
+ storage || (status.value = "unavailable");
44
+ let blocked = !1;
45
+ if (storage && text !== null) {
46
+ let envelope, parsed = !0;
47
+ try {
48
+ envelope = deserialize(text);
49
+ } catch (error) {
50
+ parsed = !1, reject("state.persist.parse", "", error);
51
+ }
52
+ if (parsed && !isEnvelope(envelope))
53
+ reject("state.persist.parse", "");
54
+ else if (parsed && isEnvelope(envelope) && envelope.version > version)
55
+ blocked = !0, status.value = "blocked", fail("state.persist.version", "");
56
+ else if (parsed && isEnvelope(envelope)) {
57
+ let data = envelope.data, migrated = !0;
58
+ for (let next = envelope.version + 1; next <= version && migrated; next++) {
59
+ const step = options.migrate?.[next];
60
+ if (!step) {
61
+ migrated = !1, reject("state.persist.migrate", "");
62
+ break;
63
+ }
64
+ try {
65
+ data = step(data);
66
+ } catch (error) {
67
+ migrated = !1, reject("state.persist.migrate", "", error);
68
+ }
69
+ }
70
+ if (migrated) {
71
+ let valid = !0, cause;
72
+ try {
73
+ valid = options.validate ? options.validate(data) : !0;
74
+ } catch (error) {
75
+ valid = !1, cause = error;
76
+ }
77
+ if (valid)
78
+ try {
79
+ action("persist/restore", () => store.update((state) => restore(state, data)))(), status.value = "restored";
80
+ } catch (error) {
81
+ valid = !1, cause = error;
82
+ }
83
+ valid || reject("state.persist.invalid", "", cause);
84
+ }
85
+ }
86
+ }
87
+ let written = select(store.getSnapshot()), pending = !1, failing = !1, disposed = !1;
88
+ const write = () => {
89
+ if (pending = !1, !storage || blocked)
90
+ return;
91
+ const selection = select(store.getSnapshot());
92
+ if (written !== NOTHING && equals(written, selection))
93
+ return;
94
+ let serialized;
95
+ try {
96
+ serialized = serialize({ version, data: selection });
97
+ } catch (error) {
98
+ failing || fail("state.persist.serialize", "", error), failing = !0;
99
+ return;
100
+ }
101
+ try {
102
+ storage.setItem(key, serialized);
103
+ } catch (error) {
104
+ failing || fail("state.persist.write", "", error), failing = !0;
105
+ return;
106
+ }
107
+ failing = !1, written = selection;
108
+ }, unsubscribe = store.subscribe(() => {
109
+ pending || disposed || (pending = !0, queueMicrotask(() => {
110
+ pending && !disposed && write();
111
+ }));
112
+ });
113
+ return {
114
+ key,
115
+ status: computed(() => status.value),
116
+ get disposed() {
117
+ return disposed;
118
+ },
119
+ flush() {
120
+ disposed || write();
121
+ },
122
+ clear() {
123
+ if (!(disposed || !storage)) {
124
+ try {
125
+ storage.removeItem(key);
126
+ } catch (error) {
127
+ fail("state.persist.write", "", error);
128
+ return;
129
+ }
130
+ blocked = !1, written = NOTHING, status.value = "empty";
131
+ }
132
+ },
133
+ dispose() {
134
+ disposed || (pending && write(), disposed = !0, unsubscribe());
135
+ }
136
+ };
137
+ }
138
+ export {
139
+ persist
140
+ };
@@ -0,0 +1,6 @@
1
+ import { action, createStore, shallowEqual } from "./store.js";
2
+ export {
3
+ action,
4
+ createStore,
5
+ shallowEqual
6
+ };
@@ -0,0 +1,167 @@
1
+ import { OddkinError } from "@oddkin/core/diagnostics";
2
+ import { batch, computed, signal, untracked } from "@oddkin/core/reactive";
3
+ const INTERNALS = /* @__PURE__ */ Symbol("oddkin.store.internals"), live = { stores: 0, subscriptions: 0 };
4
+ function liveCounts() {
5
+ return { ...live };
6
+ }
7
+ const running = [], noop = () => {
8
+ };
9
+ function isPlainObject(value) {
10
+ const proto = Object.getPrototypeOf(value);
11
+ return proto === null || Object.getPrototypeOf(proto) === null;
12
+ }
13
+ function freezeSnapshot(root) {
14
+ const pending = [root];
15
+ for (; pending.length > 0; ) {
16
+ const value = pending.pop();
17
+ if (!(typeof value != "object" || value === null || Object.isFrozen(value))) {
18
+ if (Array.isArray(value)) {
19
+ Object.freeze(value);
20
+ for (let i = 0; i < value.length; i++)
21
+ pending.push(value[i]);
22
+ } else if (isPlainObject(value)) {
23
+ Object.freeze(value);
24
+ for (const key of Object.keys(value)) {
25
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
26
+ descriptor && "value" in descriptor && pending.push(descriptor.value);
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ class StoreImpl {
33
+ name;
34
+ state;
35
+ #value;
36
+ #initial;
37
+ #freeze;
38
+ #subscriptions = /* @__PURE__ */ new Set();
39
+ #observers;
40
+ #updates = 0;
41
+ #updating = !1;
42
+ #disposed = !1;
43
+ constructor(initial, options) {
44
+ this.name = options?.name, this.#freeze = options?.freeze ?? !0, this.#freeze && freezeSnapshot(initial), this.#initial = initial;
45
+ const named = this.name === void 0 ? void 0 : { name: this.name };
46
+ this.#value = signal(initial, named), this.state = computed(() => this.#value.value, named), live.stores++;
47
+ }
48
+ get disposed() {
49
+ return this.#disposed;
50
+ }
51
+ getSnapshot = () => this.#value.peek();
52
+ subscribe = (listener) => {
53
+ if (this.#disposed)
54
+ return noop;
55
+ const off = this.#value.subscribe(listener);
56
+ let active = !0;
57
+ const release = () => {
58
+ active && (active = !1, this.#subscriptions.delete(release), live.subscriptions--, off());
59
+ };
60
+ return this.#subscriptions.add(release), live.subscriptions++, release;
61
+ };
62
+ update(updater) {
63
+ this.#check("update");
64
+ const previous = this.#value.peek();
65
+ let next;
66
+ this.#updating = !0;
67
+ try {
68
+ next = untracked(() => updater(previous));
69
+ } finally {
70
+ this.#updating = !1;
71
+ }
72
+ this.#commit(previous, next);
73
+ }
74
+ select(selector, options) {
75
+ return computed(() => selector(this.#value.value), options);
76
+ }
77
+ reset() {
78
+ this.#check("reset"), this.#commit(this.#value.peek(), this.#initial);
79
+ }
80
+ dispose() {
81
+ if (this.#disposed)
82
+ return;
83
+ this.#disposed = !0, live.stores--;
84
+ for (const release of [...this.#subscriptions])
85
+ release();
86
+ const observers = this.#observers;
87
+ if (this.#observers = void 0, observers)
88
+ for (const observer of observers)
89
+ observer.dispose();
90
+ }
91
+ get [INTERNALS]() {
92
+ const store = this;
93
+ return {
94
+ get subscribers() {
95
+ return store.#subscriptions.size;
96
+ },
97
+ get updates() {
98
+ return store.#updates;
99
+ },
100
+ observe(observer) {
101
+ return store.#disposed ? (observer.dispose(), noop) : ((store.#observers ??= /* @__PURE__ */ new Set()).add(observer), () => {
102
+ store.#observers?.delete(observer);
103
+ });
104
+ }
105
+ };
106
+ }
107
+ #check(operation) {
108
+ if (this.#disposed)
109
+ throw new OddkinError("state.store.disposed", "");
110
+ if (this.#updating)
111
+ throw new OddkinError("state.update.reentrant", "");
112
+ }
113
+ #commit(previous, next) {
114
+ Object.is(previous, next) || (this.#freeze && freezeSnapshot(next), batch(() => {
115
+ this.#value.value = next, this.#updates++;
116
+ const observers = this.#observers;
117
+ if (!observers)
118
+ return;
119
+ const record = { previous, next, actions: [...running] };
120
+ for (const observer of [...observers])
121
+ observer.update(record);
122
+ }));
123
+ }
124
+ }
125
+ function createStore(initial, options) {
126
+ return new StoreImpl(initial, options);
127
+ }
128
+ function action(name, fn) {
129
+ return (...args) => {
130
+ running.push(name);
131
+ try {
132
+ return batch(() => fn(...args));
133
+ } finally {
134
+ running.pop();
135
+ }
136
+ };
137
+ }
138
+ function shallowEqual(a, b) {
139
+ if (Object.is(a, b))
140
+ return !0;
141
+ if (typeof a != "object" || typeof b != "object" || a === null || b === null)
142
+ return !1;
143
+ if (Array.isArray(a) || Array.isArray(b)) {
144
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)
145
+ return !1;
146
+ for (let i = 0; i < a.length; i++)
147
+ if (!Object.is(a[i], b[i]))
148
+ return !1;
149
+ return !0;
150
+ }
151
+ if (!isPlainObject(a) || !isPlainObject(b))
152
+ return !1;
153
+ const keys = Object.keys(a);
154
+ if (keys.length !== Object.keys(b).length)
155
+ return !1;
156
+ for (const key of keys)
157
+ if (!Object.hasOwn(b, key) || !Object.is(a[key], b[key]))
158
+ return !1;
159
+ return !0;
160
+ }
161
+ export {
162
+ INTERNALS,
163
+ action,
164
+ createStore,
165
+ liveCounts,
166
+ shallowEqual
167
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * `@oddkin/state/store` — optional shared stores on Oddkin's reactive graph. DOM-free.
3
+ * Contract: docs/architecture/core-contracts.md §7.
4
+ */
5
+ export { action, createStore, shallowEqual } from './store.js';
6
+ export type { SelectOptions, Store, StoreOptions } from './store.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * `@oddkin/state/store` — optional shared stores on Oddkin's reactive graph. DOM-free.
3
+ * Contract: docs/architecture/core-contracts.md §7.
4
+ */
5
+ export { action, createStore, shallowEqual } from './store.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,83 @@
1
+ import { type ExternalSource, type ReactiveOptions, type Readable } from '@oddkin/core/reactive';
2
+ export interface StoreOptions {
3
+ /** Name used in diagnostics and inspection. */
4
+ name?: string;
5
+ /**
6
+ * Freeze the plain objects and arrays of every snapshot, in development and production alike,
7
+ * so a mutation throws instead of going unnoticed. Default `true`. Class instances, maps, sets,
8
+ * dates, and other objects with their own prototype are never frozen.
9
+ */
10
+ freeze?: boolean;
11
+ }
12
+ /** Options for `select()`: `equals` decides whether a newly selected value is a change. */
13
+ export type SelectOptions<S> = ReactiveOptions<S>;
14
+ export interface Store<T> extends ExternalSource<T> {
15
+ readonly name: string | undefined;
16
+ /** The current snapshot as a read-only readable; `.value` in a tracked context registers a dependency. */
17
+ readonly state: Readable<T>;
18
+ /** True after `dispose()`. */
19
+ readonly disposed: boolean;
20
+ /** The current snapshot, the same value until the state changes. Bound, so it can be passed around. */
21
+ readonly getSnapshot: () => T;
22
+ /**
23
+ * Call `listener` with the new snapshot after each change: synchronously outside a batch, once at
24
+ * the outermost boundary inside one. Returns an unsubscribe function. Bound and stable.
25
+ */
26
+ readonly subscribe: (listener: (state: T) => void) => () => void;
27
+ /**
28
+ * Replace the snapshot with `updater(current)`. Returning the current snapshot is no change.
29
+ * The updater runs untracked and must not update this store itself.
30
+ */
31
+ update(updater: (state: T) => T): void;
32
+ /** A memoized readable of part of the state that notifies only when the selected value changes. */
33
+ select<S>(selector: (state: T) => S, options?: SelectOptions<S>): Readable<S>;
34
+ /** Return to the initial snapshot. */
35
+ reset(): void;
36
+ /** Release every subscription. Reads keep the last snapshot; updates throw. Idempotent. */
37
+ dispose(): void;
38
+ }
39
+ /** @internal One committed update, as `@oddkin/state/inspect` records it. */
40
+ export interface UpdateRecord<T> {
41
+ readonly previous: T;
42
+ readonly next: T;
43
+ /** Names of the running actions, outermost first. */
44
+ readonly actions: readonly string[];
45
+ }
46
+ /** @internal Receives a store's updates and its disposal (`@oddkin/state/inspect`). */
47
+ export interface StoreObserver<T> {
48
+ update(record: UpdateRecord<T>): void;
49
+ dispose(): void;
50
+ }
51
+ /** @internal Counters and update observation, reached through `store[INTERNALS]`. */
52
+ export interface StoreInternals<T> {
53
+ readonly subscribers: number;
54
+ readonly updates: number;
55
+ observe(observer: StoreObserver<T>): () => void;
56
+ }
57
+ /** @internal Key of a store's {@link StoreInternals}. */
58
+ export declare const INTERNALS: unique symbol;
59
+ /** @internal Live stores (created, not disposed) and live `subscribe()` listeners. */
60
+ export declare function liveCounts(): {
61
+ readonly stores: number;
62
+ readonly subscriptions: number;
63
+ };
64
+ /**
65
+ * Create a store holding `initial` as its first snapshot. Update it with `update()`, which takes the
66
+ * current snapshot and returns the next one; read it through `state`, `select()`, `getSnapshot()`,
67
+ * or `subscribe()`. No provider, registry, or reducer is needed.
68
+ */
69
+ export declare function createStore<T>(initial: T, options?: StoreOptions): Store<T>;
70
+ /**
71
+ * Name a unit of work for inspection. `fn` runs inside `batch()`, so subscribers are notified once
72
+ * when it returns, and every store update it makes records the name; nested actions record the
73
+ * whole chain. Batching is not a transaction: if `fn` throws, updates it already made stay. Only
74
+ * synchronous work belongs to the action; updates after an `await` do not.
75
+ */
76
+ export declare function action<A extends unknown[], R>(name: string, fn: (...args: A) => R): (...args: A) => R;
77
+ /**
78
+ * Equality for `select()` results built from several fields: the same value, or arrays or plain
79
+ * objects with the same entries compared with `Object.is`. Maps, sets, and class instances are
80
+ * equal only when identical.
81
+ */
82
+ export declare function shallowEqual<V>(a: V, b: V): boolean;
83
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store/store.ts"],"names":[],"mappings":"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"}