@rotorsoft/act 0.29.1 → 0.30.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/README.md +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +57 -16
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +10 -4
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/@types/types/reaction.d.ts +4 -1
- package/dist/@types/types/reaction.d.ts.map +1 -1
- package/dist/index.cjs +81 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +81 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1033,24 +1033,22 @@ var Act = class {
|
|
|
1033
1033
|
* }
|
|
1034
1034
|
* ```
|
|
1035
1035
|
*
|
|
1036
|
-
* @example Reaction triggering another action
|
|
1036
|
+
* @example Reaction triggering another action (reactingTo auto-injected)
|
|
1037
1037
|
* ```typescript
|
|
1038
1038
|
* const app = act()
|
|
1039
1039
|
* .withState(Order)
|
|
1040
1040
|
* .withState(Inventory)
|
|
1041
1041
|
* .on("OrderPlaced")
|
|
1042
|
-
* .do(async (event,
|
|
1043
|
-
* //
|
|
1044
|
-
*
|
|
1042
|
+
* .do(async function reduceInventory(event, _stream, app) {
|
|
1043
|
+
* // Inside reaction handlers, reactingTo is auto-injected when omitted.
|
|
1044
|
+
* // The triggering event is used by default, maintaining the correlation chain.
|
|
1045
|
+
* await app.do(
|
|
1045
1046
|
* "reduceStock",
|
|
1046
|
-
* {
|
|
1047
|
-
*
|
|
1048
|
-
* actor: event.meta.causation.action.actor
|
|
1049
|
-
* },
|
|
1050
|
-
* { amount: event.data.items.length },
|
|
1051
|
-
* event // Pass event for correlation tracking
|
|
1047
|
+
* { stream: "inventory-1", actor: { id: "sys", name: "system" } },
|
|
1048
|
+
* { amount: event.data.items.length }
|
|
1052
1049
|
* );
|
|
1053
|
-
*
|
|
1050
|
+
* // To use a different correlation, pass reactingTo explicitly:
|
|
1051
|
+
* // await app.do("reduceStock", target, payload, customEvent);
|
|
1054
1052
|
* })
|
|
1055
1053
|
* .to("inventory-1")
|
|
1056
1054
|
* .build();
|
|
@@ -1186,6 +1184,11 @@ var Act = class {
|
|
|
1186
1184
|
* This is called by the main `drain` loop after fetching new events.
|
|
1187
1185
|
* It handles reactions, supporting retries, blocking, and error handling.
|
|
1188
1186
|
*
|
|
1187
|
+
* Each handler receives a scoped `IAct` proxy that auto-injects the
|
|
1188
|
+
* triggering event as `reactingTo` when `do()` is called without it,
|
|
1189
|
+
* maintaining correlation chains by default (#587). Handlers can still
|
|
1190
|
+
* pass an explicit `reactingTo` to override this behavior.
|
|
1191
|
+
*
|
|
1189
1192
|
* @internal
|
|
1190
1193
|
* @param lease The lease to handle
|
|
1191
1194
|
* @param payloads The reactions to handle
|
|
@@ -1196,10 +1199,24 @@ var Act = class {
|
|
|
1196
1199
|
const stream = lease.stream;
|
|
1197
1200
|
let at = payloads.at(0).event.id, handled = 0;
|
|
1198
1201
|
lease.retry > 0 && logger3.warn(`Retrying ${stream}@${at} (${lease.retry}).`);
|
|
1202
|
+
const doAction = this.do.bind(this);
|
|
1203
|
+
const scopedApp = {
|
|
1204
|
+
do: doAction,
|
|
1205
|
+
load: this.load.bind(this),
|
|
1206
|
+
query: this.query.bind(this),
|
|
1207
|
+
query_array: this.query_array.bind(this)
|
|
1208
|
+
};
|
|
1199
1209
|
for (const payload of payloads) {
|
|
1200
1210
|
const { event, handler, options } = payload;
|
|
1211
|
+
scopedApp.do = (action2, target, payload2, reactingTo, skipValidation) => doAction(
|
|
1212
|
+
action2,
|
|
1213
|
+
target,
|
|
1214
|
+
payload2,
|
|
1215
|
+
reactingTo ?? event,
|
|
1216
|
+
skipValidation
|
|
1217
|
+
);
|
|
1201
1218
|
try {
|
|
1202
|
-
await handler(event, stream,
|
|
1219
|
+
await handler(event, stream, scopedApp);
|
|
1203
1220
|
at = event.id;
|
|
1204
1221
|
handled++;
|
|
1205
1222
|
} catch (error) {
|
|
@@ -1605,6 +1622,46 @@ var Act = class {
|
|
|
1605
1622
|
this._settle_timer = void 0;
|
|
1606
1623
|
}
|
|
1607
1624
|
}
|
|
1625
|
+
/**
|
|
1626
|
+
* Reset reaction stream watermarks and request a drain on the next
|
|
1627
|
+
* `drain()` / `settle()` cycle.
|
|
1628
|
+
*
|
|
1629
|
+
* Use this to replay events through projections (or other reaction targets)
|
|
1630
|
+
* after changing handler logic. Equivalent to calling `store().reset(streams)`
|
|
1631
|
+
* directly, but also raises the orchestrator's internal "needs drain" flag —
|
|
1632
|
+
* `store().reset(...)` alone leaves the flag untouched, so a settled app
|
|
1633
|
+
* would short-circuit and skip the replay.
|
|
1634
|
+
*
|
|
1635
|
+
* Pair with `app.settle()` (or a single `app.drain()` for small streams).
|
|
1636
|
+
* `settle()` loops correlate→drain until no progress is made, so one call
|
|
1637
|
+
* fully catches up paginated streams without forcing callers to roll
|
|
1638
|
+
* their own loop.
|
|
1639
|
+
*
|
|
1640
|
+
* @param streams - Reaction target streams (e.g., projection names) to reset
|
|
1641
|
+
* @returns Count of streams that were actually reset
|
|
1642
|
+
*
|
|
1643
|
+
* @example Rebuild a projection (production)
|
|
1644
|
+
* ```typescript
|
|
1645
|
+
* await app.reset(["my-projection"]);
|
|
1646
|
+
* app.settle({ eventLimit: 1000 }); // emits "settled" when fully replayed
|
|
1647
|
+
* ```
|
|
1648
|
+
*
|
|
1649
|
+
* @example Rebuild a projection (tests / scripts)
|
|
1650
|
+
* ```typescript
|
|
1651
|
+
* await app.reset(["my-projection"]);
|
|
1652
|
+
* await app.drain({ eventLimit: 1000 }); // small streams: one pass is enough
|
|
1653
|
+
* ```
|
|
1654
|
+
*
|
|
1655
|
+
* @see {@link Store.reset} for the underlying store primitive
|
|
1656
|
+
* @see {@link settle} for the debounced full-catch-up loop
|
|
1657
|
+
*/
|
|
1658
|
+
async reset(streams) {
|
|
1659
|
+
const count = await store().reset(streams);
|
|
1660
|
+
if (count > 0 && this._reactive_events.size > 0) {
|
|
1661
|
+
this._needs_drain = true;
|
|
1662
|
+
}
|
|
1663
|
+
return count;
|
|
1664
|
+
}
|
|
1608
1665
|
/**
|
|
1609
1666
|
* Close the books — guard, archive, truncate, and optionally restart streams.
|
|
1610
1667
|
*
|
|
@@ -1772,15 +1829,19 @@ var Act = class {
|
|
|
1772
1829
|
/**
|
|
1773
1830
|
* Debounced, non-blocking correlate→drain cycle.
|
|
1774
1831
|
*
|
|
1775
|
-
* Call this after `app.do()` to schedule a background
|
|
1776
|
-
* calls within the debounce window are coalesced
|
|
1777
|
-
* correlate→drain in a loop until
|
|
1778
|
-
*
|
|
1832
|
+
* Call this after `app.do()` (or `app.reset()`) to schedule a background
|
|
1833
|
+
* drain. Multiple rapid calls within the debounce window are coalesced
|
|
1834
|
+
* into a single cycle. Runs correlate→drain in a loop until a pass makes
|
|
1835
|
+
* no progress — no new subscriptions, no acks, no blocks — then emits
|
|
1836
|
+
* the `"settled"` lifecycle event. This means a single `settle()` call
|
|
1837
|
+
* fully catches up paginated streams (e.g. after `reset()` on a long
|
|
1838
|
+
* projection) without forcing callers to loop.
|
|
1779
1839
|
*
|
|
1780
1840
|
* @param options - Settle configuration options
|
|
1781
1841
|
* @param options.debounceMs - Debounce window in milliseconds (default: 10)
|
|
1782
1842
|
* @param options.correlate - Query filter for correlation scans (default: `{ after: -1, limit: 100 }`)
|
|
1783
|
-
* @param options.maxPasses -
|
|
1843
|
+
* @param options.maxPasses - Cap on correlate→drain loops (default: `Infinity`).
|
|
1844
|
+
* Early-exit on no-progress means the cap only matters in pathological cases.
|
|
1784
1845
|
* @param options.streamLimit - Maximum streams per drain cycle (default: 10)
|
|
1785
1846
|
* @param options.eventLimit - Maximum events per stream (default: 10)
|
|
1786
1847
|
* @param options.leaseMillis - Lease duration in milliseconds (default: 10000)
|
|
@@ -1802,7 +1863,7 @@ var Act = class {
|
|
|
1802
1863
|
const {
|
|
1803
1864
|
debounceMs = 10,
|
|
1804
1865
|
correlate: correlateQuery = { after: -1, limit: 100 },
|
|
1805
|
-
maxPasses =
|
|
1866
|
+
maxPasses = Infinity,
|
|
1806
1867
|
...drainOptions
|
|
1807
1868
|
} = options;
|
|
1808
1869
|
if (this._settle_timer) clearTimeout(this._settle_timer);
|
|
@@ -1818,9 +1879,9 @@ var Act = class {
|
|
|
1818
1879
|
...correlateQuery,
|
|
1819
1880
|
after: this._correlation_checkpoint
|
|
1820
1881
|
});
|
|
1821
|
-
if (subscribed === 0 && i > 0) break;
|
|
1822
1882
|
lastDrain = await this.drain(drainOptions);
|
|
1823
|
-
|
|
1883
|
+
const made_progress = subscribed > 0 || lastDrain.acked.length > 0 || lastDrain.blocked.length > 0;
|
|
1884
|
+
if (!made_progress) break;
|
|
1824
1885
|
}
|
|
1825
1886
|
if (lastDrain) this.emit("settled", lastDrain);
|
|
1826
1887
|
})().catch((err) => logger3.error(err)).finally(() => {
|