@rotorsoft/act 1.32.20 → 1.32.22
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/act.d.ts +1 -2
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/in-memory-store.d.ts +2 -6
- package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
- package/dist/@types/builders/act-builder.d.ts.map +1 -1
- package/dist/@types/internal/audit.d.ts +1 -4
- package/dist/@types/internal/audit.d.ts.map +1 -1
- package/dist/@types/internal/config.d.ts +3 -9
- package/dist/@types/internal/config.d.ts.map +1 -1
- package/dist/@types/internal/correlate-cycle.d.ts +12 -11
- package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
- package/dist/@types/internal/defer-timer.d.ts +15 -10
- package/dist/@types/internal/defer-timer.d.ts.map +1 -1
- package/dist/@types/internal/drain-cycle.d.ts +6 -5
- package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
- package/dist/@types/internal/index.d.ts +1 -1
- package/dist/@types/internal/index.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +10 -10
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/@types/utils.d.ts +3 -2
- package/dist/@types/utils.d.ts.map +1 -1
- package/dist/{chunk-QOSQI3CA.js → chunk-T3CWXVGT.js} +14 -55
- package/dist/chunk-T3CWXVGT.js.map +1 -0
- package/dist/index.cjs +106 -113
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +94 -60
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +13 -54
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-QOSQI3CA.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
sleep,
|
|
27
27
|
store,
|
|
28
28
|
validate
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-T3CWXVGT.js";
|
|
30
30
|
import {
|
|
31
31
|
ActorSchema,
|
|
32
32
|
CausationEventSchema,
|
|
@@ -926,7 +926,6 @@ function resolveSettleConfig(options) {
|
|
|
926
926
|
return options;
|
|
927
927
|
}
|
|
928
928
|
var MAX_SHUTDOWN_GRACE_MS = 3e4;
|
|
929
|
-
var DEFAULT_SHUTDOWN_GRACE_MS = DEFAULT_LEASE_MILLIS;
|
|
930
929
|
var ShutdownOptionsSchema = z2.object({
|
|
931
930
|
// `0` is legal and is exactly today's behavior: stop scheduling and
|
|
932
931
|
// return without waiting.
|
|
@@ -1561,8 +1560,8 @@ function report_once(seen, key, message) {
|
|
|
1561
1560
|
}
|
|
1562
1561
|
|
|
1563
1562
|
// src/internal/correlate-cycle.ts
|
|
1564
|
-
var
|
|
1565
|
-
var
|
|
1563
|
+
var COLD_START_BACK_SCAN = 1e4;
|
|
1564
|
+
var CORRELATION_LEASE_MS = 5e3;
|
|
1566
1565
|
var registry_key = (events) => {
|
|
1567
1566
|
const shape = Object.keys(events).filter((name) => events[name].reactions.size > 0).sort().map((name) => [name, [...events[name].reactions.keys()].sort()]);
|
|
1568
1567
|
return createHash("sha256").update(JSON.stringify(shape)).digest("hex").slice(0, 32);
|
|
@@ -1591,8 +1590,6 @@ var CorrelateCycle = class {
|
|
|
1591
1590
|
* same holder and a restarted process never inherits a stale claim.
|
|
1592
1591
|
*/
|
|
1593
1592
|
_by = randomUUID();
|
|
1594
|
-
/** How long the correlation lease is taken for. */
|
|
1595
|
-
_lease_millis;
|
|
1596
1593
|
/**
|
|
1597
1594
|
* Which correlator this is. Computed once from the registry so identical
|
|
1598
1595
|
* workers share a lease and unrelated applications never do.
|
|
@@ -1645,12 +1642,6 @@ var CorrelateCycle = class {
|
|
|
1645
1642
|
* here, so an idle deferred stream re-arms across a restart.
|
|
1646
1643
|
*/
|
|
1647
1644
|
_on_init_async;
|
|
1648
|
-
/**
|
|
1649
|
-
* Tail re-scan window applied to the cold-start checkpoint.
|
|
1650
|
-
* See {@link DEFAULT_COLD_START_BACK_SCAN}. Constructor arg (not a
|
|
1651
|
-
* public option) so tests can shrink it; defaults otherwise.
|
|
1652
|
-
*/
|
|
1653
|
-
_cold_start_back_scan;
|
|
1654
1645
|
/** Lanes a controller exists for. See {@link CorrelateCycleDeps}. */
|
|
1655
1646
|
_declared_lanes;
|
|
1656
1647
|
/**
|
|
@@ -1667,11 +1658,8 @@ var CorrelateCycle = class {
|
|
|
1667
1658
|
declared_lanes,
|
|
1668
1659
|
shard,
|
|
1669
1660
|
on_init,
|
|
1670
|
-
on_init_async
|
|
1671
|
-
cold_start_back_scan = DEFAULT_COLD_START_BACK_SCAN,
|
|
1672
|
-
lease_millis = DEFAULT_CORRELATION_LEASE_MS
|
|
1661
|
+
on_init_async
|
|
1673
1662
|
}) {
|
|
1674
|
-
this._lease_millis = lease_millis;
|
|
1675
1663
|
this._key = shard ? `${registry_key(registry.events)}:${[...shard].sort().join(",")}` : registry_key(registry.events);
|
|
1676
1664
|
this._dynamic_subscriptions = new LruMap(max_subscribed_streams);
|
|
1677
1665
|
this._registry = registry;
|
|
@@ -1680,7 +1668,6 @@ var CorrelateCycle = class {
|
|
|
1680
1668
|
this._cd = cd;
|
|
1681
1669
|
this._on_init = on_init;
|
|
1682
1670
|
this._on_init_async = on_init_async;
|
|
1683
|
-
this._cold_start_back_scan = cold_start_back_scan;
|
|
1684
1671
|
}
|
|
1685
1672
|
/** Last correlated event id. */
|
|
1686
1673
|
get checkpoint() {
|
|
@@ -1719,7 +1706,7 @@ var CorrelateCycle = class {
|
|
|
1719
1706
|
const { watermark, correlated_at } = await this._cd.subscribe([
|
|
1720
1707
|
...this._static_targets
|
|
1721
1708
|
]);
|
|
1722
|
-
this._checkpoint = correlated_at >= 0 ? correlated_at : Math.max(-1, watermark -
|
|
1709
|
+
this._checkpoint = correlated_at >= 0 ? correlated_at : Math.max(-1, watermark - COLD_START_BACK_SCAN);
|
|
1723
1710
|
this._on_init?.();
|
|
1724
1711
|
for (const { stream, priority = 0, lane } of this._static_targets) {
|
|
1725
1712
|
this._static_subscriptions.set(stream, {
|
|
@@ -1793,13 +1780,13 @@ var CorrelateCycle = class {
|
|
|
1793
1780
|
scanned: false
|
|
1794
1781
|
};
|
|
1795
1782
|
const now = Date.now();
|
|
1796
|
-
if (lease && now >= this._lease_until -
|
|
1783
|
+
if (lease && now >= this._lease_until - CORRELATION_LEASE_MS / 2) {
|
|
1797
1784
|
const { correlating } = await this._cd.subscribe([], void 0, {
|
|
1798
1785
|
key: this._key,
|
|
1799
1786
|
by: this._by,
|
|
1800
|
-
millis:
|
|
1787
|
+
millis: CORRELATION_LEASE_MS
|
|
1801
1788
|
});
|
|
1802
|
-
this._lease_until = correlating ? now +
|
|
1789
|
+
this._lease_until = correlating ? now + CORRELATION_LEASE_MS : 0;
|
|
1803
1790
|
if (correlating === false)
|
|
1804
1791
|
return {
|
|
1805
1792
|
subscribed: 0,
|
|
@@ -1839,6 +1826,8 @@ var CorrelateCycle = class {
|
|
|
1839
1826
|
priority: carried.priority,
|
|
1840
1827
|
lane: carried.lane,
|
|
1841
1828
|
upgraded,
|
|
1829
|
+
missed: !recorded,
|
|
1830
|
+
handler: reaction.handler.name,
|
|
1842
1831
|
correlated_at: void 0
|
|
1843
1832
|
};
|
|
1844
1833
|
const seen_in_scan = correlated.has(resolved.target);
|
|
@@ -1857,6 +1846,7 @@ var CorrelateCycle = class {
|
|
|
1857
1846
|
entry.priority = carried.priority;
|
|
1858
1847
|
entry.lane = carried.lane;
|
|
1859
1848
|
entry.upgraded = upgraded;
|
|
1849
|
+
entry.handler = reaction.handler.name;
|
|
1860
1850
|
}
|
|
1861
1851
|
if (this._in_fetch_window(resolved.source, event.stream))
|
|
1862
1852
|
entry.correlated_at = event.id;
|
|
@@ -1870,6 +1860,7 @@ var CorrelateCycle = class {
|
|
|
1870
1860
|
// actor-less, so plaintext here would be un-gated disclosure.
|
|
1871
1861
|
{ ...query, after, with_pii: false }
|
|
1872
1862
|
);
|
|
1863
|
+
if (this._declared_lanes.size > 1) await this._recall(correlated);
|
|
1873
1864
|
const streams = [];
|
|
1874
1865
|
for (const [stream, entry] of correlated) {
|
|
1875
1866
|
if (entry.upgraded || entry.correlated_at !== void 0)
|
|
@@ -1886,10 +1877,10 @@ var CorrelateCycle = class {
|
|
|
1886
1877
|
const { subscribed, correlating } = await this._cd.subscribe(
|
|
1887
1878
|
streams,
|
|
1888
1879
|
last_id,
|
|
1889
|
-
lease ? { key: this._key, by: this._by, millis:
|
|
1880
|
+
lease ? { key: this._key, by: this._by, millis: CORRELATION_LEASE_MS } : void 0
|
|
1890
1881
|
);
|
|
1891
1882
|
if (lease && correlating !== false)
|
|
1892
|
-
this._lease_until = renewed_at +
|
|
1883
|
+
this._lease_until = renewed_at + CORRELATION_LEASE_MS;
|
|
1893
1884
|
const marked = streams.filter(
|
|
1894
1885
|
(entry) => entry.correlated_at !== void 0
|
|
1895
1886
|
).length;
|
|
@@ -1908,6 +1899,50 @@ var CorrelateCycle = class {
|
|
|
1908
1899
|
this._armed = found === query.limit;
|
|
1909
1900
|
return { subscribed: 0, last_id, marked: 0, scanned: true };
|
|
1910
1901
|
}
|
|
1902
|
+
/**
|
|
1903
|
+
* Give each target this scan had no record of the record its row holds.
|
|
1904
|
+
*
|
|
1905
|
+
* A target with no record is either new or forgotten. Its row, when it
|
|
1906
|
+
* has one, says what lane and priority it was subscribed at; a resolution
|
|
1907
|
+
* that doesn't beat that priority carries the row's values, exactly as if
|
|
1908
|
+
* the record had never been evicted. One read per target with no record,
|
|
1909
|
+
* and only when more than one lane is declared: with one lane there is no
|
|
1910
|
+
* lane to lose, and the store already keeps the higher priority.
|
|
1911
|
+
*/
|
|
1912
|
+
async _recall(correlated) {
|
|
1913
|
+
const missed = [...correlated].filter(([, entry]) => entry.missed);
|
|
1914
|
+
await Promise.all(
|
|
1915
|
+
missed.map(async ([stream, entry]) => {
|
|
1916
|
+
let row;
|
|
1917
|
+
await store().query_streams(
|
|
1918
|
+
(position) => {
|
|
1919
|
+
row = position;
|
|
1920
|
+
},
|
|
1921
|
+
{ stream, stream_exact: true, limit: 1 }
|
|
1922
|
+
);
|
|
1923
|
+
if (!row) return;
|
|
1924
|
+
this._dynamic_subscriptions.set(stream, {
|
|
1925
|
+
floor: row.priority,
|
|
1926
|
+
priority: row.priority,
|
|
1927
|
+
lane: row.lane
|
|
1928
|
+
});
|
|
1929
|
+
if (entry.priority > row.priority) return;
|
|
1930
|
+
const held_lane = row.lane ?? DEFAULT_LANE;
|
|
1931
|
+
const resolved_lane = entry.lane ?? DEFAULT_LANE;
|
|
1932
|
+
if (entry.priority === row.priority && held_lane !== resolved_lane)
|
|
1933
|
+
report_lane_conflict(
|
|
1934
|
+
this._reported,
|
|
1935
|
+
entry.handler,
|
|
1936
|
+
stream,
|
|
1937
|
+
held_lane,
|
|
1938
|
+
resolved_lane
|
|
1939
|
+
);
|
|
1940
|
+
entry.priority = row.priority;
|
|
1941
|
+
entry.lane = row.lane;
|
|
1942
|
+
entry.upgraded = false;
|
|
1943
|
+
})
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1911
1946
|
/**
|
|
1912
1947
|
* Hand the correlation lease back early.
|
|
1913
1948
|
*
|
|
@@ -1925,7 +1960,7 @@ var CorrelateCycle = class {
|
|
|
1925
1960
|
});
|
|
1926
1961
|
} catch (error) {
|
|
1927
1962
|
log().warn(
|
|
1928
|
-
`Could not hand back the correlation lease during shutdown; it expires on its own within ${
|
|
1963
|
+
`Could not hand back the correlation lease during shutdown; it expires on its own within ${CORRELATION_LEASE_MS}ms and correlation resumes normally after that. On a single-writer store this usually means another connection holds the database. Cause: ${String(error)}`
|
|
1929
1964
|
);
|
|
1930
1965
|
}
|
|
1931
1966
|
}
|
|
@@ -2067,9 +2102,8 @@ var DeferTimer = class {
|
|
|
2067
2102
|
_timer;
|
|
2068
2103
|
_on_wake;
|
|
2069
2104
|
/**
|
|
2070
|
-
* @param on_wake - invoked once each time the earliest due-time elapses
|
|
2071
|
-
*
|
|
2072
|
-
* for whatever is still parked.
|
|
2105
|
+
* @param on_wake - invoked once each time the earliest due-time elapses.
|
|
2106
|
+
* The consumer re-schedules for whatever is still parked.
|
|
2073
2107
|
*/
|
|
2074
2108
|
constructor(on_wake) {
|
|
2075
2109
|
this._on_wake = on_wake;
|
|
@@ -2078,14 +2112,6 @@ var DeferTimer = class {
|
|
|
2078
2112
|
get size() {
|
|
2079
2113
|
return this._due.size;
|
|
2080
2114
|
}
|
|
2081
|
-
/**
|
|
2082
|
-
* True while `stream` is parked with a due-time still in the future.
|
|
2083
|
-
* Consumers skip work for deferred streams until their window elapses.
|
|
2084
|
-
*/
|
|
2085
|
-
is_deferred = (stream) => {
|
|
2086
|
-
const next = this._due.get(stream);
|
|
2087
|
-
return next !== void 0 && next > Date.now();
|
|
2088
|
-
};
|
|
2089
2115
|
/**
|
|
2090
2116
|
* Park `stream` for a re-visit at `at` (ms since epoch). A plain
|
|
2091
2117
|
* overwrite: the caller computes the authoritative next-visit for the
|
|
@@ -2099,6 +2125,16 @@ var DeferTimer = class {
|
|
|
2099
2125
|
delete(stream) {
|
|
2100
2126
|
this._due.delete(stream);
|
|
2101
2127
|
}
|
|
2128
|
+
/**
|
|
2129
|
+
* Drop every entry due at or before `before`. The drain calls it when a
|
|
2130
|
+
* pass that started at `before` claimed nothing: whatever was due by then
|
|
2131
|
+
* was handled elsewhere (another worker) or has no work left, so waking
|
|
2132
|
+
* for it again would spin.
|
|
2133
|
+
*/
|
|
2134
|
+
prune(before) {
|
|
2135
|
+
for (const [stream, at] of this._due)
|
|
2136
|
+
if (at <= before) this._due.delete(stream);
|
|
2137
|
+
}
|
|
2102
2138
|
/**
|
|
2103
2139
|
* (Re)schedule the wake timer at the earliest pending due-time. Idempotent
|
|
2104
2140
|
* — collapses many parked streams into a single timer. A no-op clears any
|
|
@@ -2121,9 +2157,6 @@ var DeferTimer = class {
|
|
|
2121
2157
|
);
|
|
2122
2158
|
this._timer = setTimeout(() => {
|
|
2123
2159
|
this._timer = void 0;
|
|
2124
|
-
const now = Date.now();
|
|
2125
|
-
for (const [stream, at] of this._due)
|
|
2126
|
-
if (at <= now) this._due.delete(stream);
|
|
2127
2160
|
this._on_wake();
|
|
2128
2161
|
}, delay);
|
|
2129
2162
|
this._timer.unref();
|
|
@@ -2761,7 +2794,7 @@ function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
|
|
|
2761
2794
|
function budget_exhausted(lease, options, store_failing) {
|
|
2762
2795
|
if (store_failing || !options?.blockOnError || lease.retry <= options.maxRetries)
|
|
2763
2796
|
return void 0;
|
|
2764
|
-
const error = `Blocking ${lease.stream} after ${lease.retry} claims with no acknowledged progress \u2014 the retry budget (${options.maxRetries}) was spent without the handler ever reporting an error. That means every attempt lost its lease before it could ack:
|
|
2797
|
+
const error = `Blocking ${lease.stream} after ${lease.retry} claims with no acknowledged progress \u2014 the retry budget (${options.maxRetries}) was spent without the handler ever reporting an error. That means every attempt lost its lease before it could ack: move the reaction to a lane whose leaseMillis covers the handler, then unblock the stream.`;
|
|
2765
2798
|
log().error(error);
|
|
2766
2799
|
return { lease, handled: 0, acked_at: lease.at, error, block: true };
|
|
2767
2800
|
}
|
|
@@ -2841,7 +2874,9 @@ async function run_drain_cycle(deps, cycle) {
|
|
|
2841
2874
|
handled: 0,
|
|
2842
2875
|
acked_at: lease.at,
|
|
2843
2876
|
error,
|
|
2844
|
-
...block2 ? { block: true } : {
|
|
2877
|
+
...block2 ? { block: true } : {
|
|
2878
|
+
next_attempt_at: Date.now() + compute_backoff_delay(lease.retry, DEFAULT_BACKOFF)
|
|
2879
|
+
}
|
|
2845
2880
|
};
|
|
2846
2881
|
return Promise.resolve(failed);
|
|
2847
2882
|
}
|
|
@@ -2892,6 +2927,9 @@ var DrainController = class {
|
|
|
2892
2927
|
* schedule itself is persisted in the store; this runs the drain at the
|
|
2893
2928
|
* earliest pending visit. A parked stream already carries its mark, so
|
|
2894
2929
|
* the drain alone finds it, and on an idle app nothing else would.
|
|
2930
|
+
* Every drain re-aims it when it ends, and a due entry stays until a pass
|
|
2931
|
+
* handles it or a pass that started after it came due claims nothing, so
|
|
2932
|
+
* the wake keeps draining until every due stream is reached.
|
|
2895
2933
|
* `stop()` cancels the timer and a stopped drain never re-schedules it,
|
|
2896
2934
|
* so a wake never runs after a stop.
|
|
2897
2935
|
*/
|
|
@@ -2987,17 +3025,18 @@ var DrainController = class {
|
|
|
2987
3025
|
if (this._locked) return EMPTY_DRAIN;
|
|
2988
3026
|
const d = this._deps.defaults ?? {};
|
|
2989
3027
|
const streamLimit = d.streamLimit ?? options.streamLimit ?? DEFAULT_STREAM_LIMIT;
|
|
2990
|
-
const eventLimit =
|
|
3028
|
+
const eventLimit = options.eventLimit ?? DEFAULT_EVENT_LIMIT;
|
|
2991
3029
|
const leaseMillis = d.leaseMillis ?? options.leaseMillis ?? DEFAULT_LEASE_MILLIS;
|
|
3030
|
+
if (this._deps.breaker.state(Date.now()) === "open")
|
|
3031
|
+
return EMPTY_DRAIN;
|
|
2992
3032
|
try {
|
|
2993
|
-
if (this._deps.breaker.state(Date.now()) === "open")
|
|
2994
|
-
return EMPTY_DRAIN;
|
|
2995
3033
|
this._locked = true;
|
|
2996
3034
|
this._inflight = new Promise((done) => {
|
|
2997
3035
|
this._inflight_done = done;
|
|
2998
3036
|
});
|
|
2999
3037
|
const lagging = Math.ceil(streamLimit * this._ratio);
|
|
3000
3038
|
const leading = streamLimit - lagging;
|
|
3039
|
+
const started = Date.now();
|
|
3001
3040
|
const cycle = await run_drain_cycle(this._deps, {
|
|
3002
3041
|
lagging,
|
|
3003
3042
|
leading,
|
|
@@ -3007,6 +3046,7 @@ var DrainController = class {
|
|
|
3007
3046
|
store_failing: this._deps.breaker.failing
|
|
3008
3047
|
});
|
|
3009
3048
|
if (!cycle) {
|
|
3049
|
+
this._defer.prune(started);
|
|
3010
3050
|
this._deps.breaker.passed();
|
|
3011
3051
|
this._armed = false;
|
|
3012
3052
|
return EMPTY_DRAIN;
|
|
@@ -3649,9 +3689,7 @@ var Act = class {
|
|
|
3649
3689
|
_build_audit_deps() {
|
|
3650
3690
|
return {
|
|
3651
3691
|
store,
|
|
3652
|
-
logger: this._logger,
|
|
3653
3692
|
event_to_state: this._event_to_state,
|
|
3654
|
-
states: this._states,
|
|
3655
3693
|
// Declared lanes, not this process's controllers: a lane another
|
|
3656
3694
|
// worker drains is not `unknown-lane`.
|
|
3657
3695
|
declared_lanes: new Set(this._declared_lanes),
|
|
@@ -3758,9 +3796,9 @@ var Act = class {
|
|
|
3758
3796
|
* fallback, capped at the maximum. Idle lanes don't count.
|
|
3759
3797
|
*/
|
|
3760
3798
|
_derive_grace_ms(running, settling) {
|
|
3761
|
-
let max = settling ?
|
|
3799
|
+
let max = settling ? DEFAULT_LEASE_MILLIS : 0;
|
|
3762
3800
|
for (const c of running)
|
|
3763
|
-
max = Math.max(max, c.lease_millis ||
|
|
3801
|
+
max = Math.max(max, c.lease_millis || DEFAULT_LEASE_MILLIS);
|
|
3764
3802
|
return Math.min(max, MAX_SHUTDOWN_GRACE_MS);
|
|
3765
3803
|
}
|
|
3766
3804
|
async _await_inflight(grace_ms) {
|
|
@@ -4070,8 +4108,7 @@ var Act = class {
|
|
|
4070
4108
|
* Call `correlate()` before `drain()`. It is not only how dynamic targets
|
|
4071
4109
|
* are discovered: a stream is claimable while `at < correlated_at`, and
|
|
4072
4110
|
* `correlate` is the only component that raises that mark, so a
|
|
4073
|
-
* commit no correlate has seen is not drainable
|
|
4074
|
-
* targets, which were served by a probe of the event log before. For a
|
|
4111
|
+
* commit no correlate has seen is not drainable, static targets included. For a
|
|
4075
4112
|
* higher-level API that handles debouncing, correlation, and signaling
|
|
4076
4113
|
* automatically, use {@link settle}.
|
|
4077
4114
|
*
|
|
@@ -5077,6 +5114,12 @@ function act() {
|
|
|
5077
5114
|
};
|
|
5078
5115
|
const fold_projections = [];
|
|
5079
5116
|
const batch_handlers = /* @__PURE__ */ new Map();
|
|
5117
|
+
const add_projection = (proj) => {
|
|
5118
|
+
record_projection_reactions(proj);
|
|
5119
|
+
merge_projection(proj, registry.events);
|
|
5120
|
+
register_batch_handler(proj, batch_handlers);
|
|
5121
|
+
if (proj.fold) fold_projections.push(proj);
|
|
5122
|
+
};
|
|
5080
5123
|
const fold_specs = [];
|
|
5081
5124
|
const lanes = [];
|
|
5082
5125
|
let _built = false;
|
|
@@ -5176,11 +5219,7 @@ function act() {
|
|
|
5176
5219
|
},
|
|
5177
5220
|
withProjection: (proj) => {
|
|
5178
5221
|
if (_built) closed("withProjection");
|
|
5179
|
-
|
|
5180
|
-
merge_projection(proj, registry.events);
|
|
5181
|
-
register_batch_handler(proj, batch_handlers);
|
|
5182
|
-
if (proj.fold)
|
|
5183
|
-
fold_projections.push(proj);
|
|
5222
|
+
add_projection(proj);
|
|
5184
5223
|
return builder;
|
|
5185
5224
|
},
|
|
5186
5225
|
withActor: () => builder,
|
|
@@ -5197,12 +5236,7 @@ function act() {
|
|
|
5197
5236
|
resolveActConfig(options);
|
|
5198
5237
|
const patch_fn = options?.validateFoldedState === true ? validating_patch : bare_patch;
|
|
5199
5238
|
if (!_built) {
|
|
5200
|
-
for (const proj of pending_projections)
|
|
5201
|
-
record_projection_reactions(proj);
|
|
5202
|
-
merge_projection(proj, registry.events);
|
|
5203
|
-
register_batch_handler(proj, batch_handlers);
|
|
5204
|
-
if (proj.fold) fold_projections.push(proj);
|
|
5205
|
-
}
|
|
5239
|
+
for (const proj of pending_projections) add_projection(proj);
|
|
5206
5240
|
for (const proj of fold_projections) {
|
|
5207
5241
|
const fold = proj.fold;
|
|
5208
5242
|
const merged = states.get(fold.name);
|