preact-sigma 5.0.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -18
- package/dist/index.d.mts +50 -9
- package/dist/index.mjs +58 -140
- package/dist/persist.d.mts +69 -44
- package/dist/persist.mjs +40 -48
- package/dist/sigma-CJibGQ6g.mjs +383 -0
- package/dist/sigma-DD7HfTvw.d.mts +162 -0
- package/docs/context.md +65 -58
- package/docs/migrations/v5-to-v6.md +273 -0
- package/docs/persist.md +19 -18
- package/examples/async-commit.ts +38 -31
- package/examples/basic-counter.ts +21 -16
- package/examples/command-palette.tsx +114 -104
- package/examples/observe-and-restore.ts +21 -15
- package/examples/persist-search-draft.ts +33 -30
- package/examples/setup-act.ts +17 -9
- package/examples/sigma-target.ts +16 -7
- package/package.json +9 -10
- package/dist/framework-GgPzRfff.d.mts +0 -331
- package/dist/runtime-nX4Aygb8.mjs +0 -595
- package/examples/signal-access.ts +0 -31
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
4
|
|
|
5
|
-
`preact-sigma` is a typed state-model
|
|
5
|
+
`preact-sigma` is a typed state-model layer for Preact and TypeScript. It keeps top-level public state reactive, derived reads local to the model, writes explicit through class actions, and side effects owned by explicit setup.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -13,22 +13,27 @@ npm install preact-sigma @preact/signals immer preact
|
|
|
13
13
|
## Quick Example
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
import { Sigma } from "preact-sigma";
|
|
17
|
+
|
|
18
|
+
type CounterState = { count: number };
|
|
19
|
+
|
|
20
|
+
class Counter extends Sigma<CounterState> {
|
|
21
|
+
constructor() {
|
|
22
|
+
super({
|
|
23
|
+
count: 0,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get doubled() {
|
|
28
|
+
return this.count * 2;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
increment() {
|
|
32
|
+
this.count += 1;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface Counter extends CounterState {}
|
|
32
37
|
|
|
33
38
|
const counter = new Counter();
|
|
34
39
|
|
|
@@ -42,5 +47,6 @@ console.log(counter.doubled); // 2
|
|
|
42
47
|
|
|
43
48
|
- Concepts, lifecycle, invariants, and API selection live in [`docs/context.md`](./docs/context.md).
|
|
44
49
|
- Persistence-specific guidance lives in [`docs/persist.md`](./docs/persist.md).
|
|
50
|
+
- Migration guidance from v5 lives in [`docs/migrations/v5-to-v6.md`](./docs/migrations/v5-to-v6.md).
|
|
45
51
|
- Runnable usage patterns live in [`examples/`](./examples/), starting with [`examples/basic-counter.ts`](./examples/basic-counter.ts) and [`examples/command-palette.tsx`](./examples/command-palette.tsx).
|
|
46
|
-
- Exact exported signatures live in `dist
|
|
52
|
+
- Exact exported signatures and public API comments live in `dist/index.d.mts` and `dist/persist.d.mts` after `pnpm build`.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,20 +1,61 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as SigmaState, c as query, d as Draft, f as Immutable, i as SigmaRef, l as setAutoFreeze, m as Cleanup, n as Sigma, o as SigmaTarget, p as typeSymbol, r as SigmaDefinition, s as castProtected, t as Protected, u as sigma } from "./sigma-DD7HfTvw.mjs";
|
|
2
2
|
|
|
3
|
-
//#region src/
|
|
3
|
+
//#region src/defaults.d.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Shallowly applies defined initial values over a defaults object.
|
|
6
6
|
*
|
|
7
|
-
* `
|
|
8
|
-
* defines setup, `useSigma(...)` also runs `setup(...setupArgs)` in an effect
|
|
9
|
-
* and cleans it up when the setup arguments change or the component unmounts.
|
|
7
|
+
* `undefined` initial values leave their matching default value in place.
|
|
10
8
|
*/
|
|
11
|
-
declare function
|
|
9
|
+
declare function mergeDefaults<T extends object>(initial: Partial<T> | undefined, defaults: T): T;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/listener.d.ts
|
|
12
|
+
/** Sigma targets and protected sigma target views that carry typed event metadata. */
|
|
13
|
+
type SigmaListenable<TEvents extends object = any> = {
|
|
14
|
+
readonly [typeSymbol]: {
|
|
15
|
+
readonly events: TEvents;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
/** Target types supported by `listen(...)` and `useListener(...)`. */
|
|
19
|
+
type Listenable = SigmaListenable | EventTarget;
|
|
20
|
+
type InferEventMap<TTarget extends Listenable> = TTarget extends SigmaListenable<infer TEvents> ? TEvents : TTarget extends Window ? WindowEventMap : TTarget extends Document ? DocumentEventMap : TTarget extends HTMLBodyElement ? HTMLBodyElementEventMap : TTarget extends HTMLMediaElement ? HTMLMediaElementEventMap : TTarget extends HTMLElement ? HTMLElementEventMap : TTarget extends SVGSVGElement ? SVGSVGElementEventMap : TTarget extends SVGElement ? SVGElementEventMap : TTarget extends EventTarget ? Record<string, Event> : never;
|
|
21
|
+
type InferListenerArgs<TEvents extends object, TTarget extends Listenable, TEvent extends string> = [(TEvent extends keyof TEvents ? TEvents[TEvent] : never) extends infer TPayload ? TTarget extends SigmaListenable<any> ? [TPayload] extends [never] ? never : [TPayload] extends [void] ? undefined : TPayload : ([TPayload] extends [never] ? CustomEvent : Extract<TPayload, Event>) & {
|
|
22
|
+
readonly currentTarget: TTarget;
|
|
23
|
+
} : never];
|
|
24
|
+
/** Infers the listener callback shape for a target and event name. Sigma targets receive payloads directly, while DOM targets receive typed events. */
|
|
25
|
+
type InferListener<TTarget extends Listenable, TEvent extends string = string> = InferEventMap<TTarget> extends infer TEvents extends object ? ((...args: InferListenerArgs<TEvents, TTarget, TEvent>) => void) & {
|
|
26
|
+
__eventType?: TEvent;
|
|
27
|
+
} : never;
|
|
28
|
+
/** Infers the event names accepted by `listen(...)` or `useListener(...)` for a target. */
|
|
29
|
+
type InferEventType<TTarget extends Listenable> = (InferListener<TTarget> extends {
|
|
30
|
+
__eventType?: infer TEvent;
|
|
31
|
+
} ? string & TEvent : never) | (string & {});
|
|
32
|
+
/** Adds a listener to a sigma target or DOM target and returns a cleanup function that removes it. */
|
|
33
|
+
declare function listen<TTarget extends Listenable, TEvent extends InferEventType<TTarget>>(target: TTarget, name: TEvent, listener: InferListener<TTarget, TEvent>): Cleanup;
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/hooks/useListener.d.ts
|
|
12
36
|
/**
|
|
13
37
|
* Attaches an event listener in a component and cleans it up automatically.
|
|
14
38
|
*
|
|
15
39
|
* Passing `null` disables the listener. The latest callback is used without
|
|
16
40
|
* forcing the effect to resubscribe on every render.
|
|
17
41
|
*/
|
|
18
|
-
declare function useListener<TTarget extends Listenable
|
|
42
|
+
declare function useListener<TTarget extends Listenable, TEvent extends InferEventType<TTarget>>(target: TTarget | null, name: TEvent, listener: InferListener<TTarget, TEvent>): void;
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/hooks/useSigma.d.ts
|
|
45
|
+
/** Setup arguments and recreation dependencies for `useSigma(...)`. */
|
|
46
|
+
type UseSigmaOptions<TSetup extends readonly any[] = any[]> = {
|
|
47
|
+
/** Arguments passed to the sigma instance's `onSetup(...)` method. */setup: TSetup | (() => TSetup); /** Dependencies that recreate the sigma instance when they change. */
|
|
48
|
+
deps?: readonly any[];
|
|
49
|
+
};
|
|
50
|
+
/** Infers the accepted `useSigma(...)` call shape from a sigma class and its setup parameters. */
|
|
51
|
+
type UseSigmaArgs<T extends Sigma<any>> = T extends {
|
|
52
|
+
onSetup: (...params: infer TParams) => any;
|
|
53
|
+
} ? [] extends TParams ? [create: () => T, options?: Partial<UseSigmaOptions<TParams>>] : [create: () => T, options: UseSigmaOptions<TParams>] : [create: () => T, deps?: readonly any[]];
|
|
54
|
+
/**
|
|
55
|
+
* Creates or reuses a sigma instance for a component and returns its protected consumer view.
|
|
56
|
+
*
|
|
57
|
+
* Classes with `onSetup(...)` run setup in an effect and clean it up on unmount.
|
|
58
|
+
*/
|
|
59
|
+
declare function useSigma<T extends Sigma<any>>(...args: UseSigmaArgs<T>): Protected<T>;
|
|
19
60
|
//#endregion
|
|
20
|
-
export {
|
|
61
|
+
export { type Draft, type Immutable, InferEventType, InferListener, Listenable, Protected, Sigma, SigmaDefinition, SigmaListenable, SigmaRef, SigmaState, SigmaTarget, UseSigmaArgs, UseSigmaOptions, castProtected, listen, mergeDefaults, query, setAutoFreeze, sigma, useListener, useSigma };
|
package/dist/index.mjs
CHANGED
|
@@ -1,149 +1,34 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { useEffect, useRef, useState } from "preact/hooks";
|
|
5
|
-
//#region src/framework.ts
|
|
6
|
-
/** Checks whether a value is an instance created by a configured sigma type. */
|
|
7
|
-
function isSigmaState(value) {
|
|
8
|
-
return Boolean(value[sigmaStateBrand]);
|
|
9
|
-
}
|
|
1
|
+
import { a as setAutoFreeze, c as listenersSymbol, i as query, n as SigmaTarget, o as sigma, r as castProtected, t as Sigma } from "./sigma-CJibGQ6g.mjs";
|
|
2
|
+
import { useEffect, useRef } from "preact/hooks";
|
|
3
|
+
//#region src/defaults.ts
|
|
10
4
|
/**
|
|
11
|
-
*
|
|
5
|
+
* Shallowly applies defined initial values over a defaults object.
|
|
12
6
|
*
|
|
13
|
-
*
|
|
14
|
-
* invocations, which makes `query(fn)` a good fit for local tracked helpers
|
|
15
|
-
* that do not need to live on the sigma-state instance.
|
|
7
|
+
* `undefined` initial values leave their matching default value in place.
|
|
16
8
|
*/
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* queries, actions, and setup handlers.
|
|
23
|
-
*
|
|
24
|
-
* State and event inference starts from `new SigmaType<TState, TEvents>()`.
|
|
25
|
-
* Later builder methods infer names and types from the objects you pass to them.
|
|
26
|
-
*/
|
|
27
|
-
var SigmaType = class SigmaType extends Function {
|
|
28
|
-
constructor(name = "Sigma") {
|
|
29
|
-
super();
|
|
30
|
-
const { [name]: type } = { [name]: class extends Sigma {
|
|
31
|
-
static _actionFunctions = Object.create(null);
|
|
32
|
-
static _computeFunctions = Object.create(null);
|
|
33
|
-
static _defaultState = Object.create(null);
|
|
34
|
-
static _defaultStateKeys = [];
|
|
35
|
-
static _queryFunctions = Object.create(null);
|
|
36
|
-
static _setupFunction = null;
|
|
37
|
-
constructor(initialState) {
|
|
38
|
-
super();
|
|
39
|
-
initializeSigmaInstance(this, type, initialState);
|
|
40
|
-
}
|
|
41
|
-
} };
|
|
42
|
-
Object.defineProperties(type, Object.getOwnPropertyDescriptors(SigmaType.prototype));
|
|
43
|
-
return type;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Adds top-level public state and default values to the builder.
|
|
47
|
-
*
|
|
48
|
-
* Each property becomes a reactive public state property on instances. Use a
|
|
49
|
-
* zero-argument function when each instance needs a fresh object or array.
|
|
50
|
-
*/
|
|
51
|
-
defaultState(defaultState) {
|
|
52
|
-
const type = getTypeInternals(this);
|
|
53
|
-
for (const key in defaultState) {
|
|
54
|
-
if (defaultState[key] === void 0) continue;
|
|
55
|
-
type._defaultState[key] = defaultState[key];
|
|
56
|
-
type._defaultStateKeys.push(key);
|
|
57
|
-
}
|
|
58
|
-
return this;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Adds reactive getter properties for derived values that take no arguments.
|
|
62
|
-
*
|
|
63
|
-
* Computed names and return types are inferred from the object you pass.
|
|
64
|
-
* `this` exposes readonly state plus computeds that are already on the builder.
|
|
65
|
-
*/
|
|
66
|
-
computed(computeds) {
|
|
67
|
-
const type = getTypeInternals(this);
|
|
68
|
-
for (const key in computeds) {
|
|
69
|
-
assertDefinitionKeyAvailable(type, key, "computed");
|
|
70
|
-
type._computeFunctions[key] = computeds[key];
|
|
71
|
-
Object.defineProperty(this.prototype, key, { get: function() {
|
|
72
|
-
return this["#" + key].value;
|
|
73
|
-
} });
|
|
74
|
-
}
|
|
75
|
-
return this;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Adds reactive read methods that accept arguments.
|
|
79
|
-
*
|
|
80
|
-
* Query names, parameters, and return types are inferred from the object you
|
|
81
|
-
* pass. Each call tracks reactively at the call site and does not memoize
|
|
82
|
-
* results across invocations.
|
|
83
|
-
*/
|
|
84
|
-
queries(queries) {
|
|
85
|
-
const type = getTypeInternals(this);
|
|
86
|
-
for (const key in queries) {
|
|
87
|
-
assertDefinitionKeyAvailable(type, key, "query");
|
|
88
|
-
const queryFunction = queries[key];
|
|
89
|
-
type._queryFunctions[key] = queryFunction;
|
|
90
|
-
Object.defineProperty(this.prototype, key, { value: buildQueryMethod(queryFunction) });
|
|
91
|
-
}
|
|
92
|
-
return this;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Adds action methods whose `this` receives draft state, typed events, `commit()`,
|
|
96
|
-
* and the computeds, queries, and actions already defined on the builder.
|
|
97
|
-
*
|
|
98
|
-
* Actions create drafts lazily as they need them. Sync actions on the same
|
|
99
|
-
* instance reuse the current draft, so they can compose and publish once when
|
|
100
|
-
* the outer action returns. Declared async actions publish their initial
|
|
101
|
-
* synchronous work on return, then require `this.commit()` to publish later
|
|
102
|
-
* writes made after `await`. Non-async actions stay synchronous; if one
|
|
103
|
-
* returns a promise, sigma throws so async boundaries stay explicit.
|
|
104
|
-
*/
|
|
105
|
-
actions(actions) {
|
|
106
|
-
const type = getTypeInternals(this);
|
|
107
|
-
for (const key in actions) {
|
|
108
|
-
assertDefinitionKeyAvailable(type, key, "action");
|
|
109
|
-
const actionFunction = actions[key];
|
|
110
|
-
type._actionFunctions[key] = actionFunction;
|
|
111
|
-
Object.defineProperty(this.prototype, key, { value: buildActionMethod(key, actionFunction) });
|
|
112
|
-
}
|
|
113
|
-
return this;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Adds an explicit setup handler for side effects and owned resources.
|
|
117
|
-
*
|
|
118
|
-
* Every registered handler runs when `instance.setup(...)` is called, and the
|
|
119
|
-
* setup argument list is inferred from the first handler you add.
|
|
120
|
-
*/
|
|
121
|
-
setup(setup) {
|
|
122
|
-
const type = getTypeInternals(this);
|
|
123
|
-
type._setupFunction = setup;
|
|
124
|
-
return this;
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
function getTypeInternals(type) {
|
|
128
|
-
return type;
|
|
9
|
+
function mergeDefaults(initial, defaults) {
|
|
10
|
+
if (!initial) return defaults;
|
|
11
|
+
const merged = { ...defaults };
|
|
12
|
+
for (const key in initial) if (initial[key] !== void 0) merged[key] = initial[key];
|
|
13
|
+
return merged;
|
|
129
14
|
}
|
|
130
15
|
//#endregion
|
|
131
|
-
//#region src/
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
*/
|
|
139
|
-
function useSigma(create, setupArgs) {
|
|
140
|
-
const sigmaState = useState(create)[0];
|
|
141
|
-
if (shouldSetup(sigmaState)) {
|
|
142
|
-
const args = setupArgs ?? [];
|
|
143
|
-
useEffect(() => sigmaState.setup(...args), [sigmaState, ...args]);
|
|
16
|
+
//#region src/listener.ts
|
|
17
|
+
function listen(target, name, listener) {
|
|
18
|
+
if (target instanceof SigmaTarget) {
|
|
19
|
+
target[listenersSymbol].addListener(name, listener);
|
|
20
|
+
return () => {
|
|
21
|
+
target[listenersSymbol].removeListener(name, listener);
|
|
22
|
+
};
|
|
144
23
|
}
|
|
145
|
-
|
|
24
|
+
const eventTarget = target;
|
|
25
|
+
eventTarget.addEventListener(name, listener);
|
|
26
|
+
return () => {
|
|
27
|
+
eventTarget.removeEventListener(name, listener);
|
|
28
|
+
};
|
|
146
29
|
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/hooks/useListener.ts
|
|
147
32
|
/**
|
|
148
33
|
* Attaches an event listener in a component and cleans it up automatically.
|
|
149
34
|
*
|
|
@@ -159,4 +44,37 @@ function useListener(target, name, listener) {
|
|
|
159
44
|
}, [target, name]);
|
|
160
45
|
}
|
|
161
46
|
//#endregion
|
|
162
|
-
|
|
47
|
+
//#region src/hooks/useSigma.ts
|
|
48
|
+
const isArray = Array.isArray;
|
|
49
|
+
const depsCache = /* @__PURE__ */ new WeakMap();
|
|
50
|
+
function depsChanged(container, deps) {
|
|
51
|
+
const cachedDeps = depsCache.get(container);
|
|
52
|
+
if (!deps && !cachedDeps) return false;
|
|
53
|
+
if (!deps || !cachedDeps) return true;
|
|
54
|
+
if (deps.length !== cachedDeps.length || deps.some((dep, index) => !Object.is(dep, cachedDeps[index]))) return true;
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
function useSigma(create, optionsOrDeps) {
|
|
58
|
+
const container = useRef(null);
|
|
59
|
+
let setup;
|
|
60
|
+
let deps;
|
|
61
|
+
if (isArray(optionsOrDeps)) deps = optionsOrDeps;
|
|
62
|
+
else {
|
|
63
|
+
setup = optionsOrDeps?.setup;
|
|
64
|
+
deps = optionsOrDeps?.deps;
|
|
65
|
+
}
|
|
66
|
+
if (!container.current || depsChanged(container, deps)) {
|
|
67
|
+
depsCache.set(container, deps);
|
|
68
|
+
container.current = create();
|
|
69
|
+
}
|
|
70
|
+
const instance = container.current;
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if ("onSetup" in instance) {
|
|
73
|
+
const setupArgs = setup ? isArray(setup) ? setup : setup() : [];
|
|
74
|
+
return instance.setup(...setupArgs);
|
|
75
|
+
}
|
|
76
|
+
}, [instance, ...isArray(setup) ? setup : []]);
|
|
77
|
+
return castProtected(instance);
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { Sigma, SigmaTarget, castProtected, listen, mergeDefaults, query, setAutoFreeze, sigma, useListener, useSigma };
|
package/dist/persist.d.mts
CHANGED
|
@@ -1,62 +1,84 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as Immutable, n as Sigma } from "./sigma-DD7HfTvw.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/persist.d.ts
|
|
4
4
|
type MaybePromise<T> = T | Promise<T>;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/** Decode-time context passed to persistence codecs. */
|
|
6
|
+
interface PersistDecodeContext<TState extends object> {
|
|
7
|
+
/** Storage key used to read the record being decoded. */
|
|
7
8
|
key: string;
|
|
9
|
+
/** Version number stored with the record being decoded. */
|
|
8
10
|
storedVersion: number;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
/** Current committed snapshot before the decoded value is applied. */
|
|
12
|
+
baseState: Immutable<TState>;
|
|
13
|
+
}
|
|
14
|
+
/** Context passed to background write error handlers. */
|
|
15
|
+
interface PersistErrorContext<TState extends object> {
|
|
16
|
+
/** Sigma instance whose state was being persisted. */
|
|
17
|
+
instance: Sigma<TState>;
|
|
18
|
+
/** Storage key used for the failed write. */
|
|
19
|
+
key: string;
|
|
20
|
+
}
|
|
11
21
|
/** A stored persistence record with version and save-time metadata. */
|
|
12
22
|
interface PersistRecord<TStored = unknown> {
|
|
13
23
|
version: number;
|
|
14
24
|
savedAt: number;
|
|
15
25
|
value: TStored;
|
|
16
26
|
}
|
|
17
|
-
/**
|
|
18
|
-
interface PersistStore<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
/** Key-value storage adapter used by persistence helpers. The method names match Keyv and `Map`. */
|
|
28
|
+
interface PersistStore<TStored = unknown> {
|
|
29
|
+
get(key: string): MaybePromise<PersistRecord<TStored> | undefined>;
|
|
30
|
+
set(key: string, record: PersistRecord<TStored>): MaybePromise<unknown>;
|
|
31
|
+
delete(key: string): MaybePromise<unknown>;
|
|
22
32
|
}
|
|
23
33
|
/** Synchronous storage adapter used by sync restore helpers. */
|
|
24
|
-
interface SyncPersistStore<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
interface SyncPersistStore<TStored = unknown> extends PersistStore<TStored> {
|
|
35
|
+
get(key: string): PersistRecord<TStored> | undefined;
|
|
36
|
+
set(key: string, record: PersistRecord<TStored>): unknown;
|
|
37
|
+
delete(key: string): unknown;
|
|
28
38
|
}
|
|
29
|
-
/** Codec that maps between
|
|
30
|
-
interface PersistCodec<TState extends object, TStored = TState
|
|
39
|
+
/** Codec that maps between committed sigma snapshots and stored payloads. */
|
|
40
|
+
interface PersistCodec<TState extends object, TStored = Immutable<TState>> {
|
|
31
41
|
version: number;
|
|
32
|
-
encode(state:
|
|
33
|
-
decode(stored: unknown, context:
|
|
42
|
+
encode(state: Immutable<TState>): TStored;
|
|
43
|
+
decode(stored: unknown, context: PersistDecodeContext<TState>): TState;
|
|
34
44
|
}
|
|
35
45
|
/** Scheduling policy for persistence writes. */
|
|
36
46
|
type PersistSchedule = "immediate" | "microtask" | {
|
|
37
47
|
debounceMs: number;
|
|
38
48
|
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/** Storage key used for reads, writes, and removals. */
|
|
49
|
+
interface PersistLifecycleOptions<TState extends object> {
|
|
50
|
+
/** Storage key used for gets, sets, and deletes. */
|
|
42
51
|
key: string;
|
|
43
|
-
/** Store adapter that owns persistence I/O. */
|
|
44
|
-
store: PersistStore<PersistRecord<TStored>>;
|
|
45
|
-
/** Codec that maps committed snapshots to stored payloads. Defaults to an identity codec with version 1. */
|
|
46
|
-
codec?: PersistCodec<Snapshot<T>, TStored>;
|
|
47
52
|
/** Scheduling policy for future writes. Defaults to `"microtask"`. */
|
|
48
53
|
schedule?: PersistSchedule;
|
|
49
54
|
/** Writes the current committed snapshot once after persistence becomes active. */
|
|
50
55
|
writeInitial?: boolean;
|
|
51
56
|
/** Receives background write failures without stopping persistence automatically. */
|
|
52
|
-
onWriteError?: (error: unknown, context:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
onWriteError?: (error: unknown, context: PersistErrorContext<TState>) => void;
|
|
58
|
+
}
|
|
59
|
+
/** Options shared by restore and persistence helpers. */
|
|
60
|
+
interface PersistOptions<TState extends object, TStored = Immutable<TState>> extends PersistLifecycleOptions<TState> {
|
|
61
|
+
/** Store adapter that owns persistence I/O for stored records. */
|
|
62
|
+
store: PersistStore<TStored>;
|
|
63
|
+
/** Codec that maps committed snapshots to stored payloads. Defaults to an identity codec with version 1. */
|
|
64
|
+
codec?: PersistCodec<TState, TStored>;
|
|
65
|
+
pick?: never;
|
|
66
|
+
}
|
|
67
|
+
/** Options that persist selected top-level state keys without a custom codec. */
|
|
68
|
+
interface PickPersistOptions<TState extends object, TKey extends keyof TState = keyof TState> extends PersistLifecycleOptions<TState> {
|
|
69
|
+
/** Store adapter that owns persistence I/O for the selected top-level keys. */
|
|
70
|
+
store: PersistStore<Pick<TState, TKey>>;
|
|
71
|
+
/** Top-level state keys to persist and restore from the current base snapshot. */
|
|
72
|
+
pick: readonly TKey[];
|
|
73
|
+
codec?: never;
|
|
56
74
|
}
|
|
57
75
|
/** Options that require a synchronous store. */
|
|
58
|
-
interface SyncPersistOptions<
|
|
59
|
-
store: SyncPersistStore<
|
|
76
|
+
interface SyncPersistOptions<TState extends object, TStored = Immutable<TState>> extends PersistOptions<TState, TStored> {
|
|
77
|
+
store: SyncPersistStore<TStored>;
|
|
78
|
+
}
|
|
79
|
+
/** Pick-based options that require a synchronous store. */
|
|
80
|
+
interface SyncPickPersistOptions<TState extends object, TKey extends keyof TState = keyof TState> extends PickPersistOptions<TState, TKey> {
|
|
81
|
+
store: SyncPersistStore<Pick<TState, TKey>>;
|
|
60
82
|
}
|
|
61
83
|
/** Result returned by restore helpers. */
|
|
62
84
|
type RestoreResult = {
|
|
@@ -75,27 +97,30 @@ interface PersistenceHandle {
|
|
|
75
97
|
/** Stops future persistence and waits for any active write to settle. */
|
|
76
98
|
stop(): Promise<void>;
|
|
77
99
|
}
|
|
78
|
-
/** Async restore-plus-persist
|
|
79
|
-
interface
|
|
100
|
+
/** Async restore-plus-persist handle. */
|
|
101
|
+
interface HydrationHandle extends PersistenceHandle {
|
|
80
102
|
/** Resolves when restore finishes and reports whether a record was applied. */
|
|
81
103
|
readonly restored: Promise<RestoreResult>;
|
|
82
104
|
}
|
|
83
|
-
/** Sync restore-plus-persist
|
|
84
|
-
interface
|
|
105
|
+
/** Sync restore-plus-persist handle. */
|
|
106
|
+
interface SyncHydrationHandle extends PersistenceHandle {
|
|
85
107
|
/** Reports the synchronous restore result that ran before persistence started. */
|
|
86
108
|
readonly restored: RestoreResult;
|
|
87
109
|
}
|
|
88
110
|
/** Restores committed state from a persisted record through an async store. */
|
|
89
|
-
declare function
|
|
111
|
+
declare function restore<TState extends object, TKey extends keyof TState>(instance: Sigma<TState>, options: PickPersistOptions<TState, TKey>): Promise<RestoreResult>;
|
|
112
|
+
declare function restore<TState extends object, TStored = Immutable<TState>>(instance: Sigma<TState>, options: PersistOptions<TState, TStored>): Promise<RestoreResult>;
|
|
90
113
|
/** Restores committed state from a persisted record through a sync store. */
|
|
91
|
-
declare function
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
declare function
|
|
114
|
+
declare function restoreSync<TState extends object, TKey extends keyof TState>(instance: Sigma<TState>, options: SyncPickPersistOptions<TState, TKey>): RestoreResult;
|
|
115
|
+
declare function restoreSync<TState extends object, TStored = Immutable<TState>>(instance: Sigma<TState>, options: SyncPersistOptions<TState, TStored>): RestoreResult;
|
|
116
|
+
/** Persists future committed state changes for one sigma instance. */
|
|
117
|
+
declare function persist<TState extends object, TKey extends keyof TState>(instance: Sigma<TState>, options: PickPersistOptions<TState, TKey>): PersistenceHandle;
|
|
118
|
+
declare function persist<TState extends object, TStored = Immutable<TState>>(instance: Sigma<TState>, options: PersistOptions<TState, TStored>): PersistenceHandle;
|
|
96
119
|
/** Restores state, then begins persisting future committed changes. */
|
|
97
|
-
declare function
|
|
120
|
+
declare function hydrate<TState extends object, TKey extends keyof TState>(instance: Sigma<TState>, options: PickPersistOptions<TState, TKey>): HydrationHandle;
|
|
121
|
+
declare function hydrate<TState extends object, TStored = Immutable<TState>>(instance: Sigma<TState>, options: PersistOptions<TState, TStored>): HydrationHandle;
|
|
98
122
|
/** Restores state synchronously, then begins persisting future committed changes. */
|
|
99
|
-
declare function
|
|
123
|
+
declare function hydrateSync<TState extends object, TKey extends keyof TState>(instance: Sigma<TState>, options: SyncPickPersistOptions<TState, TKey>): SyncHydrationHandle;
|
|
124
|
+
declare function hydrateSync<TState extends object, TStored = Immutable<TState>>(instance: Sigma<TState>, options: SyncPersistOptions<TState, TStored>): SyncHydrationHandle;
|
|
100
125
|
//#endregion
|
|
101
|
-
export {
|
|
126
|
+
export { HydrationHandle, PersistCodec, PersistDecodeContext, PersistErrorContext, PersistOptions, PersistRecord, PersistSchedule, PersistStore, PersistenceHandle, PickPersistOptions, RestoreResult, SyncHydrationHandle, SyncPersistOptions, SyncPersistStore, SyncPickPersistOptions, hydrate, hydrateSync, persist, restore, restoreSync };
|