@hardlydifficult/state-tracker 1.0.0 → 2.0.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hardlydifficult/state-tracker
2
2
 
3
- File-based state persistence for recovery across restarts.
3
+ Atomic JSON state persistence with sync and async APIs, auto-save, and graceful degradation.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,30 +8,84 @@ File-based state persistence for recovery across restarts.
8
8
  npm install @hardlydifficult/state-tracker
9
9
  ```
10
10
 
11
- ## Quick Start
11
+ ## Usage
12
+
13
+ ### Server context (async with auto-save)
14
+
15
+ For long-running servers, use `loadAsync()` + `autoSaveMs` + `update()`. State degrades gracefully to in-memory if disk is unavailable.
12
16
 
13
17
  ```typescript
14
- import { StateTracker } from '@hardlydifficult/state-tracker';
18
+ import { StateTracker } from "@hardlydifficult/state-tracker";
15
19
 
16
- const tracker = new StateTracker({ key: 'last-sync', default: 0 });
20
+ interface AppState {
21
+ requestCount: number;
22
+ lastActiveAt: string;
23
+ }
17
24
 
18
- // Load persisted value (or default on first run)
19
- const lastSync = tracker.load();
25
+ const store = new StateTracker<AppState>({
26
+ key: "my-service",
27
+ default: { requestCount: 0, lastActiveAt: "" },
28
+ stateDirectory: "/var/data",
29
+ autoSaveMs: 5000,
30
+ onEvent: ({ level, message }) => console.log(`[${level}] ${message}`),
31
+ });
20
32
 
21
- // Save updated value (atomic write)
22
- tracker.save(Date.now());
33
+ await store.loadAsync();
34
+
35
+ store.state.requestCount; // read current state
36
+ store.update({ requestCount: store.state.requestCount + 1 }); // partial update
37
+ store.set({ requestCount: 0, lastActiveAt: new Date().toISOString() }); // full replace
38
+ await store.saveAsync(); // force immediate save
39
+ ```
40
+
41
+ ### Simple context (sync)
42
+
43
+ For tools and scripts, use the sync `load()`/`save()` API.
44
+
45
+ ```typescript
46
+ const store = new StateTracker<number>({
47
+ key: "counter",
48
+ default: 0,
49
+ });
50
+
51
+ const count = store.load();
52
+ store.save(count + 1);
23
53
  ```
24
54
 
25
55
  ## Options
26
56
 
27
- | Option | Description |
57
+ | Option | Type | Description |
58
+ |--------|------|-------------|
59
+ | `key` | `string` | Unique identifier for the state file (required) |
60
+ | `default` | `T` | Default value when no state file exists (required) |
61
+ | `stateDirectory` | `string` | Directory for state files (default: `$STATE_TRACKER_DIR` or `~/.app-state`) |
62
+ | `autoSaveMs` | `number` | Auto-save interval after `update()`/`set()`/`reset()` (default: 0 = disabled) |
63
+ | `onEvent` | `function` | Event callback for logging (`{ level, message, context }`) |
64
+
65
+ ## Properties
66
+
67
+ | Property | Type | Description |
68
+ |----------|------|-------------|
69
+ | `state` | `Readonly<T>` | Current in-memory state |
70
+ | `isPersistent` | `boolean` | Whether disk storage is available |
71
+
72
+ ## Methods
73
+
74
+ | Method | Description |
28
75
  |--------|-------------|
29
- | `key` | Unique identifier for the state file (alphanumeric, hyphens, underscores) |
30
- | `default` | Default value returned when no state exists (also sets the type) |
31
- | `stateDirectory?` | Custom directory for state files (default: `~/.app-state` or `STATE_TRACKER_DIR` env) |
76
+ | `loadAsync()` | Async load with graceful degradation (safe to call multiple times) |
77
+ | `saveAsync()` | Async atomic save (temp file + rename) |
78
+ | `load()` | Sync load |
79
+ | `save(value)` | Sync save |
80
+ | `update(changes)` | Shallow merge for object state, triggers auto-save |
81
+ | `set(newState)` | Replace entire state, triggers auto-save |
82
+ | `reset()` | Restore to defaults, triggers auto-save |
32
83
 
33
84
  ## Features
34
85
 
35
86
  - **Type inference** from the default value
36
87
  - **Atomic writes** via temp file + rename to prevent corruption
37
88
  - **Key sanitization** to prevent path traversal
89
+ - **Graceful degradation** — runs in-memory when disk is unavailable
90
+ - **Auto-save** — debounced saves after state mutations
91
+ - **Legacy format support** — reads both v1 envelope and raw formats
@@ -1,16 +1,66 @@
1
+ export type StateTrackerEventLevel = "debug" | "info" | "warn" | "error";
2
+ export interface StateTrackerEvent {
3
+ level: StateTrackerEventLevel;
4
+ message: string;
5
+ context?: Record<string, unknown>;
6
+ }
1
7
  export interface StateTrackerOptions<T> {
2
8
  key: string;
3
9
  default: T;
4
10
  stateDirectory?: string;
11
+ autoSaveMs?: number;
12
+ onEvent?: (event: StateTrackerEvent) => void;
5
13
  }
14
+ /** Atomic JSON state persistence with file-based storage, auto-save, and graceful degradation to in-memory mode. */
6
15
  export declare class StateTracker<T> {
7
16
  private readonly filePath;
8
17
  private readonly defaultValue;
18
+ private readonly autoSaveMs;
19
+ private readonly onEvent?;
20
+ private _state;
21
+ private _loaded;
22
+ private _storageAvailable;
23
+ private saveTimer;
9
24
  private static sanitizeKey;
10
25
  private static getDefaultStateDirectory;
11
26
  constructor(options: StateTrackerOptions<T>);
27
+ /** Read-only getter for cached in-memory state */
28
+ get state(): Readonly<T>;
29
+ /** Whether storage is working */
30
+ get isPersistent(): boolean;
31
+ private emit;
32
+ /**
33
+ * Extract value from parsed JSON content.
34
+ * Handles v1 envelope format ({value, lastUpdated}) and legacy
35
+ * PersistentStore format (raw T without envelope, merged with defaults).
36
+ */
37
+ private extractValue;
38
+ /** Sync load — v1 compatible. Also updates internal state cache. */
12
39
  load(): T;
40
+ /** Sync save — v1 compatible. Also updates internal state cache. */
13
41
  save(value: T): void;
42
+ /**
43
+ * Async load with graceful degradation.
44
+ * Sets _storageAvailable false on failure instead of throwing.
45
+ * Safe to call multiple times (subsequent calls are no-ops).
46
+ */
47
+ loadAsync(): Promise<void>;
48
+ /**
49
+ * Async atomic save (temp file + rename).
50
+ * Cancels any pending auto-save before writing.
51
+ */
52
+ saveAsync(): Promise<void>;
53
+ /** Replace entire state, schedules auto-save. */
54
+ set(newState: T): void;
55
+ /**
56
+ * Shallow merge for object types, schedules auto-save.
57
+ * Throws at runtime if T is not an object.
58
+ */
59
+ update(changes: Partial<T>): void;
60
+ /** Restore to defaults, schedules auto-save. */
61
+ reset(): void;
14
62
  getFilePath(): string;
63
+ private scheduleSave;
64
+ private cancelPendingSave;
15
65
  }
16
66
  //# sourceMappingURL=StateTracker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StateTracker.d.ts","sourceRoot":"","sources":["../src/StateTracker.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,CAAC,CAAC;IACX,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,YAAY,CAAC,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAI;IAEjC,OAAO,CAAC,MAAM,CAAC,WAAW;IAa1B,OAAO,CAAC,MAAM,CAAC,wBAAwB;gBAQ3B,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAY3C,IAAI,IAAI,CAAC;IAiBT,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;IAUpB,WAAW,IAAI,MAAM;CAGtB"}
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;IAe3C,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;IAkCpB,oEAAoE;IACpE,IAAI,IAAI,CAAC;IA6BT,oEAAoE;IACpE,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;IAYpB;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAoChC;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BhC,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;IA8BpB,OAAO,CAAC,iBAAiB;CAM1B"}
@@ -35,11 +35,19 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.StateTracker = void 0;
37
37
  const fs = __importStar(require("fs"));
38
+ const fsPromises = __importStar(require("fs/promises"));
38
39
  const os = __importStar(require("os"));
39
40
  const path = __importStar(require("path"));
41
+ /** Atomic JSON state persistence with file-based storage, auto-save, and graceful degradation to in-memory mode. */
40
42
  class StateTracker {
41
43
  filePath;
42
44
  defaultValue;
45
+ autoSaveMs;
46
+ onEvent;
47
+ _state;
48
+ _loaded = false;
49
+ _storageAvailable = false;
50
+ saveTimer = null;
43
51
  static sanitizeKey(key) {
44
52
  const trimmed = key.trim();
45
53
  if (trimmed === "") {
@@ -59,31 +67,95 @@ class StateTracker {
59
67
  }
60
68
  constructor(options) {
61
69
  const sanitizedKey = StateTracker.sanitizeKey(options.key);
62
- this.defaultValue = options.default;
70
+ this.defaultValue = structuredClone(options.default);
71
+ this._state = structuredClone(options.default);
72
+ this.autoSaveMs = options.autoSaveMs ?? 0;
73
+ this.onEvent = options.onEvent;
63
74
  const stateDirectory = options.stateDirectory ?? StateTracker.getDefaultStateDirectory();
64
75
  if (!fs.existsSync(stateDirectory)) {
65
76
  fs.mkdirSync(stateDirectory, { recursive: true });
66
77
  }
67
78
  this.filePath = path.join(stateDirectory, `${sanitizedKey}.json`);
68
79
  }
80
+ /** Read-only getter for cached in-memory state */
81
+ get state() {
82
+ return this._state;
83
+ }
84
+ /** Whether storage is working */
85
+ get isPersistent() {
86
+ return this._storageAvailable;
87
+ }
88
+ emit(level, message, context) {
89
+ if (this.onEvent) {
90
+ this.onEvent({ level, message, context });
91
+ }
92
+ }
93
+ /**
94
+ * Extract value from parsed JSON content.
95
+ * Handles v1 envelope format ({value, lastUpdated}) and legacy
96
+ * PersistentStore format (raw T without envelope, merged with defaults).
97
+ */
98
+ extractValue(parsed) {
99
+ if (parsed !== null &&
100
+ typeof parsed === "object" &&
101
+ !Array.isArray(parsed) &&
102
+ "value" in parsed) {
103
+ // v1 envelope format: { value, lastUpdated }
104
+ const envelope = parsed;
105
+ if (envelope.value === undefined) {
106
+ return structuredClone(this.defaultValue);
107
+ }
108
+ return envelope.value;
109
+ }
110
+ // Legacy PersistentStore format: raw T without envelope
111
+ // Only merge if T is an object type
112
+ if (parsed !== null &&
113
+ typeof parsed === "object" &&
114
+ typeof this.defaultValue === "object" &&
115
+ this.defaultValue !== null &&
116
+ !Array.isArray(parsed)) {
117
+ return {
118
+ ...structuredClone(this.defaultValue),
119
+ ...parsed,
120
+ };
121
+ }
122
+ // Fallback to defaults
123
+ return structuredClone(this.defaultValue);
124
+ }
125
+ /** Sync load — v1 compatible. Also updates internal state cache. */
69
126
  load() {
70
127
  if (!fs.existsSync(this.filePath)) {
71
- return this.defaultValue;
128
+ this._state = structuredClone(this.defaultValue);
129
+ this._loaded = true;
130
+ this._storageAvailable = true;
131
+ return this._state;
72
132
  }
73
133
  try {
74
134
  const data = fs.readFileSync(this.filePath, "utf-8");
75
135
  const state = JSON.parse(data);
76
136
  const { value } = state;
77
137
  if (value === undefined) {
138
+ this._state = structuredClone(this.defaultValue);
139
+ this._loaded = true;
140
+ this._storageAvailable = true;
78
141
  return this.defaultValue;
79
142
  }
143
+ this._state = structuredClone(value);
144
+ this._loaded = true;
145
+ this._storageAvailable = true;
80
146
  return value;
81
147
  }
82
148
  catch {
149
+ this._state = structuredClone(this.defaultValue);
150
+ this._loaded = true;
151
+ this._storageAvailable = true;
83
152
  return this.defaultValue;
84
153
  }
85
154
  }
155
+ /** Sync save — v1 compatible. Also updates internal state cache. */
86
156
  save(value) {
157
+ this.cancelPendingSave();
158
+ this._state = structuredClone(value);
87
159
  const state = {
88
160
  value,
89
161
  lastUpdated: new Date().toISOString(),
@@ -92,9 +164,131 @@ class StateTracker {
92
164
  fs.writeFileSync(tempFilePath, JSON.stringify(state, null, 2), "utf-8");
93
165
  fs.renameSync(tempFilePath, this.filePath);
94
166
  }
167
+ /**
168
+ * Async load with graceful degradation.
169
+ * Sets _storageAvailable false on failure instead of throwing.
170
+ * Safe to call multiple times (subsequent calls are no-ops).
171
+ */
172
+ async loadAsync() {
173
+ if (this._loaded) {
174
+ return;
175
+ }
176
+ this._loaded = true;
177
+ try {
178
+ const dir = path.dirname(this.filePath);
179
+ if (!fs.existsSync(dir)) {
180
+ this.emit("info", "Creating storage directory", { dir });
181
+ await fsPromises.mkdir(dir, { recursive: true });
182
+ }
183
+ if (fs.existsSync(this.filePath)) {
184
+ const data = await fsPromises.readFile(this.filePath, "utf-8");
185
+ const parsed = JSON.parse(data);
186
+ this._state = this.extractValue(parsed);
187
+ this._storageAvailable = true;
188
+ this.emit("info", "Loaded state from disk", { path: this.filePath });
189
+ }
190
+ else {
191
+ this._storageAvailable = true;
192
+ this.emit("info", "No existing state file, using defaults", {
193
+ path: this.filePath,
194
+ });
195
+ }
196
+ }
197
+ catch (err) {
198
+ this._storageAvailable = false;
199
+ const errorMessage = err instanceof Error ? err.message : String(err);
200
+ this.emit("warn", "Storage unavailable, running in-memory", {
201
+ error: errorMessage,
202
+ path: this.filePath,
203
+ });
204
+ }
205
+ }
206
+ /**
207
+ * Async atomic save (temp file + rename).
208
+ * Cancels any pending auto-save before writing.
209
+ */
210
+ async saveAsync() {
211
+ this.cancelPendingSave();
212
+ if (!this._storageAvailable) {
213
+ return;
214
+ }
215
+ try {
216
+ const state = {
217
+ value: this._state,
218
+ lastUpdated: new Date().toISOString(),
219
+ };
220
+ const tempFilePath = `${this.filePath}.tmp`;
221
+ await fsPromises.writeFile(tempFilePath, JSON.stringify(state, null, 2), "utf-8");
222
+ await fsPromises.rename(tempFilePath, this.filePath);
223
+ this.emit("debug", "Saved state to disk", { path: this.filePath });
224
+ }
225
+ catch (err) {
226
+ const errorMessage = err instanceof Error ? err.message : String(err);
227
+ this.emit("error", "Failed to save state", {
228
+ error: errorMessage,
229
+ });
230
+ }
231
+ }
232
+ /** Replace entire state, schedules auto-save. */
233
+ set(newState) {
234
+ this._state = structuredClone(newState);
235
+ this.scheduleSave();
236
+ }
237
+ /**
238
+ * Shallow merge for object types, schedules auto-save.
239
+ * Throws at runtime if T is not an object.
240
+ */
241
+ update(changes) {
242
+ if (this._state === null ||
243
+ typeof this._state !== "object" ||
244
+ Array.isArray(this._state)) {
245
+ throw new Error("update() can only be used when state is a non-array object");
246
+ }
247
+ this._state = { ...this._state, ...changes };
248
+ this.scheduleSave();
249
+ }
250
+ /** Restore to defaults, schedules auto-save. */
251
+ reset() {
252
+ this._state = structuredClone(this.defaultValue);
253
+ this.scheduleSave();
254
+ }
95
255
  getFilePath() {
96
256
  return this.filePath;
97
257
  }
258
+ scheduleSave() {
259
+ if (this.autoSaveMs <= 0 || !this._storageAvailable) {
260
+ return;
261
+ }
262
+ this.cancelPendingSave();
263
+ this.saveTimer = setTimeout(() => {
264
+ this.saveTimer = null;
265
+ // Use sync save to avoid issues with untracked promises
266
+ try {
267
+ const state = {
268
+ value: this._state,
269
+ lastUpdated: new Date().toISOString(),
270
+ };
271
+ const tempFilePath = `${this.filePath}.tmp`;
272
+ fs.writeFileSync(tempFilePath, JSON.stringify(state, null, 2), "utf-8");
273
+ fs.renameSync(tempFilePath, this.filePath);
274
+ this.emit("debug", "Auto-saved state to disk", {
275
+ path: this.filePath,
276
+ });
277
+ }
278
+ catch (err) {
279
+ const errorMessage = err instanceof Error ? err.message : String(err);
280
+ this.emit("error", "Failed to auto-save state", {
281
+ error: errorMessage,
282
+ });
283
+ }
284
+ }, this.autoSaveMs);
285
+ }
286
+ cancelPendingSave() {
287
+ if (this.saveTimer) {
288
+ clearTimeout(this.saveTimer);
289
+ this.saveTimer = null;
290
+ }
291
+ }
98
292
  }
99
293
  exports.StateTracker = StateTracker;
100
294
  //# sourceMappingURL=StateTracker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StateTracker.js","sourceRoot":"","sources":["../src/StateTracker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,uCAAyB;AACzB,2CAA6B;AAQ7B,MAAa,YAAY;IACN,QAAQ,CAAS;IACjB,YAAY,CAAI;IAEzB,MAAM,CAAC,WAAW,CAAC,GAAW;QACpC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CACb,oGAAoG,CACrG,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,MAAM,CAAC,wBAAwB;QACrC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAC7C,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;YAC1C,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;IAC/C,CAAC;IAED,YAAY,OAA+B;QACzC,MAAM,YAAY,GAAG,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3D,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;QACpC,MAAM,cAAc,GAClB,OAAO,CAAC,cAAc,IAAI,YAAY,CAAC,wBAAwB,EAAE,CAAC;QAEpE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACnC,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,YAAY,OAAO,CAAC,CAAC;IACpE,CAAC;IAED,IAAI;QACF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClC,OAAO,IAAI,CAAC,YAAY,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACrD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAC;YAC1D,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;YACxB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,OAAO,IAAI,CAAC,YAAY,CAAC;YAC3B,CAAC;YACD,OAAO,KAAU,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,YAAY,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,IAAI,CAAC,KAAQ;QACX,MAAM,KAAK,GAA4B;YACrC,KAAK;YACL,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC,CAAC;QACF,MAAM,YAAY,GAAG,GAAG,IAAI,CAAC,QAAQ,MAAM,CAAC;QAC5C,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACxE,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC7C,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF;AAnED,oCAmEC"}
1
+ {"version":3,"file":"StateTracker.js","sourceRoot":"","sources":["../src/StateTracker.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { StateTracker, type StateTrackerOptions } from "./StateTracker";
1
+ export { StateTracker, type StateTrackerOptions, type StateTrackerEvent, type StateTrackerEventLevel, } from "./StateTracker";
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+CAAwE;AAA/D,4GAAA,YAAY,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+CAKwB;AAJtB,4GAAA,YAAY,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardlydifficult/state-tracker",
3
- "version": "1.0.0",
3
+ "version": "2.0.1",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [