@rotorsoft/act-tck 1.26.4 → 1.26.6
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/.tsbuildinfo +1 -1
- package/dist/@types/store-tck.d.ts +26 -0
- package/dist/@types/store-tck.d.ts.map +1 -1
- package/dist/index.cjs +123 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +123 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -56,6 +56,32 @@ export type StoreCapabilities = {
|
|
|
56
56
|
* so correctness never depends on this flag — only probe cost.
|
|
57
57
|
*/
|
|
58
58
|
readonly source_matches?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Adapter matches a **pattern** reaction `source` (one carrying regex
|
|
61
|
+
* metacharacters, e.g. the calculator's `^(A|B)$`) as a full RegExp in
|
|
62
|
+
* claim()'s has-work probe, so a stream whose max event id exceeds the
|
|
63
|
+
* subscription watermark is claimed when its name matches the pattern.
|
|
64
|
+
* When `true`, the TCK runs the pattern-source claim suite. Literal
|
|
65
|
+
* sources stay exact everywhere regardless of this flag — the fast,
|
|
66
|
+
* index-friendly path.
|
|
67
|
+
*
|
|
68
|
+
* Stores that cannot run an arbitrary regex against candidate streams
|
|
69
|
+
* (e.g. SQLite, whose libsql build has no `REGEXP` and whose portable
|
|
70
|
+
* `LIKE` grammar cannot express alternation/grouping) leave this
|
|
71
|
+
* `false` and instead reject a non-portable claim source at
|
|
72
|
+
* {@link subscribe} time — see {@link rejects_nonportable_claim_source}.
|
|
73
|
+
*/
|
|
74
|
+
readonly pattern_claim_source?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Adapter cannot faithfully match every regex claim `source`, so it
|
|
77
|
+
* fails loud at registration: {@link subscribe} throws
|
|
78
|
+
* {@link ValidationError} for a source outside its portable subset
|
|
79
|
+
* (alternation/grouping like `^(A|B)$`), rather than silently never
|
|
80
|
+
* claiming the stream. When `true`, the TCK runs the reject-at-subscribe
|
|
81
|
+
* case. Currently only SQLite sets this — its message points operators
|
|
82
|
+
* to InMemory/PG for full regex claim sources.
|
|
83
|
+
*/
|
|
84
|
+
readonly rejects_nonportable_claim_source?: boolean;
|
|
59
85
|
};
|
|
60
86
|
/**
|
|
61
87
|
* Options for {@link runStoreTck}.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-tck.d.ts","sourceRoot":"","sources":["../../src/store-tck.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAQV,KAAK,EAEN,MAAM,sBAAsB,CAAC;AAc9B;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;;;;;;;OASG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"store-tck.d.ts","sourceRoot":"","sources":["../../src/store-tck.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAQV,KAAK,EAEN,MAAM,sBAAsB,CAAC;AAc9B;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;;;;;;;OASG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC;;;;;;;;OAQG;IACH,QAAQ,CAAC,gCAAgC,CAAC,EAAE,OAAO,CAAC;CACrD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/C;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,iBAAiB,CAAC;CAC3C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,eAAO,MAAM,WAAW,GAAI,SAAS,eAAe,KAAG,IA0iHtD,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -1568,7 +1568,130 @@ var runStoreTck = (options) => {
|
|
|
1568
1568
|
await fresh.dispose();
|
|
1569
1569
|
}
|
|
1570
1570
|
});
|
|
1571
|
+
(0, import_vitest9.it)("fetches only the exact source stream's events, never a sibling prefix", async () => {
|
|
1572
|
+
const fresh = await options.factory();
|
|
1573
|
+
try {
|
|
1574
|
+
await fresh.drop();
|
|
1575
|
+
await fresh.seed();
|
|
1576
|
+
const base = `fx-${uid()}`;
|
|
1577
|
+
const sibling = `${base}2`;
|
|
1578
|
+
const target = `agg-${uid()}`;
|
|
1579
|
+
await fresh.subscribe([{ stream: target, source: base }]);
|
|
1580
|
+
const [b1] = await seed_stream(fresh, base, 1);
|
|
1581
|
+
await seed_stream(fresh, sibling, 1);
|
|
1582
|
+
const claimed = await fresh.claim(100, 0, `w-${uid()}`, 3e4);
|
|
1583
|
+
const lease = claimed.find((l) => l.stream === target);
|
|
1584
|
+
(0, import_vitest9.expect)(lease).toBeDefined();
|
|
1585
|
+
const events2 = await collect(fresh, {
|
|
1586
|
+
stream: lease.source,
|
|
1587
|
+
stream_exact: true,
|
|
1588
|
+
after: -1
|
|
1589
|
+
});
|
|
1590
|
+
(0, import_vitest9.expect)(events2.map((e) => e.stream)).toEqual([base]);
|
|
1591
|
+
(0, import_vitest9.expect)(events2.map((e) => e.id)).toEqual([b1.id]);
|
|
1592
|
+
} finally {
|
|
1593
|
+
await fresh.dispose();
|
|
1594
|
+
}
|
|
1595
|
+
});
|
|
1571
1596
|
});
|
|
1597
|
+
import_vitest9.describe.skipIf(!caps.pattern_claim_source)(
|
|
1598
|
+
"claim pattern source matching (capability)",
|
|
1599
|
+
() => {
|
|
1600
|
+
(0, import_vitest9.it)("claims a pattern-source target when any matched stream has work (^(A|B)$)", async () => {
|
|
1601
|
+
const fresh = await options.factory();
|
|
1602
|
+
try {
|
|
1603
|
+
await fresh.drop();
|
|
1604
|
+
await fresh.seed();
|
|
1605
|
+
const a = `A-${uid()}`;
|
|
1606
|
+
const b = `B-${uid()}`;
|
|
1607
|
+
const target = `board-${uid()}`;
|
|
1608
|
+
const pattern = `^(${a}|${b})$`;
|
|
1609
|
+
await fresh.subscribe([{ stream: target, source: pattern }]);
|
|
1610
|
+
const [ea] = await seed_stream(fresh, a, 1);
|
|
1611
|
+
const first = await fresh.claim(100, 0, `w-${uid()}`, 3e4);
|
|
1612
|
+
const l1 = first.find((s) => s.stream === target);
|
|
1613
|
+
(0, import_vitest9.expect)(l1).toBeDefined();
|
|
1614
|
+
await fresh.ack([{ ...l1, at: ea.id }]);
|
|
1615
|
+
const [eb] = await seed_stream(fresh, b, 1);
|
|
1616
|
+
const second = await fresh.claim(100, 0, `w-${uid()}`, 3e4);
|
|
1617
|
+
(0, import_vitest9.expect)(second.find((s) => s.stream === target)).toBeDefined();
|
|
1618
|
+
(0, import_vitest9.expect)(eb.stream).toBe(b);
|
|
1619
|
+
} finally {
|
|
1620
|
+
await fresh.dispose();
|
|
1621
|
+
}
|
|
1622
|
+
});
|
|
1623
|
+
(0, import_vitest9.it)("does not claim a pattern-source target when no matched stream has work", async () => {
|
|
1624
|
+
const fresh = await options.factory();
|
|
1625
|
+
try {
|
|
1626
|
+
await fresh.drop();
|
|
1627
|
+
await fresh.seed();
|
|
1628
|
+
const a = `A-${uid()}`;
|
|
1629
|
+
const b = `B-${uid()}`;
|
|
1630
|
+
const other = `Z-${uid()}`;
|
|
1631
|
+
const target = `board-${uid()}`;
|
|
1632
|
+
const control = `ctl-${uid()}`;
|
|
1633
|
+
const pattern = `^(${a}|${b})$`;
|
|
1634
|
+
await fresh.subscribe([
|
|
1635
|
+
{ stream: target, source: pattern },
|
|
1636
|
+
{ stream: control, source: other }
|
|
1637
|
+
]);
|
|
1638
|
+
const [ea] = await seed_stream(fresh, a, 1);
|
|
1639
|
+
const first = await fresh.claim(100, 0, `w-${uid()}`, 3e4);
|
|
1640
|
+
const l1 = first.find((s) => s.stream === target);
|
|
1641
|
+
(0, import_vitest9.expect)(l1).toBeDefined();
|
|
1642
|
+
const c1 = first.find((s) => s.stream === control);
|
|
1643
|
+
(0, import_vitest9.expect)(c1).toBeDefined();
|
|
1644
|
+
await fresh.ack([
|
|
1645
|
+
{ ...l1, at: ea.id },
|
|
1646
|
+
{ ...c1, at: -1 }
|
|
1647
|
+
]);
|
|
1648
|
+
await seed_stream(fresh, other, 1);
|
|
1649
|
+
const claimed = await fresh.claim(100, 0, `w-${uid()}`, 3e4);
|
|
1650
|
+
const streams = claimed.map((s) => s.stream);
|
|
1651
|
+
(0, import_vitest9.expect)(streams).toContain(control);
|
|
1652
|
+
(0, import_vitest9.expect)(streams).not.toContain(target);
|
|
1653
|
+
} finally {
|
|
1654
|
+
await fresh.dispose();
|
|
1655
|
+
}
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
);
|
|
1659
|
+
import_vitest9.describe.skipIf(!caps.rejects_nonportable_claim_source)(
|
|
1660
|
+
"claim source registration (capability)",
|
|
1661
|
+
() => {
|
|
1662
|
+
(0, import_vitest9.it)("throws at subscribe for a non-portable (alternation) claim source", async () => {
|
|
1663
|
+
const fresh = await options.factory();
|
|
1664
|
+
try {
|
|
1665
|
+
await fresh.drop();
|
|
1666
|
+
await fresh.seed();
|
|
1667
|
+
await (0, import_vitest9.expect)(
|
|
1668
|
+
fresh.subscribe([
|
|
1669
|
+
{ stream: `board-${uid()}`, source: `^(${uid()}|${uid()})$` }
|
|
1670
|
+
])
|
|
1671
|
+
).rejects.toThrow(import_act2.ValidationError);
|
|
1672
|
+
} finally {
|
|
1673
|
+
await fresh.dispose();
|
|
1674
|
+
}
|
|
1675
|
+
});
|
|
1676
|
+
(0, import_vitest9.it)("accepts a portable-subset pattern claim source (^prefix.*) and claims on match", async () => {
|
|
1677
|
+
const fresh = await options.factory();
|
|
1678
|
+
try {
|
|
1679
|
+
await fresh.drop();
|
|
1680
|
+
await fresh.seed();
|
|
1681
|
+
const prefix = `pfx${uid()}`.replace(/-/g, "");
|
|
1682
|
+
const matched = `${prefix}child`;
|
|
1683
|
+
const target = `board-${uid()}`;
|
|
1684
|
+
await fresh.subscribe([{ stream: target, source: `^${prefix}.*` }]);
|
|
1685
|
+
const [e] = await seed_stream(fresh, matched, 1);
|
|
1686
|
+
const claimed = await fresh.claim(100, 0, `w-${uid()}`, 3e4);
|
|
1687
|
+
(0, import_vitest9.expect)(claimed.find((s) => s.stream === target)).toBeDefined();
|
|
1688
|
+
(0, import_vitest9.expect)(e.stream).toBe(matched);
|
|
1689
|
+
} finally {
|
|
1690
|
+
await fresh.dispose();
|
|
1691
|
+
}
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1694
|
+
);
|
|
1572
1695
|
import_vitest9.describe.skipIf(!caps.concurrent_claim)("concurrency (capability)", () => {
|
|
1573
1696
|
(0, import_vitest9.it)("never double-leases a stream across concurrent claimers", async () => {
|
|
1574
1697
|
const fresh = await options.factory();
|