@directive-run/core 0.8.1 → 0.8.3

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.
Files changed (62) hide show
  1. package/LICENSE +5 -0
  2. package/dist/adapter-utils.cjs +1 -1
  3. package/dist/adapter-utils.cjs.map +1 -1
  4. package/dist/adapter-utils.d.cts +1 -1
  5. package/dist/adapter-utils.d.ts +1 -1
  6. package/dist/adapter-utils.js +1 -1
  7. package/dist/adapter-utils.js.map +1 -1
  8. package/dist/chunk-6WG7FPH7.cjs +3 -0
  9. package/dist/chunk-6WG7FPH7.cjs.map +1 -0
  10. package/dist/chunk-DIK3SZBM.js +3 -0
  11. package/dist/chunk-DIK3SZBM.js.map +1 -0
  12. package/dist/chunk-GO63IIN5.js +2 -0
  13. package/dist/chunk-GO63IIN5.js.map +1 -0
  14. package/dist/chunk-KQKNE23L.cjs +2 -0
  15. package/dist/chunk-KQKNE23L.cjs.map +1 -0
  16. package/dist/chunk-LAH2FMON.cjs +16 -0
  17. package/dist/chunk-LAH2FMON.cjs.map +1 -0
  18. package/dist/chunk-MAARYRI4.js +16 -0
  19. package/dist/chunk-MAARYRI4.js.map +1 -0
  20. package/dist/chunk-O75OISQ2.js +2 -0
  21. package/dist/chunk-O75OISQ2.js.map +1 -0
  22. package/dist/chunk-PK2EH26L.cjs +2 -0
  23. package/dist/chunk-PK2EH26L.cjs.map +1 -0
  24. package/dist/helpers-50q7yhA9.d.ts +179 -0
  25. package/dist/helpers-B6SkcKCD.d.cts +179 -0
  26. package/dist/index.cjs +1 -16
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +42 -1421
  29. package/dist/index.d.ts +42 -1421
  30. package/dist/index.js +1 -16
  31. package/dist/index.js.map +1 -1
  32. package/dist/internals.cjs +2 -0
  33. package/dist/internals.cjs.map +1 -0
  34. package/dist/internals.d.cts +1176 -0
  35. package/dist/internals.d.ts +1176 -0
  36. package/dist/internals.js +2 -0
  37. package/dist/internals.js.map +1 -0
  38. package/dist/plugins/index.cjs +2 -2
  39. package/dist/plugins/index.cjs.map +1 -1
  40. package/dist/plugins/index.d.cts +1 -1
  41. package/dist/plugins/index.d.ts +1 -1
  42. package/dist/plugins/index.js +2 -2
  43. package/dist/plugins/index.js.map +1 -1
  44. package/dist/{plugins-DaglUQVX.d.cts → plugins-Bg_oq2sO.d.cts} +22 -2
  45. package/dist/{plugins-DaglUQVX.d.ts → plugins-Bg_oq2sO.d.ts} +22 -2
  46. package/dist/system-L2FVVUSN.js +2 -0
  47. package/dist/system-L2FVVUSN.js.map +1 -0
  48. package/dist/system-L45Z2N4U.cjs +2 -0
  49. package/dist/system-L45Z2N4U.cjs.map +1 -0
  50. package/dist/testing.cjs +1 -16
  51. package/dist/testing.cjs.map +1 -1
  52. package/dist/testing.d.cts +54 -16
  53. package/dist/testing.d.ts +54 -16
  54. package/dist/testing.js +1 -16
  55. package/dist/testing.js.map +1 -1
  56. package/dist/worker.cjs +1 -16
  57. package/dist/worker.cjs.map +1 -1
  58. package/dist/worker.d.cts +1 -1
  59. package/dist/worker.d.ts +1 -1
  60. package/dist/worker.js +1 -16
  61. package/dist/worker.js.map +1 -1
  62. package/package.json +13 -4
@@ -0,0 +1,1176 @@
1
+ import { Q as Schema, F as Facts, a1 as FactsStore, E as EffectsDef, a2 as ConstraintsDef, p as RequirementKeyFn, R as RequirementWithId, a3 as ConstraintState, a4 as ResolversDef, a5 as ResolverStatus, o as Requirement, P as Plugin, V as System, a6 as FactChange, v as FactsSnapshot, a7 as ReconcileResult, U as Snapshot, D as DirectiveError, a8 as RecoveryStrategy, _ as TraceEntry, a9 as ErrorSource, n as ErrorBoundaryConfig, aa as RetryLaterConfig, H as HistoryAPI, w as HistoryOption, W as SystemConfig } from './plugins-Bg_oq2sO.cjs';
2
+ export { ab as BatchItemResult, ac as BatchResolveResults, ad as ConstraintsControl, ae as CrossModuleConstraintDef, g as CrossModuleConstraintsDef, af as CrossModuleDerivationFn, e as CrossModuleDerivationsDef, ag as CrossModuleEffectDef, f as CrossModuleEffectsDef, ah as CrossModuleFactsWithSelf, ai as DerivationKeys, aj as DerivationReturnType, ak as DerivationsControl, al as DerivationsSchema, am as DeriveAccessor, an as DispatchEventsFromSchema, q as DistributableSnapshot, r as DistributableSnapshotOptions, ao as EffectCleanup, ap as EffectsControl, aq as EventPayloadSchema, ar as EventsAccessor, as as EventsAccessorFromSchema, at as EventsDef, au as EventsSchema, av as FactKeys, aw as FactReturnType, ax as FlexibleEventHandler, ay as HistoryConfig, az as InferEventPayloadFromSchema, aA as InferRequirementPayloadFromSchema, aB as InferSchema, aC as MutableNamespacedFacts, aD as NamespacedDerivations, aE as NamespacedEventsAccessor, aF as NamespacedFacts, aG as ObservableKeys, aH as RequirementExplanation, aI as RequirementOutput, aJ as RequirementPayloadSchema, aK as RequirementsSchema, aL as ResolverContext, aM as ResolversControl, aN as SnapshotMeta, aO as SystemEvent, aP as TraceConfig, aQ as TypedConstraintDef, b as TypedConstraintsDef, T as TypedDerivationsDef, a as TypedEventsDef, aR as TypedResolverContext, aS as TypedResolverDef, c as TypedResolversDef, aT as UnionEvents } from './plugins-Bg_oq2sO.cjs';
3
+ export { T as TypedConstraint, b as TypedResolver, c as createConstraintFactory, d as createResolverFactory } from './helpers-B6SkcKCD.cjs';
4
+
5
+ /**
6
+ * Derivation Types - Type definitions for derivations
7
+ */
8
+
9
+ /** Tracking context for auto-dependency detection */
10
+ interface TrackingContext {
11
+ readonly isTracking: boolean;
12
+ track(key: string): void;
13
+ getDependencies(): Set<string>;
14
+ }
15
+ /** Derivation definition function signature. */
16
+ interface DerivationDef<S extends Schema, T, D extends DerivationsDef<S>> {
17
+ (facts: Facts<S>, derived: DerivedValues<S, D>): T;
18
+ }
19
+ /** Map of derivation definitions. */
20
+ type DerivationsDef<S extends Schema> = Record<string, DerivationDef<S, unknown, DerivationsDef<S>>>;
21
+ /** Computed derived values. */
22
+ type DerivedValues<S extends Schema, D extends DerivationsDef<S>> = {
23
+ readonly [K in keyof D]: ReturnType<D[K]>;
24
+ };
25
+ /** Internal derivation state */
26
+ interface DerivationState<T> {
27
+ id: string;
28
+ compute: () => T;
29
+ cachedValue: T | undefined;
30
+ dependencies: Set<string>;
31
+ isStale: boolean;
32
+ isComputing: boolean;
33
+ }
34
+
35
+ /**
36
+ * Facts Store - Proxy-based reactive state with auto-tracking
37
+ *
38
+ * Features:
39
+ * - Proxy-based access (facts.phase instead of facts.get("phase"))
40
+ * - Automatic dependency tracking via tracking context
41
+ * - Batched updates with coalesced notifications
42
+ * - Granular subscriptions by key
43
+ * - Schema validation in development mode
44
+ */
45
+
46
+ /** Options for creating a facts store */
47
+ interface CreateFactsStoreOptions<S extends Schema> {
48
+ schema: S;
49
+ /** Validate values against schema (default: process.env.NODE_ENV !== 'production') */
50
+ validate?: boolean;
51
+ /** Throw on unknown schema keys (default: true in dev mode) */
52
+ strictKeys?: boolean;
53
+ /** Redact sensitive values in error messages */
54
+ redactErrors?: boolean;
55
+ /** Callback when facts change (for plugin hooks) */
56
+ onChange?: (key: string, value: unknown, prev: unknown) => void;
57
+ /** Callback for batch changes */
58
+ onBatch?: (changes: Array<{
59
+ key: string;
60
+ value: unknown;
61
+ prev: unknown;
62
+ type: "set" | "delete";
63
+ }>) => void;
64
+ }
65
+ /**
66
+ * Create a reactive facts store backed by a Map with schema validation,
67
+ * batched mutations, and granular key-level subscriptions.
68
+ *
69
+ * @remarks
70
+ * The store is the low-level primitive that powers the `facts` proxy.
71
+ * Most users should use {@link createFacts} or `createModule` instead.
72
+ *
73
+ * @param options - Store configuration including schema, validation settings, and change callbacks
74
+ * @returns A {@link FactsStore} with get/set/batch/subscribe methods and automatic schema validation
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const store = createFactsStore({
79
+ * schema: { count: t.number(), name: t.string() },
80
+ * });
81
+ *
82
+ * store.set("count", 1);
83
+ * store.get("count"); // 1
84
+ *
85
+ * store.batch(() => {
86
+ * store.set("count", 2);
87
+ * store.set("name", "hello");
88
+ * }); // listeners fire once after batch completes
89
+ * ```
90
+ *
91
+ * @internal
92
+ */
93
+ declare function createFactsStore<S extends Schema>(options: CreateFactsStoreOptions<S>): FactsStore<S>;
94
+ /**
95
+ * Create a Proxy wrapper around a {@link FactsStore} for clean property-style
96
+ * access (`facts.phase`) with automatic dependency tracking.
97
+ *
98
+ * @remarks
99
+ * Reading a property calls `store.get()` (which tracks the access for
100
+ * auto-tracked derivations). Writing a property calls `store.set()` (which
101
+ * validates against the schema). The proxy also exposes `$store` for direct
102
+ * store access and `$snapshot()` for untracked reads.
103
+ *
104
+ * @param store - The underlying facts store to wrap
105
+ * @param schema - The schema definition used for `ownKeys` enumeration
106
+ * @returns A {@link Facts} proxy with property-style get/set and prototype pollution guards
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * const store = createFactsStore({ schema: { phase: t.string() } });
111
+ * const facts = createFactsProxy(store, { phase: t.string() });
112
+ *
113
+ * facts.phase = "red";
114
+ * console.log(facts.phase); // "red"
115
+ * ```
116
+ *
117
+ * @internal
118
+ */
119
+ declare function createFactsProxy<S extends Schema>(store: FactsStore<S>, schema: S): Facts<S>;
120
+ /**
121
+ * Convenience factory that creates both a {@link FactsStore} and its
122
+ * {@link createFactsProxy | proxy wrapper} in a single call.
123
+ *
124
+ * @remarks
125
+ * This is the recommended entry point when you need low-level store access
126
+ * outside of `createModule` / `createSystem`.
127
+ *
128
+ * @param options - Same options as {@link createFactsStore}
129
+ * @returns An object with `store` (the reactive Map-backed store) and `facts` (the Proxy accessor)
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * const { store, facts } = createFacts({
134
+ * schema: { phase: t.string<"red" | "green">() },
135
+ * });
136
+ *
137
+ * facts.phase = "red";
138
+ * console.log(facts.phase); // "red"
139
+ * store.subscribe(["phase"], () => console.log("phase changed"));
140
+ * ```
141
+ *
142
+ * @internal
143
+ */
144
+ declare function createFacts<S extends Schema>(options: CreateFactsStoreOptions<S>): {
145
+ store: FactsStore<S>;
146
+ facts: Facts<S>;
147
+ };
148
+
149
+ /**
150
+ * Derivations - Auto-tracked computed values with composition
151
+ *
152
+ * Features:
153
+ * - Automatic dependency tracking (no manual deps arrays)
154
+ * - Memoization with smart invalidation
155
+ * - Derivation composition (derivations can depend on other derivations)
156
+ * - Circular dependency detection
157
+ * - Lazy evaluation
158
+ */
159
+
160
+ interface DerivationsManager<S extends Schema, D extends DerivationsDef<S>> {
161
+ /** Get a derived value (computes if stale) */
162
+ get<K extends keyof D>(id: K): ReturnType<D[K]>;
163
+ /** Check if a derivation is stale */
164
+ isStale(id: keyof D): boolean;
165
+ /** Invalidate derivations that depend on a fact key */
166
+ invalidate(factKey: string): void;
167
+ /** Invalidate derivations for multiple fact keys, notifying listeners once at the end */
168
+ invalidateMany(factKeys: Iterable<string>): void;
169
+ /** Invalidate all derivations */
170
+ invalidateAll(): void;
171
+ /** Subscribe to derivation changes */
172
+ subscribe(ids: Array<keyof D>, listener: () => void): () => void;
173
+ /** Get the proxy for composition */
174
+ getProxy(): DerivedValues<S, D>;
175
+ /** Get dependencies for a derivation */
176
+ getDependencies(id: keyof D): Set<string>;
177
+ /** Register new derivation definitions (for dynamic module registration) */
178
+ registerDefinitions(newDefs: DerivationsDef<S>): void;
179
+ /** Override an existing derivation function */
180
+ assignDefinition(id: string, fn: DerivationsDef<S>[keyof DerivationsDef<S>]): void;
181
+ /** Remove a derivation and clean up its state */
182
+ unregisterDefinition(id: string): void;
183
+ /** Compute a derivation immediately (ignores cache) */
184
+ callOne(id: string): unknown;
185
+ }
186
+ /** Options for creating a derivations manager */
187
+ interface CreateDerivationsOptions<S extends Schema, D extends DerivationsDef<S>> {
188
+ definitions: D;
189
+ facts: Facts<S>;
190
+ store: FactsStore<S>;
191
+ /** Callback when a derivation is computed */
192
+ onCompute?: (id: string, value: unknown, oldValue: unknown, deps: string[]) => void;
193
+ /** Callback when a derivation is invalidated */
194
+ onInvalidate?: (id: string) => void;
195
+ /** Callback when a derivation errors */
196
+ onError?: (id: string, error: unknown) => void;
197
+ }
198
+ /**
199
+ * Create a manager for lazily-evaluated, auto-tracked derived values.
200
+ *
201
+ * Derivations are memoized computations that automatically track which facts
202
+ * they read. When a tracked fact changes, the derivation is invalidated and
203
+ * recomputed on next access. Derivations can depend on other derivations
204
+ * (composition), and circular dependencies are detected at compute time.
205
+ *
206
+ * Notifications are deferred during invalidation so listeners always see
207
+ * consistent state across multiple simultaneous fact changes.
208
+ *
209
+ * @param options - Derivation definitions, facts proxy, store, and optional
210
+ * lifecycle callbacks.
211
+ * @returns A {@link DerivationsManager} for accessing, invalidating, and
212
+ * subscribing to derived values.
213
+ *
214
+ * @internal
215
+ */
216
+ declare function createDerivationsManager<S extends Schema, D extends DerivationsDef<S>>(options: CreateDerivationsOptions<S, D>): DerivationsManager<S, D>;
217
+
218
+ /**
219
+ * Effects - Fire-and-forget side effects
220
+ *
221
+ * Features:
222
+ * - Separate from requirement resolution
223
+ * - Error isolation (never breaks reconciliation)
224
+ * - Optional explicit dependencies for optimization
225
+ * - Runs after facts stabilize
226
+ *
227
+ * IMPORTANT: Auto-tracking limitations
228
+ * ------------------------------------
229
+ * When using auto-tracking (no explicit `deps`), only SYNCHRONOUS fact accesses
230
+ * are tracked. If your effect reads facts after an `await`, those reads are NOT
231
+ * tracked and won't trigger the effect on future changes.
232
+ *
233
+ * For async effects, always use explicit `deps`:
234
+ * @example
235
+ * ```typescript
236
+ * effects: {
237
+ * // BAD: fetchData is async, facts.userId read after await won't be tracked
238
+ * badEffect: {
239
+ * run: async (facts) => {
240
+ * await someAsyncOp();
241
+ * console.log(facts.userId); // NOT tracked!
242
+ * },
243
+ * },
244
+ * // GOOD: explicit deps for async effects
245
+ * goodEffect: {
246
+ * deps: ["userId"],
247
+ * run: async (facts) => {
248
+ * await someAsyncOp();
249
+ * console.log(facts.userId); // Works because we declared the dep
250
+ * },
251
+ * },
252
+ * }
253
+ * ```
254
+ */
255
+
256
+ /**
257
+ * Manager returned by {@link createEffectsManager} that runs fire-and-forget
258
+ * side effects after facts stabilize.
259
+ *
260
+ * @internal
261
+ */
262
+ interface EffectsManager<_S extends Schema = Schema> {
263
+ /**
264
+ * Run all effects whose tracked dependencies overlap with `changedKeys`.
265
+ *
266
+ * @remarks
267
+ * Effects with no recorded dependencies (first run or auto-tracked with no
268
+ * reads) run on any change. After execution, a snapshot of current facts is
269
+ * stored for the `prev` parameter on the next invocation.
270
+ *
271
+ * @param changedKeys - Fact keys that changed since the last run.
272
+ */
273
+ runEffects(changedKeys: Set<string>): Promise<void>;
274
+ /**
275
+ * Run every enabled effect unconditionally, regardless of dependencies.
276
+ */
277
+ runAll(): Promise<void>;
278
+ /**
279
+ * Disable an effect so it is skipped during subsequent runs.
280
+ *
281
+ * @param id - The effect definition ID.
282
+ */
283
+ disable(id: string): void;
284
+ /**
285
+ * Re-enable a previously disabled effect.
286
+ *
287
+ * @param id - The effect definition ID.
288
+ */
289
+ enable(id: string): void;
290
+ /**
291
+ * Check whether an effect is currently enabled.
292
+ *
293
+ * @param id - The effect definition ID.
294
+ * @returns `true` if the effect has not been disabled.
295
+ */
296
+ isEnabled(id: string): boolean;
297
+ /**
298
+ * Invoke every stored cleanup function and mark the manager as stopped.
299
+ *
300
+ * @remarks
301
+ * After this call, any cleanup functions returned by in-flight async effects
302
+ * will be invoked immediately rather than stored.
303
+ */
304
+ cleanupAll(): void;
305
+ /**
306
+ * Register additional effect definitions at runtime (used for dynamic
307
+ * module registration).
308
+ *
309
+ * @param newDefs - New effect definitions to merge into the manager.
310
+ */
311
+ registerDefinitions(newDefs: EffectsDef<Schema>): void;
312
+ /**
313
+ * Override an existing effect definition. Runs cleanup of the old effect first.
314
+ *
315
+ * @param id - The effect definition ID to override.
316
+ * @param def - The new effect definition.
317
+ * @throws If no effect with this ID exists.
318
+ */
319
+ assignDefinition(id: string, def: EffectsDef<Schema>[string]): void;
320
+ /**
321
+ * Remove an effect definition. Runs cleanup (try-catch) and removes from state.
322
+ *
323
+ * @param id - The effect definition ID to remove.
324
+ */
325
+ unregisterDefinition(id: string): void;
326
+ /**
327
+ * Execute an effect's `run()` function immediately.
328
+ *
329
+ * @param id - The effect definition ID.
330
+ */
331
+ callOne(id: string): Promise<void>;
332
+ }
333
+ /**
334
+ * Configuration options accepted by {@link createEffectsManager}.
335
+ *
336
+ * @internal
337
+ */
338
+ interface CreateEffectsOptions<S extends Schema> {
339
+ /** Effect definitions keyed by ID. */
340
+ definitions: EffectsDef<S>;
341
+ /** Proxy-based facts object passed to effect `run()` functions. */
342
+ facts: Facts<S>;
343
+ /** Underlying fact store used for `batch()` coalescing of mutations. */
344
+ store: FactsStore<S>;
345
+ /** Called when an effect executes, with the fact keys that triggered it. */
346
+ onRun?: (id: string, deps: string[]) => void;
347
+ /** Called when an effect's `run()` or cleanup function throws. */
348
+ onError?: (id: string, error: unknown) => void;
349
+ }
350
+ /**
351
+ * Create a manager for fire-and-forget side effects that run after facts
352
+ * stabilize.
353
+ *
354
+ * @remarks
355
+ * Effects support two dependency modes:
356
+ *
357
+ * - **Auto-tracked** (no `deps`): Dependencies are re-tracked on every run
358
+ * via {@link withTracking}, so conditional fact reads are always captured.
359
+ * Only synchronous reads are tracked; reads after an `await` are invisible.
360
+ *
361
+ * - **Explicit `deps`**: A fixed array of fact keys declared on the definition.
362
+ * Preferred for async effects where auto-tracking cannot cross `await`
363
+ * boundaries.
364
+ *
365
+ * Each effect can return a cleanup function that runs before the next
366
+ * execution or when {@link EffectsManager.cleanupAll | cleanupAll} is called.
367
+ * Errors in effects are isolated via try-catch and never break the
368
+ * reconciliation loop. Synchronous fact mutations inside effects are
369
+ * coalesced with `store.batch()`.
370
+ *
371
+ * @param options - Configuration including effect definitions, facts proxy,
372
+ * store, and lifecycle callbacks.
373
+ * @returns An {@link EffectsManager} for running, enabling/disabling, and
374
+ * cleaning up effects.
375
+ *
376
+ * @example
377
+ * ```typescript
378
+ * const effects = createEffectsManager({
379
+ * definitions: {
380
+ * logPhase: {
381
+ * run: (facts, prev) => {
382
+ * if (prev?.phase !== facts.phase) {
383
+ * console.log(`Phase changed to ${facts.phase}`);
384
+ * }
385
+ * },
386
+ * },
387
+ * },
388
+ * facts: factsProxy,
389
+ * store: factsStore,
390
+ * });
391
+ *
392
+ * await effects.runEffects(new Set(["phase"]));
393
+ * ```
394
+ *
395
+ * @internal
396
+ */
397
+ declare function createEffectsManager<S extends Schema>(options: CreateEffectsOptions<S>): EffectsManager<S>;
398
+
399
+ /**
400
+ * Constraints - Rules that produce requirements when conditions aren't met
401
+ *
402
+ * Features:
403
+ * - Sync and async constraint evaluation
404
+ * - Priority ordering (higher runs first)
405
+ * - Timeout handling for async constraints
406
+ * - Error isolation
407
+ */
408
+
409
+ /**
410
+ * Manager returned by {@link createConstraintsManager} that evaluates
411
+ * constraint rules against the current facts and produces unmet
412
+ * {@link RequirementWithId | requirements}.
413
+ *
414
+ * @internal
415
+ */
416
+ interface ConstraintsManager<_S extends Schema> {
417
+ /**
418
+ * Evaluate all enabled constraints and return unmet requirements.
419
+ *
420
+ * @remarks
421
+ * On the first call (or when `changedKeys` is empty), every enabled
422
+ * constraint is evaluated. On subsequent calls, only constraints whose
423
+ * tracked dependencies overlap with `changedKeys` are re-evaluated.
424
+ * Sync constraints run first, async constraints run in parallel, and
425
+ * `after` ordering is respected across multiple passes.
426
+ *
427
+ * @param changedKeys - Fact keys that changed since the last evaluation.
428
+ * When omitted or empty, all constraints are evaluated.
429
+ * @returns An array of {@link RequirementWithId} representing unmet requirements.
430
+ */
431
+ evaluate(changedKeys?: Set<string>): Promise<RequirementWithId[]>;
432
+ /**
433
+ * Get the current state of a constraint by its definition ID.
434
+ *
435
+ * @param id - The constraint definition ID.
436
+ * @returns The {@link ConstraintState}, or `undefined` if the ID is unknown.
437
+ */
438
+ getState(id: string): ConstraintState | undefined;
439
+ /**
440
+ * Get the state of every registered constraint.
441
+ *
442
+ * @returns An array of all {@link ConstraintState} objects.
443
+ */
444
+ getAllStates(): ConstraintState[];
445
+ /**
446
+ * Disable a constraint so it is skipped during evaluation.
447
+ *
448
+ * @param id - The constraint definition ID.
449
+ */
450
+ disable(id: string): void;
451
+ /**
452
+ * Re-enable a previously disabled constraint.
453
+ *
454
+ * @param id - The constraint definition ID.
455
+ */
456
+ enable(id: string): void;
457
+ /**
458
+ * Mark all constraints that depend on `factKey` as dirty so they are
459
+ * re-evaluated on the next {@link ConstraintsManager.evaluate | evaluate} call.
460
+ *
461
+ * @param factKey - The fact store key that changed.
462
+ */
463
+ invalidate(factKey: string): void;
464
+ /**
465
+ * Get the auto-tracked or explicit dependency set for a constraint.
466
+ *
467
+ * @param id - The constraint definition ID.
468
+ * @returns A `Set` of fact keys, or `undefined` if no dependencies have been recorded.
469
+ */
470
+ getDependencies(id: string): Set<string> | undefined;
471
+ /**
472
+ * Record that a constraint's resolver completed successfully, unblocking
473
+ * any constraints that list it in their `after` array.
474
+ *
475
+ * @param constraintId - The constraint definition ID whose resolver finished.
476
+ */
477
+ markResolved(constraintId: string): void;
478
+ /**
479
+ * Check whether a constraint is currently disabled.
480
+ *
481
+ * @param id - The constraint definition ID.
482
+ * @returns `true` if the constraint has been disabled via {@link ConstraintsManager.disable | disable}.
483
+ */
484
+ isDisabled(id: string): boolean;
485
+ /**
486
+ * Check whether a constraint has been marked as resolved.
487
+ *
488
+ * @param constraintId - The constraint definition ID.
489
+ * @returns `true` if {@link ConstraintsManager.markResolved | markResolved} was called for this constraint.
490
+ */
491
+ isResolved(constraintId: string): boolean;
492
+ /**
493
+ * Register additional constraint definitions at runtime (used for dynamic
494
+ * module registration).
495
+ *
496
+ * @remarks
497
+ * Rebuilds the topological order and reverse dependency map so new `after`
498
+ * dependencies are validated for cycles and indexed.
499
+ *
500
+ * @param newDefs - New constraint definitions to merge into the manager.
501
+ */
502
+ registerDefinitions(newDefs: ConstraintsDef<Schema>): void;
503
+ /**
504
+ * Override an existing constraint definition.
505
+ * Stores the original in an internal map for inspection.
506
+ *
507
+ * @param id - The constraint definition ID to override.
508
+ * @param def - The new constraint definition.
509
+ * @throws If no constraint with this ID exists.
510
+ */
511
+ assignDefinition(id: string, def: ConstraintsDef<Schema>[string]): void;
512
+ /**
513
+ * Remove a constraint definition and all its internal state.
514
+ *
515
+ * @param id - The constraint definition ID to remove.
516
+ */
517
+ unregisterDefinition(id: string): void;
518
+ /**
519
+ * Evaluate a single constraint and emit its requirement if active.
520
+ * Props are merged into the requirement object.
521
+ *
522
+ * @param id - The constraint definition ID.
523
+ * @param props - Optional properties to merge into the requirement.
524
+ * @returns The emitted requirements (if any).
525
+ */
526
+ callOne(id: string, props?: Record<string, unknown>): Promise<RequirementWithId[]>;
527
+ }
528
+ /**
529
+ * Configuration options accepted by {@link createConstraintsManager}.
530
+ *
531
+ * @internal
532
+ */
533
+ interface CreateConstraintsOptions<S extends Schema> {
534
+ /** Constraint definitions keyed by ID. */
535
+ definitions: ConstraintsDef<S>;
536
+ /** Proxy-based facts object used to evaluate `when()` predicates. */
537
+ facts: Facts<S>;
538
+ /** Custom key functions for requirement deduplication, keyed by constraint ID. */
539
+ requirementKeys?: Record<string, RequirementKeyFn>;
540
+ /** Default timeout in milliseconds for async constraint evaluation (defaults to 5 000). */
541
+ defaultTimeout?: number;
542
+ /** Called after each constraint evaluation with the constraint ID and whether `when()` was active. */
543
+ onEvaluate?: (id: string, active: boolean) => void;
544
+ /** Called when a constraint's `when()` or `require()` throws. */
545
+ onError?: (id: string, error: unknown) => void;
546
+ }
547
+ /**
548
+ * Create a manager that evaluates constraint rules and produces unmet
549
+ * requirements.
550
+ *
551
+ * @remarks
552
+ * Constraints are evaluated in priority order (higher priority first), with
553
+ * topological ordering for same-priority constraints connected by `after`
554
+ * dependencies. The manager supports sync and async `when()` predicates,
555
+ * incremental evaluation based on changed fact keys, and per-constraint
556
+ * enable/disable toggling. Cycle detection runs eagerly at construction time
557
+ * to prevent deadlocks in production.
558
+ *
559
+ * @param options - Configuration including constraint definitions, facts proxy,
560
+ * custom requirement key functions, and lifecycle callbacks.
561
+ * @returns A {@link ConstraintsManager} for evaluating, invalidating, and
562
+ * managing constraint lifecycle.
563
+ *
564
+ * @example
565
+ * ```typescript
566
+ * const constraints = createConstraintsManager({
567
+ * definitions: {
568
+ * mustTransition: {
569
+ * priority: 50,
570
+ * when: (facts) => facts.phase === "red" && facts.elapsed > 30,
571
+ * require: { type: "TRANSITION", to: "green" },
572
+ * },
573
+ * },
574
+ * facts: factsProxy,
575
+ * onEvaluate: (id, active) => console.log(id, active),
576
+ * });
577
+ *
578
+ * const unmet = await constraints.evaluate();
579
+ * ```
580
+ *
581
+ * @internal
582
+ */
583
+ declare function createConstraintsManager<S extends Schema>(options: CreateConstraintsOptions<S>): ConstraintsManager<S>;
584
+
585
+ /**
586
+ * Resolvers - Capability-based handlers for requirements
587
+ *
588
+ * Features:
589
+ * - Capability matching (handles predicate)
590
+ * - Custom dedupe keys
591
+ * - Retry policies with exponential backoff
592
+ * - Batched resolution for similar requirements
593
+ * - Cancellation via AbortController
594
+ */
595
+
596
+ /**
597
+ * Summary of a resolver that is currently in flight.
598
+ *
599
+ * @internal
600
+ */
601
+ interface InflightInfo {
602
+ /** The unique requirement ID being resolved. */
603
+ id: string;
604
+ /** The definition ID of the resolver handling this requirement. */
605
+ resolverId: string;
606
+ /** Epoch timestamp (ms) when resolution started. */
607
+ startedAt: number;
608
+ }
609
+ /**
610
+ * Manager returned by {@link createResolversManager} that matches
611
+ * requirements to resolver handlers and manages their execution lifecycle.
612
+ *
613
+ * @internal
614
+ */
615
+ interface ResolversManager<_S extends Schema> {
616
+ /**
617
+ * Start resolving a requirement by matching it to a resolver handler.
618
+ *
619
+ * @remarks
620
+ * Duplicate in-flight requirements (same `req.id`) are silently ignored.
621
+ * If the matched resolver has `batch.enabled`, the requirement is queued
622
+ * for batch processing instead of being resolved immediately.
623
+ *
624
+ * @param req - The requirement (with a stable identity ID) to resolve.
625
+ */
626
+ resolve(req: RequirementWithId): void;
627
+ /**
628
+ * Cancel an in-flight or batch-queued resolver by requirement ID.
629
+ *
630
+ * @remarks
631
+ * Aborts the `AbortController` for in-flight resolvers. For batch-queued
632
+ * requirements, removes the requirement from the pending batch.
633
+ *
634
+ * @param requirementId - The unique requirement ID to cancel.
635
+ */
636
+ cancel(requirementId: string): void;
637
+ /**
638
+ * Cancel every in-flight resolver and flush all pending batch queues.
639
+ */
640
+ cancelAll(): void;
641
+ /**
642
+ * Get the current status of a resolver by requirement ID.
643
+ *
644
+ * @param requirementId - The unique requirement ID to look up.
645
+ * @returns The {@link ResolverStatus} (idle, pending, running, success, error, or canceled).
646
+ */
647
+ getStatus(requirementId: string): ResolverStatus;
648
+ /**
649
+ * Get the requirement IDs of all currently in-flight resolvers.
650
+ *
651
+ * @returns An array of requirement ID strings.
652
+ */
653
+ getInflight(): string[];
654
+ /**
655
+ * Get detailed info for every in-flight resolver.
656
+ *
657
+ * @returns An array of {@link InflightInfo} objects.
658
+ */
659
+ getInflightInfo(): InflightInfo[];
660
+ /**
661
+ * Check whether a requirement is currently being resolved.
662
+ *
663
+ * @param requirementId - The unique requirement ID to check.
664
+ * @returns `true` if the requirement has an active in-flight resolver.
665
+ */
666
+ isResolving(requirementId: string): boolean;
667
+ /**
668
+ * Immediately flush all pending batch queues, executing their resolvers.
669
+ */
670
+ processBatches(): void;
671
+ /**
672
+ * Check whether any batch queues have requirements waiting to be processed.
673
+ *
674
+ * @returns `true` if at least one batch queue is non-empty.
675
+ */
676
+ hasPendingBatches(): boolean;
677
+ /**
678
+ * Register additional resolver definitions at runtime (used for dynamic
679
+ * module registration).
680
+ *
681
+ * @remarks
682
+ * Clears the resolver-by-type cache so newly registered resolvers are
683
+ * discoverable on the next {@link ResolversManager.resolve | resolve} call.
684
+ *
685
+ * @param newDefs - New resolver definitions to merge into the manager.
686
+ */
687
+ registerDefinitions(newDefs: ResolversDef<Schema>): void;
688
+ /**
689
+ * Override an existing resolver definition.
690
+ *
691
+ * @param id - The resolver definition ID to override.
692
+ * @param def - The new resolver definition.
693
+ * @throws If no resolver with this ID exists.
694
+ */
695
+ assignDefinition(id: string, def: ResolversDef<Schema>[string]): void;
696
+ /**
697
+ * Remove a resolver definition. Cancels any inflight resolution.
698
+ *
699
+ * @param id - The resolver definition ID to remove.
700
+ */
701
+ unregisterDefinition(id: string): void;
702
+ /**
703
+ * Execute a resolver with a given requirement object.
704
+ *
705
+ * @param id - The resolver definition ID.
706
+ * @param requirement - The requirement to resolve.
707
+ */
708
+ callOne(id: string, requirement: Requirement): Promise<void>;
709
+ /**
710
+ * Clean up all internal state. Called on system destroy.
711
+ */
712
+ destroy(): void;
713
+ }
714
+ /**
715
+ * Configuration options accepted by {@link createResolversManager}.
716
+ *
717
+ * @internal
718
+ */
719
+ interface CreateResolversOptions<S extends Schema> {
720
+ /** Resolver definitions keyed by ID. */
721
+ definitions: ResolversDef<S>;
722
+ /** Proxy-based facts object passed to resolver contexts. */
723
+ facts: Facts<S>;
724
+ /** Underlying fact store used for `batch()` coalescing of mutations. */
725
+ store: FactsStore<S>;
726
+ /** Called when a resolver begins execution. */
727
+ onStart?: (resolver: string, req: RequirementWithId) => void;
728
+ /** Called when a resolver completes successfully, with the wall-clock duration in ms. */
729
+ onComplete?: (resolver: string, req: RequirementWithId, duration: number) => void;
730
+ /** Called when a resolver exhausts all retry attempts. */
731
+ onError?: (resolver: string, req: RequirementWithId, error: unknown) => void;
732
+ /** Called before each retry attempt with the upcoming attempt number. */
733
+ onRetry?: (resolver: string, req: RequirementWithId, attempt: number) => void;
734
+ /** Called when a resolver is canceled via {@link ResolversManager.cancel | cancel}. */
735
+ onCancel?: (resolver: string, req: RequirementWithId) => void;
736
+ /** Called after any resolver finishes (success, error, or batch completion) to trigger reconciliation. */
737
+ onResolutionComplete?: () => void;
738
+ }
739
+ declare function createResolversManager<S extends Schema>(options: CreateResolversOptions<S>): ResolversManager<S>;
740
+
741
+ /**
742
+ * Plugin Architecture - Extensible middleware for Directive
743
+ *
744
+ * Features:
745
+ * - Lifecycle hooks for all engine events
746
+ * - Multiple plugins can be composed
747
+ * - Plugins execute in registration order
748
+ */
749
+
750
+ /**
751
+ * Internal manager that broadcasts lifecycle events to registered {@link Plugin} instances.
752
+ *
753
+ * @remarks
754
+ * PluginManager uses `Schema` (flat) internally because the engine works with
755
+ * flat schemas. The public API uses `ModuleSchema` (consolidated), and the
756
+ * conversion happens in `createSystem`.
757
+ *
758
+ * Plugins execute in registration order. All hook invocations are wrapped in
759
+ * try-catch so a misbehaving plugin never breaks the engine. Duplicate plugin
760
+ * names are detected and the older registration is replaced with a warning.
761
+ *
762
+ * Lifecycle hook categories:
763
+ * - **System lifecycle:** `emitInit`, `emitStart`, `emitStop`, `emitDestroy`
764
+ * - **Facts:** `emitFactSet`, `emitFactDelete`, `emitFactsBatch`
765
+ * - **Derivations:** `emitDerivationCompute`, `emitDerivationInvalidate`
766
+ * - **Reconciliation:** `emitReconcileStart`, `emitReconcileEnd`
767
+ * - **Constraints:** `emitConstraintEvaluate`, `emitConstraintError`
768
+ * - **Requirements:** `emitRequirementCreated`, `emitRequirementMet`, `emitRequirementCanceled`
769
+ * - **Resolvers:** `emitResolverStart`, `emitResolverComplete`, `emitResolverError`, `emitResolverRetry`, `emitResolverCancel`
770
+ * - **Effects:** `emitEffectRun`, `emitEffectError`
771
+ * - **History:** `emitSnapshot`, `emitHistoryNavigate`
772
+ * - **Errors:** `emitError`, `emitErrorRecovery`
773
+ * - **Trace:** `emitTraceComplete`
774
+ *
775
+ * @typeParam _S - The flat schema type (unused at runtime).
776
+ *
777
+ * @internal
778
+ */
779
+ interface PluginManager<_S extends Schema = any> {
780
+ /** Register a plugin */
781
+ register(plugin: Plugin<any>): void;
782
+ /** Unregister a plugin by name */
783
+ unregister(name: string): void;
784
+ /** Get all registered plugins */
785
+ getPlugins(): Plugin<any>[];
786
+ emitInit(system: System<any>): Promise<void>;
787
+ emitStart(system: System<any>): void;
788
+ emitStop(system: System<any>): void;
789
+ emitDestroy(system: System<any>): void;
790
+ emitFactSet(key: string, value: unknown, prev: unknown): void;
791
+ emitFactDelete(key: string, prev: unknown): void;
792
+ emitFactsBatch(changes: FactChange[]): void;
793
+ emitDerivationCompute(id: string, value: unknown, deps: string[]): void;
794
+ emitDerivationInvalidate(id: string): void;
795
+ emitReconcileStart(snapshot: FactsSnapshot<any>): void;
796
+ emitReconcileEnd(result: ReconcileResult): void;
797
+ emitConstraintEvaluate(id: string, active: boolean): void;
798
+ emitConstraintError(id: string, error: unknown): void;
799
+ emitRequirementCreated(req: RequirementWithId): void;
800
+ emitRequirementMet(req: RequirementWithId, byResolver: string): void;
801
+ emitRequirementCanceled(req: RequirementWithId): void;
802
+ emitResolverStart(resolver: string, req: RequirementWithId): void;
803
+ emitResolverComplete(resolver: string, req: RequirementWithId, duration: number): void;
804
+ emitResolverError(resolver: string, req: RequirementWithId, error: unknown): void;
805
+ emitResolverRetry(resolver: string, req: RequirementWithId, attempt: number): void;
806
+ emitResolverCancel(resolver: string, req: RequirementWithId): void;
807
+ emitEffectRun(id: string): void;
808
+ emitEffectError(id: string, error: unknown): void;
809
+ emitSnapshot(snapshot: Snapshot): void;
810
+ emitHistoryNavigate(from: number, to: number): void;
811
+ emitError(error: DirectiveError): void;
812
+ emitErrorRecovery(error: DirectiveError, strategy: RecoveryStrategy): void;
813
+ emitDefinitionRegister(type: string, id: string, def: unknown): void;
814
+ emitDefinitionAssign(type: string, id: string, def: unknown, original: unknown): void;
815
+ emitDefinitionUnregister(type: string, id: string): void;
816
+ emitDefinitionCall(type: string, id: string, props?: unknown): void;
817
+ emitTraceComplete(run: TraceEntry): void;
818
+ }
819
+ /**
820
+ * Create a {@link PluginManager} that broadcasts lifecycle events to registered plugins.
821
+ *
822
+ * @remarks
823
+ * Plugins are called in registration order. All hook invocations are wrapped
824
+ * in try-catch so a misbehaving plugin never breaks the engine. Duplicate
825
+ * plugin names are detected and the older registration is replaced with a
826
+ * console warning.
827
+ *
828
+ * @returns A {@link PluginManager} with `register`/`unregister`/`getPlugins` and `emit*` methods for every lifecycle event.
829
+ *
830
+ * @internal
831
+ */
832
+ declare function createPluginManager<S extends Schema = any>(): PluginManager<S>;
833
+
834
+ /**
835
+ * Error Boundaries - Configurable error handling and recovery
836
+ *
837
+ * Features:
838
+ * - Catch errors in constraints/resolvers/effects/derivations
839
+ * - Configurable recovery strategies (skip, retry, retry-later, disable, throw)
840
+ * - Circuit breaker pattern for automatic failure protection
841
+ * - Error reporting to plugins
842
+ */
843
+
844
+ /**
845
+ * A queued retry entry tracking its source, attempt count, and scheduled time.
846
+ *
847
+ * @internal
848
+ */
849
+ interface PendingRetry {
850
+ source: ErrorSource;
851
+ sourceId: string;
852
+ context: unknown;
853
+ attempt: number;
854
+ nextRetryTime: number;
855
+ callback?: () => void;
856
+ }
857
+ /**
858
+ * Create a manager for deferred retry scheduling with exponential backoff.
859
+ *
860
+ * @remarks
861
+ * Retries are stored in a Map keyed by source ID. Each entry tracks its
862
+ * attempt number and the timestamp of the next eligible retry. When
863
+ * {@link createRetryLaterManager | processDueRetries} is called (typically
864
+ * during reconciliation), entries whose scheduled time has elapsed are
865
+ * returned and removed from the queue. The delay grows exponentially:
866
+ * `delayMs * backoffMultiplier^(attempt - 1)`, capped at `maxDelayMs`.
867
+ *
868
+ * @param config - Backoff configuration including `delayMs`, `maxRetries`, `backoffMultiplier`, and `maxDelayMs`.
869
+ * @returns A manager exposing `scheduleRetry`, `getPendingRetries`, `processDueRetries`, `cancelRetry`, and `clearAll` methods.
870
+ *
871
+ * @internal
872
+ */
873
+ declare function createRetryLaterManager(config?: RetryLaterConfig): {
874
+ /** Schedule a retry */
875
+ scheduleRetry: (source: ErrorSource, sourceId: string, context: unknown, attempt: number, callback?: () => void) => PendingRetry | null;
876
+ /** Get pending retries */
877
+ getPendingRetries: () => PendingRetry[];
878
+ /** Process due retries */
879
+ processDueRetries: () => PendingRetry[];
880
+ /** Cancel a retry */
881
+ cancelRetry: (sourceId: string) => void;
882
+ /** Clear all pending retries */
883
+ clearAll: () => void;
884
+ };
885
+ /**
886
+ * Handle returned by {@link createErrorBoundaryManager} for routing errors
887
+ * through configurable recovery strategies.
888
+ *
889
+ * @internal
890
+ */
891
+ interface ErrorBoundaryManager {
892
+ /**
893
+ * Route an error through the configured recovery strategy for its source.
894
+ *
895
+ * @param source - The subsystem that produced the error.
896
+ * @param sourceId - Identifier of the specific constraint, resolver, effect, or derivation.
897
+ * @param error - The thrown value (coerced to {@link DirectiveError} internally).
898
+ * @param context - Optional context forwarded to callbacks and retry entries.
899
+ * @returns The {@link RecoveryStrategy} that was applied.
900
+ */
901
+ handleError(source: ErrorSource, sourceId: string, error: unknown, context?: unknown): RecoveryStrategy;
902
+ /**
903
+ * Return the most recently recorded error, or `null` if none exist.
904
+ *
905
+ * @returns The last {@link DirectiveError}, or `null`.
906
+ */
907
+ getLastError(): DirectiveError | null;
908
+ /**
909
+ * Return a snapshot array of all recorded errors (up to the last 100).
910
+ *
911
+ * @returns A shallow copy of the internal error ring buffer.
912
+ */
913
+ getAllErrors(): DirectiveError[];
914
+ /** Clear all recorded errors. */
915
+ clearErrors(): void;
916
+ /**
917
+ * Access the underlying retry-later manager for advanced scheduling.
918
+ *
919
+ * @returns The {@link createRetryLaterManager} instance used internally.
920
+ */
921
+ getRetryLaterManager(): ReturnType<typeof createRetryLaterManager>;
922
+ /**
923
+ * Drain and return retry entries whose scheduled time has elapsed.
924
+ *
925
+ * @returns An array of {@link PendingRetry} entries that are now due.
926
+ */
927
+ processDueRetries(): PendingRetry[];
928
+ /**
929
+ * Reset retry attempt tracking for a source, typically after a successful resolution.
930
+ *
931
+ * @param sourceId - The source identifier whose retry counter should be cleared.
932
+ */
933
+ clearRetryAttempts(sourceId: string): void;
934
+ }
935
+ /**
936
+ * Options accepted by {@link createErrorBoundaryManager}.
937
+ *
938
+ * @internal
939
+ */
940
+ interface CreateErrorBoundaryOptions {
941
+ /** Per-source recovery strategies and retry-later tuning. */
942
+ config?: ErrorBoundaryConfig;
943
+ /** Invoked every time an error is recorded, before the recovery strategy runs. */
944
+ onError?: (error: DirectiveError) => void;
945
+ /** Invoked after a recovery strategy has been selected for an error. */
946
+ onRecovery?: (error: DirectiveError, strategy: RecoveryStrategy) => void;
947
+ }
948
+ /**
949
+ * Create a manager that handles errors from constraints, resolvers, effects,
950
+ * and derivations with configurable per-source recovery strategies.
951
+ *
952
+ * @remarks
953
+ * Five recovery strategies are available:
954
+ *
955
+ * - `"skip"` -- Swallow the error and continue.
956
+ * - `"retry"` -- Signal the caller to retry immediately.
957
+ * - `"retry-later"` -- Enqueue a deferred retry with exponential backoff
958
+ * (delegated to an internal {@link createRetryLaterManager}).
959
+ * - `"disable"` -- Permanently disable the failing source.
960
+ * - `"throw"` -- Re-throw the error as a {@link DirectiveError}.
961
+ *
962
+ * Recent errors are kept in a ring buffer (last 100) for inspection via
963
+ * {@link ErrorBoundaryManager.getAllErrors | getAllErrors}. Each strategy
964
+ * can be configured per source type (`onConstraintError`, `onResolverError`,
965
+ * etc.) or as a callback that dynamically selects a strategy.
966
+ *
967
+ * @param options - Error boundary configuration, plus `onError` and `onRecovery` callbacks for plugin integration.
968
+ * @returns An {@link ErrorBoundaryManager} for routing errors through the configured strategies.
969
+ *
970
+ * @internal
971
+ */
972
+ declare function createErrorBoundaryManager(options?: CreateErrorBoundaryOptions): ErrorBoundaryManager;
973
+
974
+ /**
975
+ * History — Snapshot-based state history
976
+ *
977
+ * Features:
978
+ * - Ring buffer of state snapshots
979
+ * - Go back/forward through history
980
+ * - Replay from any snapshot
981
+ * - Export/import state history
982
+ */
983
+
984
+ /**
985
+ * Internal history manager that extends the public {@link HistoryAPI}
986
+ * with snapshot capture, restoration, and pause/resume controls.
987
+ *
988
+ * @remarks
989
+ * - `takeSnapshot(trigger)` records the current facts into the ring buffer.
990
+ * - `restore(snapshot)` deserializes a snapshot back into the facts store,
991
+ * setting `isRestoring = true` so the engine skips reconciliation.
992
+ * - `pause()` / `resume()` temporarily suspend snapshot recording (e.g.,
993
+ * during bulk imports or programmatic state resets).
994
+ * - `beginChangeset(label)` / `endChangeset()` group consecutive snapshots
995
+ * so `goBack`/`goForward` treat them as a single undo/redo unit.
996
+ *
997
+ * @typeParam _S - The schema type (unused at runtime but preserved for type safety).
998
+ *
999
+ * @internal
1000
+ */
1001
+ interface HistoryManager<_S extends Schema> extends HistoryAPI {
1002
+ /** Take a snapshot of current state */
1003
+ takeSnapshot(trigger: string): Snapshot;
1004
+ /** Restore facts from a snapshot */
1005
+ restore(snapshot: Snapshot): void;
1006
+ /** Check if history is enabled */
1007
+ readonly isEnabled: boolean;
1008
+ /** True while restoring a snapshot (engine should skip reconciliation) */
1009
+ readonly isRestoring: boolean;
1010
+ /** Pause snapshot taking */
1011
+ pause(): void;
1012
+ /** Resume snapshot taking */
1013
+ resume(): void;
1014
+ }
1015
+ /**
1016
+ * Options for creating a history manager via {@link createHistoryManager}.
1017
+ *
1018
+ * @typeParam S - The facts schema type.
1019
+ *
1020
+ * @internal
1021
+ */
1022
+ interface CreateHistoryOptions<S extends Schema> {
1023
+ historyOption: HistoryOption;
1024
+ facts: Facts<S>;
1025
+ store: FactsStore<S>;
1026
+ /** Callback when a snapshot is taken */
1027
+ onSnapshot?: (snapshot: Snapshot) => void;
1028
+ /** Callback when history navigation occurs */
1029
+ onHistoryChange?: (from: number, to: number) => void;
1030
+ }
1031
+ /**
1032
+ * Create a snapshot-based history manager backed by a ring buffer.
1033
+ *
1034
+ * @remarks
1035
+ * Snapshots are taken automatically after fact changes (during reconciliation)
1036
+ * and can be navigated with `goBack`/`goForward`/`goTo`. Use
1037
+ * `beginChangeset(label)` and `endChangeset()` to group multiple snapshots
1038
+ * into a single undo/redo unit. The entire history can be exported to JSON
1039
+ * via `export()` and re-imported with `import()` for cross-session debugging.
1040
+ *
1041
+ * Call `pause()` to temporarily stop recording snapshots (e.g., during bulk
1042
+ * fact imports) and `resume()` to re-enable recording.
1043
+ *
1044
+ * @param options - History config, facts proxy, store, and optional snapshot/history callbacks.
1045
+ * @returns A {@link HistoryManager} with snapshot capture, navigation, changeset, and export/import methods.
1046
+ *
1047
+ * @internal
1048
+ */
1049
+ declare function createHistoryManager<S extends Schema>(options: CreateHistoryOptions<S>): HistoryManager<S>;
1050
+ /**
1051
+ * Create a no-op history manager for use when history is disabled.
1052
+ *
1053
+ * @remarks
1054
+ * All methods are safe to call but perform no work. This avoids null-checks
1055
+ * throughout the engine -- callers can use the same {@link HistoryManager}
1056
+ * interface regardless of whether history is enabled.
1057
+ *
1058
+ * @returns A {@link HistoryManager} where every method is a no-op and `isEnabled` is `false`.
1059
+ *
1060
+ * @internal
1061
+ */
1062
+ declare function createDisabledHistory<S extends Schema>(): HistoryManager<S>;
1063
+
1064
+ /**
1065
+ * Engine - The core reconciliation loop
1066
+ *
1067
+ * The engine orchestrates:
1068
+ * 1. Fact changes trigger reconciliation
1069
+ * 2. Constraints produce requirements
1070
+ * 3. Resolvers fulfill requirements
1071
+ * 4. Effects run after stabilization
1072
+ * 5. Derivations are invalidated and recomputed
1073
+ */
1074
+
1075
+ /**
1076
+ * Create the core Directive reconciliation engine that wires facts, derivations,
1077
+ * effects, constraints, resolvers, plugins, error boundaries, and history
1078
+ * into a single reactive system.
1079
+ *
1080
+ * @remarks
1081
+ * This is the internal factory used by {@link createSystem}. Most users should
1082
+ * call `createSystem` instead, which provides a friendlier API and handles
1083
+ * module composition.
1084
+ *
1085
+ * @param config - Full system configuration including modules, plugins, error boundary settings, and debug options
1086
+ * @returns A {@link System} instance with facts, derive, events, dispatch, subscribe, watch, settle, and lifecycle methods
1087
+ *
1088
+ * @example
1089
+ * ```ts
1090
+ * // Prefer createSystem for most use cases:
1091
+ * import { createSystem, createModule, t } from "@directive-run/core";
1092
+ *
1093
+ * const counter = createModule("counter", {
1094
+ * schema: { count: t.number() },
1095
+ * init: (facts) => { facts.count = 0; },
1096
+ * });
1097
+ *
1098
+ * const system = createSystem({ module: counter });
1099
+ * system.start();
1100
+ * system.facts.count = 42;
1101
+ * ```
1102
+ *
1103
+ * @internal
1104
+ */
1105
+ declare function createEngine<S extends Schema>(config: SystemConfig<any>): System<any>;
1106
+
1107
+ /**
1108
+ * Dependency tracking context for auto-tracking derivations
1109
+ *
1110
+ * Uses a stack-based approach to handle nested derivation computations.
1111
+ * When a derivation accesses a fact, the tracking context records it.
1112
+ */
1113
+
1114
+ /**
1115
+ * Get the current tracking context.
1116
+ *
1117
+ * @returns The active {@link TrackingContext}, or a null context (no-op) if
1118
+ * no tracking is active.
1119
+ *
1120
+ * @internal
1121
+ */
1122
+ declare function getCurrentTracker(): TrackingContext;
1123
+ /**
1124
+ * Check if dependency tracking is currently active.
1125
+ *
1126
+ * @returns `true` if inside a {@link withTracking} call, `false` otherwise.
1127
+ *
1128
+ * @internal
1129
+ */
1130
+ declare function isTracking(): boolean;
1131
+ /**
1132
+ * Run a function with dependency tracking.
1133
+ *
1134
+ * @remarks
1135
+ * Pushes a fresh tracking context onto the stack, executes `fn`, then pops
1136
+ * the context. Any fact reads inside `fn` are recorded as dependencies.
1137
+ * Nesting is supported — inner calls get their own independent context.
1138
+ *
1139
+ * @param fn - The function to execute under tracking.
1140
+ * @returns An object with the computed `value` and a `deps` Set of accessed
1141
+ * fact keys.
1142
+ *
1143
+ * @internal
1144
+ */
1145
+ declare function withTracking<T>(fn: () => T): {
1146
+ value: T;
1147
+ deps: Set<string>;
1148
+ };
1149
+ /**
1150
+ * Run a function without tracking.
1151
+ *
1152
+ * @remarks
1153
+ * Temporarily clears the tracking stack so that fact reads inside `fn` do
1154
+ * not register as dependencies. The stack is restored after `fn` returns
1155
+ * (even on error). Useful for side-effect reads that should not trigger
1156
+ * derivation invalidation.
1157
+ *
1158
+ * @param fn - The function to execute without tracking.
1159
+ * @returns The return value of `fn`.
1160
+ *
1161
+ * @internal
1162
+ */
1163
+ declare function withoutTracking<T>(fn: () => T): T;
1164
+ /**
1165
+ * Track a specific key in the current context.
1166
+ *
1167
+ * @remarks
1168
+ * No-op if no tracking context is active.
1169
+ *
1170
+ * @param key - The fact key to record as a dependency.
1171
+ *
1172
+ * @internal
1173
+ */
1174
+ declare function trackAccess(key: string): void;
1175
+
1176
+ export { ConstraintState, ConstraintsDef, type DerivationState, type DerivationsDef, type DerivedValues, EffectsDef, ErrorSource, FactChange, FactsStore, type InflightInfo, type PendingRetry, ReconcileResult, RecoveryStrategy, RequirementKeyFn, ResolverStatus, ResolversDef, RetryLaterConfig, createConstraintsManager, createDerivationsManager, createDisabledHistory, createEffectsManager, createEngine, createErrorBoundaryManager, createFacts, createFactsProxy, createFactsStore, createHistoryManager, createPluginManager, createResolversManager, createRetryLaterManager, getCurrentTracker, isTracking, trackAccess, withTracking, withoutTracking };