@directive-run/core 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/adapter-utils.cjs +1 -1
  2. package/dist/adapter-utils.d.cts +1 -1
  3. package/dist/adapter-utils.d.ts +1 -1
  4. package/dist/adapter-utils.js +1 -1
  5. package/dist/chunk-EOLY64E6.cjs +3 -0
  6. package/dist/chunk-EOLY64E6.cjs.map +1 -0
  7. package/dist/chunk-K3KVGWLP.cjs +3 -0
  8. package/dist/chunk-K3KVGWLP.cjs.map +1 -0
  9. package/dist/chunk-OVNPYGYJ.js +3 -0
  10. package/dist/chunk-OVNPYGYJ.js.map +1 -0
  11. package/dist/chunk-QOK7CHOW.js +16 -0
  12. package/dist/chunk-QOK7CHOW.js.map +1 -0
  13. package/dist/chunk-T4ZO4IYL.cjs +16 -0
  14. package/dist/chunk-T4ZO4IYL.cjs.map +1 -0
  15. package/dist/chunk-T6IJUWYR.js +3 -0
  16. package/dist/chunk-T6IJUWYR.js.map +1 -0
  17. package/dist/{helpers-h9PR2JSJ.d.ts → helpers-BwAThjnJ.d.ts} +1 -1
  18. package/dist/{helpers-B1MiHave.d.cts → helpers-CG27mEGG.d.cts} +1 -1
  19. package/dist/index.cjs +4 -1
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +236 -6
  22. package/dist/index.d.ts +236 -6
  23. package/dist/index.js +4 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/internals.cjs +1 -1
  26. package/dist/internals.d.cts +41 -5
  27. package/dist/internals.d.ts +41 -5
  28. package/dist/internals.js +1 -1
  29. package/dist/plugins/index.cjs +1 -1
  30. package/dist/plugins/index.cjs.map +1 -1
  31. package/dist/plugins/index.d.cts +1 -1
  32. package/dist/plugins/index.d.ts +1 -1
  33. package/dist/plugins/index.js +1 -1
  34. package/dist/plugins/index.js.map +1 -1
  35. package/dist/{plugins-Bakr7js6.d.ts → plugins-DvrsPhzx.d.cts} +124 -21
  36. package/dist/{plugins-Bakr7js6.d.cts → plugins-DvrsPhzx.d.ts} +124 -21
  37. package/dist/system-5BSCMT63.cjs +2 -0
  38. package/dist/{system-CK3SHMXZ.cjs.map → system-5BSCMT63.cjs.map} +1 -1
  39. package/dist/system-DMJ6XEJ7.js +2 -0
  40. package/dist/{system-744ZPPES.js.map → system-DMJ6XEJ7.js.map} +1 -1
  41. package/dist/testing.cjs +1 -1
  42. package/dist/testing.d.cts +1 -1
  43. package/dist/testing.d.ts +1 -1
  44. package/dist/testing.js +1 -1
  45. package/dist/worker.cjs +1 -1
  46. package/dist/worker.d.cts +1 -1
  47. package/dist/worker.d.ts +1 -1
  48. package/dist/worker.js +1 -1
  49. package/package.json +1 -1
  50. package/dist/chunk-HAF5JCET.js +0 -16
  51. package/dist/chunk-HAF5JCET.js.map +0 -1
  52. package/dist/chunk-M5KZXNZX.js +0 -3
  53. package/dist/chunk-M5KZXNZX.js.map +0 -1
  54. package/dist/chunk-PGUTGWUI.cjs +0 -3
  55. package/dist/chunk-PGUTGWUI.cjs.map +0 -1
  56. package/dist/chunk-SQVKCJHE.cjs +0 -16
  57. package/dist/chunk-SQVKCJHE.cjs.map +0 -1
  58. package/dist/chunk-YCCQ73C6.js +0 -3
  59. package/dist/chunk-YCCQ73C6.js.map +0 -1
  60. package/dist/chunk-ZHS3EW2Z.cjs +0 -3
  61. package/dist/chunk-ZHS3EW2Z.cjs.map +0 -1
  62. package/dist/system-744ZPPES.js +0 -2
  63. package/dist/system-CK3SHMXZ.cjs +0 -2
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { P as PatchSpec, C as ClauseResult, F as FactTemplate, S as SchemaType, D as DefinitionMeta, M as ModuleSchema, a as Facts, T as TypedDerivationsDef, b as TypedEventsDef, E as EffectsDef, c as TypedConstraintsDef, d as TypedResolversDef, e as ModuleHooks, f as CrossModuleDeps, g as CrossModuleDerivationsDef, h as CrossModuleEffectsDef, i as CrossModuleConstraintsDef, j as ModuleDef, k as CreateSystemOptionsSingle, l as SingleModuleSystem, m as ModulesMap, n as CreateSystemOptionsNamed, N as NamespacedSystem, o as Plugin, p as TraceOption, q as ErrorBoundaryConfig, R as RequirementWithId, r as Requirement, s as RequirementKeyFn } from './plugins-Bakr7js6.cjs';
2
- export { A as AnySystem, B as BatchConfig, t as DirectiveError, u as DistributableSnapshot, v as DistributableSnapshotOptions, w as DynamicConstraintDef, x as DynamicEffectDef, y as DynamicResolverDef, z as FactPredicate, G as FactsSnapshot, H as HistoryAPI, I as HistoryOption, J as HistoryState, K as InferDerivations, L as InferEvents, O as InferFacts, Q as InferRequirementTypes, U as InferRequirements, V as InferSchemaType, W as InferSelectorState, X as KeySelector, Y as MetaAccessor, Z as MetaMatch, _ as ObservationEvent, $ as OperatorObject, a0 as PatchValue, a1 as PayloadRef, a2 as PredicateClause, a3 as PredicateCombinator, a4 as PredicateCombinatorKey, a5 as PredicateObject, a6 as PredicateOp, a7 as RetryPolicy, a8 as Schema, a9 as Snapshot, aa as System, ab as SystemConfig, ac as SystemInspection, ad as SystemMode, ae as SystemSnapshot, af as TraceEntry, ag as isNamespacedSystem, ah as isSingleModuleSystem } from './plugins-Bakr7js6.cjs';
3
- export { D as DerivationDefWithMeta, t as typedConstraint, a as typedResolver } from './helpers-B1MiHave.cjs';
1
+ import { P as PatchSpec, C as ClauseResult, F as FactTemplate, a as FactPredicate, S as SchemaType, D as DefinitionMeta, M as ModuleSchema, b as Facts, T as TypedDerivationsDef, c as TypedEventsDef, E as EffectsDef, d as TypedConstraintsDef, e as TypedResolversDef, f as ModuleHooks, g as CrossModuleDeps, h as CrossModuleDerivationsDef, i as CrossModuleEffectsDef, j as CrossModuleConstraintsDef, k as ModuleDef, l as CreateSystemOptionsSingle, m as SingleModuleSystem, n as ModulesMap, o as CreateSystemOptionsNamed, N as NamespacedSystem, p as Plugin, q as TraceOption, r as ErrorBoundaryConfig, R as RequirementWithId, s as Requirement, t as RequirementKeyFn } from './plugins-DvrsPhzx.cjs';
2
+ export { A as AnySystem, B as BatchConfig, u as DirectiveError, v as DistributableSnapshot, w as DistributableSnapshotOptions, x as DynamicConstraintDef, y as DynamicEffectDef, z as DynamicResolverDef, G as FactsSnapshot, H as HistoryAPI, I as HistoryOption, J as HistoryState, K as InferDerivations, L as InferEvents, O as InferFacts, Q as InferRequirementTypes, U as InferRequirements, V as InferSchemaType, W as InferSelectorState, X as KeySelector, Y as MetaAccessor, Z as MetaMatch, _ as ObservationEvent, $ as OperatorObject, a0 as PatchValue, a1 as PayloadRef, a2 as PredicateClause, a3 as PredicateCombinator, a4 as PredicateCombinatorKey, a5 as PredicateObject, a6 as PredicateOp, a7 as RetryPolicy, a8 as Schema, a9 as Snapshot, aa as System, ab as SystemConfig, ac as SystemInspection, ad as SystemMode, ae as SystemSnapshot, af as TraceEntry, ag as isNamespacedSystem, ah as isSingleModuleSystem } from './plugins-DvrsPhzx.cjs';
3
+ export { D as DerivationDefWithMeta, t as typedConstraint, a as typedResolver } from './helpers-CG27mEGG.cjs';
4
4
  export { D as DistributableSnapshotLike, S as SignedSnapshot, a as SnapshotDiff, b as SnapshotDiffEntry, d as diffSnapshots, i as isSignedSnapshot, c as isSnapshotExpired, s as shallowEqual, e as signSnapshot, v as validateSnapshot, f as verifySnapshotSignature } from './utils-BnQajqPu.cjs';
5
5
 
6
6
  /**
@@ -36,6 +36,39 @@ declare function isPredicate(v: unknown): boolean;
36
36
  * ```
37
37
  */
38
38
  declare function isTemplate(v: unknown): v is FactTemplate;
39
+ /**
40
+ * Throw when a predicate spec contains an operand that cannot survive a
41
+ * JSON round-trip — i.e. that would silently mis-evaluate if the spec was
42
+ * loaded from `JSON.parse`.
43
+ *
44
+ * Three failure classes are detected:
45
+ *
46
+ * - **Lost `RegExp` operand.** A `$matches` operand that is not a
47
+ * `RegExp` instance. `JSON.parse` reconstructs a serialized regex as
48
+ * `{}`, so a `$matches` clause with an empty-object operand is the
49
+ * signature of a regex that did not survive serialization. Reify it
50
+ * with `new RegExp(pattern, flags)` before installing the predicate.
51
+ * - **`bigint` operand.** `JSON.stringify` throws on `bigint`, so a
52
+ * `bigint` operand cannot have been produced by a JSON pipeline and
53
+ * cannot be persisted by one either.
54
+ * - **`Set` / `Map` operand.** Both serialize to `{}` and lose all
55
+ * members; a predicate carrying one is not JSON-safe.
56
+ *
57
+ * This is an opt-in helper — the engine does not call it automatically.
58
+ * Users who load predicates from JSON should call it after `JSON.parse`
59
+ * to fail loud rather than silently mis-evaluate. See the
60
+ * "Serialization" section of RFC-0004.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * validatePredicate({ phase: { $matches: {} } });
65
+ * // throws — empty object where a RegExp is required
66
+ *
67
+ * validatePredicate({ phase: "red", elapsed: { $gte: 30 } });
68
+ * // ok — JSON-clean operands
69
+ * ```
70
+ */
71
+ declare function validatePredicate(spec: unknown, path?: string): void;
39
72
  /**
40
73
  * Evaluate a {@link FactPredicate} against a fact scope. `prev` (a previous
41
74
  * snapshot) is consulted only by the `$changed` operator.
@@ -48,7 +81,7 @@ declare function isTemplate(v: unknown): v is FactTemplate;
48
81
  * // → false
49
82
  * ```
50
83
  */
51
- declare function evaluatePredicate(spec: unknown, facts: Scope, prev?: Scope): boolean;
84
+ declare function evaluatePredicate(spec: unknown, facts: Scope, prev?: Scope, depth?: number): boolean;
52
85
  /**
53
86
  * Evaluate a predicate and return a per-clause breakdown — the data feed for
54
87
  * devtools, `system.explain()`, and `directive explain`.
@@ -108,7 +141,7 @@ declare function memoizePredicate(predicate: object): (facts: Scope, prev?: Scop
108
141
  * // → Set { "self.phase", "auth.token" }
109
142
  * ```
110
143
  */
111
- declare function extractDeps(spec: unknown, prefix?: string, into?: Set<string>): Set<string>;
144
+ declare function extractDeps(spec: unknown, prefix?: string): Set<string>;
112
145
  /**
113
146
  * Interpolate a {@link FactTemplate} against a scope. Single-pass character
114
147
  * scanner: `${ident}` interpolates `scope[ident]`; `$${` emits a literal
@@ -173,6 +206,203 @@ declare function evaluateKeySelector(selector: readonly string[], source: Record
173
206
  */
174
207
  declare function applyPatch(spec: PatchSpec<Record<string, unknown>, Record<string, unknown>>, facts: Record<string, unknown>, payload: Record<string, unknown>): void;
175
208
 
209
+ /**
210
+ * Predicate backtest — rule-change impact.
211
+ *
212
+ * Given a recorded sequence of fact-state frames and a proposed replacement
213
+ * for a constraint's `when` predicate, re-score the frames against BOTH the
214
+ * original and the proposed predicate and produce a backtest report: how
215
+ * many frames each matched, plus the per-frame diff (frames that newly
216
+ * match / no longer match). It answers "how many recorded frames would the
217
+ * proposed rule have matched differently" against real recorded history.
218
+ *
219
+ * This is a *static* backtest, not a behavioral simulation — the engine is
220
+ * not re-run. Recorded frames are re-scored against a new predicate; the
221
+ * resulting requirements, resolvers, and downstream fact changes are NOT
222
+ * modeled. Treat the numbers as a divergence scan, not a forecast.
223
+ *
224
+ * Pure module — imports only the predicate runtime. No engine, store, or
225
+ * tracking dependency. Replay walks frames in order; for `$changed`-style
226
+ * predicates each frame is evaluated against the previous frame's facts.
227
+ */
228
+
229
+ /**
230
+ * Upper bound on the number of frames a single {@link replayUnder} call will
231
+ * process. A history file is held entirely in memory; an unbounded array is a
232
+ * denial-of-service surface. A history larger than this should be split or
233
+ * down-sampled before replay.
234
+ */
235
+ declare const MAX_REPLAY_FRAMES = 1000000;
236
+ /** One recorded fact-state frame. */
237
+ interface ReplayFrame<F = Record<string, unknown>> {
238
+ /** Stable identifier — a snapshot id, an index, a session key. */
239
+ id: string | number;
240
+ /** Optional wall-clock time (ms epoch). */
241
+ timestamp?: number;
242
+ /** The fact state at this frame. */
243
+ facts: F;
244
+ }
245
+ interface ReplayUnderOptions<F = Record<string, unknown>> {
246
+ /** Recorded frames, chronological order. */
247
+ frames: readonly ReplayFrame<F>[];
248
+ /** The constraint's current `when` predicate (the baseline). */
249
+ original: FactPredicate<F>;
250
+ /** The proposed replacement `when` predicate. */
251
+ proposed: FactPredicate<F>;
252
+ /** Max diff samples to attach per bucket (default 20). */
253
+ maxSamples?: number;
254
+ /**
255
+ * A fact key identifying the entity a frame belongs to (e.g. `"userId"`,
256
+ * `"sessionId"`). When set, the report also reports distinct-entity counts
257
+ * — how many unique entities matched, not just how many frames. Without it
258
+ * the unit is frames: one fact snapshot, not one user or session.
259
+ */
260
+ entityKey?: string;
261
+ }
262
+ /** A frame where the original and proposed predicate disagree. */
263
+ interface ReplayDiffSample {
264
+ frameId: string | number;
265
+ timestamp?: number;
266
+ /** The fact state at this frame. */
267
+ facts: Record<string, unknown>;
268
+ /** Per-clause breakdown under the original predicate. */
269
+ originalExplain: ClauseResult[];
270
+ /** Per-clause breakdown under the proposed predicate. */
271
+ proposedExplain: ClauseResult[];
272
+ }
273
+ /**
274
+ * The outcome of replaying a recorded history under two predicates — a
275
+ * static backtest of a proposed rule change, not a behavioral simulation.
276
+ */
277
+ interface PredicateBacktestReport {
278
+ /** Total frames evaluated. */
279
+ framesEvaluated: number;
280
+ /**
281
+ * Frames where the original predicate matched (was true). `matchedEntities`
282
+ * is the count of distinct `entityKey` values among matched frames — only
283
+ * populated when {@link ReplayUnderOptions.entityKey} was supplied.
284
+ */
285
+ original: {
286
+ matched: number;
287
+ matchedEntities?: number;
288
+ };
289
+ /** Frames where the proposed predicate matched. */
290
+ proposed: {
291
+ matched: number;
292
+ matchedEntities?: number;
293
+ };
294
+ /** proposed.matched - original.matched. */
295
+ delta: number;
296
+ /** Total count of frames that newly match (original false -> proposed true). */
297
+ newMatchCount: number;
298
+ /** Total count of frames that no longer match (original true -> proposed false). */
299
+ lostMatchCount: number;
300
+ /** Frames where original and proposed agree. */
301
+ unchanged: number;
302
+ /** Sampled new-match frames (capped at maxSamples), with clause explain. */
303
+ newMatches: ReplayDiffSample[];
304
+ /** Sampled lost-match frames (capped at maxSamples), with clause explain. */
305
+ lostMatches: ReplayDiffSample[];
306
+ }
307
+ /**
308
+ * Normalize a parsed-from-JSON history value into a `ReplayFrame[]`.
309
+ *
310
+ * Accepts the three documented history shapes:
311
+ *
312
+ * 1. A bare array of frames: `[{ id, timestamp?, facts }, ...]`
313
+ * 2. An object wrapping them: `{ frames: [{ id, ..., facts }, ...] }`
314
+ * 3. A bare array of fact objects: `[{ phase: "red", ... }, ...]`
315
+ * — each element is wrapped as a frame.
316
+ *
317
+ * Frame ids are kept unambiguous: a frame that supplies its own `id` keeps
318
+ * it; a frame missing an `id` (and every bare-fact frame) gets an
319
+ * **index-derived** id prefixed with `#` (`"#0"`, `"#1"`, …) so a fallback
320
+ * id can never collide with an explicit numeric or string id in a mixed
321
+ * history. This is a pure helper — it **throws** a clear `Error` on bad
322
+ * input and never calls `process.exit`, so library users can catch it.
323
+ *
324
+ * @example
325
+ * ```ts
326
+ * toReplayFrames([{ id: "s1", facts: { phase: "red" } }]);
327
+ * // → [{ id: "s1", facts: { phase: "red" } }]
328
+ * toReplayFrames([{ phase: "red" }, { phase: "green" }]);
329
+ * // → [{ id: "#0", facts: { phase: "red" } }, { id: "#1", facts: { phase: "green" } }]
330
+ * ```
331
+ */
332
+ declare function toReplayFrames(raw: unknown): ReplayFrame[];
333
+ /**
334
+ * Convert a history-manager export (the JSON produced by
335
+ * `system.history.export()`) into a `ReplayFrame[]` ready for
336
+ * {@link replayUnder}.
337
+ *
338
+ * The history manager records a ring buffer of `{ id, timestamp, facts,
339
+ * trigger }` snapshots; `export()` wraps them as `{ version, snapshots,
340
+ * currentIndex }`. Each snapshot's `facts` is the fact state at that point,
341
+ * so the snapshot sequence is exactly a frame stream.
342
+ *
343
+ * Accepts either the parsed export object, the raw JSON string, or a bare
344
+ * array of snapshots. Throws a clear `Error` on bad input.
345
+ *
346
+ * @example
347
+ * ```ts
348
+ * const frames = framesFromHistory(system.history.export());
349
+ * const report = replayUnder({ frames, original, proposed });
350
+ * ```
351
+ */
352
+ declare function framesFromHistory(historyExport: unknown): ReplayFrame[];
353
+ /**
354
+ * Convert an array of `{ id, timestamp?, facts }` snapshots — e.g. the
355
+ * `snapshots` field of a history export, or an array assembled by pushing
356
+ * `system.getSnapshot()` on each reconcile — into a `ReplayFrame[]`.
357
+ *
358
+ * Throws a clear `Error` if the argument is not an array. Each snapshot is
359
+ * normalized through the same {@link toReplayFrames} id logic.
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * const snapshots: typeof history[] = [];
364
+ * system.observe(() => snapshots.push(system.getSnapshot()));
365
+ * // ...later
366
+ * const frames = framesFromSnapshots(snapshots);
367
+ * ```
368
+ */
369
+ declare function framesFromSnapshots(snapshots: unknown): ReplayFrame[];
370
+ /**
371
+ * Replay a recorded fact-frame history through two predicates — the
372
+ * constraint's current `when` and a proposed replacement — and report how
373
+ * their match sets differ.
374
+ *
375
+ * This is a **predicate backtest**: the engine is not re-run. Each recorded
376
+ * frame is statically re-scored against both specs; the previous frame's
377
+ * facts are threaded as `prev` so a replayed effect-`on` predicate using
378
+ * `$changed` still works (for a constraint `when` it is harmless). The
379
+ * report counts matches under each spec and buckets the disagreements into
380
+ * new matches (original false, proposed true) and lost matches (original
381
+ * true, proposed false). Up to `maxSamples` diff frames per bucket carry a
382
+ * per-clause `evaluatePredicateExplained` breakdown for inspection.
383
+ *
384
+ * Both specs are validated up front — a malformed spec throws a clear
385
+ * `[Directive] replayUnder:` error identifying which spec failed, rather
386
+ * than letting a raw `evaluatePredicate` error escape mid-loop.
387
+ *
388
+ * @example
389
+ * ```ts
390
+ * const report = replayUnder({
391
+ * frames: [
392
+ * { id: 0, facts: { phase: "red", elapsed: 10 } },
393
+ * { id: 1, facts: { phase: "red", elapsed: 35 } },
394
+ * ],
395
+ * original: { phase: "red" },
396
+ * proposed: { phase: "red", elapsed: { $gte: 30 } },
397
+ * });
398
+ * // report.original.matched === 2
399
+ * // report.proposed.matched === 1
400
+ * // report.delta === -1
401
+ * // report.lostMatchCount === 1
402
+ * ```
403
+ */
404
+ declare function replayUnder<F = Record<string, unknown>>(options: ReplayUnderOptions<F>): PredicateBacktestReport;
405
+
176
406
  /** Brand symbol for branded types */
177
407
  declare const Brand: unique symbol;
178
408
  /** Branded type - adds a unique brand to a base type */
@@ -1433,4 +1663,4 @@ declare const Backoff: {
1433
1663
  readonly Exponential: "exponential";
1434
1664
  };
1435
1665
 
1436
- export { Backoff, type Branded, type ChainableSchemaType, ClauseResult, CreateSystemOptionsNamed, CreateSystemOptionsSingle, CrossModuleDeps, DefinitionMeta, ErrorBoundaryConfig, type ExtendedSchemaType, FactTemplate, Facts, type ModuleConfig, type ModuleConfigWithDeps, ModuleDef, ModuleHooks, ModuleSchema, ModulesMap, NamespacedSystem, PatchSpec, Plugin, Requirement, RequirementSet, type RequirementTypeStatus, RequirementWithId, SchemaType, type SignalClock, SingleModuleSystem, type TimerFactOpts, type TimerFactState, TraceOption, applyPatch, completeTimer, createModule, createModuleFactory, createRequirementStatusPlugin, createStatusHook, createSystem, createSystemWithStatus, defaultClock, elapsedMs, evaluateKeySelector, evaluatePredicate, evaluatePredicateExplained, evaluateTemplate, extractDeps, extractTemplateKeys, forType, generateRequirementId, initialTimerState, isPredicate, isRequirementType, isTemplate, memoizePredicate, pauseTimer, realClock, registerRepeat, remainingMs, req, resetTimer, resumeTimer, startTimer, t, tickTimer, timerOps, virtualClock };
1666
+ export { Backoff, type Branded, type ChainableSchemaType, ClauseResult, CreateSystemOptionsNamed, CreateSystemOptionsSingle, CrossModuleDeps, DefinitionMeta, ErrorBoundaryConfig, type ExtendedSchemaType, FactPredicate, FactTemplate, Facts, MAX_REPLAY_FRAMES, type ModuleConfig, type ModuleConfigWithDeps, ModuleDef, ModuleHooks, ModuleSchema, ModulesMap, NamespacedSystem, PatchSpec, Plugin, type PredicateBacktestReport, type ReplayDiffSample, type ReplayFrame, type ReplayUnderOptions, Requirement, RequirementSet, type RequirementTypeStatus, RequirementWithId, SchemaType, type SignalClock, SingleModuleSystem, type TimerFactOpts, type TimerFactState, TraceOption, applyPatch, completeTimer, createModule, createModuleFactory, createRequirementStatusPlugin, createStatusHook, createSystem, createSystemWithStatus, defaultClock, elapsedMs, evaluateKeySelector, evaluatePredicate, evaluatePredicateExplained, evaluateTemplate, extractDeps, extractTemplateKeys, forType, framesFromHistory, framesFromSnapshots, generateRequirementId, initialTimerState, isPredicate, isRequirementType, isTemplate, memoizePredicate, pauseTimer, realClock, registerRepeat, remainingMs, replayUnder, req, resetTimer, resumeTimer, startTimer, t, tickTimer, timerOps, toReplayFrames, validatePredicate, virtualClock };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { P as PatchSpec, C as ClauseResult, F as FactTemplate, S as SchemaType, D as DefinitionMeta, M as ModuleSchema, a as Facts, T as TypedDerivationsDef, b as TypedEventsDef, E as EffectsDef, c as TypedConstraintsDef, d as TypedResolversDef, e as ModuleHooks, f as CrossModuleDeps, g as CrossModuleDerivationsDef, h as CrossModuleEffectsDef, i as CrossModuleConstraintsDef, j as ModuleDef, k as CreateSystemOptionsSingle, l as SingleModuleSystem, m as ModulesMap, n as CreateSystemOptionsNamed, N as NamespacedSystem, o as Plugin, p as TraceOption, q as ErrorBoundaryConfig, R as RequirementWithId, r as Requirement, s as RequirementKeyFn } from './plugins-Bakr7js6.js';
2
- export { A as AnySystem, B as BatchConfig, t as DirectiveError, u as DistributableSnapshot, v as DistributableSnapshotOptions, w as DynamicConstraintDef, x as DynamicEffectDef, y as DynamicResolverDef, z as FactPredicate, G as FactsSnapshot, H as HistoryAPI, I as HistoryOption, J as HistoryState, K as InferDerivations, L as InferEvents, O as InferFacts, Q as InferRequirementTypes, U as InferRequirements, V as InferSchemaType, W as InferSelectorState, X as KeySelector, Y as MetaAccessor, Z as MetaMatch, _ as ObservationEvent, $ as OperatorObject, a0 as PatchValue, a1 as PayloadRef, a2 as PredicateClause, a3 as PredicateCombinator, a4 as PredicateCombinatorKey, a5 as PredicateObject, a6 as PredicateOp, a7 as RetryPolicy, a8 as Schema, a9 as Snapshot, aa as System, ab as SystemConfig, ac as SystemInspection, ad as SystemMode, ae as SystemSnapshot, af as TraceEntry, ag as isNamespacedSystem, ah as isSingleModuleSystem } from './plugins-Bakr7js6.js';
3
- export { D as DerivationDefWithMeta, t as typedConstraint, a as typedResolver } from './helpers-h9PR2JSJ.js';
1
+ import { P as PatchSpec, C as ClauseResult, F as FactTemplate, a as FactPredicate, S as SchemaType, D as DefinitionMeta, M as ModuleSchema, b as Facts, T as TypedDerivationsDef, c as TypedEventsDef, E as EffectsDef, d as TypedConstraintsDef, e as TypedResolversDef, f as ModuleHooks, g as CrossModuleDeps, h as CrossModuleDerivationsDef, i as CrossModuleEffectsDef, j as CrossModuleConstraintsDef, k as ModuleDef, l as CreateSystemOptionsSingle, m as SingleModuleSystem, n as ModulesMap, o as CreateSystemOptionsNamed, N as NamespacedSystem, p as Plugin, q as TraceOption, r as ErrorBoundaryConfig, R as RequirementWithId, s as Requirement, t as RequirementKeyFn } from './plugins-DvrsPhzx.js';
2
+ export { A as AnySystem, B as BatchConfig, u as DirectiveError, v as DistributableSnapshot, w as DistributableSnapshotOptions, x as DynamicConstraintDef, y as DynamicEffectDef, z as DynamicResolverDef, G as FactsSnapshot, H as HistoryAPI, I as HistoryOption, J as HistoryState, K as InferDerivations, L as InferEvents, O as InferFacts, Q as InferRequirementTypes, U as InferRequirements, V as InferSchemaType, W as InferSelectorState, X as KeySelector, Y as MetaAccessor, Z as MetaMatch, _ as ObservationEvent, $ as OperatorObject, a0 as PatchValue, a1 as PayloadRef, a2 as PredicateClause, a3 as PredicateCombinator, a4 as PredicateCombinatorKey, a5 as PredicateObject, a6 as PredicateOp, a7 as RetryPolicy, a8 as Schema, a9 as Snapshot, aa as System, ab as SystemConfig, ac as SystemInspection, ad as SystemMode, ae as SystemSnapshot, af as TraceEntry, ag as isNamespacedSystem, ah as isSingleModuleSystem } from './plugins-DvrsPhzx.js';
3
+ export { D as DerivationDefWithMeta, t as typedConstraint, a as typedResolver } from './helpers-BwAThjnJ.js';
4
4
  export { D as DistributableSnapshotLike, S as SignedSnapshot, a as SnapshotDiff, b as SnapshotDiffEntry, d as diffSnapshots, i as isSignedSnapshot, c as isSnapshotExpired, s as shallowEqual, e as signSnapshot, v as validateSnapshot, f as verifySnapshotSignature } from './utils-BnQajqPu.js';
5
5
 
6
6
  /**
@@ -36,6 +36,39 @@ declare function isPredicate(v: unknown): boolean;
36
36
  * ```
37
37
  */
38
38
  declare function isTemplate(v: unknown): v is FactTemplate;
39
+ /**
40
+ * Throw when a predicate spec contains an operand that cannot survive a
41
+ * JSON round-trip — i.e. that would silently mis-evaluate if the spec was
42
+ * loaded from `JSON.parse`.
43
+ *
44
+ * Three failure classes are detected:
45
+ *
46
+ * - **Lost `RegExp` operand.** A `$matches` operand that is not a
47
+ * `RegExp` instance. `JSON.parse` reconstructs a serialized regex as
48
+ * `{}`, so a `$matches` clause with an empty-object operand is the
49
+ * signature of a regex that did not survive serialization. Reify it
50
+ * with `new RegExp(pattern, flags)` before installing the predicate.
51
+ * - **`bigint` operand.** `JSON.stringify` throws on `bigint`, so a
52
+ * `bigint` operand cannot have been produced by a JSON pipeline and
53
+ * cannot be persisted by one either.
54
+ * - **`Set` / `Map` operand.** Both serialize to `{}` and lose all
55
+ * members; a predicate carrying one is not JSON-safe.
56
+ *
57
+ * This is an opt-in helper — the engine does not call it automatically.
58
+ * Users who load predicates from JSON should call it after `JSON.parse`
59
+ * to fail loud rather than silently mis-evaluate. See the
60
+ * "Serialization" section of RFC-0004.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * validatePredicate({ phase: { $matches: {} } });
65
+ * // throws — empty object where a RegExp is required
66
+ *
67
+ * validatePredicate({ phase: "red", elapsed: { $gte: 30 } });
68
+ * // ok — JSON-clean operands
69
+ * ```
70
+ */
71
+ declare function validatePredicate(spec: unknown, path?: string): void;
39
72
  /**
40
73
  * Evaluate a {@link FactPredicate} against a fact scope. `prev` (a previous
41
74
  * snapshot) is consulted only by the `$changed` operator.
@@ -48,7 +81,7 @@ declare function isTemplate(v: unknown): v is FactTemplate;
48
81
  * // → false
49
82
  * ```
50
83
  */
51
- declare function evaluatePredicate(spec: unknown, facts: Scope, prev?: Scope): boolean;
84
+ declare function evaluatePredicate(spec: unknown, facts: Scope, prev?: Scope, depth?: number): boolean;
52
85
  /**
53
86
  * Evaluate a predicate and return a per-clause breakdown — the data feed for
54
87
  * devtools, `system.explain()`, and `directive explain`.
@@ -108,7 +141,7 @@ declare function memoizePredicate(predicate: object): (facts: Scope, prev?: Scop
108
141
  * // → Set { "self.phase", "auth.token" }
109
142
  * ```
110
143
  */
111
- declare function extractDeps(spec: unknown, prefix?: string, into?: Set<string>): Set<string>;
144
+ declare function extractDeps(spec: unknown, prefix?: string): Set<string>;
112
145
  /**
113
146
  * Interpolate a {@link FactTemplate} against a scope. Single-pass character
114
147
  * scanner: `${ident}` interpolates `scope[ident]`; `$${` emits a literal
@@ -173,6 +206,203 @@ declare function evaluateKeySelector(selector: readonly string[], source: Record
173
206
  */
174
207
  declare function applyPatch(spec: PatchSpec<Record<string, unknown>, Record<string, unknown>>, facts: Record<string, unknown>, payload: Record<string, unknown>): void;
175
208
 
209
+ /**
210
+ * Predicate backtest — rule-change impact.
211
+ *
212
+ * Given a recorded sequence of fact-state frames and a proposed replacement
213
+ * for a constraint's `when` predicate, re-score the frames against BOTH the
214
+ * original and the proposed predicate and produce a backtest report: how
215
+ * many frames each matched, plus the per-frame diff (frames that newly
216
+ * match / no longer match). It answers "how many recorded frames would the
217
+ * proposed rule have matched differently" against real recorded history.
218
+ *
219
+ * This is a *static* backtest, not a behavioral simulation — the engine is
220
+ * not re-run. Recorded frames are re-scored against a new predicate; the
221
+ * resulting requirements, resolvers, and downstream fact changes are NOT
222
+ * modeled. Treat the numbers as a divergence scan, not a forecast.
223
+ *
224
+ * Pure module — imports only the predicate runtime. No engine, store, or
225
+ * tracking dependency. Replay walks frames in order; for `$changed`-style
226
+ * predicates each frame is evaluated against the previous frame's facts.
227
+ */
228
+
229
+ /**
230
+ * Upper bound on the number of frames a single {@link replayUnder} call will
231
+ * process. A history file is held entirely in memory; an unbounded array is a
232
+ * denial-of-service surface. A history larger than this should be split or
233
+ * down-sampled before replay.
234
+ */
235
+ declare const MAX_REPLAY_FRAMES = 1000000;
236
+ /** One recorded fact-state frame. */
237
+ interface ReplayFrame<F = Record<string, unknown>> {
238
+ /** Stable identifier — a snapshot id, an index, a session key. */
239
+ id: string | number;
240
+ /** Optional wall-clock time (ms epoch). */
241
+ timestamp?: number;
242
+ /** The fact state at this frame. */
243
+ facts: F;
244
+ }
245
+ interface ReplayUnderOptions<F = Record<string, unknown>> {
246
+ /** Recorded frames, chronological order. */
247
+ frames: readonly ReplayFrame<F>[];
248
+ /** The constraint's current `when` predicate (the baseline). */
249
+ original: FactPredicate<F>;
250
+ /** The proposed replacement `when` predicate. */
251
+ proposed: FactPredicate<F>;
252
+ /** Max diff samples to attach per bucket (default 20). */
253
+ maxSamples?: number;
254
+ /**
255
+ * A fact key identifying the entity a frame belongs to (e.g. `"userId"`,
256
+ * `"sessionId"`). When set, the report also reports distinct-entity counts
257
+ * — how many unique entities matched, not just how many frames. Without it
258
+ * the unit is frames: one fact snapshot, not one user or session.
259
+ */
260
+ entityKey?: string;
261
+ }
262
+ /** A frame where the original and proposed predicate disagree. */
263
+ interface ReplayDiffSample {
264
+ frameId: string | number;
265
+ timestamp?: number;
266
+ /** The fact state at this frame. */
267
+ facts: Record<string, unknown>;
268
+ /** Per-clause breakdown under the original predicate. */
269
+ originalExplain: ClauseResult[];
270
+ /** Per-clause breakdown under the proposed predicate. */
271
+ proposedExplain: ClauseResult[];
272
+ }
273
+ /**
274
+ * The outcome of replaying a recorded history under two predicates — a
275
+ * static backtest of a proposed rule change, not a behavioral simulation.
276
+ */
277
+ interface PredicateBacktestReport {
278
+ /** Total frames evaluated. */
279
+ framesEvaluated: number;
280
+ /**
281
+ * Frames where the original predicate matched (was true). `matchedEntities`
282
+ * is the count of distinct `entityKey` values among matched frames — only
283
+ * populated when {@link ReplayUnderOptions.entityKey} was supplied.
284
+ */
285
+ original: {
286
+ matched: number;
287
+ matchedEntities?: number;
288
+ };
289
+ /** Frames where the proposed predicate matched. */
290
+ proposed: {
291
+ matched: number;
292
+ matchedEntities?: number;
293
+ };
294
+ /** proposed.matched - original.matched. */
295
+ delta: number;
296
+ /** Total count of frames that newly match (original false -> proposed true). */
297
+ newMatchCount: number;
298
+ /** Total count of frames that no longer match (original true -> proposed false). */
299
+ lostMatchCount: number;
300
+ /** Frames where original and proposed agree. */
301
+ unchanged: number;
302
+ /** Sampled new-match frames (capped at maxSamples), with clause explain. */
303
+ newMatches: ReplayDiffSample[];
304
+ /** Sampled lost-match frames (capped at maxSamples), with clause explain. */
305
+ lostMatches: ReplayDiffSample[];
306
+ }
307
+ /**
308
+ * Normalize a parsed-from-JSON history value into a `ReplayFrame[]`.
309
+ *
310
+ * Accepts the three documented history shapes:
311
+ *
312
+ * 1. A bare array of frames: `[{ id, timestamp?, facts }, ...]`
313
+ * 2. An object wrapping them: `{ frames: [{ id, ..., facts }, ...] }`
314
+ * 3. A bare array of fact objects: `[{ phase: "red", ... }, ...]`
315
+ * — each element is wrapped as a frame.
316
+ *
317
+ * Frame ids are kept unambiguous: a frame that supplies its own `id` keeps
318
+ * it; a frame missing an `id` (and every bare-fact frame) gets an
319
+ * **index-derived** id prefixed with `#` (`"#0"`, `"#1"`, …) so a fallback
320
+ * id can never collide with an explicit numeric or string id in a mixed
321
+ * history. This is a pure helper — it **throws** a clear `Error` on bad
322
+ * input and never calls `process.exit`, so library users can catch it.
323
+ *
324
+ * @example
325
+ * ```ts
326
+ * toReplayFrames([{ id: "s1", facts: { phase: "red" } }]);
327
+ * // → [{ id: "s1", facts: { phase: "red" } }]
328
+ * toReplayFrames([{ phase: "red" }, { phase: "green" }]);
329
+ * // → [{ id: "#0", facts: { phase: "red" } }, { id: "#1", facts: { phase: "green" } }]
330
+ * ```
331
+ */
332
+ declare function toReplayFrames(raw: unknown): ReplayFrame[];
333
+ /**
334
+ * Convert a history-manager export (the JSON produced by
335
+ * `system.history.export()`) into a `ReplayFrame[]` ready for
336
+ * {@link replayUnder}.
337
+ *
338
+ * The history manager records a ring buffer of `{ id, timestamp, facts,
339
+ * trigger }` snapshots; `export()` wraps them as `{ version, snapshots,
340
+ * currentIndex }`. Each snapshot's `facts` is the fact state at that point,
341
+ * so the snapshot sequence is exactly a frame stream.
342
+ *
343
+ * Accepts either the parsed export object, the raw JSON string, or a bare
344
+ * array of snapshots. Throws a clear `Error` on bad input.
345
+ *
346
+ * @example
347
+ * ```ts
348
+ * const frames = framesFromHistory(system.history.export());
349
+ * const report = replayUnder({ frames, original, proposed });
350
+ * ```
351
+ */
352
+ declare function framesFromHistory(historyExport: unknown): ReplayFrame[];
353
+ /**
354
+ * Convert an array of `{ id, timestamp?, facts }` snapshots — e.g. the
355
+ * `snapshots` field of a history export, or an array assembled by pushing
356
+ * `system.getSnapshot()` on each reconcile — into a `ReplayFrame[]`.
357
+ *
358
+ * Throws a clear `Error` if the argument is not an array. Each snapshot is
359
+ * normalized through the same {@link toReplayFrames} id logic.
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * const snapshots: typeof history[] = [];
364
+ * system.observe(() => snapshots.push(system.getSnapshot()));
365
+ * // ...later
366
+ * const frames = framesFromSnapshots(snapshots);
367
+ * ```
368
+ */
369
+ declare function framesFromSnapshots(snapshots: unknown): ReplayFrame[];
370
+ /**
371
+ * Replay a recorded fact-frame history through two predicates — the
372
+ * constraint's current `when` and a proposed replacement — and report how
373
+ * their match sets differ.
374
+ *
375
+ * This is a **predicate backtest**: the engine is not re-run. Each recorded
376
+ * frame is statically re-scored against both specs; the previous frame's
377
+ * facts are threaded as `prev` so a replayed effect-`on` predicate using
378
+ * `$changed` still works (for a constraint `when` it is harmless). The
379
+ * report counts matches under each spec and buckets the disagreements into
380
+ * new matches (original false, proposed true) and lost matches (original
381
+ * true, proposed false). Up to `maxSamples` diff frames per bucket carry a
382
+ * per-clause `evaluatePredicateExplained` breakdown for inspection.
383
+ *
384
+ * Both specs are validated up front — a malformed spec throws a clear
385
+ * `[Directive] replayUnder:` error identifying which spec failed, rather
386
+ * than letting a raw `evaluatePredicate` error escape mid-loop.
387
+ *
388
+ * @example
389
+ * ```ts
390
+ * const report = replayUnder({
391
+ * frames: [
392
+ * { id: 0, facts: { phase: "red", elapsed: 10 } },
393
+ * { id: 1, facts: { phase: "red", elapsed: 35 } },
394
+ * ],
395
+ * original: { phase: "red" },
396
+ * proposed: { phase: "red", elapsed: { $gte: 30 } },
397
+ * });
398
+ * // report.original.matched === 2
399
+ * // report.proposed.matched === 1
400
+ * // report.delta === -1
401
+ * // report.lostMatchCount === 1
402
+ * ```
403
+ */
404
+ declare function replayUnder<F = Record<string, unknown>>(options: ReplayUnderOptions<F>): PredicateBacktestReport;
405
+
176
406
  /** Brand symbol for branded types */
177
407
  declare const Brand: unique symbol;
178
408
  /** Branded type - adds a unique brand to a base type */
@@ -1433,4 +1663,4 @@ declare const Backoff: {
1433
1663
  readonly Exponential: "exponential";
1434
1664
  };
1435
1665
 
1436
- export { Backoff, type Branded, type ChainableSchemaType, ClauseResult, CreateSystemOptionsNamed, CreateSystemOptionsSingle, CrossModuleDeps, DefinitionMeta, ErrorBoundaryConfig, type ExtendedSchemaType, FactTemplate, Facts, type ModuleConfig, type ModuleConfigWithDeps, ModuleDef, ModuleHooks, ModuleSchema, ModulesMap, NamespacedSystem, PatchSpec, Plugin, Requirement, RequirementSet, type RequirementTypeStatus, RequirementWithId, SchemaType, type SignalClock, SingleModuleSystem, type TimerFactOpts, type TimerFactState, TraceOption, applyPatch, completeTimer, createModule, createModuleFactory, createRequirementStatusPlugin, createStatusHook, createSystem, createSystemWithStatus, defaultClock, elapsedMs, evaluateKeySelector, evaluatePredicate, evaluatePredicateExplained, evaluateTemplate, extractDeps, extractTemplateKeys, forType, generateRequirementId, initialTimerState, isPredicate, isRequirementType, isTemplate, memoizePredicate, pauseTimer, realClock, registerRepeat, remainingMs, req, resetTimer, resumeTimer, startTimer, t, tickTimer, timerOps, virtualClock };
1666
+ export { Backoff, type Branded, type ChainableSchemaType, ClauseResult, CreateSystemOptionsNamed, CreateSystemOptionsSingle, CrossModuleDeps, DefinitionMeta, ErrorBoundaryConfig, type ExtendedSchemaType, FactPredicate, FactTemplate, Facts, MAX_REPLAY_FRAMES, type ModuleConfig, type ModuleConfigWithDeps, ModuleDef, ModuleHooks, ModuleSchema, ModulesMap, NamespacedSystem, PatchSpec, Plugin, type PredicateBacktestReport, type ReplayDiffSample, type ReplayFrame, type ReplayUnderOptions, Requirement, RequirementSet, type RequirementTypeStatus, RequirementWithId, SchemaType, type SignalClock, SingleModuleSystem, type TimerFactOpts, type TimerFactState, TraceOption, applyPatch, completeTimer, createModule, createModuleFactory, createRequirementStatusPlugin, createStatusHook, createSystem, createSystemWithStatus, defaultClock, elapsedMs, evaluateKeySelector, evaluatePredicate, evaluatePredicateExplained, evaluateTemplate, extractDeps, extractTemplateKeys, forType, framesFromHistory, framesFromSnapshots, generateRequirementId, initialTimerState, isPredicate, isRequirementType, isTemplate, memoizePredicate, pauseTimer, realClock, registerRepeat, remainingMs, replayUnder, req, resetTimer, resumeTimer, startTimer, t, tickTimer, timerOps, toReplayFrames, validatePredicate, virtualClock };
package/dist/index.js CHANGED
@@ -1,2 +1,5 @@
1
- import {a as a$1}from'./chunk-HAF5JCET.js';export{a as createSystem}from'./chunk-HAF5JCET.js';export{l as DirectiveError,y as RequirementSet,j as applyPatch,i as evaluateKeySelector,c as evaluatePredicate,d as evaluatePredicateExplained,g as evaluateTemplate,f as extractDeps,h as extractTemplateKeys,x as forType,u as generateRequirementId,r as isNamespacedSystem,a as isPredicate,w as isRequirementType,q as isSingleModuleSystem,b as isTemplate,e as memoizePredicate,v as req,o as typedConstraint,p as typedResolver}from'./chunk-YCCQ73C6.js';import {a}from'./chunk-EH2Q754B.js';export{h as diffSnapshots,i as isSignedSnapshot,f as isSnapshotExpired,d as shallowEqual,j as signSnapshot,g as validateSnapshot,k as verifySnapshotSignature}from'./chunk-M5KZXNZX.js';function h(e=[],n,t,i,s,l,o){return {_type:void 0,_validators:e,_typeName:n,_default:t,_transform:i,_description:s,_refinements:l,_meta:o,validate(p){return h([...e,p],n,t,i,s,l,o)}}}function c(e,n,t,i,s,l,o){return {...h(e,n,t,i,s,l,o),default(r){return c(e,n,r,i,s,l,o)},transform(r){return c([],n,void 0,u=>{let d=i?i(u):u;return r(d)},s,void 0,o)},brand(){return c(e,`Branded<${n}>`,t,i,s,l,o)},describe(r){return c(e,n,t,i,r,l,o)},refine(r,a){let u=[...l??[],{predicate:r,message:a}];return c([...e,r],n,t,i,s,u,o)},nullable(){return c([r=>r===null||e.every(a=>a(r))],`${n} | null`,t,i,s,void 0,o)},optional(){return c([r=>r===void 0||e.every(a=>a(r))],`${n} | undefined`,t,i,s,void 0,o)},meta(r){return c(e,n,t,i,s,l,r)}}}var ae=((...e)=>{if(e.length===0)return c([],"union");let n=e.map(t=>t._typeName??"unknown");return c([t=>e.some(i=>i._validators.every(s=>s(t)))],n.join(" | "))}),oe={string(){let e=(n,t,i,s,l,o)=>({...c(n,"string",t,i,s,l,o),minLength(r){return e([...n,a=>a.length>=r],t,i,s,l,o)},maxLength(r){return e([...n,a=>a.length<=r],t,i,s,l,o)},pattern(r){return e([...n,a=>r.test(a)],t,i,s,l,o)},default(r){return e(n,r,i,s,l,o)},describe(r){return e(n,t,i,r,l,o)},refine(r,a){let u=[...l??[],{predicate:r,message:a}];return e([...n,r],t,i,s,u,o)},meta(r){return e(n,t,i,s,l,r)}});return e([n=>typeof n=="string"])},number(){let e=(n,t,i,s,l,o)=>({...c(n,"number",t,i,s,l,o),min(r){return e([...n,a=>a>=r],t,i,s,l,o)},max(r){return e([...n,a=>a<=r],t,i,s,l,o)},default(r){return e(n,r,i,s,l,o)},describe(r){return e(n,t,i,r,l,o)},refine(r,a){let u=[...l??[],{predicate:r,message:a}];return e([...n,r],t,i,s,u,o)},meta(r){return e(n,t,i,s,l,r)}});return e([n=>typeof n=="number"])},boolean(){return c([e=>typeof e=="boolean"],"boolean")},array(){let e=(n,t,i,s,l,o)=>{let p=c(n,"array",i,void 0,s,void 0,o),r=l??{value:-1};return {...p,get _lastFailedIndex(){return r.value},set _lastFailedIndex(u){r.value=u;},of(u){let d={value:-1};return e([...n,m=>{for(let g=0;g<m.length;g++)if(!u._validators.every(F=>F(m[g])))return d.value=g,false;return true}],u,i,s,d,o)},nonEmpty(){return e([...n,u=>u.length>0],t,i,s,r,o)},maxLength(u){return e([...n,d=>d.length<=u],t,i,s,r,o)},minLength(u){return e([...n,d=>d.length>=u],t,i,s,r,o)},default(u){return e(n,t,u,s,r,o)},describe(u){return e(n,t,i,u,r,o)},meta(u){return e(n,t,i,s,r,u)}}};return e([n=>Array.isArray(n)])},object(){let e=(n,t,i,s)=>({...c(n,"object",t,void 0,i,void 0,s),shape(o){return e([...n,p=>{for(let[r,a]of Object.entries(o)){let u=p[r],d=a;if(d&&!d._validators.every(m=>m(u)))return false}return true}],t,i,s)},nonNull(){return e([...n,o=>o!=null],t,i,s)},hasKeys(...o){return e([...n,p=>o.every(r=>r in p)],t,i,s)},default(o){return e(n,o,i,s)},describe(o){return e(n,t,o,s)},meta(o){return e(n,t,i,o)}});return e([n=>typeof n=="object"&&n!==null&&!Array.isArray(n)])},enum(...e){a&&e.length===0&&console.warn("[Directive] t.enum() called with no values - this will reject all strings");let n=new Set(e);return c([t=>typeof t=="string"&&n.has(t)],`enum(${e.join("|")})`)},literal(e){return c([n=>n===e],`literal(${String(e)})`)},nullable(e){let n=e._typeName??"unknown";return h([t=>t===null?true:e._validators.every(i=>i(t))],`${n} | null`)},optional(e){let n=e._typeName??"unknown";return h([t=>t===void 0?true:e._validators.every(i=>i(t))],`${n} | undefined`)},union:ae,record(e){let n=e._typeName??"unknown";return c([t=>typeof t!="object"||t===null||Array.isArray(t)?false:Object.values(t).every(i=>e._validators.every(s=>s(i)))],`Record<string, ${n}>`)},tuple(...e){a&&e.length===0&&console.warn("[Directive] t.tuple() called with no types - this will only accept empty arrays");let n=e.map(t=>t._typeName??"unknown");return c([t=>!Array.isArray(t)||t.length!==e.length?false:e.every((i,s)=>i._validators.every(l=>l(t[s])))],`[${n.join(", ")}]`)},date(){return c([e=>e instanceof Date&&!Number.isNaN(e.getTime())],"Date")},uuid(){let e=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;return c([n=>typeof n=="string"&&e.test(n)],"uuid")},email(){let e=/^[^\s@]+@[^\s@]+\.[^\s@]+$/;return c([n=>typeof n=="string"&&e.test(n)],"email")},url(){return c([e=>{if(typeof e!="string")return false;try{return new URL(e),!0}catch{return false}}],"url")},bigint(){return c([e=>typeof e=="bigint"],"bigint")},any(){return c([],"any")},unknown(){return c([],"unknown")}};function ue(e){if(!e||typeof e!="string"){console.warn("[Directive] Module ID must be a non-empty string");return}/^(__[a-z][a-z0-9_-]*|[a-z][a-z0-9-]*)$/i.test(e)||console.warn(`[Directive] Module ID "${e}" should follow kebab-case convention (e.g., "my-module")`);}function b(e,n,t,i,s){for(let l of e)n.has(l)||console.warn(`[Directive] ${t} "${l}" not declared in ${i}`);for(let l of n)e.has(l)||console.warn(`[Directive] ${i}["${l}"] ${s}`);}function le(e,n){e.length===0&&console.warn("[Directive] history.snapshotEvents is an empty array \u2014 no events will create history snapshots. Omit history.snapshotEvents entirely to snapshot all events, or list specific events.");let t=new Set(Object.keys(n));for(let i of e)t.has(i)||console.warn(`[Directive] history.snapshotEvents entry "${i}" not declared in schema.events. Available events: ${[...t].join(", ")||"(none)"}`);}function ce(e,n){let t=new Set(Object.keys(n));for(let[i,s]of Object.entries(e)){let l=s;typeof l.requirement=="string"&&!t.has(l.requirement)&&console.warn(`[Directive] Resolver "${i}" references unknown requirement type "${l.requirement}". Available types: ${[...t].join(", ")||"(none)"}`);}}function de(e,n){ue(e),n.schema?n.schema.facts||console.warn("[Directive] Module schema.facts is required"):console.warn("[Directive] Module schema is required"),b(new Set(Object.keys(n.derive??{})),new Set(Object.keys(n.schema?.derivations??{})),"Derivation","schema.derivations","has no matching implementation in derive"),b(new Set(Object.keys(n.events??{})),new Set(Object.keys(n.schema?.events??{})),"Event","schema.events","has no matching handler in events"),n.history?.snapshotEvents&&le(n.history.snapshotEvents,n.schema?.events??{}),n.resolvers&&n.schema?.requirements&&ce(n.resolvers,n.schema.requirements);}function v(e,n){a&&de(e,n);let t="crossModuleDeps"in n?n.crossModuleDeps:void 0;return {id:e,schema:n.schema,init:n.init,derive:n.derive??{},events:n.events??{},effects:n.effects,constraints:n.constraints,resolvers:n.resolvers,hooks:n.hooks,meta:n.meta,history:n.history,crossModuleDeps:t}}function pe(e){return n=>v(n,e)}function M(){let e={pending:new Map,inflight:new Map,failed:new Map,errors:new Map,listeners:new Set};function n(){for(let r of e.listeners)r();}function t(r,a){let u=r.get(a);return u||(u=new Set,r.set(a,u)),u}function i(r){let a=e.pending.get(r)??new Set,u=e.inflight.get(r)??new Set,d=e.failed.get(r)??new Set,m=e.errors.get(r)??null;return {pending:a.size,inflight:u.size,failed:d.size,isLoading:a.size>0||u.size>0,hasError:d.size>0,lastError:m}}function s(){let r=new Set([...e.pending.keys(),...e.inflight.keys(),...e.failed.keys()]),a=new Map;for(let u of r)a.set(u,i(u));return a}function l(r){return e.listeners.add(r),()=>e.listeners.delete(r)}function o(){e.pending.clear(),e.inflight.clear(),e.failed.clear(),e.errors.clear(),n();}return {plugin:{name:"requirement-status",onRequirementCreated(r){let a=r.requirement.type;t(e.pending,a).add(r.id),e.failed.get(a)?.delete(r.id),n();},onResolverStart(r,a){let u=a.requirement.type;e.pending.get(u)?.delete(a.id),t(e.inflight,u).add(a.id),n();},onResolverComplete(r,a){let u=a.requirement.type;e.inflight.get(u)?.delete(a.id),e.pending.get(u)?.delete(a.id),n();},onResolverError(r,a,u){let d=a.requirement.type;e.inflight.get(d)?.delete(a.id),t(e.failed,d).add(a.id),e.errors.set(d,u instanceof Error?u:new Error(String(u))),n();},onResolverCancel(r,a){let u=a.requirement.type;e.pending.get(u)?.delete(a.id),e.inflight.get(u)?.delete(a.id),n();},onRequirementMet(r){let a=r.requirement.type;e.pending.get(a)?.delete(r.id),e.inflight.get(a)?.delete(r.id),n();}},getStatus:i,getAllStatus:s,subscribe:l,reset:o}}function me(e){return n=>e.getStatus(n)}function ye(e){let n=M(),i=[...e.plugins??[],n.plugin];return {system:a$1({module:e.module,plugins:i,trace:e.trace,errorBoundary:e.errorBoundary,tickMs:e.tickMs,zeroConfig:e.zeroConfig,initialFacts:e.initialFacts}),statusPlugin:n}}function D(){return {now:()=>Date.now(),setTimeout:(e,n)=>{let t=globalThis.setTimeout(e,n);return ()=>globalThis.clearTimeout(t)}}}function ge(e=0){let n=e,t=0,i=[];return {now:()=>n,setTimeout:(s,l)=>{let o={id:t++,deadlineMs:n+l,cb:s,canceled:false};return i.push(o),()=>{o.canceled=true;}},advanceBy:s=>{let l=n+s;for(;;){let o=i.filter(r=>!r.canceled&&r.deadlineMs<=l).sort((r,a)=>r.deadlineMs!==a.deadlineMs?r.deadlineMs-a.deadlineMs:r.id-a.id);if(o.length===0)break;let p=o[0];n=Math.max(n,p.deadlineMs),p.canceled=true,p.cb();}n=Math.max(n,l);}}}function he(){return D()}function S(){return {startedAtMs:null,pausedDurationMs:0,pausedAtMs:null,status:"idle",repeats:0}}function T(e,n){return e.startedAtMs===null?0:e.status==="paused"&&e.pausedAtMs!==null?Math.max(0,e.pausedAtMs-e.startedAtMs-e.pausedDurationMs):Math.max(0,n-e.startedAtMs-e.pausedDurationMs)}function x(e,n,t){return Math.max(0,t-T(e,n))}function C(e,n){return e.status==="running"||e.status==="paused"?e:{...e,startedAtMs:n,pausedDurationMs:0,pausedAtMs:null,status:"running",repeats:0}}function k(e,n){return e.status!=="running"?e:{...e,pausedAtMs:n,status:"paused"}}function w(e,n){if(e.status!=="paused"||e.pausedAtMs===null)return e;let t=Math.max(0,n-e.pausedAtMs);return {...e,pausedDurationMs:e.pausedDurationMs+t,pausedAtMs:null,status:"running"}}function R(){return S()}function A(e){return {...e,status:"completed"}}function E(e,n){return e.startedAtMs===null||e.status==="paused"?e:{...e,startedAtMs:e.startedAtMs+n,pausedDurationMs:0,pausedAtMs:null,repeats:e.repeats+1}}function j(e,n,t){if(e.status!=="running")return {kind:"no-op"};let i=T(e,n);return t.mode==="up"?{kind:"no-op"}:t.mode==="repeat"?i>=t.ms?{kind:"repeat"}:{kind:"no-op"}:i>=t.ms?{kind:"complete"}:{kind:"no-op"}}function Te(e){return {initial:S,start:C,pause:k,resume:w,reset:R,complete:A,registerRepeat:n=>E(n,e.ms),tick:(n,t)=>j(n,t,e),elapsedMs:T,remainingMs:(n,t)=>x(n,t,e.ms)}}var Re={None:"none",Linear:"linear",Exponential:"exponential"};export{Re as Backoff,A as completeTimer,v as createModule,pe as createModuleFactory,M as createRequirementStatusPlugin,me as createStatusHook,ye as createSystemWithStatus,he as defaultClock,T as elapsedMs,S as initialTimerState,k as pauseTimer,D as realClock,E as registerRepeat,x as remainingMs,R as resetTimer,w as resumeTimer,C as startTimer,oe as t,j as tickTimer,Te as timerOps,ge as virtualClock};//# sourceMappingURL=index.js.map
1
+ import {a as a$1}from'./chunk-QOK7CHOW.js';export{a as createSystem}from'./chunk-QOK7CHOW.js';import {g,h,f as f$1,c as c$1,d,a as a$2,b}from'./chunk-OVNPYGYJ.js';export{p as DirectiveError,C as RequirementSet,n as applyPatch,m as evaluateKeySelector,g as evaluatePredicate,h as evaluatePredicateExplained,k as evaluateTemplate,j as extractDeps,l as extractTemplateKeys,B as forType,y as generateRequirementId,v as isNamespacedSystem,c as isPredicate,A as isRequirementType,u as isSingleModuleSystem,e as isTemplate,i as memoizePredicate,z as req,s as typedConstraint,t as typedResolver,f as validatePredicate}from'./chunk-OVNPYGYJ.js';import {a,l}from'./chunk-EH2Q754B.js';export{j as diffSnapshots,k as isSignedSnapshot,h as isSnapshotExpired,f as shallowEqual,l as signSnapshot,i as validateSnapshot,m as verifySnapshotSignature}from'./chunk-T6IJUWYR.js';var f=1e6;function I(e,t){try{f$1(e);}catch(r){let i=r instanceof Error?r.message:String(r);throw new Error(`[Directive] replayUnder: the ${t} predicate is invalid \u2014 ${i}`)}if(!c$1(e)){let r=e===null||typeof e!="object"?`${typeof e} \u2014 ${JSON.stringify(e)}`:JSON.stringify(e).slice(0,80);throw new Error(`[Directive] replayUnder: the ${t} predicate is not a valid FactPredicate (got ${r})`)}let n;if(d(e,{operator(r,i){n===void 0&&i.startsWith("$")&&!a$2.has(i)&&(n=i);},strayOperatorKey(r){n===void 0&&!a$2.has(r)&&!b.has(r)&&(n=r);}}),n!==void 0)throw new Error(`[Directive] replayUnder: the ${t} predicate uses an unknown operator "${n}" \u2014 known operators: ${[...a$2].join(", ")}`)}function N(e){if(e&&typeof e=="object"&&!Array.isArray(e)&&Array.isArray(e.snapshots))return W(e);let t=Array.isArray(e)?e:e&&typeof e=="object"&&Array.isArray(e.frames)?e.frames:null;if(!t)throw new Error("[Directive] toReplayFrames: history must be a JSON array of frames, an object with a `frames` array, or a history export with a `snapshots` array");if(t.length>f)throw new Error(`[Directive] toReplayFrames: history has ${t.length} frames, exceeds the MAX_REPLAY_FRAMES limit (${f}) \u2014 split or down-sample the history`);return t.map((n,r)=>{if(n&&typeof n=="object"&&"facts"in n){let i=n,o={id:i.id??`#${r}`,facts:i.facts??{}};return typeof i.timestamp=="number"&&(o.timestamp=i.timestamp),o}return {id:`#${r}`,facts:n??{}}})}function W(e){let t=typeof e=="string"?JSON.parse(e):e;if(Array.isArray(t))return O(t);if(!t||typeof t!="object")throw new Error("[Directive] framesFromHistory: expected a history export object with a `snapshots` array (from system.history.export())");let n=t;if(n.version!==void 0&&n.version!==1)throw new Error(`[Directive] framesFromHistory: unsupported history export version ${JSON.stringify(n.version)} \u2014 expected 1`);if(!Array.isArray(n.snapshots))throw new Error("[Directive] framesFromHistory: expected a history export object with a `snapshots` array (from system.history.export())");return O(n.snapshots)}function O(e){if(!Array.isArray(e))throw new Error("[Directive] framesFromSnapshots: expected an array of fact-state snapshots");if(e.length>f)throw new Error(`[Directive] framesFromSnapshots: history has ${e.length} snapshots, exceeds the MAX_REPLAY_FRAMES limit (${f}) \u2014 split or down-sample the history`);for(let t=0;t<e.length;t++){let n=e[t];if(!n||typeof n!="object"||!("facts"in n))throw new Error(`[Directive] framesFromSnapshots: snapshot at index ${t} is not a { facts, ... } object`)}return N(e)}function we(e){let{frames:t,original:n,proposed:r,entityKey:i}=e,o=e.maxSamples??20,a=o>0?o:0;if(t.length>f)throw new Error(`[Directive] replayUnder: history has ${t.length} frames, exceeds the MAX_REPLAY_FRAMES limit (${f}) \u2014 split or down-sample the history`);I(n,"original"),I(r,"proposed");let p=0,s=0,u=0,l=0,d=0,m=[],y=[],h=i?new Set:void 0,x=i?new Set:void 0,g$1;for(let k of t){let T=k.facts,R=g(n,T,g$1),E=g(r,T,g$1);R&&(p++,h?.add(T[i])),E&&(s++,x?.add(T[i])),R===E?d++:!R&&E?(u++,m.length<a&&m.push(U(k,n,r,g$1))):(l++,y.length<a&&y.push(U(k,n,r,g$1))),g$1=T;}let C={framesEvaluated:t.length,original:{matched:p},proposed:{matched:s},delta:s-p,newMatchCount:u,lostMatchCount:l,unchanged:d,newMatches:m,lostMatches:y};return h&&x&&(C.original.matchedEntities=h.size,C.proposed.matchedEntities=x.size),C}function U(e,t,n,r){let i=e.facts,o={frameId:e.id,facts:i,originalExplain:h(t,i,r),proposedExplain:h(n,i,r)};return e.timestamp!==void 0&&(o.timestamp=e.timestamp),o}function D(e=[],t,n,r,i,o,a){return {_type:void 0,_validators:e,_typeName:t,_default:n,_transform:r,_description:i,_refinements:o,_meta:a,validate(p){return D([...e,p],t,n,r,i,o,a)}}}function c(e,t,n,r,i,o,a){return {...D(e,t,n,r,i,o,a),default(s){return c(e,t,s,r,i,o,a)},transform(s){return c([],t,void 0,l=>{let d=r?r(l):l;return s(d)},i,void 0,a)},brand(){return c(e,`Branded<${t}>`,n,r,i,o,a)},describe(s){return c(e,t,n,r,s,o,a)},refine(s,u){let l=[...o??[],{predicate:s,message:u}];return c([...e,s],t,n,r,i,l,a)},nullable(){return c([s=>s===null||e.every(u=>u(s))],`${t} | null`,n,r,i,void 0,a)},optional(){return c([s=>s===void 0||e.every(u=>u(s))],`${t} | undefined`,n,r,i,void 0,a)},meta(s){return c(e,t,n,r,i,o,s)}}}var xe=((...e)=>{if(e.length===0)return c([],"union");let t=e.map(n=>n._typeName??"unknown");return c([n=>e.some(r=>r._validators.every(i=>i(n)))],t.join(" | "))}),Ce={string(){let e=(t,n,r,i,o,a)=>({...c(t,"string",n,r,i,o,a),minLength(s){return e([...t,u=>u.length>=s],n,r,i,o,a)},maxLength(s){return e([...t,u=>u.length<=s],n,r,i,o,a)},pattern(s){return e([...t,u=>s.test(u)],n,r,i,o,a)},default(s){return e(t,s,r,i,o,a)},describe(s){return e(t,n,r,s,o,a)},refine(s,u){let l=[...o??[],{predicate:s,message:u}];return e([...t,s],n,r,i,l,a)},meta(s){return e(t,n,r,i,o,s)}});return e([t=>typeof t=="string"])},number(){let e=(t,n,r,i,o,a)=>({...c(t,"number",n,r,i,o,a),min(s){return e([...t,u=>u>=s],n,r,i,o,a)},max(s){return e([...t,u=>u<=s],n,r,i,o,a)},default(s){return e(t,s,r,i,o,a)},describe(s){return e(t,n,r,s,o,a)},refine(s,u){let l=[...o??[],{predicate:s,message:u}];return e([...t,s],n,r,i,l,a)},meta(s){return e(t,n,r,i,o,s)}});return e([t=>typeof t=="number"])},boolean(){return c([e=>typeof e=="boolean"],"boolean")},array(){let e=(t,n,r,i,o,a)=>{let p=c(t,"array",r,void 0,i,void 0,a),s=o??{value:-1};return {...p,get _lastFailedIndex(){return s.value},set _lastFailedIndex(l){s.value=l;},of(l){let d={value:-1};return e([...t,m=>{for(let y=0;y<m.length;y++)if(!l._validators.every(h=>h(m[y])))return d.value=y,false;return true}],l,r,i,d,a)},nonEmpty(){return e([...t,l=>l.length>0],n,r,i,s,a)},maxLength(l){return e([...t,d=>d.length<=l],n,r,i,s,a)},minLength(l){return e([...t,d=>d.length>=l],n,r,i,s,a)},default(l){return e(t,n,l,i,s,a)},describe(l){return e(t,n,r,l,s,a)},meta(l){return e(t,n,r,i,s,l)}}};return e([t=>Array.isArray(t)])},object(){let e=(t,n,r,i)=>({...c(t,"object",n,void 0,r,void 0,i),shape(a){return e([...t,p=>{for(let[s,u]of Object.entries(a)){let l=p[s],d=u;if(d&&!d._validators.every(m=>m(l)))return false}return true}],n,r,i)},nonNull(){return e([...t,a=>a!=null],n,r,i)},hasKeys(...a){return e([...t,p=>a.every(s=>s in p)],n,r,i)},default(a){return e(t,a,r,i)},describe(a){return e(t,n,a,i)},meta(a){return e(t,n,r,a)}});return e([t=>typeof t=="object"&&t!==null&&!Array.isArray(t)])},enum(...e){a&&e.length===0&&console.warn("[Directive] t.enum() called with no values - this will reject all strings");let t=new Set(e);return c([n=>typeof n=="string"&&t.has(n)],`enum(${e.join("|")})`)},literal(e){return c([t=>t===e],`literal(${String(e)})`)},nullable(e){let t=e._typeName??"unknown";return D([n=>n===null?true:e._validators.every(r=>r(n))],`${t} | null`)},optional(e){let t=e._typeName??"unknown";return D([n=>n===void 0?true:e._validators.every(r=>r(n))],`${t} | undefined`)},union:xe,record(e){let t=e._typeName??"unknown";return c([n=>typeof n!="object"||n===null||Array.isArray(n)?false:Object.values(n).every(r=>e._validators.every(i=>i(r)))],`Record<string, ${t}>`)},tuple(...e){a&&e.length===0&&console.warn("[Directive] t.tuple() called with no types - this will only accept empty arrays");let t=e.map(n=>n._typeName??"unknown");return c([n=>!Array.isArray(n)||n.length!==e.length?false:e.every((r,i)=>r._validators.every(o=>o(n[i])))],`[${t.join(", ")}]`)},date(){return c([e=>e instanceof Date&&!Number.isNaN(e.getTime())],"Date")},uuid(){let e=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;return c([t=>typeof t=="string"&&e.test(t)],"uuid")},email(){let e=/^[^\s@]+@[^\s@]+\.[^\s@]+$/;return c([t=>typeof t=="string"&&e.test(t)],"email")},url(){return c([e=>{if(typeof e!="string")return false;try{return new URL(e),!0}catch{return false}}],"url")},bigint(){return c([e=>typeof e=="bigint"],"bigint")},any(){return c([],"any")},unknown(){return c([],"unknown")}};function ke(e){if(!e||typeof e!="string"){console.warn("[Directive] Module ID must be a non-empty string");return}/^(__[a-z][a-z0-9_-]*|[a-z][a-z0-9-]*)$/i.test(e)||console.warn(`[Directive] Module ID "${e}" should follow kebab-case convention (e.g., "my-module")`);}function K(e,t,n,r,i){for(let o of e)t.has(o)||console.warn(`[Directive] ${n} "${o}" not declared in ${r}`);for(let o of t)e.has(o)||console.warn(`[Directive] ${r}["${o}"] ${i}`);}function Re(e,t){e.length===0&&console.warn("[Directive] history.snapshotEvents is an empty array \u2014 no events will create history snapshots. Omit history.snapshotEvents entirely to snapshot all events, or list specific events.");let n=new Set(Object.keys(t));for(let r of e)n.has(r)||console.warn(`[Directive] history.snapshotEvents entry "${r}" not declared in schema.events. Available events: ${[...n].join(", ")||"(none)"}`);}function Ee(e,t){let n=new Set(Object.keys(t));for(let[r,i]of Object.entries(e)){let o=i;typeof o.requirement=="string"&&!n.has(o.requirement)&&console.warn(`[Directive] Resolver "${r}" references unknown requirement type "${o.requirement}". Available types: ${[...n].join(", ")||"(none)"}`);}}function Ae(e,t){let n=t.schema?.facts??{},r=Object.keys(n);if(r.length===0)return;let i=new Set(["self","prev","current"]),o="crossModuleDeps"in t&&t.crossModuleDeps?Object.keys(t.crossModuleDeps):[];for(let a of o)i.add(a);for(let a of r)if(i.has(a))throw new Error(`[Directive] module '${e}': fact key '${a}' conflicts with a reserved namespace pivot or evaluation alias (self / prev / current / a crossModuleDep namespace). Three fixes:
2
+ 1. Rename the fact (e.g. ${a}_)
3
+ 2. Remove '${a}' from this module's crossModuleDeps if it's not actually needed
4
+ 3. Move the fact under a wrapping namespace (t.object({ inner: ... }))`)}function Fe(e,t){let n=t.constraints;if(n)for(let[r,i]of Object.entries(n)){let o=i?.owns;if(o){for(let a of o)if(l.has(a)||a.startsWith("$"))throw new Error(`[Directive] module '${e}' constraint '${r}': owns key '${a}' is reserved (BLOCKED_PROPS or $-prefixed)`)}}}function je(e,t){ke(e),t.schema?t.schema.facts||console.warn("[Directive] Module schema.facts is required"):console.warn("[Directive] Module schema is required"),K(new Set(Object.keys(t.derive??{})),new Set(Object.keys(t.schema?.derivations??{})),"Derivation","schema.derivations","has no matching implementation in derive"),K(new Set(Object.keys(t.events??{})),new Set(Object.keys(t.schema?.events??{})),"Event","schema.events","has no matching handler in events"),t.history?.snapshotEvents&&Re(t.history.snapshotEvents,t.schema?.events??{}),t.resolvers&&t.schema?.requirements&&Ee(t.resolvers,t.schema.requirements);}function L(e,t){Ae(e,t),Fe(e,t),a&&je(e,t);let n="crossModuleDeps"in t?t.crossModuleDeps:void 0;return {id:e,schema:t.schema,init:t.init,derive:t.derive??{},events:t.events??{},effects:t.effects,constraints:t.constraints,resolvers:t.resolvers,hooks:t.hooks,meta:t.meta,history:t.history,crossModuleDeps:n}}function Oe(e){return t=>L(t,e)}function P(){let e={pending:new Map,inflight:new Map,failed:new Map,errors:new Map,listeners:new Set};function t(){for(let s of e.listeners)s();}function n(s,u){let l=s.get(u);return l||(l=new Set,s.set(u,l)),l}function r(s){let u=e.pending.get(s)??new Set,l=e.inflight.get(s)??new Set,d=e.failed.get(s)??new Set,m=e.errors.get(s)??null;return {pending:u.size,inflight:l.size,failed:d.size,isLoading:u.size>0||l.size>0,hasError:d.size>0,lastError:m}}function i(){let s=new Set([...e.pending.keys(),...e.inflight.keys(),...e.failed.keys()]),u=new Map;for(let l of s)u.set(l,r(l));return u}function o(s){return e.listeners.add(s),()=>e.listeners.delete(s)}function a(){e.pending.clear(),e.inflight.clear(),e.failed.clear(),e.errors.clear(),t();}return {plugin:{name:"requirement-status",onRequirementCreated(s){let u=s.requirement.type;n(e.pending,u).add(s.id),e.failed.get(u)?.delete(s.id),t();},onResolverStart(s,u){let l=u.requirement.type;e.pending.get(l)?.delete(u.id),n(e.inflight,l).add(u.id),t();},onResolverComplete(s,u){let l=u.requirement.type;e.inflight.get(l)?.delete(u.id),e.pending.get(l)?.delete(u.id),t();},onResolverError(s,u,l){let d=u.requirement.type;e.inflight.get(d)?.delete(u.id),n(e.failed,d).add(u.id),e.errors.set(d,l instanceof Error?l:new Error(String(l))),t();},onResolverCancel(s,u){let l=u.requirement.type;e.pending.get(l)?.delete(u.id),e.inflight.get(l)?.delete(u.id),t();},onRequirementMet(s){let u=s.requirement.type;e.pending.get(u)?.delete(s.id),e.inflight.get(u)?.delete(s.id),t();}},getStatus:r,getAllStatus:i,subscribe:o,reset:a}}function Pe(e){return t=>e.getStatus(t)}function _e(e){let t=P(),r=[...e.plugins??[],t.plugin];return {system:a$1({module:e.module,plugins:r,trace:e.trace,errorBoundary:e.errorBoundary,tickMs:e.tickMs,zeroConfig:e.zeroConfig,initialFacts:e.initialFacts}),statusPlugin:t}}function z(){return {now:()=>Date.now(),setTimeout:(e,t)=>{let n=globalThis.setTimeout(e,t);return ()=>globalThis.clearTimeout(n)}}}function $e(e=0){let t=e,n=0,r=[];return {now:()=>t,setTimeout:(i,o)=>{let a={id:n++,deadlineMs:t+o,cb:i,canceled:false};return r.push(a),()=>{a.canceled=true;}},advanceBy:i=>{let o=t+i;for(;;){let a=r.filter(s=>!s.canceled&&s.deadlineMs<=o).sort((s,u)=>s.deadlineMs!==u.deadlineMs?s.deadlineMs-u.deadlineMs:s.id-u.id);if(a.length===0)break;let p=a[0];t=Math.max(t,p.deadlineMs),p.canceled=true,p.cb();}t=Math.max(t,o);}}}function Be(){return z()}function _(){return {startedAtMs:null,pausedDurationMs:0,pausedAtMs:null,status:"idle",repeats:0}}function w(e,t){return e.startedAtMs===null?0:e.status==="paused"&&e.pausedAtMs!==null?Math.max(0,e.pausedAtMs-e.startedAtMs-e.pausedDurationMs):Math.max(0,t-e.startedAtMs-e.pausedDurationMs)}function H(e,t,n){return Math.max(0,n-w(e,t))}function J(e,t){return e.status==="running"||e.status==="paused"?e:{...e,startedAtMs:t,pausedDurationMs:0,pausedAtMs:null,status:"running",repeats:0}}function X(e,t){return e.status!=="running"?e:{...e,pausedAtMs:t,status:"paused"}}function Y(e,t){if(e.status!=="paused"||e.pausedAtMs===null)return e;let n=Math.max(0,t-e.pausedAtMs);return {...e,pausedDurationMs:e.pausedDurationMs+n,pausedAtMs:null,status:"running"}}function G(){return _()}function Q(e){return {...e,status:"completed"}}function Z(e,t){return e.startedAtMs===null||e.status==="paused"?e:{...e,startedAtMs:e.startedAtMs+t,pausedDurationMs:0,pausedAtMs:null,repeats:e.repeats+1}}function V(e,t,n){if(e.status!=="running")return {kind:"no-op"};let r=w(e,t);return n.mode==="up"?{kind:"no-op"}:n.mode==="repeat"?r>=n.ms?{kind:"repeat"}:{kind:"no-op"}:r>=n.ms?{kind:"complete"}:{kind:"no-op"}}function qe(e){return {initial:_,start:J,pause:X,resume:Y,reset:G,complete:Q,registerRepeat:t=>Z(t,e.ms),tick:(t,n)=>V(t,n,e),elapsedMs:w,remainingMs:(t,n)=>H(t,n,e.ms)}}var Ve={None:"none",Linear:"linear",Exponential:"exponential"};export{Ve as Backoff,f as MAX_REPLAY_FRAMES,Q as completeTimer,L as createModule,Oe as createModuleFactory,P as createRequirementStatusPlugin,Pe as createStatusHook,_e as createSystemWithStatus,Be as defaultClock,w as elapsedMs,W as framesFromHistory,O as framesFromSnapshots,_ as initialTimerState,X as pauseTimer,z as realClock,Z as registerRepeat,H as remainingMs,we as replayUnder,G as resetTimer,Y as resumeTimer,J as startTimer,Ce as t,V as tickTimer,qe as timerOps,N as toReplayFrames,$e as virtualClock};//# sourceMappingURL=index.js.map
2
5
  //# sourceMappingURL=index.js.map