@directive-run/core 1.22.0 → 1.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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-C3FW27S5.js +3 -0
- package/dist/chunk-C3FW27S5.js.map +1 -0
- package/dist/chunk-IZNOPHPL.js +3 -0
- package/dist/chunk-IZNOPHPL.js.map +1 -0
- package/dist/chunk-LN5H74CU.js +2 -0
- package/dist/{chunk-RBF653NR.js.map → chunk-LN5H74CU.js.map} +1 -1
- package/dist/chunk-PTT4MWNL.cjs +3 -0
- package/dist/chunk-PTT4MWNL.cjs.map +1 -0
- package/dist/chunk-QR2756CJ.js +2 -0
- package/dist/chunk-QR2756CJ.js.map +1 -0
- package/dist/{chunk-GKMJ7NMP.cjs → chunk-RD2HO5NZ.cjs} +2 -2
- package/dist/{chunk-GKMJ7NMP.cjs.map → chunk-RD2HO5NZ.cjs.map} +1 -1
- package/dist/{chunk-GACC2DMS.cjs → chunk-S6W6Y44G.cjs} +2 -2
- package/dist/{chunk-GACC2DMS.cjs.map → chunk-S6W6Y44G.cjs.map} +1 -1
- package/dist/{chunk-YJEDX2JX.js → chunk-SERVIHA3.js} +3 -3
- package/dist/chunk-SERVIHA3.js.map +1 -0
- package/dist/{chunk-OAPD3HIG.cjs → chunk-UDSP7U54.cjs} +3 -3
- package/dist/chunk-UDSP7U54.cjs.map +1 -0
- package/dist/chunk-UQZ2SMGS.cjs +2 -0
- package/dist/chunk-UQZ2SMGS.cjs.map +1 -0
- package/dist/{chunk-6PF2FRBG.js → chunk-WD47DB52.js} +2 -2
- package/dist/{chunk-6PF2FRBG.js.map → chunk-WD47DB52.js.map} +1 -1
- package/dist/chunk-WU4AXN3P.cjs +3 -0
- package/dist/chunk-WU4AXN3P.cjs.map +1 -0
- package/dist/{index-DRPkZ8HE.d.cts → index-Bz6DOdDN.d.ts} +32 -5
- package/dist/{index-BgKC_ZT_.d.ts → index-Cpgj4byM.d.cts} +32 -5
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -130
- package/dist/index.d.ts +8 -130
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +1 -1
- package/dist/internals.d.cts +10 -4
- package/dist/internals.d.ts +10 -4
- package/dist/internals.js +1 -1
- package/dist/plugins/index.cjs +2 -2
- package/dist/plugins/index.cjs.map +1 -1
- package/dist/plugins/index.d.cts +202 -3
- package/dist/plugins/index.d.ts +202 -3
- package/dist/plugins/index.js +2 -2
- package/dist/plugins/index.js.map +1 -1
- package/dist/{plugins-5Supk7it.d.cts → plugins-CaPMTICa.d.cts} +323 -2
- package/dist/{plugins-5Supk7it.d.ts → plugins-CaPMTICa.d.ts} +323 -2
- package/dist/{predicate-DYb-3Mvl.d.cts → predicate-CU0YC1i6.d.cts} +1 -1
- package/dist/{predicate-C9oMO_ny.d.ts → predicate-CgpwJqf4.d.ts} +1 -1
- package/dist/system-T6EZ6EYN.js +2 -0
- package/dist/{system-6YWCXQOQ.js.map → system-T6EZ6EYN.js.map} +1 -1
- package/dist/system-V7B4YUIR.cjs +2 -0
- package/dist/{system-5FKUBLLV.cjs.map → system-V7B4YUIR.cjs.map} +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/worker.cjs +1 -1
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.cts +1 -1
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-6NCC6RBC.js +0 -3
- package/dist/chunk-6NCC6RBC.js.map +0 -1
- package/dist/chunk-GBCWXTXW.cjs +0 -3
- package/dist/chunk-GBCWXTXW.cjs.map +0 -1
- package/dist/chunk-KGTBTGOY.js +0 -2
- package/dist/chunk-KGTBTGOY.js.map +0 -1
- package/dist/chunk-MARZI3EY.cjs +0 -2
- package/dist/chunk-MARZI3EY.cjs.map +0 -1
- package/dist/chunk-OAPD3HIG.cjs.map +0 -1
- package/dist/chunk-QTY2FXZY.cjs +0 -3
- package/dist/chunk-QTY2FXZY.cjs.map +0 -1
- package/dist/chunk-RBF653NR.js +0 -2
- package/dist/chunk-SFUVPP4L.js +0 -3
- package/dist/chunk-SFUVPP4L.js.map +0 -1
- package/dist/chunk-YJEDX2JX.js.map +0 -1
- package/dist/system-5FKUBLLV.cjs +0 -2
- package/dist/system-6YWCXQOQ.js +0 -2
|
@@ -1075,6 +1075,60 @@ type EventsDef<S extends Schema> = Record<string, FlexibleEventHandler<S>>;
|
|
|
1075
1075
|
type JitterStrategy = "none" | "full" | "equal" | {
|
|
1076
1076
|
maxMs: number;
|
|
1077
1077
|
};
|
|
1078
|
+
/**
|
|
1079
|
+
* Why a resolver attempt was aborted, surfaced to {@link RetryPolicy.shouldRetry}
|
|
1080
|
+
* so the policy can distinguish "retry on race-loss" from "fail loud on bug."
|
|
1081
|
+
*
|
|
1082
|
+
* - `"clobbered"` — an `abortOn`-listed fact was written by something
|
|
1083
|
+
* outside the resolver between the resolver's baseline read and its
|
|
1084
|
+
* next write (RFC 0003 optimistic-concurrency check). The retry is
|
|
1085
|
+
* typically safe — the resolver re-reads the current value and tries
|
|
1086
|
+
* again with fresh context.
|
|
1087
|
+
* - `"timeout"` — the resolver's `timeout` ms elapsed. Retrying may
|
|
1088
|
+
* succeed if the underlying I/O was just slow; may fail again if the
|
|
1089
|
+
* timeout is set too tight for the workload.
|
|
1090
|
+
* - `"cancelled"` — `system.stop()` was called, or external code aborted
|
|
1091
|
+
* the resolver's `ctx.signal`. Retrying is almost always wrong — the
|
|
1092
|
+
* cancellation was the caller's explicit intent.
|
|
1093
|
+
* - `"error"` — the resolver threw. Default for back-compat: any abort
|
|
1094
|
+
* without a more specific reason maps here.
|
|
1095
|
+
*
|
|
1096
|
+
* Core has no supersession concept today; if a future package wants to
|
|
1097
|
+
* surface supersession, it can widen the union additively without
|
|
1098
|
+
* breaking back-compat.
|
|
1099
|
+
*
|
|
1100
|
+
* @public
|
|
1101
|
+
*/
|
|
1102
|
+
type ResolverAbortReason = "clobbered" | "timeout" | "cancelled" | "error";
|
|
1103
|
+
/**
|
|
1104
|
+
* Context object passed as the optional third argument to
|
|
1105
|
+
* {@link RetryPolicy.shouldRetry}. Lets the policy decide based on WHY
|
|
1106
|
+
* the attempt failed — not just the thrown error.
|
|
1107
|
+
*
|
|
1108
|
+
* Two-argument `shouldRetry(error, attempt)` continues to work; the
|
|
1109
|
+
* context argument is additive. Existing callers see no behavior change.
|
|
1110
|
+
*
|
|
1111
|
+
* @public
|
|
1112
|
+
*/
|
|
1113
|
+
interface ShouldRetryContext {
|
|
1114
|
+
/**
|
|
1115
|
+
* Why the attempt was aborted. Undefined when the engine couldn't
|
|
1116
|
+
* classify the cause (very rare — defaults to `"error"` in practice).
|
|
1117
|
+
*/
|
|
1118
|
+
reason?: ResolverAbortReason;
|
|
1119
|
+
/**
|
|
1120
|
+
* Populated only when `reason === "clobbered"`. Names the `abortOn`
|
|
1121
|
+
* fact whose mid-flight change tripped the binding, plus the expected
|
|
1122
|
+
* baseline value and the actual current value. Useful for
|
|
1123
|
+
* `shouldRetry: (_, _, ctx) => ctx?.clobber?.fact === "cart.discount"`
|
|
1124
|
+
* patterns that only retry contention on specific facts.
|
|
1125
|
+
*/
|
|
1126
|
+
clobber?: {
|
|
1127
|
+
fact: string;
|
|
1128
|
+
expected: unknown;
|
|
1129
|
+
actual: unknown;
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1078
1132
|
/** Retry policy configuration */
|
|
1079
1133
|
interface RetryPolicy {
|
|
1080
1134
|
/** Maximum number of attempts */
|
|
@@ -1101,10 +1155,24 @@ interface RetryPolicy {
|
|
|
1101
1155
|
* Return `true` to retry, `false` to stop immediately.
|
|
1102
1156
|
* If omitted, all errors are retried (up to `attempts`).
|
|
1103
1157
|
*
|
|
1158
|
+
* The optional third `context` argument carries the abort reason and,
|
|
1159
|
+
* for clobbers, the fact + expected/actual values. Existing two-arg
|
|
1160
|
+
* callers continue to work — the third arg is undefined when omitted.
|
|
1161
|
+
*
|
|
1162
|
+
* @example Retry on contention, fail loud on bug
|
|
1163
|
+
* ```ts
|
|
1164
|
+
* shouldRetry: (err, attempt, ctx) => {
|
|
1165
|
+
* if (ctx?.reason === "clobbered") return attempt < 5;
|
|
1166
|
+
* if (ctx?.reason === "timeout") return attempt < 2;
|
|
1167
|
+
* return false; // "error" / "cancelled" → don't retry
|
|
1168
|
+
* }
|
|
1169
|
+
* ```
|
|
1170
|
+
*
|
|
1104
1171
|
* @param error - The error that occurred
|
|
1105
1172
|
* @param attempt - The attempt number that just failed (1-based)
|
|
1173
|
+
* @param context - Optional abort context (added v1.23.0); undefined for callers that don't pass it
|
|
1106
1174
|
*/
|
|
1107
|
-
shouldRetry?: (error: Error, attempt: number) => boolean;
|
|
1175
|
+
shouldRetry?: (error: Error, attempt: number, context?: ShouldRetryContext) => boolean;
|
|
1108
1176
|
}
|
|
1109
1177
|
/** Batch configuration */
|
|
1110
1178
|
interface BatchConfig {
|
|
@@ -1315,6 +1383,128 @@ type ResolverStatus = {
|
|
|
1315
1383
|
canceledAt: number;
|
|
1316
1384
|
};
|
|
1317
1385
|
|
|
1386
|
+
/**
|
|
1387
|
+
* Structural diff between two snapshots of a system's constraint `whenSpec`
|
|
1388
|
+
* map. The "git diff for business rules" — operates on the predicate AST
|
|
1389
|
+
* instead of source-text lines.
|
|
1390
|
+
*
|
|
1391
|
+
* A predicate is a tree of leaf clauses (`{ fact: operator(value) }`) and
|
|
1392
|
+
* combinators (`$all` / `$any` / `$not`). `diffRules` flattens both trees
|
|
1393
|
+
* into path-keyed leaf lists and compares: missing path → added/removed,
|
|
1394
|
+
* same path with different operand → changed (with relaxed/tightened
|
|
1395
|
+
* classification for numeric thresholds).
|
|
1396
|
+
*
|
|
1397
|
+
* Pure module — imports only utils. No engine / store / predicate-runtime
|
|
1398
|
+
* dependency: predicates are walked as plain JSON.
|
|
1399
|
+
*/
|
|
1400
|
+
/** A leaf clause extracted from a predicate tree, keyed by its dotted path. */
|
|
1401
|
+
interface LeafClause {
|
|
1402
|
+
/** Dotted path through the predicate. E.g. `phase`, `$all[0].elapsed`, `$not.paused`. */
|
|
1403
|
+
path: string;
|
|
1404
|
+
/** Operator name. `$eq` is implied for bare-value equality. */
|
|
1405
|
+
op: string;
|
|
1406
|
+
/** Operand. */
|
|
1407
|
+
value: unknown;
|
|
1408
|
+
}
|
|
1409
|
+
/** Kind of change observed for a single clause. */
|
|
1410
|
+
type ChangeKind = "added" | "removed" | "changed" | "relaxed" | "tightened";
|
|
1411
|
+
/** A single change between two predicates at a specific path. */
|
|
1412
|
+
interface Change {
|
|
1413
|
+
path: string;
|
|
1414
|
+
kind: ChangeKind;
|
|
1415
|
+
before?: {
|
|
1416
|
+
op: string;
|
|
1417
|
+
value: unknown;
|
|
1418
|
+
};
|
|
1419
|
+
after?: {
|
|
1420
|
+
op: string;
|
|
1421
|
+
value: unknown;
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
/** Status of a single constraint across the two snapshots. */
|
|
1425
|
+
type ConstraintStatus = "added" | "removed" | "changed" | "unchanged";
|
|
1426
|
+
interface ConstraintDiff {
|
|
1427
|
+
id: string;
|
|
1428
|
+
status: ConstraintStatus;
|
|
1429
|
+
/** Empty for `unchanged`. For `added` / `removed`, every leaf is listed once. */
|
|
1430
|
+
changes: Change[];
|
|
1431
|
+
}
|
|
1432
|
+
interface RulesDiffReport {
|
|
1433
|
+
constraints: ConstraintDiff[];
|
|
1434
|
+
summary: {
|
|
1435
|
+
added: number;
|
|
1436
|
+
removed: number;
|
|
1437
|
+
changed: number;
|
|
1438
|
+
unchanged: number;
|
|
1439
|
+
totalClauseChanges: number;
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1442
|
+
interface DiffRulesOptions {
|
|
1443
|
+
before: RulesMapInput;
|
|
1444
|
+
after: RulesMapInput;
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Accepted shapes for the `before` / `after` predicate maps:
|
|
1448
|
+
* - A plain map `{ [constraintId]: whenSpec }`
|
|
1449
|
+
* - The `system.inspect().constraints` array form `Array<{ id, whenSpec? }>`
|
|
1450
|
+
* - Either wrapped as `{ constraints: <one-of-the-above> }`
|
|
1451
|
+
*
|
|
1452
|
+
* Anything else throws at `toRulesMap` so a bad input fails loud.
|
|
1453
|
+
*/
|
|
1454
|
+
type RulesMapInput = unknown;
|
|
1455
|
+
/**
|
|
1456
|
+
* Coerce supported input shapes into a flat `Record<constraintId, whenSpec>`.
|
|
1457
|
+
* Constraints without a `whenSpec` (function-form `when`) are dropped with
|
|
1458
|
+
* an undefined entry so callers can distinguish them from absent constraints
|
|
1459
|
+
* if they care; the diff treats `undefined` as "no data" and skips clause
|
|
1460
|
+
* walking.
|
|
1461
|
+
*/
|
|
1462
|
+
declare function toRulesMap(raw: RulesMapInput): Record<string, unknown>;
|
|
1463
|
+
/**
|
|
1464
|
+
* Walk a predicate tree and emit every leaf clause with its dotted path.
|
|
1465
|
+
* Combinators (`$all` / `$any` / `$not`) become indexed path segments.
|
|
1466
|
+
* Bare-value equality (`{ phase: "red" }`) emits as `op: "$eq"`.
|
|
1467
|
+
*
|
|
1468
|
+
* Array-form predicates (`[{ fact, op, value }, ...]`) are also accepted —
|
|
1469
|
+
* each clause's `fact` becomes the path, the operator is `op`, and the
|
|
1470
|
+
* value is `value`.
|
|
1471
|
+
*
|
|
1472
|
+
* **What gets dropped:** non-object combinator children (e.g. `$not: "red"`
|
|
1473
|
+
* with a string operand instead of a predicate object), function-form
|
|
1474
|
+
* predicates (the engine accepts a function for `when`; this walker only
|
|
1475
|
+
* sees data), and bare primitive predicates (a top-level `true` or `"x"`).
|
|
1476
|
+
* The walker is a tree visitor — anything not shaped like a predicate node
|
|
1477
|
+
* is silently skipped, never thrown on.
|
|
1478
|
+
*/
|
|
1479
|
+
declare function flattenPredicate(spec: unknown, pathPrefix?: string, out?: LeafClause[]): LeafClause[];
|
|
1480
|
+
/**
|
|
1481
|
+
* Diff two snapshots of a system's constraint whenSpec map.
|
|
1482
|
+
*
|
|
1483
|
+
* @example
|
|
1484
|
+
* ```ts
|
|
1485
|
+
* const report = diffRules({
|
|
1486
|
+
* before: { blockCheckout: { cartTotal: { $gte: 100 } } },
|
|
1487
|
+
* after: { blockCheckout: { cartTotal: { $gte: 50 } } },
|
|
1488
|
+
* });
|
|
1489
|
+
*
|
|
1490
|
+
* report.constraints[0].status; // "changed"
|
|
1491
|
+
* report.constraints[0].changes[0].kind; // "relaxed"
|
|
1492
|
+
* report.summary.totalClauseChanges; // 1
|
|
1493
|
+
* ```
|
|
1494
|
+
*
|
|
1495
|
+
* The input shape is forgiving — either a flat `{ id: whenSpec }` map, the
|
|
1496
|
+
* `system.inspect().constraints` array form, or either wrapped as
|
|
1497
|
+
* `{ constraints: ... }`. Constraints whose `when` is a function (no
|
|
1498
|
+
* `whenSpec`) are tracked as added/removed but cannot be clause-diffed
|
|
1499
|
+
* (the function form is opaque).
|
|
1500
|
+
*/
|
|
1501
|
+
declare function diffRules(options: DiffRulesOptions): RulesDiffReport;
|
|
1502
|
+
/**
|
|
1503
|
+
* Diff two predicate trees and return the list of leaf-level changes.
|
|
1504
|
+
* Exported for reuse beyond the full per-constraint report.
|
|
1505
|
+
*/
|
|
1506
|
+
declare function diffClauses(before: unknown, after: unknown): Change[];
|
|
1507
|
+
|
|
1318
1508
|
/**
|
|
1319
1509
|
* Error Types - Type definitions for error handling
|
|
1320
1510
|
*/
|
|
@@ -3077,6 +3267,46 @@ interface MetaAccessor {
|
|
|
3077
3267
|
/** Find all definitions matching a tag across all types. */
|
|
3078
3268
|
byTag(tag: string): MetaMatch[];
|
|
3079
3269
|
}
|
|
3270
|
+
/**
|
|
3271
|
+
* Discriminated proof of why two resolvers' `when:` predicates fire on
|
|
3272
|
+
* the same state — attached to `resolver.clobber.loop.detected` events
|
|
3273
|
+
* so the warning can point at the specific clauses that co-fire instead
|
|
3274
|
+
* of stopping at "these resolvers fight."
|
|
3275
|
+
*
|
|
3276
|
+
* - `matched` — both predicates have identical structural clauses.
|
|
3277
|
+
* The strongest verdict; the rules are syntactic duplicates.
|
|
3278
|
+
* - `overlap` — clauses share at least one path and at least one
|
|
3279
|
+
* pairwise comparison says they co-fire (with no direct
|
|
3280
|
+
* contradictions). Strong verdict, slightly weaker than `matched`.
|
|
3281
|
+
* - `indeterminate` — a non-COMPARABLE operator (`$regex`, `$elemMatch`,
|
|
3282
|
+
* `$matches`, custom) appeared. The proof builder declines to assert
|
|
3283
|
+
* overlap; the message says so explicitly rather than falsely
|
|
3284
|
+
* reporting a contradiction.
|
|
3285
|
+
* - `function-form-opaque` — at least one constraint uses a function
|
|
3286
|
+
* `when:` (`(facts) => ...`), so structural comparison is impossible.
|
|
3287
|
+
* The warning text disclaims; if audit-ledger is mounted and its
|
|
3288
|
+
* `whenSourceCache` is available, identifying hashes of the function
|
|
3289
|
+
* source are included for cross-version diffing.
|
|
3290
|
+
*
|
|
3291
|
+
* @public
|
|
3292
|
+
*/
|
|
3293
|
+
type PredicateOverlapProof = {
|
|
3294
|
+
verdict: "matched";
|
|
3295
|
+
coFireClauses: readonly LeafClause[];
|
|
3296
|
+
conflictingClauses: readonly never[];
|
|
3297
|
+
} | {
|
|
3298
|
+
verdict: "overlap";
|
|
3299
|
+
coFireClauses: readonly LeafClause[];
|
|
3300
|
+
conflictingClauses: readonly LeafClause[];
|
|
3301
|
+
} | {
|
|
3302
|
+
verdict: "indeterminate";
|
|
3303
|
+
reason: "non-comparable-operator";
|
|
3304
|
+
coFireClauses: readonly LeafClause[];
|
|
3305
|
+
} | {
|
|
3306
|
+
verdict: "function-form-opaque";
|
|
3307
|
+
reason: "one-or-both-when-is-a-function";
|
|
3308
|
+
whenSourceHashes?: readonly string[];
|
|
3309
|
+
};
|
|
3080
3310
|
/** Typed events emitted by system.observe(). */
|
|
3081
3311
|
type ObservationEvent = {
|
|
3082
3312
|
type: "fact.change";
|
|
@@ -3188,6 +3418,52 @@ type ObservationEvent = {
|
|
|
3188
3418
|
requirementId: string;
|
|
3189
3419
|
reason: "clobbered";
|
|
3190
3420
|
dropped: number;
|
|
3421
|
+
}
|
|
3422
|
+
/**
|
|
3423
|
+
* v1.23.0 — fires when `clobberLoopPlugin` detects a sustained pattern
|
|
3424
|
+
* of clobbers on a fact involving the same set of resolvers above
|
|
3425
|
+
* threshold within a time window. A single clobber is fine; the
|
|
3426
|
+
* binding catches the race and the audit ledger records it. A *loop*
|
|
3427
|
+
* is two or more resolvers whose `when:` predicates both satisfy a
|
|
3428
|
+
* shared state and rewrite the fact every reconcile tick.
|
|
3429
|
+
*
|
|
3430
|
+
* `participants` is the unordered, distinct set of resolver IDs
|
|
3431
|
+
* contributing to the loop. `predicateOverlap` (when both sides use a
|
|
3432
|
+
* data-form `when:`) explains WHY the loop occurs — which clauses
|
|
3433
|
+
* co-fire — so the suggested fix (add `priority:`, narrow `when:`,
|
|
3434
|
+
* merge) is grounded in the actual rules, not a guess.
|
|
3435
|
+
*/
|
|
3436
|
+
| {
|
|
3437
|
+
type: "resolver.clobber.loop.detected";
|
|
3438
|
+
systemId: string;
|
|
3439
|
+
fact: string;
|
|
3440
|
+
participants: readonly string[];
|
|
3441
|
+
participantModules: readonly string[];
|
|
3442
|
+
count: number;
|
|
3443
|
+
windowMs: number;
|
|
3444
|
+
firstAt: number;
|
|
3445
|
+
lastAt: number;
|
|
3446
|
+
predicateOverlap?: PredicateOverlapProof;
|
|
3447
|
+
severity: "warn" | "error";
|
|
3448
|
+
factTags: readonly string[];
|
|
3449
|
+
suppressedSinceLastEmit: number;
|
|
3450
|
+
rejectionSeqs: readonly number[];
|
|
3451
|
+
}
|
|
3452
|
+
/**
|
|
3453
|
+
* v1.23.0 — fires when a previously-detected clobber loop closes
|
|
3454
|
+
* cleanly, so dashboards can show "5 active loops" not "47
|
|
3455
|
+
* historical loops". A loop is considered resolved when the
|
|
3456
|
+
* `(fact, participantSet)` goes a quiet window without further
|
|
3457
|
+
* `resolver.write.rejected` events, OR a participant is unregistered,
|
|
3458
|
+
* OR a constraint re-registration changes a participant's `whenSpec`.
|
|
3459
|
+
*/
|
|
3460
|
+
| {
|
|
3461
|
+
type: "resolver.clobber.loop.resolved";
|
|
3462
|
+
systemId: string;
|
|
3463
|
+
fact: string;
|
|
3464
|
+
participants: readonly string[];
|
|
3465
|
+
durationMs: number;
|
|
3466
|
+
resolution: "no-recurrence-in-window" | "participant-disabled" | "predicate-narrowed";
|
|
3191
3467
|
} | {
|
|
3192
3468
|
type: "effect.run";
|
|
3193
3469
|
id: string;
|
|
@@ -3375,6 +3651,31 @@ interface System<M extends ModuleSchema = ModuleSchema> {
|
|
|
3375
3651
|
*/
|
|
3376
3652
|
readonly notify: {
|
|
3377
3653
|
guardrailBlocked(plugin: string, key: string, kind: "redact" | "alert" | "detect", count: number, category?: string): void;
|
|
3654
|
+
/**
|
|
3655
|
+
* v1.23.0 — plugin authoring surface for emitting the
|
|
3656
|
+
* `"resolver.clobber.loop.detected"` ObservationEvent. Used by
|
|
3657
|
+
* `clobberLoopPlugin` (and any compatible third-party detector). The
|
|
3658
|
+
* call fans out to all registered plugins' `onClobberLoopDetected`
|
|
3659
|
+
* hooks (including the synthetic plugins that back `system.observe()`)
|
|
3660
|
+
* so audit-ledger, devtools, and OTel exporters capture the event
|
|
3661
|
+
* without taking a dependency on the originating detector.
|
|
3662
|
+
*
|
|
3663
|
+
* Application code should never call this directly — use
|
|
3664
|
+
* `system.observe()` to subscribe.
|
|
3665
|
+
*/
|
|
3666
|
+
clobberLoopDetected(event: ObservationEvent & {
|
|
3667
|
+
type: "resolver.clobber.loop.detected";
|
|
3668
|
+
}): void;
|
|
3669
|
+
/**
|
|
3670
|
+
* v1.23.0 — companion to {@link clobberLoopDetected}. Fires when a
|
|
3671
|
+
* previously-detected loop is considered resolved (quiet window
|
|
3672
|
+
* elapsed, participant unregistered, or predicate narrowed). Lets
|
|
3673
|
+
* monitoring dashboards show "active loops" rather than
|
|
3674
|
+
* "historical loops."
|
|
3675
|
+
*/
|
|
3676
|
+
clobberLoopResolved(event: ObservationEvent & {
|
|
3677
|
+
type: "resolver.clobber.loop.resolved";
|
|
3678
|
+
}): void;
|
|
3378
3679
|
};
|
|
3379
3680
|
/** Per-run trace entries (null if trace is not enabled) */
|
|
3380
3681
|
readonly trace: TraceEntry[] | null;
|
|
@@ -3874,6 +4175,26 @@ interface Plugin<M extends ModuleSchema = ModuleSchema> {
|
|
|
3874
4175
|
* payloads.
|
|
3875
4176
|
*/
|
|
3876
4177
|
onGuardrailBlocked?: (plugin: string, key: string, kind: "redact" | "alert" | "detect", count: number, category?: string) => void;
|
|
4178
|
+
/**
|
|
4179
|
+
* Called when `clobberLoopPlugin` (or any equivalent detector) publishes
|
|
4180
|
+
* a structured loop event through `system.notify.clobberLoopDetected(...)`.
|
|
4181
|
+
* Surfaces as the `"resolver.clobber.loop.detected"` `ObservationEvent`
|
|
4182
|
+
* for `system.observe()` subscribers + audit-ledger + devtools, so
|
|
4183
|
+
* downstream backends can capture loops without taking a direct
|
|
4184
|
+
* dependency on `clobberLoopPlugin`.
|
|
4185
|
+
*/
|
|
4186
|
+
onClobberLoopDetected?: (event: ObservationEvent & {
|
|
4187
|
+
type: "resolver.clobber.loop.detected";
|
|
4188
|
+
}) => void;
|
|
4189
|
+
/**
|
|
4190
|
+
* Called when a previously-detected loop is considered resolved (quiet
|
|
4191
|
+
* window elapsed, participant unregistered, or predicate narrowed).
|
|
4192
|
+
* Pairs with `onClobberLoopDetected` so dashboards can show "active
|
|
4193
|
+
* loops" rather than "historical loops."
|
|
4194
|
+
*/
|
|
4195
|
+
onClobberLoopResolved?: (event: ObservationEvent & {
|
|
4196
|
+
type: "resolver.clobber.loop.resolved";
|
|
4197
|
+
}) => void;
|
|
3877
4198
|
/**
|
|
3878
4199
|
* Called when a history snapshot is taken.
|
|
3879
4200
|
* @param snapshot - The snapshot that was captured
|
|
@@ -3932,4 +4253,4 @@ interface Plugin<M extends ModuleSchema = ModuleSchema> {
|
|
|
3932
4253
|
onTraceComplete?: (entry: TraceEntry) => void;
|
|
3933
4254
|
}
|
|
3934
4255
|
|
|
3935
|
-
export { type
|
|
4256
|
+
export { type InferDerivations 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 CrossModuleEffectDef as G, type DiffRulesOptions as H, DirectiveError as I, type DistributableSnapshot as J, type DistributableSnapshotOptions as K, type DynamicConstraintDef as L, type ModuleSchema as M, type NamespacedSystem as N, type DynamicEffectDef as O, type Plugin as P, type DynamicResolverDef as Q, type RequirementWithId as R, type SchemaType as S, type TypedDerivationsDef as T, type EffectDef as U, type EventsDef as V, type FactTemplate as W, type FactsSnapshot as X, type HistoryAPI as Y, type HistoryOption as Z, type HistoryState as _, type Facts as a, type CrossModuleDerivationFn as a$, type InferEvents as a0, type InferFacts as a1, type InferRequirementTypes as a2, type InferRequirements as a3, type InferSchemaType as a4, type InferSelectorState as a5, type KeySelector as a6, type LeafClause as a7, type MetaAccessor as a8, type MetaMatch as a9, type System as aA, type SystemConfig as aB, type SystemDerived as aC, type SystemFacts as aD, type SystemInspection as aE, type SystemMode as aF, type SystemSnapshot as aG, type TraceEntry as aH, type TypedConstraintDef as aI, type TypedResolverDef as aJ, diffClauses as aK, diffRules as aL, flattenPredicate as aM, isNamespacedSystem as aN, isSingleModuleSystem as aO, toRulesMap as aP, type FactsStore as aQ, type ConstraintState as aR, type ResolverStatus as aS, type FactChange as aT, type ReconcileResult as aU, type RecoveryStrategy as aV, type ErrorSource as aW, type RetryLaterConfig as aX, type BatchItemResult as aY, type BatchResolveResults as aZ, type ConstraintsControl as a_, type ObservationEvent as aa, type OperatorObject as ab, type PatchSpec as ac, type PatchValue as ad, type PayloadRef as ae, type PredicateClause as af, type PredicateCombinator as ag, type PredicateCombinatorKey as ah, type PredicateObject as ai, type PredicateOp as aj, type PredicateOverlapProof as ak, type ResolverAbortReason as al, type ResolverDef as am, type ResolversDef as an, type RetryPolicy as ao, type RulesDiffReport as ap, type RulesMapInput as aq, type Schema as ar, type SchemaTypedResolversDef as as, type ShouldRetryContext as at, type Snapshot as au, type SourceDef as av, type SourceDropReason as aw, type SourcePublish as ax, type SourceReportError as ay, type SourceUnsubscribe as az, type TypedEventsDef as b, type CrossModuleFactsWithSelf as b0, type DerivationKeys as b1, type DerivationReturnType as b2, type DerivationsControl as b3, type DerivationsSchema as b4, type DeriveAccessor as b5, type DispatchEventsFromSchema as b6, type EffectCleanup as b7, type EffectsControl as b8, type EventPayloadSchema as b9, type RequirementOutput$1 as bA, type EventsAccessor as ba, type EventsAccessorFromSchema as bb, type EventsSchema as bc, type FactKeys as bd, type FactReturnType as be, type FlexibleEventHandler as bf, type HistoryConfig as bg, type InferEventPayloadFromSchema as bh, type InferRequirementPayloadFromSchema as bi, type InferSchema as bj, type MutableNamespacedFacts as bk, type NamespacedDerivations as bl, type NamespacedEventsAccessor as bm, type NamespacedFacts as bn, type ObservableKeys as bo, type RequirementExplanation as bp, type RequirementOutput as bq, type RequirementPayloadSchema$1 as br, type RequirementsSchema as bs, type ResolverContext as bt, type ResolversControl as bu, type SnapshotMeta as bv, type SystemEvent as bw, type TraceConfig as bx, type TypedResolverContext as by, type UnionEvents as bz, 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 Change as t, type ChangeKind as u, type ConstraintDef as v, type ConstraintDiff as w, type ConstraintStatus as x, type ConstraintsDef as y, type CrossModuleConstraintDef as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ar as Schema, a as Facts, F as FactPredicate, bj as InferSchema, W as FactTemplate, D as DefinitionMeta, r as Requirement, bA as RequirementOutput, ao as RetryPolicy, B as BatchConfig, bt as ResolverContext, aj as PredicateOp, ac as PatchSpec, C as ClauseResult } from './plugins-CaPMTICa.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Derivation Types - Type definitions for derivations
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ar as Schema, a as Facts, F as FactPredicate, bj as InferSchema, W as FactTemplate, D as DefinitionMeta, r as Requirement, bA as RequirementOutput, ao as RetryPolicy, B as BatchConfig, bt as ResolverContext, aj as PredicateOp, ac as PatchSpec, C as ClauseResult } from './plugins-CaPMTICa.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Derivation Types - Type definitions for derivations
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"system-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"system-T6EZ6EYN.js"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use strict';var chunkUDSP7U54_cjs=require('./chunk-UDSP7U54.cjs');require('./chunk-WU4AXN3P.cjs'),require('./chunk-S6W6Y44G.cjs'),require('./chunk-RD2HO5NZ.cjs'),require('./chunk-PTT4MWNL.cjs');Object.defineProperty(exports,"createSystem",{enumerable:true,get:function(){return chunkUDSP7U54_cjs.a}});//# sourceMappingURL=system-V7B4YUIR.cjs.map
|
|
2
|
+
//# sourceMappingURL=system-V7B4YUIR.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"system-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"system-V7B4YUIR.cjs"}
|
package/dist/testing.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var chunkUDSP7U54_cjs=require('./chunk-UDSP7U54.cjs');require('./chunk-WU4AXN3P.cjs'),require('./chunk-S6W6Y44G.cjs'),require('./chunk-RD2HO5NZ.cjs'),require('./chunk-PTT4MWNL.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=chunkUDSP7U54_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=chunkUDSP7U54_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
|