@rotorsoft/act 1.22.9 → 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/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +33 -2
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/console-logger.d.ts.map +1 -1
- package/dist/@types/adapters/in-memory-cache.d.ts.map +1 -1
- package/dist/@types/adapters/in-memory-store.d.ts +10 -0
- 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/config.d.ts +5 -5
- package/dist/@types/csv.d.ts.map +1 -1
- package/dist/@types/internal/builder-utils.d.ts.map +1 -1
- package/dist/@types/internal/circuit-breaker.d.ts.map +1 -1
- package/dist/@types/internal/close-signal.d.ts.map +1 -1
- package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
- package/dist/@types/internal/defer-signal.d.ts.map +1 -1
- package/dist/@types/internal/defer-timer.d.ts.map +1 -1
- package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
- package/dist/@types/internal/drain.d.ts.map +1 -1
- package/dist/@types/internal/event-sourcing.d.ts +59 -2
- package/dist/@types/internal/event-sourcing.d.ts.map +1 -1
- package/dist/@types/internal/index.d.ts +3 -3
- package/dist/@types/internal/index.d.ts.map +1 -1
- package/dist/@types/internal/lru-map.d.ts.map +1 -1
- package/dist/@types/internal/merge.d.ts.map +1 -1
- package/dist/@types/internal/projection-fold.d.ts +46 -0
- package/dist/@types/internal/projection-fold.d.ts.map +1 -0
- package/dist/@types/internal/settle.d.ts.map +1 -1
- package/dist/@types/internal/tracing.d.ts +2 -2
- package/dist/@types/internal/tracing.d.ts.map +1 -1
- package/dist/@types/ports.d.ts +1 -1
- package/dist/@types/ports.d.ts.map +1 -1
- package/dist/@types/types/errors.d.ts.map +1 -1
- package/dist/@types/types/index.d.ts.map +1 -1
- package/dist/@types/utils.d.ts.map +1 -1
- package/dist/{chunk-YVLB5MMB.js → chunk-4HYYZOEH.js} +9 -2
- package/dist/chunk-4HYYZOEH.js.map +1 -0
- package/dist/index.cjs +128 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +121 -90
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +8 -1
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.js +1 -1
- package/package.json +2 -2
- package/dist/@types/internal/state-fold.d.ts +0 -18
- package/dist/@types/internal/state-fold.d.ts.map +0 -1
- package/dist/chunk-YVLB5MMB.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
sleep,
|
|
21
21
|
store,
|
|
22
22
|
validate
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-4HYYZOEH.js";
|
|
24
24
|
import {
|
|
25
25
|
ActorSchema,
|
|
26
26
|
CausationEventSchema,
|
|
@@ -1736,6 +1736,15 @@ function compute_backoff_delay(retry, opts) {
|
|
|
1736
1736
|
}
|
|
1737
1737
|
|
|
1738
1738
|
// src/internal/event-sourcing.ts
|
|
1739
|
+
var bare_patch = (_me, state2, partial) => patch(state2, partial);
|
|
1740
|
+
var validating_patch = (me, state2, partial, event) => {
|
|
1741
|
+
const next = patch(state2, partial);
|
|
1742
|
+
return validate(
|
|
1743
|
+
`${me.name}.${String(event.name)}#${event.id}`,
|
|
1744
|
+
next,
|
|
1745
|
+
me.state
|
|
1746
|
+
);
|
|
1747
|
+
};
|
|
1739
1748
|
var DEFAULT_BATCH = 500;
|
|
1740
1749
|
async function snap(snapshot) {
|
|
1741
1750
|
const { id, stream, name, meta, version } = snapshot.event;
|
|
@@ -1890,7 +1899,7 @@ async function scan(source, opts = {}, callback) {
|
|
|
1890
1899
|
}
|
|
1891
1900
|
};
|
|
1892
1901
|
}
|
|
1893
|
-
async function load(me, target, callback) {
|
|
1902
|
+
async function load(me, target, callback, patch_fn = bare_patch) {
|
|
1894
1903
|
const { stream, actor, asOf } = target;
|
|
1895
1904
|
const time_travel = !!asOf && Object.values(asOf).some((v) => v !== void 0);
|
|
1896
1905
|
const cached = time_travel ? void 0 : await cache().get(stream);
|
|
@@ -1909,7 +1918,7 @@ async function load(me, target, callback) {
|
|
|
1909
1918
|
patches = 0;
|
|
1910
1919
|
replayed++;
|
|
1911
1920
|
} else if (me.patch[event.name]) {
|
|
1912
|
-
state2 =
|
|
1921
|
+
state2 = patch_fn(me, state2, me.patch[event.name](event, state2), event);
|
|
1913
1922
|
patches++;
|
|
1914
1923
|
replayed++;
|
|
1915
1924
|
} else if (event.name !== TOMBSTONE_EVENT) {
|
|
@@ -1960,7 +1969,7 @@ async function load(me, target, callback) {
|
|
|
1960
1969
|
replayed
|
|
1961
1970
|
};
|
|
1962
1971
|
}
|
|
1963
|
-
async function action(me, action2, target, payload, options) {
|
|
1972
|
+
async function action(me, action2, target, payload, options, patch_fn = bare_patch) {
|
|
1964
1973
|
const { stream, expectedVersion, actor } = target;
|
|
1965
1974
|
if (!stream) throw new Error("Missing target stream");
|
|
1966
1975
|
const reactingTo = options?.reactingTo;
|
|
@@ -1970,7 +1979,12 @@ async function action(me, action2, target, payload, options) {
|
|
|
1970
1979
|
const max_retries = opts?.maxRetries ?? 0;
|
|
1971
1980
|
for (let attempt = 0; ; attempt++) {
|
|
1972
1981
|
try {
|
|
1973
|
-
const snapshot = await load(
|
|
1982
|
+
const snapshot = await load(
|
|
1983
|
+
me,
|
|
1984
|
+
{ stream, actor: target.actor },
|
|
1985
|
+
void 0,
|
|
1986
|
+
patch_fn
|
|
1987
|
+
);
|
|
1974
1988
|
if (snapshot.event?.name === TOMBSTONE_EVENT)
|
|
1975
1989
|
throw new StreamClosedError(stream);
|
|
1976
1990
|
const expected = expectedVersion ?? (snapshot.version >= 0 ? snapshot.version : void 0);
|
|
@@ -2041,7 +2055,7 @@ async function action(me, action2, target, payload, options) {
|
|
|
2041
2055
|
const snapshots = committed.map((row, i) => {
|
|
2042
2056
|
const event = { ...row, data: valid[i].data };
|
|
2043
2057
|
const p = me.patch[event.name](event, state2);
|
|
2044
|
-
state2 =
|
|
2058
|
+
state2 = patch_fn(me, state2, p, event);
|
|
2045
2059
|
patches++;
|
|
2046
2060
|
return {
|
|
2047
2061
|
event,
|
|
@@ -2137,12 +2151,20 @@ var traced = (inner, exit, entry) => (async (...args) => {
|
|
|
2137
2151
|
exit?.(result, ...args);
|
|
2138
2152
|
return result;
|
|
2139
2153
|
});
|
|
2140
|
-
function build_es(logger, correlator = default_correlator) {
|
|
2141
|
-
const bound_action = (me, action_name, target, payload, options) => action(
|
|
2154
|
+
function build_es(logger, correlator = default_correlator, patch_fn = bare_patch) {
|
|
2155
|
+
const bound_action = (me, action_name, target, payload, options) => action(
|
|
2156
|
+
me,
|
|
2157
|
+
action_name,
|
|
2158
|
+
target,
|
|
2159
|
+
payload,
|
|
2160
|
+
{ correlator, ...options },
|
|
2161
|
+
patch_fn
|
|
2162
|
+
);
|
|
2163
|
+
const bound_load = (me, target, callback) => load(me, target, callback, patch_fn);
|
|
2142
2164
|
if (logger.level !== "trace") {
|
|
2143
2165
|
return {
|
|
2144
2166
|
snap,
|
|
2145
|
-
load,
|
|
2167
|
+
load: bound_load,
|
|
2146
2168
|
action: bound_action,
|
|
2147
2169
|
tombstone
|
|
2148
2170
|
};
|
|
@@ -2157,7 +2179,7 @@ function build_es(logger, correlator = default_correlator) {
|
|
|
2157
2179
|
)
|
|
2158
2180
|
);
|
|
2159
2181
|
}),
|
|
2160
|
-
load: traced(
|
|
2182
|
+
load: traced(bound_load, (result, _me, target) => {
|
|
2161
2183
|
const stats = stats_marker(
|
|
2162
2184
|
result.version,
|
|
2163
2185
|
result.replayed,
|
|
@@ -2468,6 +2490,83 @@ var DrainController = class {
|
|
|
2468
2490
|
}
|
|
2469
2491
|
};
|
|
2470
2492
|
|
|
2493
|
+
// src/internal/projection-fold.ts
|
|
2494
|
+
import { z as z5 } from "zod";
|
|
2495
|
+
var DEFAULT_FOLD_FLUSH_EVERY = 1e3;
|
|
2496
|
+
var DEFAULT_MAX_CACHED_STATES = 1e4;
|
|
2497
|
+
var FoldOptionsSchema = z5.object({
|
|
2498
|
+
flushEvery: z5.number().int().min(1).default(DEFAULT_FOLD_FLUSH_EVERY),
|
|
2499
|
+
maxCachedStates: z5.number().int().min(1).default(DEFAULT_MAX_CACHED_STATES)
|
|
2500
|
+
});
|
|
2501
|
+
function resolveFoldConfig(options) {
|
|
2502
|
+
return FoldOptionsSchema.parse(options);
|
|
2503
|
+
}
|
|
2504
|
+
function make_fold_handler(me, flush, config2, patch_fn = bare_patch) {
|
|
2505
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
2506
|
+
const row = ({ dirty: _, ...row2 }) => row2;
|
|
2507
|
+
const flush_dirty = async () => {
|
|
2508
|
+
const rows = [];
|
|
2509
|
+
const flushed = [];
|
|
2510
|
+
for (const f of cache2.values())
|
|
2511
|
+
if (f.dirty) {
|
|
2512
|
+
rows.push(row(f));
|
|
2513
|
+
flushed.push(f);
|
|
2514
|
+
}
|
|
2515
|
+
if (rows.length === 0) return;
|
|
2516
|
+
await flush(rows);
|
|
2517
|
+
for (const f of flushed) f.dirty = false;
|
|
2518
|
+
};
|
|
2519
|
+
return async (events) => {
|
|
2520
|
+
let folded_since_flush = 0;
|
|
2521
|
+
for (const event of events) {
|
|
2522
|
+
const stream = event.stream;
|
|
2523
|
+
let fold = cache2.get(stream);
|
|
2524
|
+
if (fold) {
|
|
2525
|
+
cache2.delete(stream);
|
|
2526
|
+
cache2.set(stream, fold);
|
|
2527
|
+
} else {
|
|
2528
|
+
if (cache2.size >= config2.maxCachedStates) {
|
|
2529
|
+
const oldest = cache2.keys().next().value;
|
|
2530
|
+
const evictee = cache2.get(oldest);
|
|
2531
|
+
if (evictee.dirty) await flush([row(evictee)]);
|
|
2532
|
+
cache2.delete(oldest);
|
|
2533
|
+
}
|
|
2534
|
+
const snapshot = await load(me, { stream }, void 0, patch_fn);
|
|
2535
|
+
fold = {
|
|
2536
|
+
stream,
|
|
2537
|
+
state: snapshot.state,
|
|
2538
|
+
version: snapshot.version,
|
|
2539
|
+
event_id: snapshot.id,
|
|
2540
|
+
patches: snapshot.patches,
|
|
2541
|
+
snaps: snapshot.snaps,
|
|
2542
|
+
dirty: true
|
|
2543
|
+
};
|
|
2544
|
+
cache2.set(stream, fold);
|
|
2545
|
+
}
|
|
2546
|
+
if (event.id > fold.event_id) {
|
|
2547
|
+
const reducer = me.patch[event.name];
|
|
2548
|
+
fold.state = patch_fn(
|
|
2549
|
+
me,
|
|
2550
|
+
fold.state,
|
|
2551
|
+
reducer(event, fold.state),
|
|
2552
|
+
event
|
|
2553
|
+
);
|
|
2554
|
+
fold.version = event.version;
|
|
2555
|
+
fold.event_id = event.id;
|
|
2556
|
+
fold.patches++;
|
|
2557
|
+
fold.dirty = true;
|
|
2558
|
+
} else {
|
|
2559
|
+
fold.dirty = true;
|
|
2560
|
+
}
|
|
2561
|
+
if (++folded_since_flush >= config2.flushEvery) {
|
|
2562
|
+
await flush_dirty();
|
|
2563
|
+
folded_since_flush = 0;
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
await flush_dirty();
|
|
2567
|
+
};
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2471
2570
|
// src/internal/reactions.ts
|
|
2472
2571
|
function finalize(lease, handled, at, error, options, logger, failed_at) {
|
|
2473
2572
|
if (!error) return { lease, handled, acked_at: at };
|
|
@@ -2673,82 +2772,6 @@ var SettleLoop = class {
|
|
|
2673
2772
|
}
|
|
2674
2773
|
};
|
|
2675
2774
|
|
|
2676
|
-
// src/internal/state-fold.ts
|
|
2677
|
-
import { patch as patch2 } from "@rotorsoft/act-patch";
|
|
2678
|
-
import { z as z5 } from "zod";
|
|
2679
|
-
var DEFAULT_FOLD_FLUSH_EVERY = 1e3;
|
|
2680
|
-
var DEFAULT_MAX_CACHED_STATES = 1e4;
|
|
2681
|
-
var FoldOptionsSchema = z5.object({
|
|
2682
|
-
flushEvery: z5.number().int().min(1).default(DEFAULT_FOLD_FLUSH_EVERY),
|
|
2683
|
-
maxCachedStates: z5.number().int().min(1).default(DEFAULT_MAX_CACHED_STATES)
|
|
2684
|
-
});
|
|
2685
|
-
function resolveFoldConfig(options) {
|
|
2686
|
-
return FoldOptionsSchema.parse(options);
|
|
2687
|
-
}
|
|
2688
|
-
function make_fold_handler(me, flush, config2) {
|
|
2689
|
-
const cache2 = /* @__PURE__ */ new Map();
|
|
2690
|
-
const row = ({ dirty: _, ...row2 }) => row2;
|
|
2691
|
-
const flush_dirty = async () => {
|
|
2692
|
-
const rows = [];
|
|
2693
|
-
const flushed = [];
|
|
2694
|
-
for (const f of cache2.values())
|
|
2695
|
-
if (f.dirty) {
|
|
2696
|
-
rows.push(row(f));
|
|
2697
|
-
flushed.push(f);
|
|
2698
|
-
}
|
|
2699
|
-
if (rows.length === 0) return;
|
|
2700
|
-
await flush(rows);
|
|
2701
|
-
for (const f of flushed) f.dirty = false;
|
|
2702
|
-
};
|
|
2703
|
-
return async (events) => {
|
|
2704
|
-
let folded_since_flush = 0;
|
|
2705
|
-
for (const event of events) {
|
|
2706
|
-
const stream = event.stream;
|
|
2707
|
-
let fold = cache2.get(stream);
|
|
2708
|
-
if (fold) {
|
|
2709
|
-
cache2.delete(stream);
|
|
2710
|
-
cache2.set(stream, fold);
|
|
2711
|
-
} else {
|
|
2712
|
-
if (cache2.size >= config2.maxCachedStates) {
|
|
2713
|
-
const oldest = cache2.keys().next().value;
|
|
2714
|
-
const evictee = cache2.get(oldest);
|
|
2715
|
-
if (evictee.dirty) await flush([row(evictee)]);
|
|
2716
|
-
cache2.delete(oldest);
|
|
2717
|
-
}
|
|
2718
|
-
const snapshot = await load(me, { stream });
|
|
2719
|
-
fold = {
|
|
2720
|
-
stream,
|
|
2721
|
-
state: snapshot.state,
|
|
2722
|
-
version: snapshot.version,
|
|
2723
|
-
event_id: snapshot.id,
|
|
2724
|
-
patches: snapshot.patches,
|
|
2725
|
-
snaps: snapshot.snaps,
|
|
2726
|
-
dirty: true
|
|
2727
|
-
};
|
|
2728
|
-
cache2.set(stream, fold);
|
|
2729
|
-
}
|
|
2730
|
-
if (event.id > fold.event_id) {
|
|
2731
|
-
const reducer = me.patch[event.name];
|
|
2732
|
-
fold.state = patch2(
|
|
2733
|
-
fold.state,
|
|
2734
|
-
reducer(event, fold.state)
|
|
2735
|
-
);
|
|
2736
|
-
fold.version = event.version;
|
|
2737
|
-
fold.event_id = event.id;
|
|
2738
|
-
fold.patches++;
|
|
2739
|
-
fold.dirty = true;
|
|
2740
|
-
} else {
|
|
2741
|
-
fold.dirty = true;
|
|
2742
|
-
}
|
|
2743
|
-
if (++folded_since_flush >= config2.flushEvery) {
|
|
2744
|
-
await flush_dirty();
|
|
2745
|
-
folded_since_flush = 0;
|
|
2746
|
-
}
|
|
2747
|
-
}
|
|
2748
|
-
await flush_dirty();
|
|
2749
|
-
};
|
|
2750
|
-
}
|
|
2751
|
-
|
|
2752
2775
|
// src/act.ts
|
|
2753
2776
|
var DEFAULT_MAX_SUBSCRIBED_STREAMS = 1e3;
|
|
2754
2777
|
var DEFAULT_SETTLE_DEBOUNCE_MS = 10;
|
|
@@ -2905,8 +2928,14 @@ var Act = class {
|
|
|
2905
2928
|
* @param lanes Declared drain lanes (ACT-1103). The builder collects
|
|
2906
2929
|
* these from `.withLane(...)` calls. Slice 1 records them on the
|
|
2907
2930
|
* instance; later slices fan out one `DrainController` per lane.
|
|
2931
|
+
* @param patch_fn The per-event patch step selected once by the builder
|
|
2932
|
+
* from `ActOptions.validateFoldedState` (ACT-1238) — `bare_patch` by
|
|
2933
|
+
* default, `validating_patch` when the flag is on. The builder uses
|
|
2934
|
+
* the same value for its projection-fold handlers, so there is a
|
|
2935
|
+
* single selection site. Defaults to `bare_patch` for direct
|
|
2936
|
+
* construction.
|
|
2908
2937
|
*/
|
|
2909
|
-
constructor(registry, states = /* @__PURE__ */ new Map(), batch_handlers = /* @__PURE__ */ new Map(), options = {}, lanes = []) {
|
|
2938
|
+
constructor(registry, states = /* @__PURE__ */ new Map(), batch_handlers = /* @__PURE__ */ new Map(), options = {}, lanes = [], patch_fn = bare_patch) {
|
|
2910
2939
|
this.registry = registry;
|
|
2911
2940
|
this._states = states;
|
|
2912
2941
|
this._batch_handlers = batch_handlers;
|
|
@@ -2914,7 +2943,7 @@ var Act = class {
|
|
|
2914
2943
|
validate_only_lanes(options, lanes);
|
|
2915
2944
|
this._scoped = options.scoped ? (fn) => scoped.run(options.scoped, fn) : (fn) => fn();
|
|
2916
2945
|
this._correlator = options.correlator ?? default_correlator;
|
|
2917
|
-
this._es = build_es(this._logger, this._correlator);
|
|
2946
|
+
this._es = build_es(this._logger, this._correlator, patch_fn);
|
|
2918
2947
|
this._cd = build_drain(this._logger);
|
|
2919
2948
|
this._handle = build_handle({
|
|
2920
2949
|
logger: this._logger,
|
|
@@ -4155,6 +4184,7 @@ function act() {
|
|
|
4155
4184
|
},
|
|
4156
4185
|
on: (event) => reaction_on(event, registry.events, builder),
|
|
4157
4186
|
build: (options) => {
|
|
4187
|
+
const patch_fn = options?.validateFoldedState === true ? validating_patch : bare_patch;
|
|
4158
4188
|
if (!_built) {
|
|
4159
4189
|
for (const proj of pending_projections) {
|
|
4160
4190
|
merge_projection(proj, registry.events);
|
|
@@ -4177,7 +4207,7 @@ function act() {
|
|
|
4177
4207
|
);
|
|
4178
4208
|
batch_handlers.set(
|
|
4179
4209
|
proj.target,
|
|
4180
|
-
make_fold_handler(merged, fold.flush, fold.config)
|
|
4210
|
+
make_fold_handler(merged, fold.flush, fold.config, patch_fn)
|
|
4181
4211
|
);
|
|
4182
4212
|
}
|
|
4183
4213
|
finalize_deprecations();
|
|
@@ -4250,7 +4280,8 @@ function act() {
|
|
|
4250
4280
|
states,
|
|
4251
4281
|
batch_handlers,
|
|
4252
4282
|
options,
|
|
4253
|
-
lanes
|
|
4283
|
+
lanes,
|
|
4284
|
+
patch_fn
|
|
4254
4285
|
);
|
|
4255
4286
|
},
|
|
4256
4287
|
events: registry.events
|