@directive-run/core 1.20.2 → 1.22.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 (82) hide show
  1. package/README.md +33 -0
  2. package/dist/adapter-utils.cjs +1 -1
  3. package/dist/adapter-utils.d.cts +2 -2
  4. package/dist/adapter-utils.d.ts +2 -2
  5. package/dist/adapter-utils.js +1 -1
  6. package/dist/chunk-6NCC6RBC.js +3 -0
  7. package/dist/chunk-6NCC6RBC.js.map +1 -0
  8. package/dist/chunk-6PF2FRBG.js +7 -0
  9. package/dist/chunk-6PF2FRBG.js.map +1 -0
  10. package/dist/{chunk-RWFKUNF7.cjs → chunk-GACC2DMS.cjs} +2 -2
  11. package/dist/{chunk-RWFKUNF7.cjs.map → chunk-GACC2DMS.cjs.map} +1 -1
  12. package/dist/{chunk-4MNQDXH7.cjs → chunk-GBCWXTXW.cjs} +3 -3
  13. package/dist/chunk-GBCWXTXW.cjs.map +1 -0
  14. package/dist/chunk-GKMJ7NMP.cjs +7 -0
  15. package/dist/chunk-GKMJ7NMP.cjs.map +1 -0
  16. package/dist/{chunk-WKCMOU2F.js → chunk-KGTBTGOY.js} +2 -2
  17. package/dist/{chunk-WKCMOU2F.js.map → chunk-KGTBTGOY.js.map} +1 -1
  18. package/dist/{chunk-4QCKAJCX.cjs → chunk-MARZI3EY.cjs} +2 -2
  19. package/dist/{chunk-4QCKAJCX.cjs.map → chunk-MARZI3EY.cjs.map} +1 -1
  20. package/dist/chunk-OAPD3HIG.cjs +16 -0
  21. package/dist/chunk-OAPD3HIG.cjs.map +1 -0
  22. package/dist/chunk-QTY2FXZY.cjs +3 -0
  23. package/dist/chunk-QTY2FXZY.cjs.map +1 -0
  24. package/dist/{chunk-O4GQEV4G.js → chunk-RBF653NR.js} +2 -2
  25. package/dist/{chunk-O4GQEV4G.js.map → chunk-RBF653NR.js.map} +1 -1
  26. package/dist/{chunk-PXRV64PA.js → chunk-SFUVPP4L.js} +3 -3
  27. package/dist/chunk-SFUVPP4L.js.map +1 -0
  28. package/dist/chunk-YJEDX2JX.js +16 -0
  29. package/dist/chunk-YJEDX2JX.js.map +1 -0
  30. package/dist/{index-D_K7eEOF.d.ts → index-BgKC_ZT_.d.ts} +1 -1
  31. package/dist/{index-DApsqJ0h.d.cts → index-DRPkZ8HE.d.cts} +1 -1
  32. package/dist/index.cjs +2 -2
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +47 -43
  35. package/dist/index.d.ts +47 -43
  36. package/dist/index.js +2 -2
  37. package/dist/index.js.map +1 -1
  38. package/dist/internals.cjs +1 -1
  39. package/dist/internals.d.cts +60 -28
  40. package/dist/internals.d.ts +60 -28
  41. package/dist/internals.js +1 -1
  42. package/dist/plugins/index.cjs +2 -2
  43. package/dist/plugins/index.cjs.map +1 -1
  44. package/dist/plugins/index.d.cts +159 -3
  45. package/dist/plugins/index.d.ts +159 -3
  46. package/dist/plugins/index.js +2 -2
  47. package/dist/plugins/index.js.map +1 -1
  48. package/dist/{plugins-C6MxOvot.d.cts → plugins-5Supk7it.d.cts} +174 -43
  49. package/dist/{plugins-C6MxOvot.d.ts → plugins-5Supk7it.d.ts} +174 -43
  50. package/dist/{predicate-C92yT5IR.d.ts → predicate-C9oMO_ny.d.ts} +1 -1
  51. package/dist/{predicate-CV3YJDup.d.cts → predicate-DYb-3Mvl.d.cts} +1 -1
  52. package/dist/system-5FKUBLLV.cjs +2 -0
  53. package/dist/{system-BXCEQBBS.cjs.map → system-5FKUBLLV.cjs.map} +1 -1
  54. package/dist/system-6YWCXQOQ.js +2 -0
  55. package/dist/{system-AWEKWMNI.js.map → system-6YWCXQOQ.js.map} +1 -1
  56. package/dist/testing.cjs +1 -1
  57. package/dist/testing.d.cts +1 -1
  58. package/dist/testing.d.ts +1 -1
  59. package/dist/testing.js +1 -1
  60. package/dist/{utils-BZBBwS5A.d.cts → utils-DY8KTiD6.d.cts} +20 -7
  61. package/dist/{utils-BZBBwS5A.d.ts → utils-DY8KTiD6.d.ts} +20 -7
  62. package/dist/worker.cjs +1 -1
  63. package/dist/worker.d.cts +1 -1
  64. package/dist/worker.d.ts +1 -1
  65. package/dist/worker.js +1 -1
  66. package/package.json +1 -1
  67. package/dist/chunk-3ETCZLAY.js +0 -7
  68. package/dist/chunk-3ETCZLAY.js.map +0 -1
  69. package/dist/chunk-4MNQDXH7.cjs.map +0 -1
  70. package/dist/chunk-CLJMEU2A.js +0 -3
  71. package/dist/chunk-CLJMEU2A.js.map +0 -1
  72. package/dist/chunk-JGPPJV5P.cjs +0 -7
  73. package/dist/chunk-JGPPJV5P.cjs.map +0 -1
  74. package/dist/chunk-MDMMMZUZ.cjs +0 -3
  75. package/dist/chunk-MDMMMZUZ.cjs.map +0 -1
  76. package/dist/chunk-PNB73G3E.cjs +0 -16
  77. package/dist/chunk-PNB73G3E.cjs.map +0 -1
  78. package/dist/chunk-PXRV64PA.js.map +0 -1
  79. package/dist/chunk-QQEXRNAI.js +0 -16
  80. package/dist/chunk-QQEXRNAI.js.map +0 -1
  81. package/dist/system-AWEKWMNI.js +0 -2
  82. package/dist/system-BXCEQBBS.cjs +0 -2
@@ -568,26 +568,29 @@ interface ConstraintDef<S extends Schema, R extends Requirement = Requirement> {
568
568
  /** Timeout for async constraints (ms) */
569
569
  timeout?: number;
570
570
  /**
571
- * Fact keys whose **value the resolver compare-and-swaps**. Writes to
572
- * these facts land only if they still hold the snapshot value taken at
573
- * resolver dispatch; otherwise the write is dropped and the resolver
574
- * aborted.
575
- *
576
- * This is value-based per-fact compare-and-swap with one-shot
577
- * fact-level poisoning not a lock, not document versioning. Writes
578
- * to facts not listed always land; `when()` is not consulted. Omit for
579
- * no binding (default). Ignored on async constraints.
571
+ * Fact keys this resolver **aborts on** when they change mid-flight.
572
+ * The engine snapshots their values at resolver dispatch; if any of
573
+ * them changes before the resolver writes, the resolver's writes are
574
+ * dropped and the resolver aborted.
575
+ *
576
+ * Reads aloud as "abort on changes to these facts." This is the
577
+ * opposite shape of a lock the resolver yields to whoever wrote
578
+ * first; it does NOT prevent other writers. Value-based per-fact
579
+ * compare-and-swap with one-shot fact-level poisoning, not document
580
+ * versioning. Writes to facts not listed always land; `when()` is not
581
+ * consulted. Omit for no binding (default). Ignored on async
582
+ * constraints.
580
583
  *
581
584
  * @example
582
585
  * ```ts
583
586
  * executeAction: {
584
587
  * when: (f) => f.status === 'mutating',
585
588
  * require: { type: 'EXECUTE_ACTION' },
586
- * owns: ['status'], // the resolver owns `status`
589
+ * abortOn: ['status'], // abort if `status` changes mid-flight
587
590
  * }
588
591
  * ```
589
592
  */
590
- owns?: readonly string[];
593
+ abortOn?: readonly string[];
591
594
  /**
592
595
  * Constraint IDs whose resolvers must complete before this constraint is evaluated.
593
596
  * If a dependency's `when()` returns false (no requirements), this constraint proceeds.
@@ -724,8 +727,8 @@ type EffectsDef<S extends Schema> = Record<string, EffectDef<S>>;
724
727
  *
725
728
  * The "hook-as-bridge" pattern — a `useEffect` that owns an external
726
729
  * subscription, maps incoming payloads, and dispatches `sys.events.X()` —
727
- * shows up in 7+ call sites across the Sizls workspace (Minglingo's
728
- * `useActiveRoundSystem`, `useBattleRoyaleSystem`, `eventClaims.realtime.ts`,
730
+ * shows up in 7+ call sites in the production app we dogfood Directive
731
+ * on (multiple realtime hooks plus a per-event-stream realtime adapter,
729
732
  * etc.). Each site re-derives the lifecycle plumbing.
730
733
  *
731
734
  * A `source` declares that plumbing as a first-class module field. The
@@ -813,6 +816,18 @@ type EffectsDef<S extends Schema> = Record<string, EffectDef<S>>;
813
816
  * an external stream).
814
817
  */
815
818
  type SourceUnsubscribe = () => void | Promise<void>;
819
+ /**
820
+ * Why a source publish was rejected. Mirrored across the three
821
+ * surfaces that report drops:
822
+ *
823
+ * - `SourceInspectionRow.lastDropReason` (operator-facing, on inspect())
824
+ * - `Plugin.onSourceDrop` (plugin hook)
825
+ * - `ObservationEvent` `source.drop` variant (system.observe())
826
+ *
827
+ * Centralizing the union here keeps the three from drifting when a
828
+ * new drop path is added to the engine.
829
+ */
830
+ type SourceDropReason = "post-destroy" | "post-stop" | "blocked-event-name" | "invalid-event-name" | "coalesced";
816
831
  /**
817
832
  * Typed event dispatcher passed to a source's `attach`. Calls into the same
818
833
  * dispatch queue used by `system.events.X(payload)`.
@@ -966,6 +981,24 @@ interface SourceDef {
966
981
  * 0009 documents the full DO-eviction recipe.
967
982
  */
968
983
  onEvict?: () => void | Promise<void>;
984
+ /**
985
+ * Per-source lifecycle timeout in milliseconds. Caps how long the
986
+ * manager waits for THIS source's `unsubscribe()` or `onEvict()`
987
+ * during teardown / eviction before declaring it hung and moving on.
988
+ *
989
+ * Defaults to 5000ms — comfortable for healthy transports, short
990
+ * enough for ops to recognize a hang. Override per source for
991
+ * legitimate long-tail teardowns:
992
+ *
993
+ * - Supabase channel that flushes a backlog before closing → 15000
994
+ * - OpenTelemetry batch span exporter draining a queue → 10000
995
+ * - Cloudflare DO storage flush awaiting D1 commit → 8000
996
+ *
997
+ * Sources that timeout still have their underlying work continue in
998
+ * the background — the manager just unblocks the rest of teardown.
999
+ * Setting this to `Infinity` disables the cap for this source only.
1000
+ */
1001
+ evictTimeoutMs?: number;
969
1002
  }
970
1003
  /**
971
1004
  * Map of source definitions, keyed by source name. Collision rules match
@@ -2061,7 +2094,7 @@ interface ModuleHooks<M extends ModuleSchema> {
2061
2094
  *
2062
2095
  * @param error - The error the resolver threw (already normalized to `Error`).
2063
2096
  * @param requirement - The requirement object that the failing resolver was handling.
2064
- * @param ctx - Hook context, including a typed snapshot of this module's facts.
2097
+ * @param context - Hook context, including a typed snapshot of this module's facts.
2065
2098
  */
2066
2099
  onResolverError?: (error: Error, requirement: {
2067
2100
  type: string;
@@ -2142,12 +2175,13 @@ interface TypedConstraintDef<M extends ModuleSchema> {
2142
2175
  /** Timeout for async constraints (ms) */
2143
2176
  timeout?: number;
2144
2177
  /**
2145
- * Fact keys whose **value the resolver compare-and-swaps**. Writes to
2146
- * these facts land only if they still hold the snapshot value taken at
2147
- * resolver dispatch; otherwise the write is dropped and the resolver
2148
- * aborted. Omit for no binding (default). Ignored on async constraints.
2178
+ * Fact keys this resolver aborts on when they change mid-flight. The
2179
+ * engine snapshots their values at resolver dispatch; if any of them
2180
+ * changes before the resolver writes, the resolver's writes are
2181
+ * dropped and the resolver aborted. Omit for no binding (default).
2182
+ * Ignored on async constraints.
2149
2183
  */
2150
- owns?: readonly string[];
2184
+ abortOn?: readonly string[];
2151
2185
  /**
2152
2186
  * Constraint IDs whose resolvers must complete before this constraint is evaluated.
2153
2187
  * If a dependency's `when()` returns false (no requirements), this constraint proceeds.
@@ -2193,12 +2227,13 @@ interface CrossModuleConstraintDef<M extends ModuleSchema, Deps extends CrossMod
2193
2227
  /** Timeout for async constraints (ms) */
2194
2228
  timeout?: number;
2195
2229
  /**
2196
- * Fact keys whose **value the resolver compare-and-swaps**. Writes to
2197
- * these facts land only if they still hold the snapshot value taken at
2198
- * resolver dispatch; otherwise the write is dropped and the resolver
2199
- * aborted. Omit for no binding (default). Ignored on async constraints.
2230
+ * Fact keys this resolver aborts on when they change mid-flight. The
2231
+ * engine snapshots their values at resolver dispatch; if any of them
2232
+ * changes before the resolver writes, the resolver's writes are
2233
+ * dropped and the resolver aborted. Omit for no binding (default).
2234
+ * Ignored on async constraints.
2200
2235
  */
2201
- owns?: readonly string[];
2236
+ abortOn?: readonly string[];
2202
2237
  /**
2203
2238
  * Constraint IDs whose resolvers must complete before this constraint is evaluated.
2204
2239
  * If a dependency's `when()` returns false (no requirements), this constraint proceeds.
@@ -2386,10 +2421,6 @@ interface ModuleDef<M extends ModuleSchema = ModuleSchema> {
2386
2421
  crossModuleDeps?: CrossModuleDeps;
2387
2422
  }
2388
2423
 
2389
- /**
2390
- * System Types - Type definitions for the system
2391
- */
2392
-
2393
2424
  /**
2394
2425
  * Derive accessor from module schema.
2395
2426
  */
@@ -2424,6 +2455,35 @@ interface HistoryConfig {
2424
2455
  maxSnapshots?: number;
2425
2456
  /** Only snapshot events from these modules. Omit to snapshot all modules. Multi-module only. */
2426
2457
  snapshotModules?: string[];
2458
+ /**
2459
+ * Optional transform applied to the facts snapshot BEFORE it's
2460
+ * cloned into the ring buffer. The default (`undefined`) stores
2461
+ * facts verbatim — including any PII a source published into a
2462
+ * fact since the last snapshot.
2463
+ *
2464
+ * Wire a redactor to strip PII from the ring buffer (and from
2465
+ * `export()` payloads) for GDPR Art.17 erasure / SOC2 audit hygiene.
2466
+ * Pair with `createFactPIIGuardrail` on the input boundary for
2467
+ * end-to-end coverage — the guardrail redacts on writes,
2468
+ * `redactSnapshot` redacts whatever still escapes into history.
2469
+ *
2470
+ * Throws inside the redactor are caught and the snapshot falls
2471
+ * back to the raw facts with a structured `console.warn`; the
2472
+ * redactor must be defensive (return a safe fallback rather than
2473
+ * throwing) if redaction is load-bearing for compliance.
2474
+ *
2475
+ * @example
2476
+ * ```ts
2477
+ * createSystem({
2478
+ * module,
2479
+ * history: {
2480
+ * maxSnapshots: 100,
2481
+ * redactSnapshot: (facts) => ({ ...facts, email: "[REDACTED]" }),
2482
+ * },
2483
+ * });
2484
+ * ```
2485
+ */
2486
+ redactSnapshot?: (facts: Record<string, unknown>) => Record<string, unknown>;
2427
2487
  }
2428
2488
  /** History option: boolean shorthand or full config (presence implies enabled) */
2429
2489
  type HistoryOption = boolean | HistoryConfig;
@@ -2589,16 +2649,17 @@ interface SystemInspection {
2589
2649
  */
2590
2650
  whenSpec?: FactPredicate<Record<string, unknown>>;
2591
2651
  /**
2592
- * Owned-fact list for RFC-0003 binding. Populated from the
2593
- * constraint definition's `owns:` field. Exposed for `doctor.checkOwns()`
2594
- * so it can flag candidates that would race or shadow these writes.
2595
- * Absent when the constraint declares no `owns`.
2652
+ * Abort-binding fact list for RFC-0003 constraint binding. Populated
2653
+ * from the constraint definition's `abortOn:` field. Exposed for
2654
+ * `doctor.checkAbortOn()` so it can flag candidates that would race
2655
+ * or shadow these writes. Absent when the constraint declares no
2656
+ * `abortOn`.
2596
2657
  */
2597
- readonly owns?: readonly string[];
2658
+ readonly abortOn?: readonly string[];
2598
2659
  /**
2599
2660
  * Fact paths the constraint `bind:`s to. v2 promise — the runtime
2600
2661
  * does not yet emit a `bind` field on inspect snapshots, but the
2601
- * type slot is reserved so `doctor.checkOwns()` is stable across
2662
+ * type slot is reserved so `doctor.checkAbortOn()` is stable across
2602
2663
  * the rollout. (F1)
2603
2664
  */
2604
2665
  readonly bind?: readonly string[];
@@ -2664,7 +2725,7 @@ interface SystemInspection {
2664
2725
  * - `"coalesced"` — manager debounced a same-event-name publish
2665
2726
  * when `SourceDef.coalesce === "lastWriteWins"`
2666
2727
  */
2667
- lastDropReason: "post-destroy" | "post-stop" | "blocked-event-name" | "invalid-event-name" | "coalesced" | null;
2728
+ lastDropReason: SourceDropReason | null;
2668
2729
  /** Wall-clock ms of the most recent rejected publish, or `null`. */
2669
2730
  lastDropAt: number | null;
2670
2731
  /** Total attach + cleanup errors since the last attachAll. */
@@ -3035,6 +3096,26 @@ type ObservationEvent = {
3035
3096
  type: "constraint.error";
3036
3097
  id: string;
3037
3098
  error: unknown;
3099
+ }
3100
+ /**
3101
+ * Fired when the engine silently disables a constraint's `abortOn:`
3102
+ * binding because the constraint is async (declared `async: true` OR
3103
+ * runtime-promoted because its `when()` returned a Promise). The
3104
+ * dev-mode `console.warn` is the human-facing signal; this event is
3105
+ * the SIEM-facing one. Without it, a production constraint loses its
3106
+ * clobber-protection with no plugin / observer trail.
3107
+ *
3108
+ * - `reason: "async-declared"` — the constraint def has `async: true`.
3109
+ * The author opted in; the warning + event are advisory.
3110
+ * - `reason: "async-promoted"` — the constraint's `when()` returned
3111
+ * a Promise at runtime. The author probably did not realize. This
3112
+ * is the more dangerous case — the binding silently disables and
3113
+ * the clobber check no-ops.
3114
+ */
3115
+ | {
3116
+ type: "constraint.binding.disabled";
3117
+ id: string;
3118
+ reason: "async-declared" | "async-promoted";
3038
3119
  } | {
3039
3120
  type: "requirement.created";
3040
3121
  id: string;
@@ -3062,7 +3143,7 @@ type ObservationEvent = {
3062
3143
  error: unknown;
3063
3144
  } | {
3064
3145
  /**
3065
- * A real per-write rejection. A bound resolver's owned-fact write was
3146
+ * A real per-write rejection. A bound resolver's abort-bound write was
3066
3147
  * dropped because the fact was changed by something outside the
3067
3148
  * resolver between the resolver's baseline and its next write (RFC-0003
3068
3149
  * optimistic-concurrency check). `reason` keeps the observation protocol
@@ -3136,6 +3217,22 @@ type ObservationEvent = {
3136
3217
  moduleId: string;
3137
3218
  eventName: string;
3138
3219
  }
3220
+ /**
3221
+ * Engine- or manager-rejected publish. Pairs with `source.publish`
3222
+ * so observers see both halves of the publish path without polling
3223
+ * `inspect().sources[i].dropCount`. `reason` mirrors what the inspect
3224
+ * row records:
3225
+ * - `"post-destroy"` / `"post-stop"` — leaked transport firing after teardown
3226
+ * - `"blocked-event-name"` / `"invalid-event-name"` — engine guard probe
3227
+ * - `"coalesced"` — manager debounced a same-event publish within one microtask
3228
+ */
3229
+ | {
3230
+ type: "source.drop";
3231
+ id: string;
3232
+ moduleId: string;
3233
+ eventName: string;
3234
+ reason: SourceDropReason;
3235
+ }
3139
3236
  /** Source detached at `system.stop()` (reverse-registration order). */
3140
3237
  | {
3141
3238
  type: "source.detach";
@@ -3452,10 +3549,6 @@ interface SystemConfig<M extends ModuleSchema = ModuleSchema> {
3452
3549
  cloud?: boolean | string;
3453
3550
  }
3454
3551
 
3455
- /**
3456
- * Plugin Types - Type definitions for plugins
3457
- */
3458
-
3459
3552
  /** Reconcile result */
3460
3553
  interface ReconcileResult {
3461
3554
  unmet: RequirementWithId[];
@@ -3572,6 +3665,27 @@ interface Plugin<M extends ModuleSchema = ModuleSchema> {
3572
3665
  * @param error - The error that was thrown
3573
3666
  */
3574
3667
  onConstraintError?: (id: string, error: unknown) => void;
3668
+ /**
3669
+ * Called when the engine silently disables a constraint's `abortOn:`
3670
+ * binding because the constraint is async. Pairs with the dev-mode
3671
+ * `console.warn` for SIEM-side visibility — without this signal, a
3672
+ * production constraint loses its clobber-protection with no
3673
+ * plugin / observer trail.
3674
+ *
3675
+ * - `"async-declared"` — the constraint def has `async: true`. The
3676
+ * author opted in; treat as advisory.
3677
+ * - `"async-promoted"` — the constraint's `when()` returned a Promise
3678
+ * at runtime, even though `async: true` was not set. The author
3679
+ * probably did not realize. This is the dangerous case — escalate.
3680
+ *
3681
+ * Fired at most once per `getConstraintBinding` lookup; deduping
3682
+ * across reconcile ticks is the consumer's responsibility (the
3683
+ * audit-ledger plugin does this with a per-id sticky bit).
3684
+ *
3685
+ * @param id - The constraint ID whose binding was disabled
3686
+ * @param reason - Whether the async state was author-declared or runtime-promoted
3687
+ */
3688
+ onConstraintBindingDisabled?: (id: string, reason: "async-declared" | "async-promoted") => void;
3575
3689
  /**
3576
3690
  * Called when a new requirement is created by a constraint.
3577
3691
  * @param req - The requirement with its computed ID
@@ -3624,8 +3738,9 @@ interface Plugin<M extends ModuleSchema = ModuleSchema> {
3624
3738
  /**
3625
3739
  * Called when a resolver's write is rejected by the runtime. The only
3626
3740
  * `reason` today is `"clobbered"`: a bound resolver (RFC-0003) dropped a
3627
- * write to an owned fact because the fact was changed by something outside
3628
- * the resolver between the resolver's baseline and its next write the
3741
+ * write to an abort-bound fact (one listed in the constraint's
3742
+ * `abortOn:`) because the fact was changed by something outside the
3743
+ * resolver between the resolver's baseline and its next write — the
3629
3744
  * resolver's `AbortController` is aborted in the same step. See
3630
3745
  * {@link createBoundFacts} for the per-fact optimistic-concurrency model.
3631
3746
  * `reason` keeps the hook backend-neutral.
@@ -3696,6 +3811,22 @@ interface Plugin<M extends ModuleSchema = ModuleSchema> {
3696
3811
  * @param eventName - The dispatched event name (the first arg to `publish`).
3697
3812
  */
3698
3813
  onSourcePublish?: (id: string, moduleId: string, eventName: string) => void;
3814
+ /**
3815
+ * Called when the engine OR the manager rejects a source publish.
3816
+ * Pairs with `onSourcePublish` so observers see both halves of the
3817
+ * publish path without polling `inspect().sources[i].dropCount`.
3818
+ *
3819
+ * `reason` mirrors `SourceInspectionRow.lastDropReason`:
3820
+ * - `"post-destroy"` / `"post-stop"` — leaked transport firing after teardown
3821
+ * - `"blocked-event-name"` / `"invalid-event-name"` — engine guard probe
3822
+ * - `"coalesced"` — manager debounced an in-tick same-event publish
3823
+ *
3824
+ * @param id - The source ID.
3825
+ * @param moduleId - The owning module's id.
3826
+ * @param eventName - The dispatched event name (the first arg to `publish`).
3827
+ * @param reason - Why the publish was rejected.
3828
+ */
3829
+ onSourceDrop?: (id: string, moduleId: string, eventName: string, reason: SourceDropReason) => void;
3699
3830
  /**
3700
3831
  * Called when a source detaches at `system.stop()` (reverse-registration
3701
3832
  * order across all modules).
@@ -3801,4 +3932,4 @@ interface Plugin<M extends ModuleSchema = ModuleSchema> {
3801
3932
  onTraceComplete?: (entry: TraceEntry) => void;
3802
3933
  }
3803
3934
 
3804
- export { type InferSchemaType as $, type AnySystem as A, type BatchConfig as B, type ClauseResult as C, type DefinitionMeta as D, type EffectsDef as E, type FactPredicate as F, type DynamicConstraintDef as G, type DynamicEffectDef as H, type DynamicResolverDef as I, type EffectDef as J, type EventsDef as K, type FactTemplate as L, type ModuleSchema as M, type NamespacedSystem as N, type FactsSnapshot as O, type Plugin as P, type HistoryAPI as Q, type RequirementWithId as R, type SchemaType as S, type TypedDerivationsDef as T, type HistoryOption as U, type HistoryState as V, type InferDerivations as W, type InferEvents as X, type InferFacts as Y, type InferRequirementTypes as Z, type InferRequirements as _, type Facts as a, type FlexibleEventHandler as a$, type InferSelectorState as a0, type KeySelector as a1, type MetaAccessor as a2, type MetaMatch as a3, type ObservationEvent as a4, type OperatorObject as a5, type PatchSpec as a6, type PatchValue as a7, type PayloadRef as a8, type PredicateClause as a9, type FactsStore as aA, type ConstraintState as aB, type ResolverStatus as aC, type FactChange as aD, type ReconcileResult as aE, type RecoveryStrategy as aF, type ErrorSource as aG, type RetryLaterConfig as aH, type BatchItemResult as aI, type BatchResolveResults as aJ, type ConstraintsControl as aK, type CrossModuleDerivationFn as aL, type CrossModuleFactsWithSelf as aM, type DerivationKeys as aN, type DerivationReturnType as aO, type DerivationsControl as aP, type DerivationsSchema as aQ, type DeriveAccessor as aR, type DispatchEventsFromSchema as aS, type EffectCleanup as aT, type EffectsControl as aU, type EventPayloadSchema as aV, type EventsAccessor as aW, type EventsAccessorFromSchema as aX, type EventsSchema as aY, type FactKeys as aZ, type FactReturnType as a_, type PredicateCombinator as aa, type PredicateCombinatorKey as ab, type PredicateObject as ac, type PredicateOp as ad, type ResolverDef as ae, type ResolversDef as af, type RetryPolicy as ag, type Schema as ah, type SchemaTypedResolversDef as ai, type Snapshot as aj, type SourceDef as ak, type SourcePublish as al, type SourceReportError as am, type SourceUnsubscribe as an, type System as ao, type SystemConfig as ap, type SystemDerived as aq, type SystemFacts as ar, type SystemInspection as as, type SystemMode as at, type SystemSnapshot as au, type TraceEntry as av, type TypedConstraintDef as aw, type TypedResolverDef as ax, isNamespacedSystem as ay, isSingleModuleSystem as az, type TypedEventsDef as b, type HistoryConfig as b0, type InferEventPayloadFromSchema as b1, type InferRequirementPayloadFromSchema as b2, type InferSchema as b3, type MutableNamespacedFacts as b4, type NamespacedDerivations as b5, type NamespacedEventsAccessor as b6, type NamespacedFacts as b7, type ObservableKeys as b8, type RequirementExplanation as b9, type RequirementOutput as ba, type RequirementPayloadSchema$1 as bb, type RequirementsSchema as bc, type ResolverContext as bd, type ResolversControl as be, type SnapshotMeta as bf, type SystemEvent as bg, type TraceConfig as bh, type TypedResolverContext as bi, type UnionEvents as bj, type RequirementOutput$1 as bk, type SourcesDef as c, type TypedConstraintsDef as d, type TypedResolversDef as e, type ModuleHooks as f, type CrossModuleDeps as g, type CrossModuleDerivationsDef as h, type CrossModuleEffectsDef as i, type CrossModuleConstraintsDef as j, type ModuleDef as k, type CreateSystemOptionsSingle as l, type SingleModuleSystem as m, type ModulesMap as n, type CreateSystemOptionsNamed as o, type TraceOption as p, type ErrorBoundaryConfig as q, type Requirement as r, type RequirementKeyFn as s, type ConstraintDef as t, type ConstraintsDef as u, type CrossModuleConstraintDef as v, type CrossModuleEffectDef as w, DirectiveError as x, type DistributableSnapshot as y, type DistributableSnapshotOptions as z };
3935
+ export { type InferSchemaType as $, type AnySystem as A, type BatchConfig as B, type ClauseResult as C, type DefinitionMeta as D, type EffectsDef as E, type FactPredicate as F, type DynamicConstraintDef as G, type DynamicEffectDef as H, type DynamicResolverDef as I, type EffectDef as J, type EventsDef as K, type FactTemplate as L, type ModuleSchema as M, type NamespacedSystem as N, type FactsSnapshot as O, type Plugin as P, type HistoryAPI as Q, type RequirementWithId as R, type SchemaType as S, type TypedDerivationsDef as T, type HistoryOption as U, type HistoryState as V, type InferDerivations as W, type InferEvents as X, type InferFacts as Y, type InferRequirementTypes as Z, type InferRequirements as _, type Facts as a, type FactReturnType as a$, type InferSelectorState as a0, type KeySelector as a1, type MetaAccessor as a2, type MetaMatch as a3, type ObservationEvent as a4, type OperatorObject as a5, type PatchSpec as a6, type PatchValue as a7, type PayloadRef as a8, type PredicateClause as a9, isSingleModuleSystem as aA, type FactsStore as aB, type ConstraintState as aC, type ResolverStatus as aD, type FactChange as aE, type ReconcileResult as aF, type RecoveryStrategy as aG, type ErrorSource as aH, type RetryLaterConfig as aI, type BatchItemResult as aJ, type BatchResolveResults as aK, type ConstraintsControl as aL, type CrossModuleDerivationFn as aM, type CrossModuleFactsWithSelf as aN, type DerivationKeys as aO, type DerivationReturnType as aP, type DerivationsControl as aQ, type DerivationsSchema as aR, type DeriveAccessor as aS, type DispatchEventsFromSchema as aT, type EffectCleanup as aU, type EffectsControl as aV, type EventPayloadSchema as aW, type EventsAccessor as aX, type EventsAccessorFromSchema as aY, type EventsSchema as aZ, type FactKeys as a_, type PredicateCombinator as aa, type PredicateCombinatorKey as ab, type PredicateObject as ac, type PredicateOp as ad, type ResolverDef as ae, type ResolversDef as af, type RetryPolicy as ag, type Schema as ah, type SchemaTypedResolversDef as ai, type Snapshot as aj, type SourceDef as ak, type SourceDropReason as al, type SourcePublish as am, type SourceReportError as an, type SourceUnsubscribe as ao, type System as ap, type SystemConfig as aq, type SystemDerived as ar, type SystemFacts as as, type SystemInspection as at, type SystemMode as au, type SystemSnapshot as av, type TraceEntry as aw, type TypedConstraintDef as ax, type TypedResolverDef as ay, isNamespacedSystem as az, type TypedEventsDef as b, type FlexibleEventHandler as b0, type HistoryConfig as b1, type InferEventPayloadFromSchema as b2, type InferRequirementPayloadFromSchema as b3, type InferSchema as b4, type MutableNamespacedFacts as b5, type NamespacedDerivations as b6, type NamespacedEventsAccessor as b7, type NamespacedFacts as b8, type ObservableKeys as b9, type RequirementExplanation as ba, type RequirementOutput as bb, type RequirementPayloadSchema$1 as bc, type RequirementsSchema as bd, type ResolverContext as be, type ResolversControl as bf, type SnapshotMeta as bg, type SystemEvent as bh, type TraceConfig as bi, type TypedResolverContext as bj, type UnionEvents as bk, type RequirementOutput$1 as bl, type SourcesDef as c, type TypedConstraintsDef as d, type TypedResolversDef as e, type ModuleHooks as f, type CrossModuleDeps as g, type CrossModuleDerivationsDef as h, type CrossModuleEffectsDef as i, type CrossModuleConstraintsDef as j, type ModuleDef as k, type CreateSystemOptionsSingle as l, type SingleModuleSystem as m, type ModulesMap as n, type CreateSystemOptionsNamed as o, type TraceOption as p, type ErrorBoundaryConfig as q, type Requirement as r, type RequirementKeyFn as s, type ConstraintDef as t, type ConstraintsDef as u, type CrossModuleConstraintDef as v, type CrossModuleEffectDef as w, DirectiveError as x, type DistributableSnapshot as y, type DistributableSnapshotOptions as z };
@@ -1,4 +1,4 @@
1
- import { ah as Schema, a as Facts, F as FactPredicate, b3 as InferSchema, L as FactTemplate, D as DefinitionMeta, r as Requirement, bk as RequirementOutput, ag as RetryPolicy, B as BatchConfig, bd as ResolverContext, ad as PredicateOp, a6 as PatchSpec, C as ClauseResult } from './plugins-C6MxOvot.js';
1
+ import { ah as Schema, a as Facts, F as FactPredicate, b4 as InferSchema, L as FactTemplate, D as DefinitionMeta, r as Requirement, bl as RequirementOutput, ag as RetryPolicy, B as BatchConfig, be as ResolverContext, ad as PredicateOp, a6 as PatchSpec, C as ClauseResult } from './plugins-5Supk7it.js';
2
2
 
3
3
  /**
4
4
  * Derivation Types - Type definitions for derivations
@@ -1,4 +1,4 @@
1
- import { ah as Schema, a as Facts, F as FactPredicate, b3 as InferSchema, L as FactTemplate, D as DefinitionMeta, r as Requirement, bk as RequirementOutput, ag as RetryPolicy, B as BatchConfig, bd as ResolverContext, ad as PredicateOp, a6 as PatchSpec, C as ClauseResult } from './plugins-C6MxOvot.cjs';
1
+ import { ah as Schema, a as Facts, F as FactPredicate, b4 as InferSchema, L as FactTemplate, D as DefinitionMeta, r as Requirement, bl as RequirementOutput, ag as RetryPolicy, B as BatchConfig, be as ResolverContext, ad as PredicateOp, a6 as PatchSpec, C as ClauseResult } from './plugins-5Supk7it.cjs';
2
2
 
3
3
  /**
4
4
  * Derivation Types - Type definitions for derivations
@@ -0,0 +1,2 @@
1
+ 'use strict';var chunkOAPD3HIG_cjs=require('./chunk-OAPD3HIG.cjs');require('./chunk-QTY2FXZY.cjs'),require('./chunk-GACC2DMS.cjs'),require('./chunk-GKMJ7NMP.cjs'),require('./chunk-GBCWXTXW.cjs');Object.defineProperty(exports,"createSystem",{enumerable:true,get:function(){return chunkOAPD3HIG_cjs.a}});//# sourceMappingURL=system-5FKUBLLV.cjs.map
2
+ //# sourceMappingURL=system-5FKUBLLV.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"system-BXCEQBBS.cjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"system-5FKUBLLV.cjs"}
@@ -0,0 +1,2 @@
1
+ export{a as createSystem}from'./chunk-YJEDX2JX.js';import'./chunk-6NCC6RBC.js';import'./chunk-RBF653NR.js';import'./chunk-6PF2FRBG.js';import'./chunk-SFUVPP4L.js';//# sourceMappingURL=system-6YWCXQOQ.js.map
2
+ //# sourceMappingURL=system-6YWCXQOQ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"system-AWEKWMNI.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"system-6YWCXQOQ.js"}
package/dist/testing.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var chunkPNB73G3E_cjs=require('./chunk-PNB73G3E.cjs');require('./chunk-MDMMMZUZ.cjs'),require('./chunk-RWFKUNF7.cjs'),require('./chunk-JGPPJV5P.cjs'),require('./chunk-4MNQDXH7.cjs');async function R(){for(let e=0;e<10;e++)await Promise.resolve();}async function T(){for(let e=0;e<10;e++)await Promise.resolve();await new Promise(e=>setTimeout(e,0));for(let e=0;e<10;e++)await Promise.resolve();await new Promise(e=>setTimeout(e,0));for(let e=0;e<10;e++)await Promise.resolve();}async function D(e,s,r={}){let{totalTime:o=5e3,stepSize:c=10,maxIterations:l=1e3}=r,m=0,d=0;for(;m<o&&d<l;){if(await R(),e.inspect().inflight.length===0){await R();return}s(c),m+=c,d++;}let v=e.inspect();if(v.inflight.length>0){let f=v.inflight.map(p=>p.resolverId).join(", ");throw new Error(`[Directive] settleWithFakeTimers did not settle after ${o}ms. ${v.inflight.length} resolvers still inflight: ${f}`)}}function C(){let e=0,s=[];return {async advance(r){let o=e+r;for(;s.length>0&&s[0].time<=o;){let c=s.shift();e=c.time,c.callback(),await Promise.resolve();}e=o;},async next(){if(s.length===0)return;let r=s.shift();e=r.time,r.callback(),await Promise.resolve();},async runAll(){for(;s.length>0;)await this.next();},now(){return e},reset(){e=0,s.length=0;}}}function b(e){let s=typeof e=="string"?{requirement:(o=>o.type===e)}:e,r=s.calls??[];return {requirement:s.requirement??(o=>true),async resolve(o,c){if(r.push(o),s.delay&&await new Promise(l=>setTimeout(l,s.delay)),s.error)throw typeof s.error=="string"?new Error(s.error):s.error;s.resolve&&await s.resolve(o,c);}}}function E(e){let s=[],r=[];return {...{get calls(){return s},get pending(){return r},resolve(l){let m=r.shift();m&&m.resolve(l);},reject(l){let m=r.shift();m&&m.reject(l);},resolveAll(l){for(;r.length>0;)this.resolve(l);},rejectAll(l){for(;r.length>0;)this.reject(l);},reset(){s.length=0,r.length=0;}},handler:(l,m)=>(s.push(l),new Promise((d,v)=>{r.push({requirement:l,resolve:f=>d(f),reject:v});}))}}function P(e){return "module"in e?x(e):M(e)}function x(e){let s=[],r=new Map,o=[],c=[],l={};if(e.mocks?.resolvers)for(let[i,t]of Object.entries(e.mocks.resolvers)){let n=[];r.set(i,n),l[i]=b({...t,calls:n});}let m={...e.module,resolvers:{...e.module.resolvers,...l}},v=chunkPNB73G3E_cjs.a({...e,module:m,plugins:[{name:"__test-tracking__",onFactSet:(i,t,n)=>{c.push({key:i,fullKey:i,namespace:void 0,previousValue:n,newValue:t,timestamp:Date.now()});},onRequirementCreated:i=>{o.push(i);}},...e.plugins??[]]}),f=v.dispatch.bind(v);return v.dispatch=i=>{s.push(i),f(i);},{...v,eventHistory:s,resolverCalls:r,get allRequirements(){return o},getFactsHistory(){return [...c]},resetFactsHistory(){c.length=0;},async waitForIdle(i=5e3){let t=Date.now(),n=async()=>{await new Promise(u=>setTimeout(u,0));let a=v.inspect();if(a.inflight.length>0){if(Date.now()-t>i){let u=a.inflight.map(g=>g.id).join(", ");throw new Error(`[Directive] waitForIdle timed out after ${i}ms. ${a.inflight.length} resolvers still inflight: ${u}`)}return await new Promise(u=>setTimeout(u,10)),n()}};return n()},assertRequirement(i){if(!o.some(n=>n.requirement.type===i))throw new Error(`[Directive] Expected requirement of type "${i}" but none found`)},assertResolverCalled(i,t){let n=r.get(i)??[];if(t!==void 0){if(n.length!==t)throw new Error(`[Directive] Expected resolver "${i}" to be called ${t} times but was called ${n.length} times`)}else if(n.length===0)throw new Error(`[Directive] Expected resolver "${i}" to be called but it was not`)},assertFactSet(i,t){let n=c.filter(a=>a.key===i);if(n.length===0)throw new Error(`[Directive] Expected fact "${i}" to be set but it was not`);if(t!==void 0&&!n.some(u=>u.newValue===t)){let u=n.map(g=>JSON.stringify(g.newValue)).join(", ");throw new Error(`[Directive] Expected fact "${i}" to be set to ${JSON.stringify(t)} but got: ${u}`)}},assertFactChanges(i,t){let n=c.filter(a=>a.key===i);if(n.length!==t)throw new Error(`[Directive] Expected fact "${i}" to change ${t} times but it changed ${n.length} times`)}}}function M(e){let s=[],r=new Map,o=[],c=[],l={};if(e.mocks?.resolvers)for(let[t,n]of Object.entries(e.mocks.resolvers)){let a=[];r.set(t,a),l[t]=b({...n,calls:a});}let m={};for(let[t,n]of Object.entries(e.modules))m[t]={...n,resolvers:{...n.resolvers,...l}};let d=new Set(Object.keys(e.modules)),f=chunkPNB73G3E_cjs.a({...e,modules:m,plugins:[{name:"__test-tracking__",onFactSet:(t,n,a)=>{let g=t.indexOf("::"),y,h;if(g>0){let S=t.substring(0,g);d.has(S)?(y=S,h=t.substring(g+2)):h=t;}else h=t;c.push({key:h,fullKey:t,namespace:y,previousValue:a,newValue:n,timestamp:Date.now()});},onRequirementCreated:t=>{o.push(t);}},...e.plugins??[]]}),p=f.dispatch.bind(f);return f.dispatch=t=>{s.push(t),p(t);},{...f,eventHistory:s,resolverCalls:r,get allRequirements(){return o},getFactsHistory(){return [...c]},resetFactsHistory(){c.length=0;},async waitForIdle(t=5e3){let n=Date.now(),a=async()=>{await new Promise(g=>setTimeout(g,0));let u=f.inspect();if(u.inflight.length>0){if(Date.now()-n>t){let g=u.inflight.map(y=>y.id).join(", ");throw new Error(`[Directive] waitForIdle timed out after ${t}ms. ${u.inflight.length} resolvers still inflight: ${g}`)}return await new Promise(g=>setTimeout(g,10)),a()}};return a()},assertRequirement(t){if(!o.some(a=>a.requirement.type===t))throw new Error(`[Directive] Expected requirement of type "${t}" but none found`)},assertResolverCalled(t,n){let a=r.get(t)??[];if(n!==void 0){if(a.length!==n)throw new Error(`[Directive] Expected resolver "${t}" to be called ${n} times but was called ${a.length} times`)}else if(a.length===0)throw new Error(`[Directive] Expected resolver "${t}" to be called but it was not`)},assertFactSet(t,n){let a=c.filter(u=>u.key===t);if(a.length===0)throw new Error(`[Directive] Expected fact "${t}" to be set but it was not`);if(n!==void 0&&!a.some(g=>g.newValue===n)){let g=a.map(y=>JSON.stringify(y.newValue)).join(", ");throw new Error(`[Directive] Expected fact "${t}" to be set to ${JSON.stringify(n)} but got: ${g}`)}},assertFactChanges(t,n){let a=c.filter(u=>u.key===t);if(a.length!==n)throw new Error(`[Directive] Expected fact "${t}" to change ${n} times but it changed ${a.length} times`)}}}function O(e,s,r){if(!k(e,s,r))throw new Error(`[Directive] Expected ${s} "${r}" to be dynamic, but it is not.`)}function $(e,s,r){if(k(e,s,r))throw new Error(`[Directive] Expected ${s} "${r}" to NOT be dynamic, but it is.`)}function k(e,s,r){switch(s){case "constraint":return e.constraints.isDynamic(r);case "resolver":return e.resolvers.isDynamic(r);case "derivation":return e.derive.isDynamic(r);case "effect":return e.effects.isDynamic(r)}}function F(e){let s=new Set,r=new Set,o=new Set,c=new Set,l=null;return {async run(m){l=e.observe(d=>{switch(d.type){case "constraint.evaluate":d.active&&s.add(d.id);break;case "resolver.start":r.add(d.resolver);break;case "effect.run":o.add(d.id);break;case "derivation.compute":c.add(d.id);break}});try{await m();}finally{l?.(),l=null;}},report(){let m=e.inspect(),d=new Set(m.constraints.map(i=>i.id)),v=new Set(m.resolverDefs.map(i=>i.id)),f=new Set;for(let i of d)s.has(i)||f.add(i);let p=new Set;for(let i of v)r.has(i)||p.add(i);return {constraintsHit:s,constraintsMissed:f,resolversRun:r,resolversMissed:p,effectsRun:o,derivationsComputed:c,constraintCoverage:d.size===0?1:s.size/d.size,resolverCoverage:v.size===0?1:r.size/v.size,effectCoverage:m.effects.length===0?1:o.size/m.effects.length,derivationCoverage:m.derivations.length===0?1:c.size/m.derivations.length}}}}function I(e){let s=[],r=e.observe(o=>s.push(o));return {events:s,ofType(o){return s.filter(c=>c.type===o)},clear(){s.length=0;},dispose(){r();}}}exports.assertDynamic=O;exports.assertNotDynamic=$;exports.createCoverageTracker=F;exports.createFakeTimers=C;exports.createMockResolver=b;exports.createTestObserver=I;exports.createTestSystem=P;exports.flushAsync=T;exports.flushMicrotasks=R;exports.mockResolver=E;exports.settleWithFakeTimers=D;//# sourceMappingURL=testing.cjs.map
1
+ 'use strict';var chunkOAPD3HIG_cjs=require('./chunk-OAPD3HIG.cjs');require('./chunk-QTY2FXZY.cjs'),require('./chunk-GACC2DMS.cjs'),require('./chunk-GKMJ7NMP.cjs'),require('./chunk-GBCWXTXW.cjs');async function R(){for(let e=0;e<10;e++)await Promise.resolve();}async function T(){for(let e=0;e<10;e++)await Promise.resolve();await new Promise(e=>setTimeout(e,0));for(let e=0;e<10;e++)await Promise.resolve();await new Promise(e=>setTimeout(e,0));for(let e=0;e<10;e++)await Promise.resolve();}async function D(e,s,r={}){let{totalTime:o=5e3,stepSize:c=10,maxIterations:l=1e3}=r,m=0,d=0;for(;m<o&&d<l;){if(await R(),e.inspect().inflight.length===0){await R();return}s(c),m+=c,d++;}let v=e.inspect();if(v.inflight.length>0){let f=v.inflight.map(p=>p.resolverId).join(", ");throw new Error(`[Directive] settleWithFakeTimers did not settle after ${o}ms. ${v.inflight.length} resolvers still inflight: ${f}`)}}function C(){let e=0,s=[];return {async advance(r){let o=e+r;for(;s.length>0&&s[0].time<=o;){let c=s.shift();e=c.time,c.callback(),await Promise.resolve();}e=o;},async next(){if(s.length===0)return;let r=s.shift();e=r.time,r.callback(),await Promise.resolve();},async runAll(){for(;s.length>0;)await this.next();},now(){return e},reset(){e=0,s.length=0;}}}function b(e){let s=typeof e=="string"?{requirement:(o=>o.type===e)}:e,r=s.calls??[];return {requirement:s.requirement??(o=>true),async resolve(o,c){if(r.push(o),s.delay&&await new Promise(l=>setTimeout(l,s.delay)),s.error)throw typeof s.error=="string"?new Error(s.error):s.error;s.resolve&&await s.resolve(o,c);}}}function E(e){let s=[],r=[];return {...{get calls(){return s},get pending(){return r},resolve(l){let m=r.shift();m&&m.resolve(l);},reject(l){let m=r.shift();m&&m.reject(l);},resolveAll(l){for(;r.length>0;)this.resolve(l);},rejectAll(l){for(;r.length>0;)this.reject(l);},reset(){s.length=0,r.length=0;}},handler:(l,m)=>(s.push(l),new Promise((d,v)=>{r.push({requirement:l,resolve:f=>d(f),reject:v});}))}}function P(e){return "module"in e?x(e):M(e)}function x(e){let s=[],r=new Map,o=[],c=[],l={};if(e.mocks?.resolvers)for(let[i,t]of Object.entries(e.mocks.resolvers)){let n=[];r.set(i,n),l[i]=b({...t,calls:n});}let m={...e.module,resolvers:{...e.module.resolvers,...l}},v=chunkOAPD3HIG_cjs.a({...e,module:m,plugins:[{name:"__test-tracking__",onFactSet:(i,t,n)=>{c.push({key:i,fullKey:i,namespace:void 0,previousValue:n,newValue:t,timestamp:Date.now()});},onRequirementCreated:i=>{o.push(i);}},...e.plugins??[]]}),f=v.dispatch.bind(v);return v.dispatch=i=>{s.push(i),f(i);},{...v,eventHistory:s,resolverCalls:r,get allRequirements(){return o},getFactsHistory(){return [...c]},resetFactsHistory(){c.length=0;},async waitForIdle(i=5e3){let t=Date.now(),n=async()=>{await new Promise(u=>setTimeout(u,0));let a=v.inspect();if(a.inflight.length>0){if(Date.now()-t>i){let u=a.inflight.map(g=>g.id).join(", ");throw new Error(`[Directive] waitForIdle timed out after ${i}ms. ${a.inflight.length} resolvers still inflight: ${u}`)}return await new Promise(u=>setTimeout(u,10)),n()}};return n()},assertRequirement(i){if(!o.some(n=>n.requirement.type===i))throw new Error(`[Directive] Expected requirement of type "${i}" but none found`)},assertResolverCalled(i,t){let n=r.get(i)??[];if(t!==void 0){if(n.length!==t)throw new Error(`[Directive] Expected resolver "${i}" to be called ${t} times but was called ${n.length} times`)}else if(n.length===0)throw new Error(`[Directive] Expected resolver "${i}" to be called but it was not`)},assertFactSet(i,t){let n=c.filter(a=>a.key===i);if(n.length===0)throw new Error(`[Directive] Expected fact "${i}" to be set but it was not`);if(t!==void 0&&!n.some(u=>u.newValue===t)){let u=n.map(g=>JSON.stringify(g.newValue)).join(", ");throw new Error(`[Directive] Expected fact "${i}" to be set to ${JSON.stringify(t)} but got: ${u}`)}},assertFactChanges(i,t){let n=c.filter(a=>a.key===i);if(n.length!==t)throw new Error(`[Directive] Expected fact "${i}" to change ${t} times but it changed ${n.length} times`)}}}function M(e){let s=[],r=new Map,o=[],c=[],l={};if(e.mocks?.resolvers)for(let[t,n]of Object.entries(e.mocks.resolvers)){let a=[];r.set(t,a),l[t]=b({...n,calls:a});}let m={};for(let[t,n]of Object.entries(e.modules))m[t]={...n,resolvers:{...n.resolvers,...l}};let d=new Set(Object.keys(e.modules)),f=chunkOAPD3HIG_cjs.a({...e,modules:m,plugins:[{name:"__test-tracking__",onFactSet:(t,n,a)=>{let g=t.indexOf("::"),y,h;if(g>0){let S=t.substring(0,g);d.has(S)?(y=S,h=t.substring(g+2)):h=t;}else h=t;c.push({key:h,fullKey:t,namespace:y,previousValue:a,newValue:n,timestamp:Date.now()});},onRequirementCreated:t=>{o.push(t);}},...e.plugins??[]]}),p=f.dispatch.bind(f);return f.dispatch=t=>{s.push(t),p(t);},{...f,eventHistory:s,resolverCalls:r,get allRequirements(){return o},getFactsHistory(){return [...c]},resetFactsHistory(){c.length=0;},async waitForIdle(t=5e3){let n=Date.now(),a=async()=>{await new Promise(g=>setTimeout(g,0));let u=f.inspect();if(u.inflight.length>0){if(Date.now()-n>t){let g=u.inflight.map(y=>y.id).join(", ");throw new Error(`[Directive] waitForIdle timed out after ${t}ms. ${u.inflight.length} resolvers still inflight: ${g}`)}return await new Promise(g=>setTimeout(g,10)),a()}};return a()},assertRequirement(t){if(!o.some(a=>a.requirement.type===t))throw new Error(`[Directive] Expected requirement of type "${t}" but none found`)},assertResolverCalled(t,n){let a=r.get(t)??[];if(n!==void 0){if(a.length!==n)throw new Error(`[Directive] Expected resolver "${t}" to be called ${n} times but was called ${a.length} times`)}else if(a.length===0)throw new Error(`[Directive] Expected resolver "${t}" to be called but it was not`)},assertFactSet(t,n){let a=c.filter(u=>u.key===t);if(a.length===0)throw new Error(`[Directive] Expected fact "${t}" to be set but it was not`);if(n!==void 0&&!a.some(g=>g.newValue===n)){let g=a.map(y=>JSON.stringify(y.newValue)).join(", ");throw new Error(`[Directive] Expected fact "${t}" to be set to ${JSON.stringify(n)} but got: ${g}`)}},assertFactChanges(t,n){let a=c.filter(u=>u.key===t);if(a.length!==n)throw new Error(`[Directive] Expected fact "${t}" to change ${n} times but it changed ${a.length} times`)}}}function O(e,s,r){if(!k(e,s,r))throw new Error(`[Directive] Expected ${s} "${r}" to be dynamic, but it is not.`)}function $(e,s,r){if(k(e,s,r))throw new Error(`[Directive] Expected ${s} "${r}" to NOT be dynamic, but it is.`)}function k(e,s,r){switch(s){case "constraint":return e.constraints.isDynamic(r);case "resolver":return e.resolvers.isDynamic(r);case "derivation":return e.derive.isDynamic(r);case "effect":return e.effects.isDynamic(r)}}function F(e){let s=new Set,r=new Set,o=new Set,c=new Set,l=null;return {async run(m){l=e.observe(d=>{switch(d.type){case "constraint.evaluate":d.active&&s.add(d.id);break;case "resolver.start":r.add(d.resolver);break;case "effect.run":o.add(d.id);break;case "derivation.compute":c.add(d.id);break}});try{await m();}finally{l?.(),l=null;}},report(){let m=e.inspect(),d=new Set(m.constraints.map(i=>i.id)),v=new Set(m.resolverDefs.map(i=>i.id)),f=new Set;for(let i of d)s.has(i)||f.add(i);let p=new Set;for(let i of v)r.has(i)||p.add(i);return {constraintsHit:s,constraintsMissed:f,resolversRun:r,resolversMissed:p,effectsRun:o,derivationsComputed:c,constraintCoverage:d.size===0?1:s.size/d.size,resolverCoverage:v.size===0?1:r.size/v.size,effectCoverage:m.effects.length===0?1:o.size/m.effects.length,derivationCoverage:m.derivations.length===0?1:c.size/m.derivations.length}}}}function I(e){let s=[],r=e.observe(o=>s.push(o));return {events:s,ofType(o){return s.filter(c=>c.type===o)},clear(){s.length=0;},dispose(){r();}}}exports.assertDynamic=O;exports.assertNotDynamic=$;exports.createCoverageTracker=F;exports.createFakeTimers=C;exports.createMockResolver=b;exports.createTestObserver=I;exports.createTestSystem=P;exports.flushAsync=T;exports.flushMicrotasks=R;exports.mockResolver=E;exports.settleWithFakeTimers=D;//# sourceMappingURL=testing.cjs.map
2
2
  //# sourceMappingURL=testing.cjs.map
@@ -1,4 +1,4 @@
1
- import { n as ModulesMap, o as CreateSystemOptionsNamed, r as Requirement, M as ModuleSchema, l as CreateSystemOptionsSingle, N as NamespacedSystem, R as RequirementWithId, m as SingleModuleSystem, a4 as ObservationEvent, as as SystemInspection } from './plugins-C6MxOvot.cjs';
1
+ import { n as ModulesMap, o as CreateSystemOptionsNamed, r as Requirement, M as ModuleSchema, l as CreateSystemOptionsSingle, N as NamespacedSystem, R as RequirementWithId, m as SingleModuleSystem, a4 as ObservationEvent, at as SystemInspection } from './plugins-5Supk7it.cjs';
2
2
 
3
3
  /**
4
4
  * Flush all pending microtasks by awaiting multiple rounds of `Promise.resolve()`.
package/dist/testing.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as ModulesMap, o as CreateSystemOptionsNamed, r as Requirement, M as ModuleSchema, l as CreateSystemOptionsSingle, N as NamespacedSystem, R as RequirementWithId, m as SingleModuleSystem, a4 as ObservationEvent, as as SystemInspection } from './plugins-C6MxOvot.js';
1
+ import { n as ModulesMap, o as CreateSystemOptionsNamed, r as Requirement, M as ModuleSchema, l as CreateSystemOptionsSingle, N as NamespacedSystem, R as RequirementWithId, m as SingleModuleSystem, a4 as ObservationEvent, at as SystemInspection } from './plugins-5Supk7it.js';
2
2
 
3
3
  /**
4
4
  * Flush all pending microtasks by awaiting multiple rounds of `Promise.resolve()`.
package/dist/testing.js CHANGED
@@ -1,2 +1,2 @@
1
- import {a}from'./chunk-QQEXRNAI.js';import'./chunk-CLJMEU2A.js';import'./chunk-O4GQEV4G.js';import'./chunk-3ETCZLAY.js';import'./chunk-PXRV64PA.js';async function R(){for(let e=0;e<10;e++)await Promise.resolve();}async function T(){for(let e=0;e<10;e++)await Promise.resolve();await new Promise(e=>setTimeout(e,0));for(let e=0;e<10;e++)await Promise.resolve();await new Promise(e=>setTimeout(e,0));for(let e=0;e<10;e++)await Promise.resolve();}async function D(e,s,r={}){let{totalTime:o=5e3,stepSize:c=10,maxIterations:l=1e3}=r,m=0,d=0;for(;m<o&&d<l;){if(await R(),e.inspect().inflight.length===0){await R();return}s(c),m+=c,d++;}let v=e.inspect();if(v.inflight.length>0){let f=v.inflight.map(p=>p.resolverId).join(", ");throw new Error(`[Directive] settleWithFakeTimers did not settle after ${o}ms. ${v.inflight.length} resolvers still inflight: ${f}`)}}function C(){let e=0,s=[];return {async advance(r){let o=e+r;for(;s.length>0&&s[0].time<=o;){let c=s.shift();e=c.time,c.callback(),await Promise.resolve();}e=o;},async next(){if(s.length===0)return;let r=s.shift();e=r.time,r.callback(),await Promise.resolve();},async runAll(){for(;s.length>0;)await this.next();},now(){return e},reset(){e=0,s.length=0;}}}function b(e){let s=typeof e=="string"?{requirement:(o=>o.type===e)}:e,r=s.calls??[];return {requirement:s.requirement??(o=>true),async resolve(o,c){if(r.push(o),s.delay&&await new Promise(l=>setTimeout(l,s.delay)),s.error)throw typeof s.error=="string"?new Error(s.error):s.error;s.resolve&&await s.resolve(o,c);}}}function E(e){let s=[],r=[];return {...{get calls(){return s},get pending(){return r},resolve(l){let m=r.shift();m&&m.resolve(l);},reject(l){let m=r.shift();m&&m.reject(l);},resolveAll(l){for(;r.length>0;)this.resolve(l);},rejectAll(l){for(;r.length>0;)this.reject(l);},reset(){s.length=0,r.length=0;}},handler:(l,m)=>(s.push(l),new Promise((d,v)=>{r.push({requirement:l,resolve:f=>d(f),reject:v});}))}}function P(e){return "module"in e?x(e):M(e)}function x(e){let s=[],r=new Map,o=[],c=[],l={};if(e.mocks?.resolvers)for(let[i,t]of Object.entries(e.mocks.resolvers)){let n=[];r.set(i,n),l[i]=b({...t,calls:n});}let m={...e.module,resolvers:{...e.module.resolvers,...l}},v=a({...e,module:m,plugins:[{name:"__test-tracking__",onFactSet:(i,t,n)=>{c.push({key:i,fullKey:i,namespace:void 0,previousValue:n,newValue:t,timestamp:Date.now()});},onRequirementCreated:i=>{o.push(i);}},...e.plugins??[]]}),f=v.dispatch.bind(v);return v.dispatch=i=>{s.push(i),f(i);},{...v,eventHistory:s,resolverCalls:r,get allRequirements(){return o},getFactsHistory(){return [...c]},resetFactsHistory(){c.length=0;},async waitForIdle(i=5e3){let t=Date.now(),n=async()=>{await new Promise(u=>setTimeout(u,0));let a=v.inspect();if(a.inflight.length>0){if(Date.now()-t>i){let u=a.inflight.map(g=>g.id).join(", ");throw new Error(`[Directive] waitForIdle timed out after ${i}ms. ${a.inflight.length} resolvers still inflight: ${u}`)}return await new Promise(u=>setTimeout(u,10)),n()}};return n()},assertRequirement(i){if(!o.some(n=>n.requirement.type===i))throw new Error(`[Directive] Expected requirement of type "${i}" but none found`)},assertResolverCalled(i,t){let n=r.get(i)??[];if(t!==void 0){if(n.length!==t)throw new Error(`[Directive] Expected resolver "${i}" to be called ${t} times but was called ${n.length} times`)}else if(n.length===0)throw new Error(`[Directive] Expected resolver "${i}" to be called but it was not`)},assertFactSet(i,t){let n=c.filter(a=>a.key===i);if(n.length===0)throw new Error(`[Directive] Expected fact "${i}" to be set but it was not`);if(t!==void 0&&!n.some(u=>u.newValue===t)){let u=n.map(g=>JSON.stringify(g.newValue)).join(", ");throw new Error(`[Directive] Expected fact "${i}" to be set to ${JSON.stringify(t)} but got: ${u}`)}},assertFactChanges(i,t){let n=c.filter(a=>a.key===i);if(n.length!==t)throw new Error(`[Directive] Expected fact "${i}" to change ${t} times but it changed ${n.length} times`)}}}function M(e){let s=[],r=new Map,o=[],c=[],l={};if(e.mocks?.resolvers)for(let[t,n]of Object.entries(e.mocks.resolvers)){let a=[];r.set(t,a),l[t]=b({...n,calls:a});}let m={};for(let[t,n]of Object.entries(e.modules))m[t]={...n,resolvers:{...n.resolvers,...l}};let d=new Set(Object.keys(e.modules)),f=a({...e,modules:m,plugins:[{name:"__test-tracking__",onFactSet:(t,n,a)=>{let g=t.indexOf("::"),y,h;if(g>0){let S=t.substring(0,g);d.has(S)?(y=S,h=t.substring(g+2)):h=t;}else h=t;c.push({key:h,fullKey:t,namespace:y,previousValue:a,newValue:n,timestamp:Date.now()});},onRequirementCreated:t=>{o.push(t);}},...e.plugins??[]]}),p=f.dispatch.bind(f);return f.dispatch=t=>{s.push(t),p(t);},{...f,eventHistory:s,resolverCalls:r,get allRequirements(){return o},getFactsHistory(){return [...c]},resetFactsHistory(){c.length=0;},async waitForIdle(t=5e3){let n=Date.now(),a=async()=>{await new Promise(g=>setTimeout(g,0));let u=f.inspect();if(u.inflight.length>0){if(Date.now()-n>t){let g=u.inflight.map(y=>y.id).join(", ");throw new Error(`[Directive] waitForIdle timed out after ${t}ms. ${u.inflight.length} resolvers still inflight: ${g}`)}return await new Promise(g=>setTimeout(g,10)),a()}};return a()},assertRequirement(t){if(!o.some(a=>a.requirement.type===t))throw new Error(`[Directive] Expected requirement of type "${t}" but none found`)},assertResolverCalled(t,n){let a=r.get(t)??[];if(n!==void 0){if(a.length!==n)throw new Error(`[Directive] Expected resolver "${t}" to be called ${n} times but was called ${a.length} times`)}else if(a.length===0)throw new Error(`[Directive] Expected resolver "${t}" to be called but it was not`)},assertFactSet(t,n){let a=c.filter(u=>u.key===t);if(a.length===0)throw new Error(`[Directive] Expected fact "${t}" to be set but it was not`);if(n!==void 0&&!a.some(g=>g.newValue===n)){let g=a.map(y=>JSON.stringify(y.newValue)).join(", ");throw new Error(`[Directive] Expected fact "${t}" to be set to ${JSON.stringify(n)} but got: ${g}`)}},assertFactChanges(t,n){let a=c.filter(u=>u.key===t);if(a.length!==n)throw new Error(`[Directive] Expected fact "${t}" to change ${n} times but it changed ${a.length} times`)}}}function O(e,s,r){if(!k(e,s,r))throw new Error(`[Directive] Expected ${s} "${r}" to be dynamic, but it is not.`)}function $(e,s,r){if(k(e,s,r))throw new Error(`[Directive] Expected ${s} "${r}" to NOT be dynamic, but it is.`)}function k(e,s,r){switch(s){case "constraint":return e.constraints.isDynamic(r);case "resolver":return e.resolvers.isDynamic(r);case "derivation":return e.derive.isDynamic(r);case "effect":return e.effects.isDynamic(r)}}function F(e){let s=new Set,r=new Set,o=new Set,c=new Set,l=null;return {async run(m){l=e.observe(d=>{switch(d.type){case "constraint.evaluate":d.active&&s.add(d.id);break;case "resolver.start":r.add(d.resolver);break;case "effect.run":o.add(d.id);break;case "derivation.compute":c.add(d.id);break}});try{await m();}finally{l?.(),l=null;}},report(){let m=e.inspect(),d=new Set(m.constraints.map(i=>i.id)),v=new Set(m.resolverDefs.map(i=>i.id)),f=new Set;for(let i of d)s.has(i)||f.add(i);let p=new Set;for(let i of v)r.has(i)||p.add(i);return {constraintsHit:s,constraintsMissed:f,resolversRun:r,resolversMissed:p,effectsRun:o,derivationsComputed:c,constraintCoverage:d.size===0?1:s.size/d.size,resolverCoverage:v.size===0?1:r.size/v.size,effectCoverage:m.effects.length===0?1:o.size/m.effects.length,derivationCoverage:m.derivations.length===0?1:c.size/m.derivations.length}}}}function I(e){let s=[],r=e.observe(o=>s.push(o));return {events:s,ofType(o){return s.filter(c=>c.type===o)},clear(){s.length=0;},dispose(){r();}}}export{O as assertDynamic,$ as assertNotDynamic,F as createCoverageTracker,C as createFakeTimers,b as createMockResolver,I as createTestObserver,P as createTestSystem,T as flushAsync,R as flushMicrotasks,E as mockResolver,D as settleWithFakeTimers};//# sourceMappingURL=testing.js.map
1
+ import {a}from'./chunk-YJEDX2JX.js';import'./chunk-6NCC6RBC.js';import'./chunk-RBF653NR.js';import'./chunk-6PF2FRBG.js';import'./chunk-SFUVPP4L.js';async function R(){for(let e=0;e<10;e++)await Promise.resolve();}async function T(){for(let e=0;e<10;e++)await Promise.resolve();await new Promise(e=>setTimeout(e,0));for(let e=0;e<10;e++)await Promise.resolve();await new Promise(e=>setTimeout(e,0));for(let e=0;e<10;e++)await Promise.resolve();}async function D(e,s,r={}){let{totalTime:o=5e3,stepSize:c=10,maxIterations:l=1e3}=r,m=0,d=0;for(;m<o&&d<l;){if(await R(),e.inspect().inflight.length===0){await R();return}s(c),m+=c,d++;}let v=e.inspect();if(v.inflight.length>0){let f=v.inflight.map(p=>p.resolverId).join(", ");throw new Error(`[Directive] settleWithFakeTimers did not settle after ${o}ms. ${v.inflight.length} resolvers still inflight: ${f}`)}}function C(){let e=0,s=[];return {async advance(r){let o=e+r;for(;s.length>0&&s[0].time<=o;){let c=s.shift();e=c.time,c.callback(),await Promise.resolve();}e=o;},async next(){if(s.length===0)return;let r=s.shift();e=r.time,r.callback(),await Promise.resolve();},async runAll(){for(;s.length>0;)await this.next();},now(){return e},reset(){e=0,s.length=0;}}}function b(e){let s=typeof e=="string"?{requirement:(o=>o.type===e)}:e,r=s.calls??[];return {requirement:s.requirement??(o=>true),async resolve(o,c){if(r.push(o),s.delay&&await new Promise(l=>setTimeout(l,s.delay)),s.error)throw typeof s.error=="string"?new Error(s.error):s.error;s.resolve&&await s.resolve(o,c);}}}function E(e){let s=[],r=[];return {...{get calls(){return s},get pending(){return r},resolve(l){let m=r.shift();m&&m.resolve(l);},reject(l){let m=r.shift();m&&m.reject(l);},resolveAll(l){for(;r.length>0;)this.resolve(l);},rejectAll(l){for(;r.length>0;)this.reject(l);},reset(){s.length=0,r.length=0;}},handler:(l,m)=>(s.push(l),new Promise((d,v)=>{r.push({requirement:l,resolve:f=>d(f),reject:v});}))}}function P(e){return "module"in e?x(e):M(e)}function x(e){let s=[],r=new Map,o=[],c=[],l={};if(e.mocks?.resolvers)for(let[i,t]of Object.entries(e.mocks.resolvers)){let n=[];r.set(i,n),l[i]=b({...t,calls:n});}let m={...e.module,resolvers:{...e.module.resolvers,...l}},v=a({...e,module:m,plugins:[{name:"__test-tracking__",onFactSet:(i,t,n)=>{c.push({key:i,fullKey:i,namespace:void 0,previousValue:n,newValue:t,timestamp:Date.now()});},onRequirementCreated:i=>{o.push(i);}},...e.plugins??[]]}),f=v.dispatch.bind(v);return v.dispatch=i=>{s.push(i),f(i);},{...v,eventHistory:s,resolverCalls:r,get allRequirements(){return o},getFactsHistory(){return [...c]},resetFactsHistory(){c.length=0;},async waitForIdle(i=5e3){let t=Date.now(),n=async()=>{await new Promise(u=>setTimeout(u,0));let a=v.inspect();if(a.inflight.length>0){if(Date.now()-t>i){let u=a.inflight.map(g=>g.id).join(", ");throw new Error(`[Directive] waitForIdle timed out after ${i}ms. ${a.inflight.length} resolvers still inflight: ${u}`)}return await new Promise(u=>setTimeout(u,10)),n()}};return n()},assertRequirement(i){if(!o.some(n=>n.requirement.type===i))throw new Error(`[Directive] Expected requirement of type "${i}" but none found`)},assertResolverCalled(i,t){let n=r.get(i)??[];if(t!==void 0){if(n.length!==t)throw new Error(`[Directive] Expected resolver "${i}" to be called ${t} times but was called ${n.length} times`)}else if(n.length===0)throw new Error(`[Directive] Expected resolver "${i}" to be called but it was not`)},assertFactSet(i,t){let n=c.filter(a=>a.key===i);if(n.length===0)throw new Error(`[Directive] Expected fact "${i}" to be set but it was not`);if(t!==void 0&&!n.some(u=>u.newValue===t)){let u=n.map(g=>JSON.stringify(g.newValue)).join(", ");throw new Error(`[Directive] Expected fact "${i}" to be set to ${JSON.stringify(t)} but got: ${u}`)}},assertFactChanges(i,t){let n=c.filter(a=>a.key===i);if(n.length!==t)throw new Error(`[Directive] Expected fact "${i}" to change ${t} times but it changed ${n.length} times`)}}}function M(e){let s=[],r=new Map,o=[],c=[],l={};if(e.mocks?.resolvers)for(let[t,n]of Object.entries(e.mocks.resolvers)){let a=[];r.set(t,a),l[t]=b({...n,calls:a});}let m={};for(let[t,n]of Object.entries(e.modules))m[t]={...n,resolvers:{...n.resolvers,...l}};let d=new Set(Object.keys(e.modules)),f=a({...e,modules:m,plugins:[{name:"__test-tracking__",onFactSet:(t,n,a)=>{let g=t.indexOf("::"),y,h;if(g>0){let S=t.substring(0,g);d.has(S)?(y=S,h=t.substring(g+2)):h=t;}else h=t;c.push({key:h,fullKey:t,namespace:y,previousValue:a,newValue:n,timestamp:Date.now()});},onRequirementCreated:t=>{o.push(t);}},...e.plugins??[]]}),p=f.dispatch.bind(f);return f.dispatch=t=>{s.push(t),p(t);},{...f,eventHistory:s,resolverCalls:r,get allRequirements(){return o},getFactsHistory(){return [...c]},resetFactsHistory(){c.length=0;},async waitForIdle(t=5e3){let n=Date.now(),a=async()=>{await new Promise(g=>setTimeout(g,0));let u=f.inspect();if(u.inflight.length>0){if(Date.now()-n>t){let g=u.inflight.map(y=>y.id).join(", ");throw new Error(`[Directive] waitForIdle timed out after ${t}ms. ${u.inflight.length} resolvers still inflight: ${g}`)}return await new Promise(g=>setTimeout(g,10)),a()}};return a()},assertRequirement(t){if(!o.some(a=>a.requirement.type===t))throw new Error(`[Directive] Expected requirement of type "${t}" but none found`)},assertResolverCalled(t,n){let a=r.get(t)??[];if(n!==void 0){if(a.length!==n)throw new Error(`[Directive] Expected resolver "${t}" to be called ${n} times but was called ${a.length} times`)}else if(a.length===0)throw new Error(`[Directive] Expected resolver "${t}" to be called but it was not`)},assertFactSet(t,n){let a=c.filter(u=>u.key===t);if(a.length===0)throw new Error(`[Directive] Expected fact "${t}" to be set but it was not`);if(n!==void 0&&!a.some(g=>g.newValue===n)){let g=a.map(y=>JSON.stringify(y.newValue)).join(", ");throw new Error(`[Directive] Expected fact "${t}" to be set to ${JSON.stringify(n)} but got: ${g}`)}},assertFactChanges(t,n){let a=c.filter(u=>u.key===t);if(a.length!==n)throw new Error(`[Directive] Expected fact "${t}" to change ${n} times but it changed ${a.length} times`)}}}function O(e,s,r){if(!k(e,s,r))throw new Error(`[Directive] Expected ${s} "${r}" to be dynamic, but it is not.`)}function $(e,s,r){if(k(e,s,r))throw new Error(`[Directive] Expected ${s} "${r}" to NOT be dynamic, but it is.`)}function k(e,s,r){switch(s){case "constraint":return e.constraints.isDynamic(r);case "resolver":return e.resolvers.isDynamic(r);case "derivation":return e.derive.isDynamic(r);case "effect":return e.effects.isDynamic(r)}}function F(e){let s=new Set,r=new Set,o=new Set,c=new Set,l=null;return {async run(m){l=e.observe(d=>{switch(d.type){case "constraint.evaluate":d.active&&s.add(d.id);break;case "resolver.start":r.add(d.resolver);break;case "effect.run":o.add(d.id);break;case "derivation.compute":c.add(d.id);break}});try{await m();}finally{l?.(),l=null;}},report(){let m=e.inspect(),d=new Set(m.constraints.map(i=>i.id)),v=new Set(m.resolverDefs.map(i=>i.id)),f=new Set;for(let i of d)s.has(i)||f.add(i);let p=new Set;for(let i of v)r.has(i)||p.add(i);return {constraintsHit:s,constraintsMissed:f,resolversRun:r,resolversMissed:p,effectsRun:o,derivationsComputed:c,constraintCoverage:d.size===0?1:s.size/d.size,resolverCoverage:v.size===0?1:r.size/v.size,effectCoverage:m.effects.length===0?1:o.size/m.effects.length,derivationCoverage:m.derivations.length===0?1:c.size/m.derivations.length}}}}function I(e){let s=[],r=e.observe(o=>s.push(o));return {events:s,ofType(o){return s.filter(c=>c.type===o)},clear(){s.length=0;},dispose(){r();}}}export{O as assertDynamic,$ as assertNotDynamic,F as createCoverageTracker,C as createFakeTimers,b as createMockResolver,I as createTestObserver,P as createTestSystem,T as flushAsync,R as flushMicrotasks,E as mockResolver,D as settleWithFakeTimers};//# sourceMappingURL=testing.js.map
2
2
  //# sourceMappingURL=testing.js.map
@@ -207,28 +207,41 @@ declare function signSnapshot<T>(snapshot: DistributableSnapshotLike<T>, secret:
207
207
  * **Important:** Always verify signatures before trusting snapshot data,
208
208
  * especially if the snapshot was received from an untrusted source (client, cache).
209
209
  *
210
+ * The default verification enforces `expiresAt` — a captured-and-replayed
211
+ * snapshot stops verifying once its `expiresAt` is in the past. Callers
212
+ * that legitimately need signature-only validation (testing infrastructure,
213
+ * archival validation) can pass `{ ignoreExpiry: true }`.
214
+ *
210
215
  * @example
211
216
  * ```typescript
212
217
  * // Receive signed snapshot from client or cache
213
218
  * const snapshot = JSON.parse(cachedData);
214
219
  *
215
- * // Verify before using
220
+ * // Verify before using. `verifySnapshotSignature` returns false for an
221
+ * // expired snapshot even when the HMAC is valid; treat it as the
222
+ * // single attestation gate.
216
223
  * const isValid = await verifySnapshotSignature(snapshot, process.env.SNAPSHOT_SECRET);
217
224
  * if (!isValid) {
218
- * throw new Error('Invalid snapshot signature - possible tampering');
225
+ * throw new Error('Invalid or expired snapshot');
219
226
  * }
220
227
  *
221
228
  * // Now safe to use snapshot.data
222
- * if (snapshot.data.canUseFeature.api) {
223
- * // Grant access
224
- * }
229
+ * processSnapshotData(snapshot.data);
225
230
  * ```
226
231
  *
227
232
  * @param signedSnapshot - The signed snapshot to verify
228
233
  * @param secret - The HMAC secret (must match the signing secret)
229
- * @returns True if signature is valid, false otherwise
234
+ * @param options - Optional flags:
235
+ * - `ignoreExpiry`: skip the `expiresAt` check (signature-only mode)
236
+ * - `now`: override the current time used for expiry comparison
237
+ * (test helper)
238
+ * @returns True if signature is valid AND (unless `ignoreExpiry`) not
239
+ * expired; false otherwise
230
240
  */
231
- declare function verifySnapshotSignature<T>(signedSnapshot: SignedSnapshot<T>, secret: string | Uint8Array): Promise<boolean>;
241
+ declare function verifySnapshotSignature<T>(signedSnapshot: SignedSnapshot<T>, secret: string | Uint8Array, options?: {
242
+ ignoreExpiry?: boolean;
243
+ now?: number;
244
+ }): Promise<boolean>;
232
245
  /**
233
246
  * Safely stringify any value for display. Handles circular references,
234
247
  * BigInt, throwing toJSON, and optional truncation.
@@ -207,28 +207,41 @@ declare function signSnapshot<T>(snapshot: DistributableSnapshotLike<T>, secret:
207
207
  * **Important:** Always verify signatures before trusting snapshot data,
208
208
  * especially if the snapshot was received from an untrusted source (client, cache).
209
209
  *
210
+ * The default verification enforces `expiresAt` — a captured-and-replayed
211
+ * snapshot stops verifying once its `expiresAt` is in the past. Callers
212
+ * that legitimately need signature-only validation (testing infrastructure,
213
+ * archival validation) can pass `{ ignoreExpiry: true }`.
214
+ *
210
215
  * @example
211
216
  * ```typescript
212
217
  * // Receive signed snapshot from client or cache
213
218
  * const snapshot = JSON.parse(cachedData);
214
219
  *
215
- * // Verify before using
220
+ * // Verify before using. `verifySnapshotSignature` returns false for an
221
+ * // expired snapshot even when the HMAC is valid; treat it as the
222
+ * // single attestation gate.
216
223
  * const isValid = await verifySnapshotSignature(snapshot, process.env.SNAPSHOT_SECRET);
217
224
  * if (!isValid) {
218
- * throw new Error('Invalid snapshot signature - possible tampering');
225
+ * throw new Error('Invalid or expired snapshot');
219
226
  * }
220
227
  *
221
228
  * // Now safe to use snapshot.data
222
- * if (snapshot.data.canUseFeature.api) {
223
- * // Grant access
224
- * }
229
+ * processSnapshotData(snapshot.data);
225
230
  * ```
226
231
  *
227
232
  * @param signedSnapshot - The signed snapshot to verify
228
233
  * @param secret - The HMAC secret (must match the signing secret)
229
- * @returns True if signature is valid, false otherwise
234
+ * @param options - Optional flags:
235
+ * - `ignoreExpiry`: skip the `expiresAt` check (signature-only mode)
236
+ * - `now`: override the current time used for expiry comparison
237
+ * (test helper)
238
+ * @returns True if signature is valid AND (unless `ignoreExpiry`) not
239
+ * expired; false otherwise
230
240
  */
231
- declare function verifySnapshotSignature<T>(signedSnapshot: SignedSnapshot<T>, secret: string | Uint8Array): Promise<boolean>;
241
+ declare function verifySnapshotSignature<T>(signedSnapshot: SignedSnapshot<T>, secret: string | Uint8Array, options?: {
242
+ ignoreExpiry?: boolean;
243
+ now?: number;
244
+ }): Promise<boolean>;
232
245
  /**
233
246
  * Safely stringify any value for display. Handles circular references,
234
247
  * BigInt, throwing toJSON, and optional truncation.