@hardlydifficult/state-tracker 2.0.10 → 2.0.12
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 +193 -138
- package/dist/StateTracker.d.ts +26 -0
- package/dist/StateTracker.d.ts.map +1 -1
- package/dist/StateTracker.js +98 -37
- package/dist/StateTracker.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @hardlydifficult/state-tracker
|
|
2
2
|
|
|
3
|
-
Atomic JSON state persistence with sync/async APIs, auto-save, and graceful degradation for TypeScript
|
|
3
|
+
Atomic JSON state persistence with sync/async APIs, auto-save debouncing, and graceful degradation to in-memory mode for TypeScript.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -13,205 +13,266 @@ npm install @hardlydifficult/state-tracker
|
|
|
13
13
|
```typescript
|
|
14
14
|
import { StateTracker } from "@hardlydifficult/state-tracker";
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const store = new StateTracker<AppState>({
|
|
22
|
-
key: "my-service",
|
|
23
|
-
default: { requestCount: 0, lastActiveAt: "" },
|
|
24
|
-
stateDirectory: "/var/data",
|
|
25
|
-
autoSaveMs: 5000,
|
|
26
|
-
onEvent: ({ level, message }) => console.log(`[${level}] ${message}`),
|
|
16
|
+
const tracker = new StateTracker({
|
|
17
|
+
key: "user-settings",
|
|
18
|
+
default: { theme: "light", notifications: true },
|
|
19
|
+
autoSaveMs: 1000,
|
|
27
20
|
});
|
|
28
21
|
|
|
29
|
-
|
|
22
|
+
// Load persisted state (sync or async)
|
|
23
|
+
tracker.load(); // or await tracker.loadAsync();
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
// Update state and auto-save
|
|
26
|
+
tracker.update({ theme: "dark" });
|
|
27
|
+
// State is saved automatically after 1 second of inactivity
|
|
28
|
+
|
|
29
|
+
// Read current state
|
|
30
|
+
console.log(tracker.state); // { theme: "dark", notifications: true }
|
|
35
31
|
```
|
|
36
32
|
|
|
37
|
-
##
|
|
33
|
+
## State Management
|
|
38
34
|
|
|
39
|
-
StateTracker
|
|
35
|
+
The `StateTracker` class provides a robust interface for managing persistent application state.
|
|
40
36
|
|
|
41
|
-
|
|
42
|
-
new StateTracker({ key: "../evil", default: 0 }); // throws: "invalid characters"
|
|
43
|
-
new StateTracker({ key: "foo/bar", default: 0 }); // throws: "invalid characters"
|
|
44
|
-
```
|
|
37
|
+
### Constructor
|
|
45
38
|
|
|
46
|
-
|
|
39
|
+
| Option | Type | Default | Description |
|
|
40
|
+
|--------|------|---------|-------------|
|
|
41
|
+
| `key` | `string` | — | Unique identifier for the state file (alphanumeric, hyphens, underscores only) |
|
|
42
|
+
| `default` | `T` | — | Default state value used if no persisted state exists |
|
|
43
|
+
| `stateDirectory` | `string` | `~/.app-state` or `$STATE_TRACKER_DIR` | Directory to store state files |
|
|
44
|
+
| `autoSaveMs` | `number` | `0` | Debounce delay (ms) for auto-save after state changes |
|
|
45
|
+
| `onEvent` | `(event: StateTrackerEvent) => void` | `undefined` | Callback for internal events (debug/info/warn/error) |
|
|
46
|
+
|
|
47
|
+
### State Accessors
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
- **`state: Readonly<T>`** — Read-only getter for the current in-memory state.
|
|
50
|
+
- **`isPersistent: boolean`** — Indicates whether disk persistence is available (set after `loadAsync()`).
|
|
49
51
|
|
|
50
52
|
```typescript
|
|
51
53
|
const tracker = new StateTracker({
|
|
52
|
-
key: "
|
|
53
|
-
default:
|
|
54
|
+
key: "counter",
|
|
55
|
+
default: 0,
|
|
56
|
+
stateDirectory: "./data",
|
|
54
57
|
});
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
console.log(tracker.
|
|
59
|
+
console.log(tracker.state); // 0
|
|
60
|
+
await tracker.loadAsync();
|
|
61
|
+
console.log(tracker.isPersistent); // true if disk write succeeded
|
|
59
62
|
```
|
|
60
63
|
|
|
61
|
-
|
|
64
|
+
### Persistence Operations
|
|
62
65
|
|
|
63
|
-
|
|
66
|
+
#### `load(): T`
|
|
67
|
+
Synchronous state load from disk. Returns the current state (default if missing or corrupted).
|
|
64
68
|
|
|
65
69
|
```typescript
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
key: "counter",
|
|
70
|
-
default: 0,
|
|
70
|
+
const tracker = new StateTracker({
|
|
71
|
+
key: "config",
|
|
72
|
+
default: { version: 1 },
|
|
71
73
|
});
|
|
72
|
-
|
|
73
|
-
const count = store.load(); // returns current state
|
|
74
|
-
store.save(count + 1); // writes entire state atomically
|
|
74
|
+
const config = tracker.load(); // Loads from disk or uses default
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Async operations that gracefully degrade to in-memory mode on errors.
|
|
77
|
+
#### `loadOrDefault(options?): T`
|
|
78
|
+
Explicit "safe load" convenience. Behaves like `load()` and supports typed legacy migrations.
|
|
80
79
|
|
|
81
80
|
```typescript
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
import { defineStateMigration, StateTracker } from "@hardlydifficult/state-tracker";
|
|
82
|
+
|
|
83
|
+
interface LegacySyncState {
|
|
84
|
+
offset: number;
|
|
85
|
+
completedIds: string[];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const tracker = new StateTracker({
|
|
89
|
+
key: "sync-state",
|
|
90
|
+
default: { cursor: 0, done: [] as string[] },
|
|
87
91
|
});
|
|
88
92
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
const legacyMigration = defineStateMigration<
|
|
94
|
+
{ cursor: number; done: string[] },
|
|
95
|
+
LegacySyncState
|
|
96
|
+
>({
|
|
97
|
+
name: "sync-state-v0",
|
|
98
|
+
isLegacy(input): input is LegacySyncState {
|
|
99
|
+
return (
|
|
100
|
+
input !== null &&
|
|
101
|
+
typeof input === "object" &&
|
|
102
|
+
!Array.isArray(input) &&
|
|
103
|
+
typeof (input as Record<string, unknown>).offset === "number" &&
|
|
104
|
+
Array.isArray((input as Record<string, unknown>).completedIds)
|
|
105
|
+
);
|
|
106
|
+
},
|
|
107
|
+
migrate(legacy) {
|
|
108
|
+
return { cursor: legacy.offset, done: legacy.completedIds };
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const state = tracker.loadOrDefault({ migrations: [legacyMigration] });
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### `save(value: T): void`
|
|
116
|
+
Synchronous atomic save using temp file + rename.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
tracker.save({ version: 2 });
|
|
120
|
+
// File is updated atomically; previous state preserved if crash occurs mid-write
|
|
92
121
|
```
|
|
93
122
|
|
|
94
|
-
|
|
123
|
+
#### `saveWithMeta(value: T, meta?: Record<string, unknown>): void`
|
|
124
|
+
Synchronous atomic save with optional metadata in the envelope.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
tracker.saveWithMeta(
|
|
128
|
+
{ version: 3 },
|
|
129
|
+
{ source: "sync-script", reason: "manual-run" }
|
|
130
|
+
);
|
|
131
|
+
```
|
|
95
132
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
| `set(newState)` | Replace entire state, triggers auto-save | `tracker.set({ count: 5 })` |
|
|
99
|
-
| `update(changes)` | Shallow merge (object state only), triggers auto-save | `tracker.update({ count: 5 })` |
|
|
100
|
-
| `reset()` | Restore to default, triggers auto-save | `tracker.reset()` |
|
|
101
|
-
| `state` (getter) | Read-only current state | `tracker.state` |
|
|
102
|
-
| `isPersistent` (getter) | Whether storage is available | `tracker.isPersistent` |
|
|
133
|
+
#### `loadAsync(): Promise<void>`
|
|
134
|
+
Async state load with graceful degradation. Sets `isPersistent = false` on failure instead of throwing.
|
|
103
135
|
|
|
104
136
|
```typescript
|
|
105
137
|
const tracker = new StateTracker({
|
|
106
|
-
key: "
|
|
107
|
-
default: {
|
|
138
|
+
key: "preferences",
|
|
139
|
+
default: { darkMode: false },
|
|
108
140
|
});
|
|
109
141
|
|
|
110
|
-
tracker.
|
|
111
|
-
tracker.
|
|
112
|
-
|
|
142
|
+
await tracker.loadAsync();
|
|
143
|
+
if (!tracker.isPersistent) {
|
|
144
|
+
console.warn("Running in-memory mode (disk unavailable)");
|
|
145
|
+
}
|
|
113
146
|
```
|
|
114
147
|
|
|
115
|
-
|
|
148
|
+
#### `saveAsync(): Promise<void>`
|
|
149
|
+
Async atomic save (temp file + rename). Cancels any pending auto-save before writing.
|
|
116
150
|
|
|
117
|
-
|
|
151
|
+
```typescript
|
|
152
|
+
tracker.set({ darkMode: true });
|
|
153
|
+
await tracker.saveAsync(); // Immediate save, bypassing debounce
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### State Mutations
|
|
157
|
+
|
|
158
|
+
#### `set(newState: T): void`
|
|
159
|
+
Replace entire state and schedule auto-save.
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
tracker.set({ darkMode: true, theme: "midnight" });
|
|
163
|
+
// Auto-saves after configured delay (if autoSaveMs > 0)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### `update(changes: Partial<T>): void`
|
|
167
|
+
Shallow merge for object types and schedule auto-save.
|
|
118
168
|
|
|
119
169
|
```typescript
|
|
120
|
-
|
|
121
|
-
primitive.update(100 as never); // throws: "update() can only be used when state is a non-array object"
|
|
170
|
+
tracker.update({ theme: "dark" }); // Preserves darkMode: true
|
|
122
171
|
```
|
|
123
172
|
|
|
124
|
-
|
|
173
|
+
> **Note:** Throws at runtime if state is not an object (array/primitive).
|
|
125
174
|
|
|
126
|
-
|
|
175
|
+
#### `reset(): void`
|
|
176
|
+
Restore state to the default value and schedule auto-save.
|
|
127
177
|
|
|
128
178
|
```typescript
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
default: { count: 0 },
|
|
132
|
-
autoSaveMs: 500,
|
|
133
|
-
});
|
|
179
|
+
tracker.reset(); // Reverts to default state
|
|
180
|
+
```
|
|
134
181
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
182
|
+
### File Management
|
|
183
|
+
|
|
184
|
+
#### `getFilePath(): string`
|
|
185
|
+
Returns the full path to the state file.
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
console.log(tracker.getFilePath()); // "/home/user/.app-state/counter.json"
|
|
138
189
|
```
|
|
139
190
|
|
|
140
|
-
## Event
|
|
191
|
+
## Event System
|
|
141
192
|
|
|
142
|
-
|
|
193
|
+
Events are emitted for internal operations via the optional `onEvent` callback.
|
|
194
|
+
|
|
195
|
+
| Level | Description |
|
|
196
|
+
|-------|-------------|
|
|
197
|
+
| `debug` | Low-level operations (e.g., save completion) |
|
|
198
|
+
| `info` | Normal operations (e.g., file read/write) |
|
|
199
|
+
| `warn` | Recoverable failures (e.g., disk I/O errors) |
|
|
200
|
+
| `error` | Non-recoverable failures (e.g., permission issues) |
|
|
143
201
|
|
|
144
202
|
```typescript
|
|
145
203
|
const tracker = new StateTracker({
|
|
146
|
-
key: "
|
|
147
|
-
default: {
|
|
204
|
+
key: "app",
|
|
205
|
+
default: {},
|
|
148
206
|
onEvent: (event) => {
|
|
149
|
-
console.
|
|
207
|
+
console[event.level](`[${event.level}] ${event.message}`, event.context);
|
|
150
208
|
},
|
|
151
209
|
});
|
|
152
210
|
|
|
153
211
|
await tracker.loadAsync();
|
|
154
|
-
// Outputs: [info]
|
|
212
|
+
// Outputs: [info] Loaded state from disk { path: ".../app.json" }
|
|
155
213
|
```
|
|
156
214
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
| Field | Type | Description |
|
|
160
|
-
|-------|------|-------------|
|
|
161
|
-
| `level` | `"debug" \| "info" \| "warn" \| "error"` | Severity level |
|
|
162
|
-
| `message` | `string` | Human-readable message |
|
|
163
|
-
| `context`? | `Record<string, unknown>` | Additional metadata (e.g., `path`, `error`) |
|
|
164
|
-
|
|
165
|
-
## File Format
|
|
166
|
-
|
|
167
|
-
StateTracker uses an envelope format for storage:
|
|
215
|
+
## Persistence Format
|
|
168
216
|
|
|
217
|
+
### v2 (Envelope) Format
|
|
169
218
|
```json
|
|
170
219
|
{
|
|
171
|
-
"value":
|
|
172
|
-
"lastUpdated": "
|
|
220
|
+
"value": { "theme": "dark", "notifications": true },
|
|
221
|
+
"lastUpdated": "2024-05-01T12:00:00.000Z",
|
|
222
|
+
"meta": { "source": "sync-script" }
|
|
173
223
|
}
|
|
174
224
|
```
|
|
175
225
|
|
|
176
|
-
### Migration
|
|
226
|
+
### Legacy (PersistentStore) Migration
|
|
227
|
+
The tracker automatically detects and merges legacy raw JSON objects with defaults on load.
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// If disk contains: { "count": 42 }
|
|
231
|
+
// And default is: { "count": 0, "name": "default" }
|
|
232
|
+
// Loaded state becomes: { "count": 42, "name": "default" }
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
After the first `saveAsync()`, files are rewritten in the v2 envelope format.
|
|
236
|
+
|
|
237
|
+
For custom legacy formats, use typed migrations with `defineStateMigration(...)`
|
|
238
|
+
and pass them to `loadOrDefault({ migrations })`.
|
|
239
|
+
|
|
240
|
+
## Auto-Save Behavior
|
|
241
|
+
|
|
242
|
+
When `autoSaveMs > 0`, state changes are debounced:
|
|
177
243
|
|
|
178
|
-
|
|
244
|
+
1. `set()` or `update()` triggers a timer.
|
|
245
|
+
2. Subsequent changes within the window reset the timer.
|
|
246
|
+
3. After `autoSaveMs` ms of inactivity, the state is saved.
|
|
179
247
|
|
|
180
248
|
```typescript
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
249
|
+
const tracker = new StateTracker({
|
|
250
|
+
key: "debounced",
|
|
251
|
+
default: { x: 0 },
|
|
252
|
+
autoSaveMs: 500,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
tracker.set({ x: 1 });
|
|
256
|
+
tracker.set({ x: 2 }); // Timer resets
|
|
257
|
+
await new Promise(r => setTimeout(r, 100));
|
|
258
|
+
tracker.set({ x: 3 }); // Timer resets again
|
|
259
|
+
|
|
260
|
+
// Only saved once after 500ms of inactivity with final value { x: 3 }
|
|
184
261
|
```
|
|
185
262
|
|
|
186
|
-
|
|
263
|
+
Calling `save()` or `saveAsync()` cancels pending auto-saves and writes immediately.
|
|
187
264
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|----------|------|-------------|
|
|
200
|
-
| `state` | `Readonly<T>` | Current in-memory state |
|
|
201
|
-
| `isPersistent` | `boolean` | Whether disk storage is available |
|
|
202
|
-
|
|
203
|
-
## Methods
|
|
204
|
-
|
|
205
|
-
| Method | Description |
|
|
206
|
-
|--------|-------------|
|
|
207
|
-
| `loadAsync()` | Async load with graceful degradation (safe to call multiple times) |
|
|
208
|
-
| `saveAsync()` | Async atomic save (temp file + rename) |
|
|
209
|
-
| `load()` | Sync load (v1 compatible envelope format) |
|
|
210
|
-
| `save(value)` | Sync save (overwrites entire state, v1 compatible) |
|
|
211
|
-
| `update(changes)` | Shallow merge for object state, triggers auto-save |
|
|
212
|
-
| `set(newState)` | Replace entire state, triggers auto-save |
|
|
213
|
-
| `reset()` | Restore to defaults, triggers auto-save |
|
|
214
|
-
| `getFilePath()` | Returns the full path to the state file |
|
|
265
|
+
## Types
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
export type StateTrackerEventLevel = "debug" | "info" | "warn" | "error";
|
|
269
|
+
|
|
270
|
+
export interface StateTrackerEvent {
|
|
271
|
+
level: StateTrackerEventLevel;
|
|
272
|
+
message: string;
|
|
273
|
+
context?: Record<string, unknown>;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
215
276
|
|
|
216
277
|
## Environment Variable
|
|
217
278
|
|
|
@@ -229,11 +290,5 @@ STATE_TRACKER_DIR=/custom/path npm start
|
|
|
229
290
|
- **Graceful degradation** — runs in-memory when disk is unavailable
|
|
230
291
|
- **Auto-save** — debounced saves after state mutations
|
|
231
292
|
- **Legacy format support** — reads both v1 envelope format and legacy PersistentStore formats
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
The package also exports the following types for advanced usage:
|
|
236
|
-
|
|
237
|
-
- `StateTrackerOptions<T>` — Constructor options interface
|
|
238
|
-
- `StateTrackerEvent` — Event payload interface `{ level, message, context? }`
|
|
239
|
-
- `StateTrackerEventLevel` — Event level union type `"debug" \| "info" \| "warn" \| "error"`
|
|
293
|
+
- **Typed migration helper** — declarative migration rules for old JSON shapes
|
|
294
|
+
- **Optional save metadata** — annotate saved state with `saveWithMeta(...)`
|
package/dist/StateTracker.d.ts
CHANGED
|
@@ -11,6 +11,19 @@ export interface StateTrackerOptions<T> {
|
|
|
11
11
|
autoSaveMs?: number;
|
|
12
12
|
onEvent?: (event: StateTrackerEvent) => void;
|
|
13
13
|
}
|
|
14
|
+
export interface StateTrackerMigration<TCurrent, TLegacy = unknown> {
|
|
15
|
+
readonly name?: string;
|
|
16
|
+
isLegacy(input: unknown): input is TLegacy;
|
|
17
|
+
migrate(legacy: TLegacy): TCurrent;
|
|
18
|
+
}
|
|
19
|
+
export interface StateTrackerLoadOrDefaultOptions<T> {
|
|
20
|
+
migrations?: readonly StateTrackerMigration<T>[];
|
|
21
|
+
}
|
|
22
|
+
export type StateTrackerSaveMeta = Record<string, unknown>;
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
*/
|
|
26
|
+
export declare function defineStateMigration<TCurrent, TLegacy>(migration: StateTrackerMigration<TCurrent, TLegacy>): StateTrackerMigration<TCurrent, TLegacy>;
|
|
14
27
|
/** Atomic JSON state persistence with file-based storage, auto-save, and graceful degradation to in-memory mode. */
|
|
15
28
|
export declare class StateTracker<T> {
|
|
16
29
|
private readonly filePath;
|
|
@@ -29,6 +42,11 @@ export declare class StateTracker<T> {
|
|
|
29
42
|
/** Whether storage is working */
|
|
30
43
|
get isPersistent(): boolean;
|
|
31
44
|
private emit;
|
|
45
|
+
private buildEnvelope;
|
|
46
|
+
private writeEnvelopeSync;
|
|
47
|
+
private mergeWithDefaults;
|
|
48
|
+
private extractMigrationCandidate;
|
|
49
|
+
private tryApplyMigrations;
|
|
32
50
|
/**
|
|
33
51
|
* Extract value from parsed JSON content.
|
|
34
52
|
* Handles v1 envelope format ({value, lastUpdated}) and legacy
|
|
@@ -37,8 +55,16 @@ export declare class StateTracker<T> {
|
|
|
37
55
|
private extractValue;
|
|
38
56
|
/** Sync load — v1 compatible. Also updates internal state cache. */
|
|
39
57
|
load(): T;
|
|
58
|
+
/**
|
|
59
|
+
* Sync load that explicitly falls back to defaults if disk state is missing,
|
|
60
|
+
* unreadable, or invalid. Supports optional typed legacy migrations.
|
|
61
|
+
*/
|
|
62
|
+
loadOrDefault(options?: StateTrackerLoadOrDefaultOptions<T>): T;
|
|
63
|
+
private loadSync;
|
|
40
64
|
/** Sync save — v1 compatible. Also updates internal state cache. */
|
|
41
65
|
save(value: T): void;
|
|
66
|
+
/** Sync save with optional metadata in the JSON envelope. */
|
|
67
|
+
saveWithMeta(value: T, meta?: StateTrackerSaveMeta): void;
|
|
42
68
|
/**
|
|
43
69
|
* Async load with graceful degradation.
|
|
44
70
|
* Sets _storageAvailable false on failure instead of throwing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StateTracker.d.ts","sourceRoot":"","sources":["../src/StateTracker.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEzE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,sBAAsB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,CAAC,CAAC;IACX,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC9C;AAED,oHAAoH;AACpH,qBAAa,YAAY,CAAC,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAI;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAqC;IAE9D,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,SAAS,CAA8C;IAE/D,OAAO,CAAC,MAAM,CAAC,WAAW;IAa1B,OAAO,CAAC,MAAM,CAAC,wBAAwB;gBAQ3B,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAoB3C,kDAAkD;IAClD,IAAI,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,CAEvB;IAED,iCAAiC;IACjC,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,OAAO,CAAC,IAAI;IAUZ;;;;OAIG;IACH,OAAO,CAAC,YAAY;
|
|
1
|
+
{"version":3,"file":"StateTracker.d.ts","sourceRoot":"","sources":["../src/StateTracker.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEzE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,sBAAsB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,CAAC,CAAC;IACX,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC9C;AAED,MAAM,WAAW,qBAAqB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO;IAChE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAAC;IAC3C,OAAO,CAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,CAAC;CACpC;AAED,MAAM,WAAW,gCAAgC,CAAC,CAAC;IACjD,UAAU,CAAC,EAAE,SAAS,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC;CAClD;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3D;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EACpD,SAAS,EAAE,qBAAqB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAClD,qBAAqB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAE1C;AAED,oHAAoH;AACpH,qBAAa,YAAY,CAAC,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAI;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAqC;IAE9D,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,SAAS,CAA8C;IAE/D,OAAO,CAAC,MAAM,CAAC,WAAW;IAa1B,OAAO,CAAC,MAAM,CAAC,wBAAwB;gBAQ3B,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAoB3C,kDAAkD;IAClD,IAAI,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,CAEvB;IAED,iCAAiC;IACjC,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,OAAO,CAAC,IAAI;IAUZ,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,yBAAyB;IAYjC,OAAO,CAAC,kBAAkB;IAiC1B;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAuCpB,oEAAoE;IACpE,IAAI,IAAI,CAAC;IAIT;;;OAGG;IACH,aAAa,CAAC,OAAO,CAAC,EAAE,gCAAgC,CAAC,CAAC,CAAC,GAAG,CAAC;IAI/D,OAAO,CAAC,QAAQ;IAmBhB,oEAAoE;IACpE,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;IAIpB,6DAA6D;IAC7D,YAAY,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,IAAI;IAOzD;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAoChC;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBhC,iDAAiD;IACjD,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI;IAKtB;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI;IAcjC,gDAAgD;IAChD,KAAK,IAAI,IAAI;IAKb,WAAW,IAAI,MAAM;IAIrB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,iBAAiB;CAM1B"}
|
package/dist/StateTracker.js
CHANGED
|
@@ -34,10 +34,17 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.StateTracker = void 0;
|
|
37
|
+
exports.defineStateMigration = defineStateMigration;
|
|
37
38
|
const fs = __importStar(require("fs"));
|
|
38
39
|
const fsPromises = __importStar(require("fs/promises"));
|
|
39
40
|
const os = __importStar(require("os"));
|
|
40
41
|
const path = __importStar(require("path"));
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
*/
|
|
45
|
+
function defineStateMigration(migration) {
|
|
46
|
+
return migration;
|
|
47
|
+
}
|
|
41
48
|
/** Atomic JSON state persistence with file-based storage, auto-save, and graceful degradation to in-memory mode. */
|
|
42
49
|
class StateTracker {
|
|
43
50
|
filePath;
|
|
@@ -96,12 +103,80 @@ class StateTracker {
|
|
|
96
103
|
this.onEvent({ level, message, context });
|
|
97
104
|
}
|
|
98
105
|
}
|
|
106
|
+
buildEnvelope(value, meta) {
|
|
107
|
+
const envelope = {
|
|
108
|
+
value,
|
|
109
|
+
lastUpdated: new Date().toISOString(),
|
|
110
|
+
};
|
|
111
|
+
if (meta !== undefined) {
|
|
112
|
+
envelope.meta = structuredClone(meta);
|
|
113
|
+
}
|
|
114
|
+
return envelope;
|
|
115
|
+
}
|
|
116
|
+
writeEnvelopeSync(envelope) {
|
|
117
|
+
const tempFilePath = `${this.filePath}.tmp`;
|
|
118
|
+
fs.writeFileSync(tempFilePath, JSON.stringify(envelope, null, 2), "utf-8");
|
|
119
|
+
fs.renameSync(tempFilePath, this.filePath);
|
|
120
|
+
}
|
|
121
|
+
mergeWithDefaults(value) {
|
|
122
|
+
if (value !== null &&
|
|
123
|
+
typeof value === "object" &&
|
|
124
|
+
typeof this.defaultValue === "object" &&
|
|
125
|
+
this.defaultValue !== null &&
|
|
126
|
+
!Array.isArray(value)) {
|
|
127
|
+
return {
|
|
128
|
+
...structuredClone(this.defaultValue),
|
|
129
|
+
...value,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return value;
|
|
133
|
+
}
|
|
134
|
+
extractMigrationCandidate(parsed) {
|
|
135
|
+
if (parsed !== null &&
|
|
136
|
+
typeof parsed === "object" &&
|
|
137
|
+
!Array.isArray(parsed) &&
|
|
138
|
+
"value" in parsed) {
|
|
139
|
+
return parsed.value;
|
|
140
|
+
}
|
|
141
|
+
return parsed;
|
|
142
|
+
}
|
|
143
|
+
tryApplyMigrations(parsed, migrations) {
|
|
144
|
+
if (migrations === undefined || migrations.length === 0) {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
const candidate = this.extractMigrationCandidate(parsed);
|
|
148
|
+
for (const migration of migrations) {
|
|
149
|
+
if (!migration.isLegacy(candidate)) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const migrated = migration.migrate(candidate);
|
|
154
|
+
this.emit("info", "Migrated legacy state payload", {
|
|
155
|
+
migration: migration.name ?? "anonymous",
|
|
156
|
+
});
|
|
157
|
+
return this.mergeWithDefaults(migrated);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
161
|
+
this.emit("warn", "Legacy state migration failed", {
|
|
162
|
+
migration: migration.name ?? "anonymous",
|
|
163
|
+
error: errorMessage,
|
|
164
|
+
});
|
|
165
|
+
return structuredClone(this.defaultValue);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
99
170
|
/**
|
|
100
171
|
* Extract value from parsed JSON content.
|
|
101
172
|
* Handles v1 envelope format ({value, lastUpdated}) and legacy
|
|
102
173
|
* PersistentStore format (raw T without envelope, merged with defaults).
|
|
103
174
|
*/
|
|
104
|
-
extractValue(parsed) {
|
|
175
|
+
extractValue(parsed, migrations) {
|
|
176
|
+
const migrated = this.tryApplyMigrations(parsed, migrations);
|
|
177
|
+
if (migrated !== undefined) {
|
|
178
|
+
return migrated;
|
|
179
|
+
}
|
|
105
180
|
if (parsed !== null &&
|
|
106
181
|
typeof parsed === "object" &&
|
|
107
182
|
!Array.isArray(parsed) &&
|
|
@@ -111,17 +186,7 @@ class StateTracker {
|
|
|
111
186
|
if (envelope.value === undefined) {
|
|
112
187
|
return structuredClone(this.defaultValue);
|
|
113
188
|
}
|
|
114
|
-
|
|
115
|
-
typeof envelope.value === "object" &&
|
|
116
|
-
typeof this.defaultValue === "object" &&
|
|
117
|
-
this.defaultValue !== null &&
|
|
118
|
-
!Array.isArray(envelope.value)) {
|
|
119
|
-
return {
|
|
120
|
-
...structuredClone(this.defaultValue),
|
|
121
|
-
...envelope.value,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
return envelope.value;
|
|
189
|
+
return this.mergeWithDefaults(envelope.value);
|
|
125
190
|
}
|
|
126
191
|
// Legacy PersistentStore format: raw T without envelope
|
|
127
192
|
// Only merge if T is an object type
|
|
@@ -130,16 +195,23 @@ class StateTracker {
|
|
|
130
195
|
typeof this.defaultValue === "object" &&
|
|
131
196
|
this.defaultValue !== null &&
|
|
132
197
|
!Array.isArray(parsed)) {
|
|
133
|
-
return
|
|
134
|
-
...structuredClone(this.defaultValue),
|
|
135
|
-
...parsed,
|
|
136
|
-
};
|
|
198
|
+
return this.mergeWithDefaults(parsed);
|
|
137
199
|
}
|
|
138
200
|
// Fallback to defaults
|
|
139
201
|
return structuredClone(this.defaultValue);
|
|
140
202
|
}
|
|
141
203
|
/** Sync load — v1 compatible. Also updates internal state cache. */
|
|
142
204
|
load() {
|
|
205
|
+
return this.loadSync();
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Sync load that explicitly falls back to defaults if disk state is missing,
|
|
209
|
+
* unreadable, or invalid. Supports optional typed legacy migrations.
|
|
210
|
+
*/
|
|
211
|
+
loadOrDefault(options) {
|
|
212
|
+
return this.loadSync(options?.migrations);
|
|
213
|
+
}
|
|
214
|
+
loadSync(migrations) {
|
|
143
215
|
this._loaded = true;
|
|
144
216
|
this._storageAvailable = true;
|
|
145
217
|
if (!fs.existsSync(this.filePath)) {
|
|
@@ -149,7 +221,7 @@ class StateTracker {
|
|
|
149
221
|
try {
|
|
150
222
|
const data = fs.readFileSync(this.filePath, "utf-8");
|
|
151
223
|
const parsed = JSON.parse(data);
|
|
152
|
-
this._state = this.extractValue(parsed);
|
|
224
|
+
this._state = this.extractValue(parsed, migrations);
|
|
153
225
|
return this._state;
|
|
154
226
|
}
|
|
155
227
|
catch {
|
|
@@ -159,15 +231,14 @@ class StateTracker {
|
|
|
159
231
|
}
|
|
160
232
|
/** Sync save — v1 compatible. Also updates internal state cache. */
|
|
161
233
|
save(value) {
|
|
234
|
+
this.saveWithMeta(value);
|
|
235
|
+
}
|
|
236
|
+
/** Sync save with optional metadata in the JSON envelope. */
|
|
237
|
+
saveWithMeta(value, meta) {
|
|
162
238
|
this.cancelPendingSave();
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
lastUpdated: new Date().toISOString(),
|
|
167
|
-
};
|
|
168
|
-
const tempFilePath = `${this.filePath}.tmp`;
|
|
169
|
-
fs.writeFileSync(tempFilePath, JSON.stringify(state, null, 2), "utf-8");
|
|
170
|
-
fs.renameSync(tempFilePath, this.filePath);
|
|
239
|
+
const clonedValue = structuredClone(value);
|
|
240
|
+
this._state = clonedValue;
|
|
241
|
+
this.writeEnvelopeSync(this.buildEnvelope(clonedValue, meta));
|
|
171
242
|
}
|
|
172
243
|
/**
|
|
173
244
|
* Async load with graceful degradation.
|
|
@@ -218,12 +289,8 @@ class StateTracker {
|
|
|
218
289
|
return;
|
|
219
290
|
}
|
|
220
291
|
try {
|
|
221
|
-
const state = {
|
|
222
|
-
value: this._state,
|
|
223
|
-
lastUpdated: new Date().toISOString(),
|
|
224
|
-
};
|
|
225
292
|
const tempFilePath = `${this.filePath}.tmp`;
|
|
226
|
-
await fsPromises.writeFile(tempFilePath, JSON.stringify(
|
|
293
|
+
await fsPromises.writeFile(tempFilePath, JSON.stringify(this.buildEnvelope(this._state), null, 2), "utf-8");
|
|
227
294
|
await fsPromises.rename(tempFilePath, this.filePath);
|
|
228
295
|
this.emit("debug", "Saved state to disk", { path: this.filePath });
|
|
229
296
|
}
|
|
@@ -269,13 +336,7 @@ class StateTracker {
|
|
|
269
336
|
this.saveTimer = null;
|
|
270
337
|
// Use sync save to avoid issues with untracked promises
|
|
271
338
|
try {
|
|
272
|
-
|
|
273
|
-
value: this._state,
|
|
274
|
-
lastUpdated: new Date().toISOString(),
|
|
275
|
-
};
|
|
276
|
-
const tempFilePath = `${this.filePath}.tmp`;
|
|
277
|
-
fs.writeFileSync(tempFilePath, JSON.stringify(state, null, 2), "utf-8");
|
|
278
|
-
fs.renameSync(tempFilePath, this.filePath);
|
|
339
|
+
this.writeEnvelopeSync(this.buildEnvelope(this._state));
|
|
279
340
|
this.emit("debug", "Auto-saved state to disk", {
|
|
280
341
|
path: this.filePath,
|
|
281
342
|
});
|
package/dist/StateTracker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StateTracker.js","sourceRoot":"","sources":["../src/StateTracker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"StateTracker.js","sourceRoot":"","sources":["../src/StateTracker.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** Persistent state with auto-save to disk. */
|
|
2
|
-
export { StateTracker, type StateTrackerOptions, type StateTrackerEvent, type StateTrackerEventLevel, } from "./StateTracker";
|
|
2
|
+
export { StateTracker, defineStateMigration, type StateTrackerOptions, type StateTrackerEvent, type StateTrackerEventLevel, type StateTrackerLoadOrDefaultOptions, type StateTrackerMigration, type StateTrackerSaveMeta, } from "./StateTracker";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,OAAO,EACL,YAAY,EACZ,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,gCAAgC,EACrC,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StateTracker = void 0;
|
|
3
|
+
exports.defineStateMigration = exports.StateTracker = void 0;
|
|
4
4
|
/** Persistent state with auto-save to disk. */
|
|
5
5
|
var StateTracker_1 = require("./StateTracker");
|
|
6
6
|
Object.defineProperty(exports, "StateTracker", { enumerable: true, get: function () { return StateTracker_1.StateTracker; } });
|
|
7
|
+
Object.defineProperty(exports, "defineStateMigration", { enumerable: true, get: function () { return StateTracker_1.defineStateMigration; } });
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+CAA+C;AAC/C,+
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+CAA+C;AAC/C,+CASwB;AARtB,4GAAA,YAAY,OAAA;AACZ,oHAAA,oBAAoB,OAAA"}
|