@rotorsoft/act 0.36.0 → 0.38.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/README.md +33 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +14 -0
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/builders/act-builder.d.ts.map +1 -1
- package/dist/@types/internal/event-sourcing.d.ts.map +1 -1
- package/dist/@types/internal/event-versions.d.ts +44 -0
- package/dist/@types/internal/event-versions.d.ts.map +1 -0
- package/dist/@types/internal/index.d.ts +1 -0
- package/dist/@types/internal/index.d.ts.map +1 -1
- package/dist/@types/ports.d.ts +10 -51
- package/dist/@types/ports.d.ts.map +1 -1
- package/dist/index.cjs +206 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +205 -87
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,6 +15,9 @@ import {
|
|
|
15
15
|
ZodEmpty
|
|
16
16
|
} from "./chunk-AGWZY6YT.js";
|
|
17
17
|
|
|
18
|
+
// src/ports.ts
|
|
19
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
20
|
+
|
|
18
21
|
// src/adapters/console-logger.ts
|
|
19
22
|
var LEVEL_VALUES = {
|
|
20
23
|
fatal: 60,
|
|
@@ -803,6 +806,7 @@ var InMemoryStore = class {
|
|
|
803
806
|
};
|
|
804
807
|
|
|
805
808
|
// src/ports.ts
|
|
809
|
+
var scoped = new AsyncLocalStorage();
|
|
806
810
|
var ExitCodes = ["ERROR", "EXIT"];
|
|
807
811
|
var adapters = /* @__PURE__ */ new Map();
|
|
808
812
|
function port(injector) {
|
|
@@ -822,11 +826,17 @@ var log = port(function log2(adapter) {
|
|
|
822
826
|
pretty: cfg.env !== "production"
|
|
823
827
|
});
|
|
824
828
|
});
|
|
825
|
-
var
|
|
826
|
-
return adapter
|
|
829
|
+
var _store = port(function store(adapter) {
|
|
830
|
+
return adapter ?? new InMemoryStore();
|
|
831
|
+
});
|
|
832
|
+
var store2 = ((adapter) => {
|
|
833
|
+
return scoped.getStore()?.store ?? _store(adapter);
|
|
827
834
|
});
|
|
828
|
-
var
|
|
829
|
-
return adapter
|
|
835
|
+
var _cache = port(function cache(adapter) {
|
|
836
|
+
return adapter ?? new InMemoryCache();
|
|
837
|
+
});
|
|
838
|
+
var cache2 = ((adapter) => {
|
|
839
|
+
return scoped.getStore()?.cache ?? _cache(adapter);
|
|
830
840
|
});
|
|
831
841
|
var disposers = [];
|
|
832
842
|
async function disposeAndExit(code = "EXIT") {
|
|
@@ -956,7 +966,7 @@ async function scanStreamHeads(streams) {
|
|
|
956
966
|
let maxId = -1;
|
|
957
967
|
let version = -1;
|
|
958
968
|
let lastEventName = "";
|
|
959
|
-
await
|
|
969
|
+
await store2().query(
|
|
960
970
|
(e) => {
|
|
961
971
|
if (e.name === TOMBSTONE_EVENT || maxId !== -1) return;
|
|
962
972
|
maxId = e.id;
|
|
@@ -973,7 +983,7 @@ async function scanStreamHeads(streams) {
|
|
|
973
983
|
async function partitionBySafety(streamInfo, reactiveEventsSize, skipped) {
|
|
974
984
|
if (reactiveEventsSize === 0) return [...streamInfo.keys()];
|
|
975
985
|
const pendingSet = /* @__PURE__ */ new Set();
|
|
976
|
-
await
|
|
986
|
+
await store2().query_streams((position) => {
|
|
977
987
|
const sourceRe = position.source ? RegExp(position.source) : void 0;
|
|
978
988
|
for (const [stream, info] of streamInfo) {
|
|
979
989
|
if ((!sourceRe || sourceRe.test(stream)) && position.at < info.maxId) {
|
|
@@ -1044,13 +1054,13 @@ async function truncateAndWarmCache(guarded, seedStates, guardEvents, correlatio
|
|
|
1044
1054
|
}
|
|
1045
1055
|
};
|
|
1046
1056
|
});
|
|
1047
|
-
const truncated = await
|
|
1057
|
+
const truncated = await store2().truncate(truncTargets);
|
|
1048
1058
|
await Promise.all(
|
|
1049
1059
|
guarded.map(async (stream) => {
|
|
1050
1060
|
const entry = truncated.get(stream);
|
|
1051
1061
|
const state2 = seedStates.get(stream);
|
|
1052
1062
|
if (state2 && entry) {
|
|
1053
|
-
await
|
|
1063
|
+
await cache2().set(stream, {
|
|
1054
1064
|
state: state2,
|
|
1055
1065
|
version: entry.committed.version,
|
|
1056
1066
|
event_id: entry.committed.id,
|
|
@@ -1058,7 +1068,7 @@ async function truncateAndWarmCache(guarded, seedStates, guardEvents, correlatio
|
|
|
1058
1068
|
snaps: 1
|
|
1059
1069
|
});
|
|
1060
1070
|
} else {
|
|
1061
|
-
await
|
|
1071
|
+
await cache2().invalidate(stream);
|
|
1062
1072
|
}
|
|
1063
1073
|
})
|
|
1064
1074
|
);
|
|
@@ -1093,7 +1103,7 @@ var CorrelateCycle = class {
|
|
|
1093
1103
|
async init() {
|
|
1094
1104
|
if (this._initialized) return;
|
|
1095
1105
|
this._initialized = true;
|
|
1096
|
-
const { watermark } = await
|
|
1106
|
+
const { watermark } = await store2().subscribe([...this.staticTargets]);
|
|
1097
1107
|
this._checkpoint = watermark;
|
|
1098
1108
|
this.onInit?.();
|
|
1099
1109
|
for (const { stream } of this.staticTargets) {
|
|
@@ -1112,7 +1122,7 @@ var CorrelateCycle = class {
|
|
|
1112
1122
|
const after = Math.max(this._checkpoint, query.after || -1);
|
|
1113
1123
|
const correlated = /* @__PURE__ */ new Map();
|
|
1114
1124
|
let last_id = after;
|
|
1115
|
-
await
|
|
1125
|
+
await store2().query(
|
|
1116
1126
|
(event) => {
|
|
1117
1127
|
last_id = event.id;
|
|
1118
1128
|
const register = this.registry.events[event.name];
|
|
@@ -1317,6 +1327,43 @@ var DrainController = class {
|
|
|
1317
1327
|
}
|
|
1318
1328
|
};
|
|
1319
1329
|
|
|
1330
|
+
// src/internal/event-versions.ts
|
|
1331
|
+
var VERSION_SUFFIX = /^(.+?)_v(\d+)$/;
|
|
1332
|
+
function parse(name) {
|
|
1333
|
+
const m = name.match(VERSION_SUFFIX);
|
|
1334
|
+
if (m) {
|
|
1335
|
+
const v = Number.parseInt(m[2], 10);
|
|
1336
|
+
if (v >= 2) return { base: m[1], version: v };
|
|
1337
|
+
}
|
|
1338
|
+
return { base: name, version: 1 };
|
|
1339
|
+
}
|
|
1340
|
+
function deprecatedEventNames(names) {
|
|
1341
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1342
|
+
for (const name of names) {
|
|
1343
|
+
const { base, version } = parse(name);
|
|
1344
|
+
const list = groups.get(base);
|
|
1345
|
+
if (list) list.push({ version, name });
|
|
1346
|
+
else groups.set(base, [{ version, name }]);
|
|
1347
|
+
}
|
|
1348
|
+
const deprecated = /* @__PURE__ */ new Set();
|
|
1349
|
+
for (const list of groups.values()) {
|
|
1350
|
+
if (list.length < 2) continue;
|
|
1351
|
+
list.sort((a, b) => b.version - a.version);
|
|
1352
|
+
for (let i = 1; i < list.length; i++) deprecated.add(list[i].name);
|
|
1353
|
+
}
|
|
1354
|
+
return deprecated;
|
|
1355
|
+
}
|
|
1356
|
+
function currentVersionOf(deprecatedName, allNames) {
|
|
1357
|
+
const target = parse(deprecatedName);
|
|
1358
|
+
let highest;
|
|
1359
|
+
for (const name of allNames) {
|
|
1360
|
+
const { base, version } = parse(name);
|
|
1361
|
+
if (base !== target.base) continue;
|
|
1362
|
+
if (!highest || version > highest.version) highest = { version, name };
|
|
1363
|
+
}
|
|
1364
|
+
return highest && highest.version > target.version ? highest.name : void 0;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1320
1367
|
// src/internal/merge.ts
|
|
1321
1368
|
import { ZodObject } from "zod";
|
|
1322
1369
|
function baseTypeName(zodType) {
|
|
@@ -1595,12 +1642,12 @@ var SettleLoop = class {
|
|
|
1595
1642
|
};
|
|
1596
1643
|
|
|
1597
1644
|
// src/internal/drain.ts
|
|
1598
|
-
var claim = (lagging, leading, by, millis) =>
|
|
1645
|
+
var claim = (lagging, leading, by, millis) => store2().claim(lagging, leading, by, millis);
|
|
1599
1646
|
async function fetch(leased, eventLimit) {
|
|
1600
1647
|
return Promise.all(
|
|
1601
1648
|
leased.map(async ({ stream, source, at, lagging }) => {
|
|
1602
1649
|
const events = [];
|
|
1603
|
-
await
|
|
1650
|
+
await store2().query((e) => events.push(e), {
|
|
1604
1651
|
stream: source,
|
|
1605
1652
|
after: at,
|
|
1606
1653
|
limit: eventLimit
|
|
@@ -1609,9 +1656,9 @@ async function fetch(leased, eventLimit) {
|
|
|
1609
1656
|
})
|
|
1610
1657
|
);
|
|
1611
1658
|
}
|
|
1612
|
-
var ack = (leases) =>
|
|
1613
|
-
var block = (leases) =>
|
|
1614
|
-
var subscribe = (streams) =>
|
|
1659
|
+
var ack = (leases) => store2().ack(leases);
|
|
1660
|
+
var block = (leases) => store2().block(leases);
|
|
1661
|
+
var subscribe = (streams) => store2().subscribe(streams);
|
|
1615
1662
|
|
|
1616
1663
|
// src/internal/event-sourcing.ts
|
|
1617
1664
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
@@ -1619,7 +1666,7 @@ import { patch } from "@rotorsoft/act-patch";
|
|
|
1619
1666
|
async function snap(snapshot) {
|
|
1620
1667
|
try {
|
|
1621
1668
|
const { id, stream, name, meta, version } = snapshot.event;
|
|
1622
|
-
await
|
|
1669
|
+
await store2().commit(
|
|
1623
1670
|
stream,
|
|
1624
1671
|
[{ name: SNAP_EVENT, data: snapshot.state }],
|
|
1625
1672
|
{
|
|
@@ -1635,7 +1682,7 @@ async function snap(snapshot) {
|
|
|
1635
1682
|
}
|
|
1636
1683
|
async function tombstone(stream, expectedVersion, correlation) {
|
|
1637
1684
|
try {
|
|
1638
|
-
const [committed] = await
|
|
1685
|
+
const [committed] = await store2().commit(
|
|
1639
1686
|
stream,
|
|
1640
1687
|
[{ name: TOMBSTONE_EVENT, data: {} }],
|
|
1641
1688
|
{ correlation, causation: {} },
|
|
@@ -1649,7 +1696,7 @@ async function tombstone(stream, expectedVersion, correlation) {
|
|
|
1649
1696
|
}
|
|
1650
1697
|
async function load(me, stream, callback, asOf) {
|
|
1651
1698
|
const timeTravel = !!asOf && Object.values(asOf).some((v) => v !== void 0);
|
|
1652
|
-
const cached = timeTravel ? void 0 : await
|
|
1699
|
+
const cached = timeTravel ? void 0 : await cache2().get(stream);
|
|
1653
1700
|
const cache_hit = !!cached;
|
|
1654
1701
|
let state2 = cached?.state ?? (me.init ? me.init() : {});
|
|
1655
1702
|
let patches = cached?.patches ?? 0;
|
|
@@ -1657,7 +1704,7 @@ async function load(me, stream, callback, asOf) {
|
|
|
1657
1704
|
let version = cached?.version ?? -1;
|
|
1658
1705
|
let replayed = 0;
|
|
1659
1706
|
let event;
|
|
1660
|
-
await
|
|
1707
|
+
await store2().query(
|
|
1661
1708
|
(e) => {
|
|
1662
1709
|
event = e;
|
|
1663
1710
|
version = e.version;
|
|
@@ -1692,7 +1739,7 @@ async function load(me, stream, callback, asOf) {
|
|
|
1692
1739
|
}
|
|
1693
1740
|
);
|
|
1694
1741
|
if (replayed > 0 && !timeTravel && event) {
|
|
1695
|
-
await
|
|
1742
|
+
await cache2().set(stream, {
|
|
1696
1743
|
state: state2,
|
|
1697
1744
|
version,
|
|
1698
1745
|
event_id: event.id,
|
|
@@ -1729,6 +1776,20 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
1729
1776
|
return [snapshot];
|
|
1730
1777
|
}
|
|
1731
1778
|
const tuples = Array.isArray(result[0]) ? result : [result];
|
|
1779
|
+
const deprecated = me._deprecated;
|
|
1780
|
+
if (deprecated && deprecated.size > 0) {
|
|
1781
|
+
const me_ = me;
|
|
1782
|
+
const warned = me_._warned ?? (me_._warned = /* @__PURE__ */ new Set());
|
|
1783
|
+
for (const [name] of tuples) {
|
|
1784
|
+
const evt = name;
|
|
1785
|
+
if (deprecated.has(evt) && !warned.has(evt)) {
|
|
1786
|
+
warned.add(evt);
|
|
1787
|
+
log().warn(
|
|
1788
|
+
`Action "${String(action2)}" emitted deprecated event "${evt}". A newer version exists in the registry \u2014 update the action's .emit() to target the current version. (warned once per process)`
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1732
1793
|
const emitted = tuples.map(([name, data]) => ({
|
|
1733
1794
|
name,
|
|
1734
1795
|
data: skipValidation ? data : validate(name, data, me.events[name])
|
|
@@ -1751,7 +1812,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
1751
1812
|
};
|
|
1752
1813
|
let committed;
|
|
1753
1814
|
try {
|
|
1754
|
-
committed = await
|
|
1815
|
+
committed = await store2().commit(
|
|
1755
1816
|
stream,
|
|
1756
1817
|
emitted,
|
|
1757
1818
|
meta,
|
|
@@ -1763,7 +1824,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
1763
1824
|
);
|
|
1764
1825
|
} catch (error) {
|
|
1765
1826
|
if (error instanceof ConcurrencyError) {
|
|
1766
|
-
await
|
|
1827
|
+
await cache2().invalidate(stream);
|
|
1767
1828
|
}
|
|
1768
1829
|
throw error;
|
|
1769
1830
|
}
|
|
@@ -1785,7 +1846,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
1785
1846
|
});
|
|
1786
1847
|
const last = snapshots.at(-1);
|
|
1787
1848
|
const snapped = me.snap?.(last);
|
|
1788
|
-
|
|
1849
|
+
cache2().set(stream, {
|
|
1789
1850
|
state: last.state,
|
|
1790
1851
|
version: last.event.version,
|
|
1791
1852
|
event_id: last.event.id,
|
|
@@ -1980,6 +2041,7 @@ var Act = class {
|
|
|
1980
2041
|
this.registry = registry;
|
|
1981
2042
|
this._states = _states;
|
|
1982
2043
|
this._batch_handlers = batchHandlers;
|
|
2044
|
+
this._scoped = options.scoped ? (fn) => scoped.run(options.scoped, fn) : (fn) => fn();
|
|
1983
2045
|
this._es = buildEs(this._logger);
|
|
1984
2046
|
this._cd = buildDrain(this._logger);
|
|
1985
2047
|
this._handle = buildHandle({
|
|
@@ -2025,7 +2087,7 @@ var Act = class {
|
|
|
2025
2087
|
},
|
|
2026
2088
|
options.settleDebounceMs ?? DEFAULT_SETTLE_DEBOUNCE_MS
|
|
2027
2089
|
);
|
|
2028
|
-
this._notify_disposer = this._wireNotify();
|
|
2090
|
+
this._notify_disposer = this._wireNotify(options.scoped?.store ?? store2());
|
|
2029
2091
|
dispose(async () => {
|
|
2030
2092
|
this._emitter.removeAllListeners();
|
|
2031
2093
|
this.stop_correlations();
|
|
@@ -2094,6 +2156,11 @@ var Act = class {
|
|
|
2094
2156
|
_event_to_state;
|
|
2095
2157
|
/** Logger resolved at construction time (after user port configuration) */
|
|
2096
2158
|
_logger = log();
|
|
2159
|
+
/** Wraps a public-method body so internal `store()`/`cache()` resolve to the
|
|
2160
|
+
* per-Act ports (ACT-501). No-op when the Act is unscoped — so the singleton
|
|
2161
|
+
* path keeps reading fresh `store()`/`cache()` per call, which matters for
|
|
2162
|
+
* tests that dispose and re-seed mid-suite. */
|
|
2163
|
+
_scoped;
|
|
2097
2164
|
/** Pre-bound IAct methods reused across drain cycles. Only `do` varies per
|
|
2098
2165
|
* payload (it captures the triggering event for reactingTo auto-inject). */
|
|
2099
2166
|
_bound_do = this.do.bind(this);
|
|
@@ -2109,9 +2176,8 @@ var Act = class {
|
|
|
2109
2176
|
* subscription was made). Errors during subscription are logged but
|
|
2110
2177
|
* never thrown — `notify` is a hint, not a contract.
|
|
2111
2178
|
*/
|
|
2112
|
-
async _wireNotify() {
|
|
2179
|
+
async _wireNotify(s) {
|
|
2113
2180
|
if (this._reactive_events.size === 0) return void 0;
|
|
2114
|
-
const s = store();
|
|
2115
2181
|
if (!s.notify) return void 0;
|
|
2116
2182
|
try {
|
|
2117
2183
|
return await s.notify((notification) => {
|
|
@@ -2215,35 +2281,39 @@ var Act = class {
|
|
|
2215
2281
|
* @see {@link ValidationError}, {@link InvariantError}, {@link ConcurrencyError}
|
|
2216
2282
|
*/
|
|
2217
2283
|
async do(action2, target, payload, reactingTo, skipValidation = false) {
|
|
2218
|
-
|
|
2219
|
-
this.
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
this.
|
|
2230
|
-
|
|
2284
|
+
return this._scoped(async () => {
|
|
2285
|
+
const snapshots = await this._es.action(
|
|
2286
|
+
this.registry.actions[action2],
|
|
2287
|
+
action2,
|
|
2288
|
+
target,
|
|
2289
|
+
payload,
|
|
2290
|
+
reactingTo,
|
|
2291
|
+
skipValidation
|
|
2292
|
+
);
|
|
2293
|
+
if (this._reactive_events.size > 0) {
|
|
2294
|
+
for (const snap2 of snapshots) {
|
|
2295
|
+
if (snap2.event?.name && this._reactive_events.has(snap2.event.name)) {
|
|
2296
|
+
this._drain.arm();
|
|
2297
|
+
break;
|
|
2298
|
+
}
|
|
2231
2299
|
}
|
|
2232
2300
|
}
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2301
|
+
this.emit("committed", snapshots);
|
|
2302
|
+
return snapshots;
|
|
2303
|
+
});
|
|
2236
2304
|
}
|
|
2237
2305
|
async load(stateOrName, stream, callback, asOf) {
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2306
|
+
return this._scoped(async () => {
|
|
2307
|
+
let merged;
|
|
2308
|
+
if (typeof stateOrName === "string") {
|
|
2309
|
+
const found = this._states.get(stateOrName);
|
|
2310
|
+
if (!found) throw new Error(`State "${stateOrName}" not found`);
|
|
2311
|
+
merged = found;
|
|
2312
|
+
} else {
|
|
2313
|
+
merged = this._states.get(stateOrName.name) || stateOrName;
|
|
2314
|
+
}
|
|
2315
|
+
return await this._es.load(merged, stream, callback, asOf);
|
|
2316
|
+
});
|
|
2247
2317
|
}
|
|
2248
2318
|
/**
|
|
2249
2319
|
* Queries the event store for events matching a filter.
|
|
@@ -2292,14 +2362,16 @@ var Act = class {
|
|
|
2292
2362
|
* @see {@link query_array} for loading events into memory
|
|
2293
2363
|
*/
|
|
2294
2364
|
async query(query, callback) {
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2365
|
+
return this._scoped(async () => {
|
|
2366
|
+
let first;
|
|
2367
|
+
let last;
|
|
2368
|
+
const count = await store2().query((e) => {
|
|
2369
|
+
if (!first) first = e;
|
|
2370
|
+
last = e;
|
|
2371
|
+
callback?.(e);
|
|
2372
|
+
}, query);
|
|
2373
|
+
return { first, last, count };
|
|
2374
|
+
});
|
|
2303
2375
|
}
|
|
2304
2376
|
/**
|
|
2305
2377
|
* Queries the event store and returns all matching events in memory.
|
|
@@ -2328,9 +2400,11 @@ var Act = class {
|
|
|
2328
2400
|
* @see {@link query} for large result sets
|
|
2329
2401
|
*/
|
|
2330
2402
|
async query_array(query) {
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2403
|
+
return this._scoped(async () => {
|
|
2404
|
+
const events = [];
|
|
2405
|
+
await store2().query((e) => events.push(e), query);
|
|
2406
|
+
return events;
|
|
2407
|
+
});
|
|
2334
2408
|
}
|
|
2335
2409
|
/**
|
|
2336
2410
|
* Processes pending reactions by draining uncommitted events from the event store.
|
|
@@ -2370,7 +2444,7 @@ var Act = class {
|
|
|
2370
2444
|
* @see {@link start_correlations} for automatic correlation
|
|
2371
2445
|
*/
|
|
2372
2446
|
async drain(options = {}) {
|
|
2373
|
-
return this._drain.drain(options);
|
|
2447
|
+
return this._scoped(() => this._drain.drain(options));
|
|
2374
2448
|
}
|
|
2375
2449
|
/**
|
|
2376
2450
|
* Discovers and registers new streams dynamically based on reaction resolvers.
|
|
@@ -2418,7 +2492,7 @@ var Act = class {
|
|
|
2418
2492
|
* @see {@link stop_correlations} to stop automatic correlation
|
|
2419
2493
|
*/
|
|
2420
2494
|
async correlate(query = { after: -1, limit: 10 }) {
|
|
2421
|
-
return this._correlate.correlate(query);
|
|
2495
|
+
return this._scoped(() => this._correlate.correlate(query));
|
|
2422
2496
|
}
|
|
2423
2497
|
/**
|
|
2424
2498
|
* Starts automatic periodic correlation worker for discovering new streams.
|
|
@@ -2539,9 +2613,11 @@ var Act = class {
|
|
|
2539
2613
|
* @see {@link settle} for the debounced full-catch-up loop
|
|
2540
2614
|
*/
|
|
2541
2615
|
async reset(streams) {
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2616
|
+
return this._scoped(async () => {
|
|
2617
|
+
const count = await store2().reset(streams);
|
|
2618
|
+
if (count > 0 && this._reactive_events.size > 0) this._drain.arm();
|
|
2619
|
+
return count;
|
|
2620
|
+
});
|
|
2545
2621
|
}
|
|
2546
2622
|
/**
|
|
2547
2623
|
* Bulk-update scheduling priority for streams matching `filter`.
|
|
@@ -2582,7 +2658,7 @@ var Act = class {
|
|
|
2582
2658
|
* @see {@link claim} for how priority biases scheduling
|
|
2583
2659
|
*/
|
|
2584
2660
|
async prioritize(filter, priority) {
|
|
2585
|
-
return
|
|
2661
|
+
return this._scoped(() => store2().prioritize(filter, priority));
|
|
2586
2662
|
}
|
|
2587
2663
|
/**
|
|
2588
2664
|
* Close the books — guard, archive, truncate, and optionally restart streams.
|
|
@@ -2619,16 +2695,18 @@ var Act = class {
|
|
|
2619
2695
|
*/
|
|
2620
2696
|
async close(targets) {
|
|
2621
2697
|
if (!targets.length) return { truncated: /* @__PURE__ */ new Map(), skipped: [] };
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2698
|
+
return this._scoped(async () => {
|
|
2699
|
+
await this.correlate({ limit: 1e3 });
|
|
2700
|
+
const result = await runCloseCycle(targets, {
|
|
2701
|
+
reactiveEventsSize: this._reactive_events.size,
|
|
2702
|
+
eventToState: this._event_to_state,
|
|
2703
|
+
load: this._es.load,
|
|
2704
|
+
tombstone: this._es.tombstone,
|
|
2705
|
+
logger: this._logger
|
|
2706
|
+
});
|
|
2707
|
+
this.emit("closed", result);
|
|
2708
|
+
return result;
|
|
2629
2709
|
});
|
|
2630
|
-
this.emit("closed", result);
|
|
2631
|
-
return result;
|
|
2632
2710
|
}
|
|
2633
2711
|
/**
|
|
2634
2712
|
* Debounced, non-blocking correlate→drain cycle.
|
|
@@ -2682,6 +2760,41 @@ function act() {
|
|
|
2682
2760
|
};
|
|
2683
2761
|
const pendingProjections = [];
|
|
2684
2762
|
const batchHandlers = /* @__PURE__ */ new Map();
|
|
2763
|
+
let _built = false;
|
|
2764
|
+
const finalizeDeprecations = () => {
|
|
2765
|
+
const deprecationSummary = [];
|
|
2766
|
+
for (const state2 of states.values()) {
|
|
2767
|
+
const eventNames = Object.keys(state2.events);
|
|
2768
|
+
const deprecated = deprecatedEventNames(eventNames);
|
|
2769
|
+
if (deprecated.size === 0) continue;
|
|
2770
|
+
state2._deprecated = deprecated;
|
|
2771
|
+
for (const name of deprecated) {
|
|
2772
|
+
const current = currentVersionOf(name, eventNames);
|
|
2773
|
+
deprecationSummary.push({
|
|
2774
|
+
stateName: state2.name,
|
|
2775
|
+
deprecated: name,
|
|
2776
|
+
current
|
|
2777
|
+
});
|
|
2778
|
+
}
|
|
2779
|
+
for (const [actionName, handler] of Object.entries(state2.on)) {
|
|
2780
|
+
const staticTarget = handler?._staticEmit;
|
|
2781
|
+
if (staticTarget && deprecated.has(staticTarget)) {
|
|
2782
|
+
const current = currentVersionOf(staticTarget, eventNames);
|
|
2783
|
+
throw new Error(
|
|
2784
|
+
`Action "${actionName}" in state "${state2.name}" emits deprecated event "${staticTarget}". A newer version exists: "${current}". Update the .emit() call to target the current version. The reducer (.patch) for "${staticTarget}" stays as-is \u2014 historical events still need it.`
|
|
2785
|
+
);
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
if (deprecationSummary.length > 0) {
|
|
2790
|
+
const list = deprecationSummary.map(
|
|
2791
|
+
(d) => `"${d.deprecated}" (current: "${d.current}", state: "${d.stateName}")`
|
|
2792
|
+
).join(", ");
|
|
2793
|
+
log().info(
|
|
2794
|
+
`Act registered ${deprecationSummary.length} deprecated event(s): ${list}. These are legacy versions kept for the read path. Consider truncating closed streams via app.close() when feasible to reduce historical event load. See docs/docs/architecture/event-schema-evolution.md.`
|
|
2795
|
+
);
|
|
2796
|
+
}
|
|
2797
|
+
};
|
|
2685
2798
|
const builder = {
|
|
2686
2799
|
withState: (state2) => {
|
|
2687
2800
|
registerState(state2, states, registry.actions, registry.events);
|
|
@@ -2725,9 +2838,13 @@ function act() {
|
|
|
2725
2838
|
}
|
|
2726
2839
|
}),
|
|
2727
2840
|
build: (options) => {
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2841
|
+
if (!_built) {
|
|
2842
|
+
for (const proj of pendingProjections) {
|
|
2843
|
+
mergeProjection(proj, registry.events);
|
|
2844
|
+
registerBatchHandler(proj, batchHandlers);
|
|
2845
|
+
}
|
|
2846
|
+
finalizeDeprecations();
|
|
2847
|
+
_built = true;
|
|
2731
2848
|
}
|
|
2732
2849
|
return new Act(
|
|
2733
2850
|
registry,
|
|
@@ -2915,10 +3032,10 @@ function action_builder(state2) {
|
|
|
2915
3032
|
function emit(handler) {
|
|
2916
3033
|
if (typeof handler === "string") {
|
|
2917
3034
|
const eventName = handler;
|
|
2918
|
-
|
|
2919
|
-
eventName
|
|
2920
|
-
|
|
2921
|
-
];
|
|
3035
|
+
const emitFn = Object.assign((payload) => [eventName, payload], {
|
|
3036
|
+
_staticEmit: eventName
|
|
3037
|
+
});
|
|
3038
|
+
internal.on[action2] = emitFn;
|
|
2922
3039
|
} else {
|
|
2923
3040
|
internal.on[action2] = handler;
|
|
2924
3041
|
}
|
|
@@ -2962,7 +3079,7 @@ export {
|
|
|
2962
3079
|
ValidationError,
|
|
2963
3080
|
ZodEmpty,
|
|
2964
3081
|
act,
|
|
2965
|
-
cache,
|
|
3082
|
+
cache2 as cache,
|
|
2966
3083
|
config,
|
|
2967
3084
|
dispose,
|
|
2968
3085
|
disposeAndExit,
|
|
@@ -2970,10 +3087,11 @@ export {
|
|
|
2970
3087
|
log,
|
|
2971
3088
|
port,
|
|
2972
3089
|
projection,
|
|
3090
|
+
scoped,
|
|
2973
3091
|
sleep,
|
|
2974
3092
|
slice,
|
|
2975
3093
|
state,
|
|
2976
|
-
store,
|
|
3094
|
+
store2 as store,
|
|
2977
3095
|
validate
|
|
2978
3096
|
};
|
|
2979
3097
|
//# sourceMappingURL=index.js.map
|