preact-sigma 4.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.
@@ -0,0 +1,126 @@
1
+ import { f as Immutable, n as Sigma } from "./sigma-DD7HfTvw.mjs";
2
+
3
+ //#region src/persist.d.ts
4
+ type MaybePromise<T> = T | Promise<T>;
5
+ /** Decode-time context passed to persistence codecs. */
6
+ interface PersistDecodeContext<TState extends object> {
7
+ /** Storage key used to read the record being decoded. */
8
+ key: string;
9
+ /** Version number stored with the record being decoded. */
10
+ storedVersion: number;
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
+ }
21
+ /** A stored persistence record with version and save-time metadata. */
22
+ interface PersistRecord<TStored = unknown> {
23
+ version: number;
24
+ savedAt: number;
25
+ value: TStored;
26
+ }
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>;
32
+ }
33
+ /** Synchronous storage adapter used by sync restore helpers. */
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;
38
+ }
39
+ /** Codec that maps between committed sigma snapshots and stored payloads. */
40
+ interface PersistCodec<TState extends object, TStored = Immutable<TState>> {
41
+ version: number;
42
+ encode(state: Immutable<TState>): TStored;
43
+ decode(stored: unknown, context: PersistDecodeContext<TState>): TState;
44
+ }
45
+ /** Scheduling policy for persistence writes. */
46
+ type PersistSchedule = "immediate" | "microtask" | {
47
+ debounceMs: number;
48
+ };
49
+ interface PersistLifecycleOptions<TState extends object> {
50
+ /** Storage key used for gets, sets, and deletes. */
51
+ key: string;
52
+ /** Scheduling policy for future writes. Defaults to `"microtask"`. */
53
+ schedule?: PersistSchedule;
54
+ /** Writes the current committed snapshot once after persistence becomes active. */
55
+ writeInitial?: boolean;
56
+ /** Receives background write failures without stopping persistence automatically. */
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;
74
+ }
75
+ /** Options that require a synchronous store. */
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>>;
82
+ }
83
+ /** Result returned by restore helpers. */
84
+ type RestoreResult = {
85
+ status: "missing";
86
+ } | {
87
+ status: "restored";
88
+ savedAt: number;
89
+ storedVersion: number;
90
+ };
91
+ /** Handle returned by persistence bindings. */
92
+ interface PersistenceHandle {
93
+ /** Waits for any scheduled or active write for this binding to finish. */
94
+ flush(): Promise<void>;
95
+ /** Removes the stored record and keeps the binding active for later writes. */
96
+ clear(): Promise<void>;
97
+ /** Stops future persistence and waits for any active write to settle. */
98
+ stop(): Promise<void>;
99
+ }
100
+ /** Async restore-plus-persist handle. */
101
+ interface HydrationHandle extends PersistenceHandle {
102
+ /** Resolves when restore finishes and reports whether a record was applied. */
103
+ readonly restored: Promise<RestoreResult>;
104
+ }
105
+ /** Sync restore-plus-persist handle. */
106
+ interface SyncHydrationHandle extends PersistenceHandle {
107
+ /** Reports the synchronous restore result that ran before persistence started. */
108
+ readonly restored: RestoreResult;
109
+ }
110
+ /** Restores committed state from a persisted record through an async store. */
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>;
113
+ /** Restores committed state from a persisted record through a sync store. */
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;
119
+ /** Restores state, then begins persisting future committed changes. */
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;
122
+ /** Restores state synchronously, then begins persisting future committed changes. */
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;
125
+ //#endregion
126
+ export { HydrationHandle, PersistCodec, PersistDecodeContext, PersistErrorContext, PersistOptions, PersistRecord, PersistSchedule, PersistStore, PersistenceHandle, PickPersistOptions, RestoreResult, SyncHydrationHandle, SyncPersistOptions, SyncPersistStore, SyncPickPersistOptions, hydrate, hydrateSync, persist, restore, restoreSync };
@@ -0,0 +1,240 @@
1
+ import { o as sigma, s as isPlainObject } from "./sigma-CJibGQ6g.mjs";
2
+ //#region src/persist.ts
3
+ function createIdentityCodec() {
4
+ return {
5
+ version: 1,
6
+ encode(state) {
7
+ return state;
8
+ },
9
+ decode(stored) {
10
+ return stored;
11
+ }
12
+ };
13
+ }
14
+ function createPickCodec(keys) {
15
+ return {
16
+ version: 1,
17
+ encode(state) {
18
+ const stored = {};
19
+ for (const key of keys) stored[key] = state[key];
20
+ return stored;
21
+ },
22
+ decode(stored, context) {
23
+ if (!isPlainObject(stored)) throw new Error("[preact-sigma/persist] pick requires a plain object payload");
24
+ const partialStored = stored;
25
+ const restored = { ...context.baseState };
26
+ for (const key of keys) if (key in partialStored) restored[key] = partialStored[key];
27
+ return restored;
28
+ }
29
+ };
30
+ }
31
+ function getCodec(options) {
32
+ if (options.codec) return options.codec;
33
+ if (options.pick) return createPickCodec(options.pick);
34
+ return createIdentityCodec();
35
+ }
36
+ function applyRecord(instance, key, record, codec) {
37
+ if (!record) return { status: "missing" };
38
+ const baseState = sigma.captureState(instance);
39
+ const nextState = codec.decode(record.value, {
40
+ baseState,
41
+ key,
42
+ storedVersion: record.version
43
+ });
44
+ sigma.replaceState(instance, nextState);
45
+ return {
46
+ status: "restored",
47
+ savedAt: record.savedAt,
48
+ storedVersion: record.version
49
+ };
50
+ }
51
+ async function restore(instance, options) {
52
+ const codec = getCodec(options);
53
+ const record = await options.store.get(options.key);
54
+ return applyRecord(instance, options.key, record, codec);
55
+ }
56
+ function restoreSync(instance, options) {
57
+ const codec = getCodec(options);
58
+ const record = options.store.get(options.key);
59
+ return applyRecord(instance, options.key, record, codec);
60
+ }
61
+ function persist(instance, options) {
62
+ const codec = getCodec(options);
63
+ const schedule = options.schedule ?? "microtask";
64
+ const key = options.key;
65
+ const store = options.store;
66
+ let stopped = false;
67
+ let suspended = false;
68
+ let hasPendingState = false;
69
+ let pendingState;
70
+ let microtaskScheduled = false;
71
+ let debounceTimer;
72
+ let runningWrite;
73
+ let backgroundWrite;
74
+ const cancelScheduledWrite = () => {
75
+ microtaskScheduled = false;
76
+ if (debounceTimer !== void 0) {
77
+ clearTimeout(debounceTimer);
78
+ debounceTimer = void 0;
79
+ }
80
+ };
81
+ const createRecord = (state) => ({
82
+ version: codec.version,
83
+ savedAt: Date.now(),
84
+ value: codec.encode(state)
85
+ });
86
+ const startBackgroundWrite = () => {
87
+ if (backgroundWrite) return;
88
+ backgroundWrite = drainPendingWrites().catch((error) => {
89
+ options.onWriteError?.(error, {
90
+ instance,
91
+ key
92
+ });
93
+ }).finally(() => {
94
+ backgroundWrite = void 0;
95
+ });
96
+ };
97
+ const scheduleWrite = () => {
98
+ if (stopped || suspended) return;
99
+ if (schedule === "immediate") {
100
+ startBackgroundWrite();
101
+ return;
102
+ }
103
+ if (schedule === "microtask") {
104
+ if (microtaskScheduled) return;
105
+ microtaskScheduled = true;
106
+ queueMicrotask(() => {
107
+ microtaskScheduled = false;
108
+ if (stopped || suspended) return;
109
+ startBackgroundWrite();
110
+ });
111
+ return;
112
+ }
113
+ if (debounceTimer !== void 0) clearTimeout(debounceTimer);
114
+ debounceTimer = setTimeout(() => {
115
+ debounceTimer = void 0;
116
+ if (stopped || suspended) return;
117
+ startBackgroundWrite();
118
+ }, schedule.debounceMs);
119
+ };
120
+ const queueStateWrite = () => {
121
+ pendingState = sigma.captureState(instance);
122
+ hasPendingState = true;
123
+ scheduleWrite();
124
+ };
125
+ async function drainPendingWrites() {
126
+ if (runningWrite) return runningWrite;
127
+ cancelScheduledWrite();
128
+ runningWrite = (async () => {
129
+ while (hasPendingState && !stopped && !suspended) {
130
+ const state = pendingState;
131
+ hasPendingState = false;
132
+ await store.set(key, createRecord(state));
133
+ }
134
+ })();
135
+ try {
136
+ await runningWrite;
137
+ } finally {
138
+ runningWrite = void 0;
139
+ if (hasPendingState && !stopped && !suspended) startBackgroundWrite();
140
+ }
141
+ }
142
+ const stopSubscription = sigma.subscribe(instance, queueStateWrite);
143
+ if (options.writeInitial) queueStateWrite();
144
+ return {
145
+ async flush() {
146
+ cancelScheduledWrite();
147
+ if (!hasPendingState) {
148
+ await runningWrite;
149
+ return;
150
+ }
151
+ await drainPendingWrites();
152
+ },
153
+ async clear() {
154
+ suspended = true;
155
+ cancelScheduledWrite();
156
+ hasPendingState = false;
157
+ pendingState = void 0;
158
+ try {
159
+ await runningWrite;
160
+ await store.delete(key);
161
+ } finally {
162
+ suspended = false;
163
+ if (hasPendingState && !stopped) scheduleWrite();
164
+ }
165
+ },
166
+ async stop() {
167
+ if (stopped) {
168
+ await runningWrite;
169
+ return;
170
+ }
171
+ stopped = true;
172
+ suspended = true;
173
+ stopSubscription();
174
+ cancelScheduledWrite();
175
+ hasPendingState = false;
176
+ pendingState = void 0;
177
+ await runningWrite;
178
+ }
179
+ };
180
+ }
181
+ function hydrate(instance, options) {
182
+ let stopped = false;
183
+ let handle;
184
+ const restored = (async () => {
185
+ const result = await restore(instance, options);
186
+ if (!stopped) handle = persist(instance, options);
187
+ return result;
188
+ })();
189
+ return {
190
+ restored,
191
+ async flush() {
192
+ await restored;
193
+ await handle?.flush();
194
+ },
195
+ async clear() {
196
+ try {
197
+ await restored;
198
+ } catch {
199
+ await options.store.delete(options.key);
200
+ return;
201
+ }
202
+ if (handle) {
203
+ await handle.clear();
204
+ return;
205
+ }
206
+ await options.store.delete(options.key);
207
+ },
208
+ async stop() {
209
+ if (stopped) {
210
+ await handle?.stop();
211
+ return;
212
+ }
213
+ stopped = true;
214
+ try {
215
+ await restored;
216
+ } catch {
217
+ return;
218
+ }
219
+ await handle?.stop();
220
+ }
221
+ };
222
+ }
223
+ function hydrateSync(instance, options) {
224
+ const restored = restoreSync(instance, options);
225
+ const handle = persist(instance, options);
226
+ return {
227
+ restored,
228
+ clear() {
229
+ return handle.clear();
230
+ },
231
+ flush() {
232
+ return handle.flush();
233
+ },
234
+ stop() {
235
+ return handle.stop();
236
+ }
237
+ };
238
+ }
239
+ //#endregion
240
+ export { hydrate, hydrateSync, persist, restore, restoreSync };