@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.
- package/dist/adapter-utils.cjs +1 -1
- package/dist/adapter-utils.d.cts +1 -1
- package/dist/adapter-utils.d.ts +1 -1
- package/dist/adapter-utils.js +1 -1
- package/dist/chunk-EOLY64E6.cjs +3 -0
- package/dist/chunk-EOLY64E6.cjs.map +1 -0
- package/dist/chunk-K3KVGWLP.cjs +3 -0
- package/dist/chunk-K3KVGWLP.cjs.map +1 -0
- package/dist/chunk-OVNPYGYJ.js +3 -0
- package/dist/chunk-OVNPYGYJ.js.map +1 -0
- package/dist/chunk-QOK7CHOW.js +16 -0
- package/dist/chunk-QOK7CHOW.js.map +1 -0
- package/dist/chunk-T4ZO4IYL.cjs +16 -0
- package/dist/chunk-T4ZO4IYL.cjs.map +1 -0
- package/dist/chunk-T6IJUWYR.js +3 -0
- package/dist/chunk-T6IJUWYR.js.map +1 -0
- package/dist/{helpers-h9PR2JSJ.d.ts → helpers-BwAThjnJ.d.ts} +1 -1
- package/dist/{helpers-B1MiHave.d.cts → helpers-CG27mEGG.d.cts} +1 -1
- package/dist/index.cjs +4 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +236 -6
- package/dist/index.d.ts +236 -6
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +1 -1
- package/dist/internals.d.cts +41 -5
- package/dist/internals.d.ts +41 -5
- package/dist/internals.js +1 -1
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.cjs.map +1 -1
- package/dist/plugins/index.d.cts +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/index.js +1 -1
- package/dist/plugins/index.js.map +1 -1
- package/dist/{plugins-Bakr7js6.d.ts → plugins-DvrsPhzx.d.cts} +124 -21
- package/dist/{plugins-Bakr7js6.d.cts → plugins-DvrsPhzx.d.ts} +124 -21
- package/dist/system-5BSCMT63.cjs +2 -0
- package/dist/{system-CK3SHMXZ.cjs.map → system-5BSCMT63.cjs.map} +1 -1
- package/dist/system-DMJ6XEJ7.js +2 -0
- package/dist/{system-744ZPPES.js.map → system-DMJ6XEJ7.js.map} +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/worker.cjs +1 -1
- package/dist/worker.d.cts +1 -1
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-HAF5JCET.js +0 -16
- package/dist/chunk-HAF5JCET.js.map +0 -1
- package/dist/chunk-M5KZXNZX.js +0 -3
- package/dist/chunk-M5KZXNZX.js.map +0 -1
- package/dist/chunk-PGUTGWUI.cjs +0 -3
- package/dist/chunk-PGUTGWUI.cjs.map +0 -1
- package/dist/chunk-SQVKCJHE.cjs +0 -16
- package/dist/chunk-SQVKCJHE.cjs.map +0 -1
- package/dist/chunk-YCCQ73C6.js +0 -3
- package/dist/chunk-YCCQ73C6.js.map +0 -1
- package/dist/chunk-ZHS3EW2Z.cjs +0 -3
- package/dist/chunk-ZHS3EW2Z.cjs.map +0 -1
- package/dist/system-744ZPPES.js +0 -2
- 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,
|
|
2
|
-
export { A as AnySystem, B as BatchConfig,
|
|
3
|
-
export { D as DerivationDefWithMeta, t as typedConstraint, a as typedResolver } from './helpers-
|
|
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
|
|
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,
|
|
2
|
-
export { A as AnySystem, B as BatchConfig,
|
|
3
|
-
export { D as DerivationDefWithMeta, t as typedConstraint, a as typedResolver } from './helpers-
|
|
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
|
|
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
|