@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.
- package/LICENSE +21 -0
- package/README.md +82 -2
- package/dist/context/context.d.ts +77 -0
- package/dist/context/context.d.ts.map +1 -0
- package/dist/context/context.js +335 -0
- package/dist/context/context.js.map +1 -0
- package/dist/context/index.d.ts +8 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +7 -0
- package/dist/context/index.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect/index.d.ts +33 -0
- package/dist/inspect/index.d.ts.map +1 -0
- package/dist/inspect/index.js +63 -0
- package/dist/inspect/index.js.map +1 -0
- package/dist/internal/dev.d.ts +6 -0
- package/dist/internal/dev.d.ts.map +1 -0
- package/dist/internal/dev.js +6 -0
- package/dist/internal/dev.js.map +1 -0
- package/dist/persist/index.d.ts +74 -0
- package/dist/persist/index.d.ts.map +1 -0
- package/dist/persist/index.js +228 -0
- package/dist/persist/index.js.map +1 -0
- package/dist/prod/context/context.js +222 -0
- package/dist/prod/context/index.js +8 -0
- package/dist/prod/index.js +7 -0
- package/dist/prod/inspect/index.js +45 -0
- package/dist/prod/internal/dev.js +4 -0
- package/dist/prod/persist/index.js +140 -0
- package/dist/prod/store/index.js +6 -0
- package/dist/prod/store/store.js +167 -0
- package/dist/store/index.d.ts +7 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +6 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/store.d.ts +83 -0
- package/dist/store/store.d.ts.map +1 -0
- package/dist/store/store.js +235 -0
- package/dist/store/store.js.map +1 -0
- package/package.json +50 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Brian Brady
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,83 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @oddkin/state
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Optional stores, selectors, context, persistence, and inspection. Reusable components never need it: an application feature owns a store and hands values to components as properties.
|
|
4
|
+
|
|
5
|
+
**Status:** M6 in progress. Implemented: `./store` and `./context` (both re-exported from the root entry), `./inspect`, and `./persist`. Contract: [core-contracts.md §7](../../docs/architecture/core-contracts.md); entries: [packages.md](../../docs/architecture/packages.md).
|
|
6
|
+
|
|
7
|
+
## Stores (`@oddkin/state/store`, DOM-free)
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
import { action, createStore, shallowEqual } from '@oddkin/state/store';
|
|
11
|
+
|
|
12
|
+
const cart = createStore({ items: [], coupon: '' }, { name: 'cart' });
|
|
13
|
+
const count = cart.select((state) => state.items.length); // memoized readable
|
|
14
|
+
const summary = cart.select((s) => ({ count: s.items.length, coupon: s.coupon }), {
|
|
15
|
+
equals: shallowEqual,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const addItem = action('cart/add', (item) => {
|
|
19
|
+
cart.update((state) => ({ ...state, items: [...state.items, item] }));
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- `cart.state` and selectors are ordinary Oddkin readables: bind them in templates (`${count}`), read them in effects, combine them with other signals. A selector follows the store only while something observes it, and notifies only when the selected value changes.
|
|
24
|
+
- `cart.getSnapshot` and `cart.subscribe` are the shared external-store contract, so `useSyncExternalStore(cart.subscribe, cart.getSnapshot)` in React and `fromExternal(cart)` in Oddkin take the store as is. Subscribers are notified once per `batch()` or `action()`.
|
|
25
|
+
- Every snapshot's plain objects and arrays are frozen in both builds, so mutating one throws. Build the next snapshot instead and keep unchanged parts by reference; replace maps and sets (`new Map(map).set(key, value)`). `createStore(initial, { freeze: false })` opts out.
|
|
26
|
+
- `reset()` returns to the initial snapshot; `dispose()` releases every subscriber, after which updates throw `state.store.disposed`.
|
|
27
|
+
|
|
28
|
+
## Context (`@oddkin/state/context`)
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import { consume, createContext, provide } from '@oddkin/state/context';
|
|
32
|
+
|
|
33
|
+
export const cartContext = createContext('cart');
|
|
34
|
+
|
|
35
|
+
// An application shell or any ancestor element provides a value (or a readable to follow):
|
|
36
|
+
class ShopShell extends OddkinElement {
|
|
37
|
+
#provider = provide(this, cartContext, cart);
|
|
38
|
+
connected(scope) {
|
|
39
|
+
scope.use(this.#provider);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// A descendant reads the nearest provider's value as a readable:
|
|
44
|
+
class CartBadge extends OddkinElement {
|
|
45
|
+
cart = consume(this, cartContext, { required: true });
|
|
46
|
+
connected(scope) {
|
|
47
|
+
scope.use(this.cart);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Requests use the community context protocol (`context-request` events), so they cross shadow roots and interoperate with other implementations such as Lit's. The nearest provider wins; a consumer moved elsewhere, or whose provider stops, finds the next provider; a provider that connects later is found too. `required: true` reports `state.context.missing` when nothing answers.
|
|
53
|
+
|
|
54
|
+
## Persistence (`@oddkin/state/persist`, DOM-free)
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
import { persist } from '@oddkin/state/persist';
|
|
58
|
+
|
|
59
|
+
const persistence = persist(settings, {
|
|
60
|
+
key: 'settings',
|
|
61
|
+
version: 2,
|
|
62
|
+
select: (state) => state.preferences, // nothing is stored unless selected (or the whole state)
|
|
63
|
+
restore: (state, preferences) => ({ ...state, preferences }),
|
|
64
|
+
migrate: { 2: (v1) => ({ ...v1, density: 'comfortable' }) },
|
|
65
|
+
validate: (data) => preferencesModel.validate(data).ok,
|
|
66
|
+
});
|
|
67
|
+
persistence.status.value; // 'empty' | 'restored' | 'rejected' | 'blocked' | 'unavailable'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Stored data is restored, migrated, and validated before `persist()` returns; changes are written once per microtask when the selection changed. Quota errors, unreachable storage, and bad stored data are reported (once per failing streak) and never reach the store or its subscribers. Data from a newer version is left alone until `clear()`.
|
|
71
|
+
|
|
72
|
+
## Inspection (`@oddkin/state/inspect`)
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
import { inspect, storeStats } from '@oddkin/state/inspect';
|
|
76
|
+
|
|
77
|
+
const inspector = inspect(cart, { limit: 20 });
|
|
78
|
+
addItem({ id: 'tea' });
|
|
79
|
+
inspector.updates; // [{ previous, next, actions: ['cart/add'] }]
|
|
80
|
+
storeStats(); // { stores, subscriptions } — live counts for leak tests
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Stores carry only counters and one observer hook; nothing is recorded unless a store is inspected.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type Readable } from '@oddkin/core/reactive';
|
|
2
|
+
import type { Controller } from '@oddkin/core/scope';
|
|
3
|
+
/**
|
|
4
|
+
* A typed context key. Providers and consumers match keys by identity, so each `createContext()`
|
|
5
|
+
* call creates a distinct context. Structurally compatible with the community protocol's
|
|
6
|
+
* `Context<Key, Value>`.
|
|
7
|
+
*/
|
|
8
|
+
export interface Context<T> {
|
|
9
|
+
/** Name used in diagnostics. */
|
|
10
|
+
readonly name: string;
|
|
11
|
+
/** Carries the value type for TypeScript; absent at runtime (community context protocol). */
|
|
12
|
+
readonly __context__: T;
|
|
13
|
+
}
|
|
14
|
+
/** The value type of a context. */
|
|
15
|
+
export type ContextType<C> = C extends Context<infer T> ? T : never;
|
|
16
|
+
/** Receives a provided value; `unsubscribe` is passed when the request subscribed. */
|
|
17
|
+
export type ContextCallback<T> = (value: T, unsubscribe?: () => void) => void;
|
|
18
|
+
/** Create a context key with a name for diagnostics. */
|
|
19
|
+
export declare function createContext<T>(name: string): Context<T>;
|
|
20
|
+
/** A consumer asks for a context (community context protocol). Bubbles and is composed. */
|
|
21
|
+
export declare class ContextRequestEvent<T> extends Event {
|
|
22
|
+
readonly context: Context<T>;
|
|
23
|
+
/** The requesting element; `target` is retargeted across shadow roots. */
|
|
24
|
+
readonly contextTarget: Element;
|
|
25
|
+
readonly callback: ContextCallback<T>;
|
|
26
|
+
/** True when the callback may be called again as the value changes. */
|
|
27
|
+
readonly subscribe: boolean;
|
|
28
|
+
constructor(context: Context<T>, contextTarget: Element, callback: ContextCallback<T>, subscribe?: boolean);
|
|
29
|
+
}
|
|
30
|
+
/** A provider announces itself, so enclosing providers and waiting consumers can re-request. */
|
|
31
|
+
export declare class ContextProviderEvent<T> extends Event {
|
|
32
|
+
readonly context: Context<T>;
|
|
33
|
+
readonly contextTarget: Node;
|
|
34
|
+
constructor(context: Context<T>, contextTarget: Node);
|
|
35
|
+
}
|
|
36
|
+
export interface ConsumeOptions<T> {
|
|
37
|
+
/** The value while no provider supplies one. Default `undefined`. */
|
|
38
|
+
fallback?: T;
|
|
39
|
+
/** Report `state.context.missing` when no provider answers as the consumer connects. */
|
|
40
|
+
required?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** A readable of the nearest provider's value, activated with `scope.use()`. */
|
|
43
|
+
export interface ContextConsumer<V> extends Readable<V>, Controller {
|
|
44
|
+
readonly context: Context<unknown>;
|
|
45
|
+
readonly host: Element;
|
|
46
|
+
/** True while a provider supplies the value. Tracked like `value`. */
|
|
47
|
+
readonly provided: boolean;
|
|
48
|
+
/** Ask again for the nearest provider, e.g. from `moved()` after a state-preserving move. */
|
|
49
|
+
resolve(): void;
|
|
50
|
+
}
|
|
51
|
+
/** Provides a value to consumers below its host, activated with `scope.use()`. */
|
|
52
|
+
export interface ContextProvider<T> extends Controller {
|
|
53
|
+
readonly context: Context<T>;
|
|
54
|
+
readonly host: Node;
|
|
55
|
+
/** The provided value. Assign a value, or a readable to follow it. */
|
|
56
|
+
get value(): T;
|
|
57
|
+
set value(next: T | Readable<T>);
|
|
58
|
+
/** Consumers currently subscribed to this provider. */
|
|
59
|
+
readonly consumers: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Provide `value` (or follow a readable) to consumers of `context` below `host`, which may be an
|
|
63
|
+
* element, a shadow root, or a document. Activate it with `scope.use(provider)`; disposing that
|
|
64
|
+
* scope stops providing, and its consumers look for the next provider up.
|
|
65
|
+
*/
|
|
66
|
+
export declare function provide<T>(host: Node, context: Context<T>, value: T | Readable<T>): ContextProvider<T>;
|
|
67
|
+
/**
|
|
68
|
+
* Read `context` from the nearest provider above `host`. Activate it with `scope.use(consumer)`,
|
|
69
|
+
* usually in `connected(scope)`; the subscription ends with that scope. Until a provider answers,
|
|
70
|
+
* the value is `fallback` and `provided` is false; a provider that connects later is found when it
|
|
71
|
+
* announces itself.
|
|
72
|
+
*/
|
|
73
|
+
export declare function consume<T>(host: Element, context: Context<T>, options: ConsumeOptions<T> & {
|
|
74
|
+
fallback: T;
|
|
75
|
+
}): ContextConsumer<T>;
|
|
76
|
+
export declare function consume<T>(host: Element, context: Context<T>, options?: ConsumeOptions<T>): ContextConsumer<T | undefined>;
|
|
77
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/context/context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context (core-contracts.md §7.2): typed values from the nearest provider in the composed tree,
|
|
3
|
+
* over the community context protocol (`context-request` events with `context`, `contextTarget`,
|
|
4
|
+
* `callback`, and `subscribe`; providers stop immediate propagation), so Oddkin providers and
|
|
5
|
+
* consumers interoperate with other implementations such as Lit's `@lit/context`. A provider also
|
|
6
|
+
* announces itself with a `context-provider` event so waiting consumers and enclosing providers can
|
|
7
|
+
* hand consumers over. Between Oddkin peers the provider hands over its readable itself, so a
|
|
8
|
+
* consumer reads through one reactive graph; other peers receive values through the callback.
|
|
9
|
+
*
|
|
10
|
+
* Imports without DOM globals (it only extends `Event`); providers and consumers need a DOM.
|
|
11
|
+
*/
|
|
12
|
+
import { DEV } from '../internal/dev.js';
|
|
13
|
+
import { OddkinError, reportOddkinError } from '@oddkin/core/diagnostics';
|
|
14
|
+
import { READABLE, batch, computed, isReadable, signal, } from '@oddkin/core/reactive';
|
|
15
|
+
/** Create a context key with a name for diagnostics. */
|
|
16
|
+
export function createContext(name) {
|
|
17
|
+
return Object.freeze({ name });
|
|
18
|
+
}
|
|
19
|
+
/** A consumer asks for a context (community context protocol). Bubbles and is composed. */
|
|
20
|
+
export class ContextRequestEvent extends Event {
|
|
21
|
+
context;
|
|
22
|
+
/** The requesting element; `target` is retargeted across shadow roots. */
|
|
23
|
+
contextTarget;
|
|
24
|
+
callback;
|
|
25
|
+
/** True when the callback may be called again as the value changes. */
|
|
26
|
+
subscribe;
|
|
27
|
+
constructor(context, contextTarget, callback, subscribe = false) {
|
|
28
|
+
super('context-request', { bubbles: true, composed: true });
|
|
29
|
+
this.context = context;
|
|
30
|
+
this.contextTarget = contextTarget;
|
|
31
|
+
this.callback = callback;
|
|
32
|
+
this.subscribe = subscribe;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** A provider announces itself, so enclosing providers and waiting consumers can re-request. */
|
|
36
|
+
export class ContextProviderEvent extends Event {
|
|
37
|
+
context;
|
|
38
|
+
contextTarget;
|
|
39
|
+
constructor(context, contextTarget) {
|
|
40
|
+
super('context-provider', { bubbles: true, composed: true });
|
|
41
|
+
this.context = context;
|
|
42
|
+
this.contextTarget = contextTarget;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Oddkin consumers tag their callback so an Oddkin provider can hand over its readable. */
|
|
46
|
+
const CONSUMER = Symbol('oddkin.context.consumer');
|
|
47
|
+
const ATTACH = Symbol('oddkin.context.attach');
|
|
48
|
+
const DETACH = Symbol('oddkin.context.detach');
|
|
49
|
+
const targetOf = (event) => event.contextTarget ?? event.composedPath()[0];
|
|
50
|
+
class ConsumerImpl {
|
|
51
|
+
[READABLE] = true;
|
|
52
|
+
context;
|
|
53
|
+
host;
|
|
54
|
+
#fallback;
|
|
55
|
+
#required;
|
|
56
|
+
#source = signal(undefined);
|
|
57
|
+
#view;
|
|
58
|
+
#callback;
|
|
59
|
+
#local;
|
|
60
|
+
#unsubscribe;
|
|
61
|
+
#connection;
|
|
62
|
+
#answered = false;
|
|
63
|
+
constructor(host, context, options) {
|
|
64
|
+
this.host = host;
|
|
65
|
+
this.context = context;
|
|
66
|
+
this.#fallback = options?.fallback;
|
|
67
|
+
this.#required = options?.required ?? false;
|
|
68
|
+
this.#view = computed(() => {
|
|
69
|
+
const source = this.#source.value;
|
|
70
|
+
return source ? source.value : this.#fallback;
|
|
71
|
+
});
|
|
72
|
+
const callback = (value, unsubscribe) => this.#receive(value, unsubscribe);
|
|
73
|
+
callback[CONSUMER] = this;
|
|
74
|
+
this.#callback = callback;
|
|
75
|
+
}
|
|
76
|
+
get value() {
|
|
77
|
+
return this.#view.value;
|
|
78
|
+
}
|
|
79
|
+
peek() {
|
|
80
|
+
return this.#view.peek();
|
|
81
|
+
}
|
|
82
|
+
subscribe = (onChange) => this.#view.subscribe(onChange);
|
|
83
|
+
get provided() {
|
|
84
|
+
return this.#source.value !== undefined;
|
|
85
|
+
}
|
|
86
|
+
connect(scope) {
|
|
87
|
+
if (scope.disposed)
|
|
88
|
+
return;
|
|
89
|
+
this.#disconnect(); // one connection at a time
|
|
90
|
+
const connection = { scope, waiting: undefined };
|
|
91
|
+
this.#connection = connection;
|
|
92
|
+
scope.add(() => {
|
|
93
|
+
if (this.#connection === connection)
|
|
94
|
+
this.#disconnect();
|
|
95
|
+
}, 'context consumer');
|
|
96
|
+
this.#request();
|
|
97
|
+
if (this.#required && this.#source.peek() === undefined) {
|
|
98
|
+
reportOddkinError(new OddkinError('state.context.missing', DEV
|
|
99
|
+
? `<${this.host.localName}> requires context "${this.context.name}", but no provider answered when it connected. Provide it on an ancestor that connects first (provide() with scope.use(), or the application's provide), or give the consumer a fallback.`
|
|
100
|
+
: ''), { code: 'state.context.missing', origin: this.host.localName });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
resolve() {
|
|
104
|
+
this.#request();
|
|
105
|
+
}
|
|
106
|
+
[ATTACH](view, unsubscribe) {
|
|
107
|
+
this.#answered = true;
|
|
108
|
+
this.#switch(unsubscribe);
|
|
109
|
+
this.#source.value = view;
|
|
110
|
+
this.#stopWaiting();
|
|
111
|
+
}
|
|
112
|
+
[DETACH](unsubscribe) {
|
|
113
|
+
if (unsubscribe !== this.#unsubscribe)
|
|
114
|
+
return;
|
|
115
|
+
this.#unsubscribe = undefined;
|
|
116
|
+
this.#source.value = undefined;
|
|
117
|
+
if (this.host.isConnected)
|
|
118
|
+
this.#request();
|
|
119
|
+
}
|
|
120
|
+
#receive(value, unsubscribe) {
|
|
121
|
+
this.#answered = true;
|
|
122
|
+
batch(() => {
|
|
123
|
+
this.#switch(unsubscribe);
|
|
124
|
+
if (this.#local)
|
|
125
|
+
this.#local.value = value;
|
|
126
|
+
else
|
|
127
|
+
this.#local = signal(value);
|
|
128
|
+
this.#source.value = this.#local;
|
|
129
|
+
});
|
|
130
|
+
this.#stopWaiting();
|
|
131
|
+
}
|
|
132
|
+
/** Adopt a provider's unsubscribe function, leaving the previous provider. */
|
|
133
|
+
#switch(unsubscribe) {
|
|
134
|
+
if (unsubscribe === this.#unsubscribe)
|
|
135
|
+
return;
|
|
136
|
+
const previous = this.#unsubscribe;
|
|
137
|
+
this.#unsubscribe = unsubscribe;
|
|
138
|
+
previous?.();
|
|
139
|
+
}
|
|
140
|
+
#request() {
|
|
141
|
+
if (!this.#connection)
|
|
142
|
+
return;
|
|
143
|
+
this.#answered = false;
|
|
144
|
+
this.host.dispatchEvent(new ContextRequestEvent(this.context, this.host, this.#callback, true));
|
|
145
|
+
if (this.#answered || !this.#connection)
|
|
146
|
+
return;
|
|
147
|
+
// Nobody answered: leave any previous provider and wait for one to announce itself.
|
|
148
|
+
const previous = this.#unsubscribe;
|
|
149
|
+
this.#unsubscribe = undefined;
|
|
150
|
+
this.#source.value = undefined;
|
|
151
|
+
previous?.();
|
|
152
|
+
this.#startWaiting();
|
|
153
|
+
}
|
|
154
|
+
#startWaiting() {
|
|
155
|
+
const connection = this.#connection;
|
|
156
|
+
if (!connection || connection.waiting)
|
|
157
|
+
return;
|
|
158
|
+
connection.waiting = connection.scope.listen(this.host.ownerDocument, 'context-provider', (event) => {
|
|
159
|
+
if (event.context === this.context)
|
|
160
|
+
this.#request();
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
#stopWaiting() {
|
|
164
|
+
const connection = this.#connection;
|
|
165
|
+
const release = connection?.waiting;
|
|
166
|
+
if (!connection || !release)
|
|
167
|
+
return;
|
|
168
|
+
connection.waiting = undefined;
|
|
169
|
+
release();
|
|
170
|
+
}
|
|
171
|
+
#disconnect() {
|
|
172
|
+
const connection = this.#connection;
|
|
173
|
+
if (!connection)
|
|
174
|
+
return;
|
|
175
|
+
this.#connection = undefined;
|
|
176
|
+
connection.waiting?.();
|
|
177
|
+
const previous = this.#unsubscribe;
|
|
178
|
+
this.#unsubscribe = undefined;
|
|
179
|
+
this.#source.value = undefined;
|
|
180
|
+
previous?.();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
class ProviderImpl {
|
|
184
|
+
context;
|
|
185
|
+
host;
|
|
186
|
+
#current;
|
|
187
|
+
#view;
|
|
188
|
+
#subscribers = new Map();
|
|
189
|
+
#own;
|
|
190
|
+
#foreign;
|
|
191
|
+
#connection;
|
|
192
|
+
constructor(host, context, value) {
|
|
193
|
+
this.host = host;
|
|
194
|
+
this.context = context;
|
|
195
|
+
this.#current = signal(this.#readable(value));
|
|
196
|
+
this.#view = computed(() => this.#current.value.value);
|
|
197
|
+
}
|
|
198
|
+
get value() {
|
|
199
|
+
return this.#view.value;
|
|
200
|
+
}
|
|
201
|
+
set value(next) {
|
|
202
|
+
this.#current.value = this.#readable(next);
|
|
203
|
+
}
|
|
204
|
+
get consumers() {
|
|
205
|
+
return this.#subscribers.size;
|
|
206
|
+
}
|
|
207
|
+
connect(scope) {
|
|
208
|
+
if (scope.disposed)
|
|
209
|
+
return;
|
|
210
|
+
this.#disconnect(); // one connection at a time
|
|
211
|
+
const connection = {};
|
|
212
|
+
this.#connection = connection;
|
|
213
|
+
// Registered first, so it runs after the listeners below are removed.
|
|
214
|
+
scope.add(() => {
|
|
215
|
+
if (this.#connection === connection)
|
|
216
|
+
this.#disconnect();
|
|
217
|
+
}, 'context provider');
|
|
218
|
+
scope.listen(this.host, 'context-request', (event) => {
|
|
219
|
+
if (this.#connection === connection)
|
|
220
|
+
this.#onRequest(event);
|
|
221
|
+
});
|
|
222
|
+
scope.listen(this.host, 'context-provider', (event) => {
|
|
223
|
+
if (this.#connection === connection)
|
|
224
|
+
this.#onProvider(event);
|
|
225
|
+
});
|
|
226
|
+
this.host.dispatchEvent(new ContextProviderEvent(this.context, this.host));
|
|
227
|
+
}
|
|
228
|
+
#readable(value) {
|
|
229
|
+
if (isReadable(value))
|
|
230
|
+
return value;
|
|
231
|
+
if (this.#own)
|
|
232
|
+
this.#own.value = value;
|
|
233
|
+
else
|
|
234
|
+
this.#own = signal(value);
|
|
235
|
+
return this.#own;
|
|
236
|
+
}
|
|
237
|
+
#onRequest(event) {
|
|
238
|
+
if (event.context !== this.context)
|
|
239
|
+
return;
|
|
240
|
+
const target = targetOf(event);
|
|
241
|
+
if (target === this.host)
|
|
242
|
+
return; // the host's own request goes to an enclosing provider
|
|
243
|
+
event.stopImmediatePropagation();
|
|
244
|
+
const callback = event.callback;
|
|
245
|
+
if (!event.subscribe) {
|
|
246
|
+
callback(this.#view.peek()); // one value; never retained
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
let subscription = this.#subscribers.get(callback);
|
|
250
|
+
if (!subscription) {
|
|
251
|
+
const created = {
|
|
252
|
+
host: target,
|
|
253
|
+
consumer: callback[CONSUMER],
|
|
254
|
+
unsubscribe: () => this.#remove(callback, created),
|
|
255
|
+
};
|
|
256
|
+
subscription = created;
|
|
257
|
+
this.#subscribers.set(callback, created);
|
|
258
|
+
}
|
|
259
|
+
if (subscription.consumer) {
|
|
260
|
+
subscription.consumer[ATTACH](this.#view, subscription.unsubscribe);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
this.#watch();
|
|
264
|
+
callback(this.#view.peek(), subscription.unsubscribe);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/** A provider appeared below this one: consumers now closer to it move there. */
|
|
268
|
+
#onProvider(event) {
|
|
269
|
+
if (event.context !== this.context || targetOf(event) === this.host)
|
|
270
|
+
return;
|
|
271
|
+
event.stopPropagation();
|
|
272
|
+
for (const [callback, subscription] of [...this.#subscribers]) {
|
|
273
|
+
if (this.#subscribers.get(callback) !== subscription)
|
|
274
|
+
continue;
|
|
275
|
+
subscription.host.dispatchEvent(new ContextRequestEvent(this.context, subscription.host, callback, true));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/** Other implementations' consumers receive values through their callbacks, each isolated. */
|
|
279
|
+
#watch() {
|
|
280
|
+
if (this.#foreign)
|
|
281
|
+
return;
|
|
282
|
+
this.#foreign = this.#view.subscribe((value) => {
|
|
283
|
+
for (const [callback, subscription] of [...this.#subscribers]) {
|
|
284
|
+
if (subscription.consumer || this.#subscribers.get(callback) !== subscription)
|
|
285
|
+
continue;
|
|
286
|
+
try {
|
|
287
|
+
callback(value, subscription.unsubscribe);
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
reportOddkinError(error, { code: 'state.context.callback', origin: this.context.name });
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
#remove(callback, subscription) {
|
|
296
|
+
if (this.#subscribers.get(callback) !== subscription)
|
|
297
|
+
return;
|
|
298
|
+
this.#subscribers.delete(callback);
|
|
299
|
+
if (!this.#foreign)
|
|
300
|
+
return;
|
|
301
|
+
for (const other of this.#subscribers.values())
|
|
302
|
+
if (!other.consumer)
|
|
303
|
+
return;
|
|
304
|
+
this.#foreign();
|
|
305
|
+
this.#foreign = undefined;
|
|
306
|
+
}
|
|
307
|
+
/** Stop providing: consumers look for the next provider up (or wait for one). */
|
|
308
|
+
#disconnect() {
|
|
309
|
+
if (!this.#connection)
|
|
310
|
+
return;
|
|
311
|
+
this.#connection = undefined;
|
|
312
|
+
this.#foreign?.();
|
|
313
|
+
this.#foreign = undefined;
|
|
314
|
+
const subscriptions = [...this.#subscribers];
|
|
315
|
+
this.#subscribers.clear();
|
|
316
|
+
for (const [callback, subscription] of subscriptions) {
|
|
317
|
+
if (subscription.consumer)
|
|
318
|
+
subscription.consumer[DETACH](subscription.unsubscribe);
|
|
319
|
+
else if (subscription.host.isConnected)
|
|
320
|
+
subscription.host.dispatchEvent(new ContextRequestEvent(this.context, subscription.host, callback, true));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Provide `value` (or follow a readable) to consumers of `context` below `host`, which may be an
|
|
326
|
+
* element, a shadow root, or a document. Activate it with `scope.use(provider)`; disposing that
|
|
327
|
+
* scope stops providing, and its consumers look for the next provider up.
|
|
328
|
+
*/
|
|
329
|
+
export function provide(host, context, value) {
|
|
330
|
+
return new ProviderImpl(host, context, value);
|
|
331
|
+
}
|
|
332
|
+
export function consume(host, context, options) {
|
|
333
|
+
return new ConsumerImpl(host, context, options);
|
|
334
|
+
}
|
|
335
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/context/context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@oddkin/state/context` — typed values from the nearest provider in the composed tree, over the
|
|
3
|
+
* community context protocol. Imports without DOM globals; providers and consumers need a DOM.
|
|
4
|
+
* Contract: docs/architecture/core-contracts.md §7.2.
|
|
5
|
+
*/
|
|
6
|
+
export { ContextProviderEvent, ContextRequestEvent, consume, createContext, provide, } from './context.js';
|
|
7
|
+
export type { ConsumeOptions, Context, ContextCallback, ContextConsumer, ContextProvider, ContextType, } from './context.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,OAAO,EACP,aAAa,EACb,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,cAAc,EACd,OAAO,EACP,eAAe,EACf,eAAe,EACf,eAAe,EACf,WAAW,GACZ,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@oddkin/state/context` — typed values from the nearest provider in the composed tree, over the
|
|
3
|
+
* community context protocol. Imports without DOM globals; providers and consumers need a DOM.
|
|
4
|
+
* Contract: docs/architecture/core-contracts.md §7.2.
|
|
5
|
+
*/
|
|
6
|
+
export { ContextProviderEvent, ContextRequestEvent, consume, createContext, provide, } from './context.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,OAAO,EACP,aAAa,EACb,OAAO,GACR,MAAM,cAAc,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@oddkin/state` root entry: re-exports the store (`./store`) and context (`./context`).
|
|
3
|
+
* Inspection (`./inspect`) and, when it lands, persistence stay separate imports. Imports without
|
|
4
|
+
* DOM globals.
|
|
5
|
+
*/
|
|
6
|
+
export * from './store/index.js';
|
|
7
|
+
export * from './context/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* Package marker read by the plain-HTML example and the docs app skeleton.
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare const packageName = "@oddkin/state";
|
|
13
|
+
/** @internal Internal packages this package is allowed to depend on. */
|
|
14
|
+
export declare const internalDependencies: readonly string[];
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAE3C,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@oddkin/state` root entry: re-exports the store (`./store`) and context (`./context`).
|
|
3
|
+
* Inspection (`./inspect`) and, when it lands, persistence stay separate imports. Imports without
|
|
4
|
+
* DOM globals.
|
|
5
|
+
*/
|
|
6
|
+
export * from './store/index.js';
|
|
7
|
+
export * from './context/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* Package marker read by the plain-HTML example and the docs app skeleton.
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export const packageName = '@oddkin/state';
|
|
13
|
+
/** @internal Internal packages this package is allowed to depend on. */
|
|
14
|
+
export const internalDependencies = ['@oddkin/core'];
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AAEnC;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,eAAe,CAAC;AAE3C,wEAAwE;AACxE,MAAM,CAAC,MAAM,oBAAoB,GAAsB,CAAC,cAAc,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Store } from '../store/store.js';
|
|
2
|
+
/** One recorded update. */
|
|
3
|
+
export interface StoreUpdate<T> {
|
|
4
|
+
readonly previous: T;
|
|
5
|
+
readonly next: T;
|
|
6
|
+
/** Names of the actions running when the update was made, outermost first; empty outside an action. */
|
|
7
|
+
readonly actions: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
export interface InspectOptions {
|
|
10
|
+
/** Most recent updates kept (default 50). `0` counts updates without keeping them. */
|
|
11
|
+
limit?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface StoreInspector<T> {
|
|
14
|
+
readonly store: Store<T>;
|
|
15
|
+
/** The most recent updates since inspection started, oldest first; at most `limit`. */
|
|
16
|
+
readonly updates: readonly StoreUpdate<T>[];
|
|
17
|
+
/** Updates seen since inspection started, including those no longer kept. */
|
|
18
|
+
readonly recorded: number;
|
|
19
|
+
/** Live `subscribe()` listeners of the store. */
|
|
20
|
+
readonly subscribers: number;
|
|
21
|
+
/** True once inspection stopped, by `dispose()` or because the store was disposed. */
|
|
22
|
+
readonly stopped: boolean;
|
|
23
|
+
/** Stop recording. What was recorded stays readable. Idempotent. */
|
|
24
|
+
dispose(): void;
|
|
25
|
+
}
|
|
26
|
+
/** Live stores (created and not disposed) and live `subscribe()` listeners, across all stores. */
|
|
27
|
+
export declare function storeStats(): {
|
|
28
|
+
readonly stores: number;
|
|
29
|
+
readonly subscriptions: number;
|
|
30
|
+
};
|
|
31
|
+
/** Record a store's updates and their actions, keeping the most recent `limit`. */
|
|
32
|
+
export declare function inspect<T>(store: Store<T>, options?: InspectOptions): StoreInspector<T>;
|
|
33
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inspect/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAyB,KAAK,KAAK,EAAuB,MAAM,mBAAmB,CAAC;AAE3F,2BAA2B;AAC3B,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,uGAAuG;IACvG,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC7B,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,uFAAuF;IACvF,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,sFAAsF;IACtF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,oEAAoE;IACpE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,kGAAkG;AAClG,wBAAgB,UAAU,IAAI;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAExF;AAED,mFAAmF;AACnF,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,CAmDvF"}
|