@rotorsoft/act 1.35.3 → 1.37.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/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +19 -39
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/in-memory-store.d.ts +0 -4
- 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/autoclose-reaction.d.ts +2 -2
- package/dist/@types/internal/circuit-breaker.d.ts +0 -7
- package/dist/@types/internal/circuit-breaker.d.ts.map +1 -1
- package/dist/@types/internal/correlate-cycle.d.ts +0 -18
- package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
- package/dist/@types/internal/drain-cycle.d.ts +0 -14
- package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
- package/dist/@types/internal/event-sourcing.d.ts +1 -1
- package/dist/@types/internal/settle.d.ts +0 -9
- package/dist/@types/internal/settle.d.ts.map +1 -1
- package/dist/@types/types/action.d.ts +2 -2
- package/dist/@types/types/errors.d.ts +11 -26
- package/dist/@types/types/errors.d.ts.map +1 -1
- package/dist/{chunk-H2QN755D.js → chunk-A3XDAB7T.js} +1 -1
- package/dist/chunk-A3XDAB7T.js.map +1 -0
- package/dist/{chunk-SVVVS6GA.js → chunk-BRJZQ4IY.js} +8 -8
- package/dist/chunk-BRJZQ4IY.js.map +1 -0
- package/dist/{chunk-F2YAA4SE.cjs → chunk-C67XTW3W.cjs} +19 -19
- package/dist/{chunk-F2YAA4SE.cjs.map → chunk-C67XTW3W.cjs.map} +1 -1
- package/dist/{chunk-4KDMNSPJ.cjs → chunk-NXURHBSB.cjs} +1 -1
- package/dist/chunk-NXURHBSB.cjs.map +1 -0
- package/dist/index.cjs +264 -243
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +122 -101
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +4 -4
- package/dist/test/index.js +2 -2
- package/dist/types/index.cjs +2 -2
- package/dist/types/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-4KDMNSPJ.cjs.map +0 -1
- package/dist/chunk-H2QN755D.js.map +0 -1
- package/dist/chunk-SVVVS6GA.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
sleep,
|
|
41
41
|
store,
|
|
42
42
|
validate
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-BRJZQ4IY.js";
|
|
44
44
|
import {
|
|
45
45
|
ActorSchema,
|
|
46
46
|
CausationEventSchema,
|
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
pii_fields,
|
|
72
72
|
pii_schemas,
|
|
73
73
|
sensitive
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-A3XDAB7T.js";
|
|
75
75
|
|
|
76
76
|
// src/signals.ts
|
|
77
77
|
process.once("SIGINT", async (arg) => {
|
|
@@ -709,12 +709,10 @@ var CircuitBreaker = class {
|
|
|
709
709
|
stop() {
|
|
710
710
|
this._clear_wake();
|
|
711
711
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
* keeps the process alive.
|
|
717
|
-
*/
|
|
712
|
+
// Schedule the `on_retry` wake `cooldownMs` out so the breaker re-trials
|
|
713
|
+
// the store on its own. No-op when no `on_retry` hook is wired (e.g. unit
|
|
714
|
+
// tests of the pure state machine). The timer is `unref`'d so it never
|
|
715
|
+
// keeps the process alive.
|
|
718
716
|
_schedule_wake() {
|
|
719
717
|
if (!this._hooks.on_retry) return;
|
|
720
718
|
this._clear_wake();
|
|
@@ -730,7 +728,7 @@ var CircuitBreaker = class {
|
|
|
730
728
|
this._wake = void 0;
|
|
731
729
|
}
|
|
732
730
|
}
|
|
733
|
-
|
|
731
|
+
// Pure state transition for a failure — no side effects.
|
|
734
732
|
_advance(now) {
|
|
735
733
|
if (this._opened_at !== void 0) {
|
|
736
734
|
this._opened_at = now;
|
|
@@ -1157,23 +1155,19 @@ function report_lane_conflict(seen, handler, target, kept, dropped) {
|
|
|
1157
1155
|
}
|
|
1158
1156
|
var CorrelateCycle = class {
|
|
1159
1157
|
_checkpoint = -1;
|
|
1160
|
-
|
|
1158
|
+
// Lease holder id; per instance, so a restart never inherits a stale claim.
|
|
1161
1159
|
_by = randomUUID();
|
|
1162
1160
|
_key;
|
|
1163
|
-
|
|
1161
|
+
// Local expiry of the held lease (0 = none); stale only costs a duplicate scan.
|
|
1164
1162
|
_lease_until = 0;
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
* `_lowered` (the raise count the last short page saw). Starts armed.
|
|
1168
|
-
*/
|
|
1163
|
+
// Armed while `_raised` (bumped by a commit or notification) is ahead of
|
|
1164
|
+
// `_lowered` (the raise count the last short page saw). Starts armed.
|
|
1169
1165
|
_raised = 1;
|
|
1170
1166
|
_lowered = 0;
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
* across one writes nothing.
|
|
1174
|
-
*/
|
|
1167
|
+
// Bumped by a release (shutdown), so a scan or lease reply that was out
|
|
1168
|
+
// across one writes nothing.
|
|
1175
1169
|
_epoch = 0;
|
|
1176
|
-
|
|
1170
|
+
// Passes in flight: a restore waits for them, and refuses new ones.
|
|
1177
1171
|
_passes = /* @__PURE__ */ new Set();
|
|
1178
1172
|
_restoring = false;
|
|
1179
1173
|
_init_promise;
|
|
@@ -1187,7 +1181,7 @@ var CorrelateCycle = class {
|
|
|
1187
1181
|
_cd;
|
|
1188
1182
|
_on_init;
|
|
1189
1183
|
_declared_lanes;
|
|
1190
|
-
|
|
1184
|
+
// Report-once keys; per instance because `internal/` holds no module state.
|
|
1191
1185
|
_reported = /* @__PURE__ */ new Set();
|
|
1192
1186
|
constructor({
|
|
1193
1187
|
registry,
|
|
@@ -1254,7 +1248,7 @@ var CorrelateCycle = class {
|
|
|
1254
1248
|
forget_subscribed(streams) {
|
|
1255
1249
|
for (const stream of streams) this._dynamic_subscriptions.delete(stream);
|
|
1256
1250
|
}
|
|
1257
|
-
|
|
1251
|
+
// Would the target's own `fetch` (filtered by `source`) return this event?
|
|
1258
1252
|
_in_fetch_window(source, stream) {
|
|
1259
1253
|
if (source === void 0 || source === stream) return true;
|
|
1260
1254
|
if (is_literal_source(source)) return false;
|
|
@@ -1413,11 +1407,9 @@ var CorrelateCycle = class {
|
|
|
1413
1407
|
if (!stopped && found !== limit) this._lowered = raised;
|
|
1414
1408
|
return { kind: "scanned", last_id, subscribed: 0, marked: 0, read };
|
|
1415
1409
|
}
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
* Only called with more than one lane declared.
|
|
1420
|
-
*/
|
|
1410
|
+
// Read the row of each target this scan had no record of (new or evicted),
|
|
1411
|
+
// so a resolution that doesn't beat its priority keeps the row's lane.
|
|
1412
|
+
// Only called with more than one lane declared.
|
|
1421
1413
|
async _recall(correlated) {
|
|
1422
1414
|
const missed = [...correlated].filter(([, entry]) => entry.missed);
|
|
1423
1415
|
await Promise.all(
|
|
@@ -2396,21 +2388,17 @@ function merge_drains(drains) {
|
|
|
2396
2388
|
}
|
|
2397
2389
|
var RETRY = "";
|
|
2398
2390
|
var DrainController = class {
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
* during it.
|
|
2403
|
-
*/
|
|
2391
|
+
// Armed while `_raised` is ahead of `_lowered` (the raise count the last
|
|
2392
|
+
// empty claim saw), so a claim never lowers over a raise that landed
|
|
2393
|
+
// during it.
|
|
2404
2394
|
_raised = 0;
|
|
2405
2395
|
_lowered = 0;
|
|
2406
2396
|
_ratio = 0.5;
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
* stays until handled or until a later pass claims nothing.
|
|
2413
|
-
*/
|
|
2397
|
+
// Local wake at the earliest parked (backoff or defer) visit, or at the
|
|
2398
|
+
// lease expiry after a failed pass (the {@link RETRY} key); the schedule
|
|
2399
|
+
// itself is persisted. On an idle app nothing else would drain it. It
|
|
2400
|
+
// drains until a pass leases nothing or the controller stops, and an entry
|
|
2401
|
+
// stays until handled or until a later pass claims nothing.
|
|
2414
2402
|
_defer = new DeferTimer(() => {
|
|
2415
2403
|
this.arm();
|
|
2416
2404
|
void this._deps.run_scoped(async () => {
|
|
@@ -2420,7 +2408,7 @@ var DrainController = class {
|
|
|
2420
2408
|
_worker;
|
|
2421
2409
|
_misrouted = /* @__PURE__ */ new Set();
|
|
2422
2410
|
_stopped = false;
|
|
2423
|
-
|
|
2411
|
+
// The pass in flight. Never rejects; graceful shutdown waits on it.
|
|
2424
2412
|
_inflight;
|
|
2425
2413
|
_deps;
|
|
2426
2414
|
constructor(deps) {
|
|
@@ -2487,7 +2475,7 @@ var DrainController = class {
|
|
|
2487
2475
|
this._inflight = pass;
|
|
2488
2476
|
return pass;
|
|
2489
2477
|
}
|
|
2490
|
-
|
|
2478
|
+
// One claim → fetch → handle → ack pass. Never throws.
|
|
2491
2479
|
async _pass(streamLimit, eventLimit, leaseMillis) {
|
|
2492
2480
|
try {
|
|
2493
2481
|
const lagging = Math.ceil(streamLimit * this._ratio);
|
|
@@ -2848,21 +2836,19 @@ function build_handle_batch(logger) {
|
|
|
2848
2836
|
// src/internal/settle.ts
|
|
2849
2837
|
var SettleLoop = class {
|
|
2850
2838
|
_timer = void 0;
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
* (`stop()` cancels scheduling only). Never rejects.
|
|
2854
|
-
*/
|
|
2839
|
+
// The cycle in flight, set while one runs. Shutdown waits for it
|
|
2840
|
+
// (`stop()` cancels scheduling only). Never rejects.
|
|
2855
2841
|
_inflight;
|
|
2856
|
-
|
|
2842
|
+
// A wake-up arrived while a cycle ran: run one more pass after it.
|
|
2857
2843
|
_pending = false;
|
|
2858
|
-
|
|
2844
|
+
// The last caller's options, used by the next pass.
|
|
2859
2845
|
_next = void 0;
|
|
2860
|
-
|
|
2846
|
+
// When the scheduled pass fires (epoch ms).
|
|
2861
2847
|
_due = 0;
|
|
2862
|
-
|
|
2848
|
+
// Set at shutdown: nothing schedules again.
|
|
2863
2849
|
_stopped = false;
|
|
2864
2850
|
_deps;
|
|
2865
|
-
|
|
2851
|
+
// Debounce window applied when the caller doesn't override via `SettleOptions.debounceMs`.
|
|
2866
2852
|
_default_debounce_ms;
|
|
2867
2853
|
constructor(deps, default_debounce_ms) {
|
|
2868
2854
|
this._deps = deps;
|
|
@@ -2960,18 +2946,16 @@ var Act = class {
|
|
|
2960
2946
|
_breaker;
|
|
2961
2947
|
_drain;
|
|
2962
2948
|
_auto_settle;
|
|
2963
|
-
|
|
2949
|
+
// Whether any event has a reaction; nothing arms without one.
|
|
2964
2950
|
_reactive;
|
|
2965
2951
|
_drain_controllers;
|
|
2966
2952
|
_correlate;
|
|
2967
2953
|
_settle;
|
|
2968
2954
|
_poll;
|
|
2969
|
-
|
|
2955
|
+
// The poll's correlate `limit`, used by every settle pass while it runs.
|
|
2970
2956
|
_poll_limit;
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
* injected after `build()` is never notified.
|
|
2974
|
-
*/
|
|
2957
|
+
// Wired at construction against the store current then, so a store
|
|
2958
|
+
// injected after `build()` is never notified.
|
|
2975
2959
|
_notify_disposer;
|
|
2976
2960
|
/** Public registry — kept as-is per the no-prefix-on-public convention. */
|
|
2977
2961
|
registry;
|
|
@@ -2989,58 +2973,70 @@ var Act = class {
|
|
|
2989
2973
|
* returns "had listeners" to preserve the `EventEmitter.emit` contract.
|
|
2990
2974
|
*/
|
|
2991
2975
|
emit(event, args) {
|
|
2992
|
-
|
|
2976
|
+
return this._notify(event, args);
|
|
2977
|
+
}
|
|
2978
|
+
// Run each listener of `key` on its own, logging any that throws.
|
|
2979
|
+
_notify(key, args) {
|
|
2980
|
+
const listeners = this._emitter.rawListeners(key);
|
|
2993
2981
|
for (const listener of listeners) {
|
|
2994
2982
|
try {
|
|
2995
2983
|
listener(args);
|
|
2996
2984
|
} catch (error) {
|
|
2997
|
-
this._logger.error(error, `${
|
|
2985
|
+
this._logger.error(error, `${key} listener threw`);
|
|
2998
2986
|
}
|
|
2999
2987
|
}
|
|
3000
2988
|
return listeners.length > 0;
|
|
3001
2989
|
}
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
2990
|
+
// The emitter key of one state's `committed` listeners.
|
|
2991
|
+
_committed_key(state2) {
|
|
2992
|
+
const name = typeof state2 === "string" ? state2 : state2.name;
|
|
2993
|
+
if (!this._states.has(name))
|
|
2994
|
+
throw new Error(`committed: "${name}" is not a state of this app`);
|
|
2995
|
+
return `committed:${name}`;
|
|
2996
|
+
}
|
|
2997
|
+
// The one place a store failure is logged and emitted (the breaker's
|
|
2998
|
+
// `on_error`). The emit is guarded: an unhandled `"error"` emission
|
|
2999
|
+
// would crash the process.
|
|
3007
3000
|
_emit_error(error, circuit) {
|
|
3008
3001
|
this._logger.error(error);
|
|
3009
3002
|
if (this._emitter.listenerCount("error") > 0)
|
|
3010
3003
|
this.emit("error", { error, circuit });
|
|
3011
3004
|
}
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3005
|
+
on(event, state_or_listener, listener) {
|
|
3006
|
+
if (listener)
|
|
3007
|
+
this._emitter.on(
|
|
3008
|
+
this._committed_key(state_or_listener),
|
|
3009
|
+
listener
|
|
3010
|
+
);
|
|
3011
|
+
else this._emitter.on(event, state_or_listener);
|
|
3018
3012
|
return this;
|
|
3019
3013
|
}
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3014
|
+
off(event, state_or_listener, listener) {
|
|
3015
|
+
if (listener)
|
|
3016
|
+
this._emitter.off(
|
|
3017
|
+
this._committed_key(state_or_listener),
|
|
3018
|
+
listener
|
|
3019
|
+
);
|
|
3020
|
+
else this._emitter.off(event, state_or_listener);
|
|
3025
3021
|
return this;
|
|
3026
3022
|
}
|
|
3027
3023
|
_batch_handlers;
|
|
3028
3024
|
_es;
|
|
3029
3025
|
_cd;
|
|
3030
|
-
|
|
3026
|
+
// Unambiguous: merge rejects an event name declared by two states.
|
|
3031
3027
|
_event_to_state;
|
|
3032
|
-
|
|
3028
|
+
// Lanes to arm per event; `"all"` when a dynamic resolver hides the lane.
|
|
3033
3029
|
_event_to_lanes;
|
|
3034
3030
|
_audit_deps;
|
|
3035
3031
|
_logger = log();
|
|
3036
|
-
|
|
3032
|
+
// This Act's ports: its own bag, or the singleton adapters.
|
|
3037
3033
|
_ports;
|
|
3038
|
-
|
|
3034
|
+
// Runs a body so internal `store()`/`cache()` calls resolve to `_ports`.
|
|
3039
3035
|
_scoped;
|
|
3040
3036
|
_correlator;
|
|
3041
3037
|
_lanes;
|
|
3042
3038
|
_close_lock = new CloseLock();
|
|
3043
|
-
|
|
3039
|
+
// Every lane a controller can exist for: `"default"` plus each declared one.
|
|
3044
3040
|
_declared_lanes;
|
|
3045
3041
|
/** Drain lanes declared via `.withLane(...)`. Implicit default not included. */
|
|
3046
3042
|
get lanes() {
|
|
@@ -3105,7 +3101,7 @@ var Act = class {
|
|
|
3105
3101
|
);
|
|
3106
3102
|
register_weak_disposer(new WeakRef(this), (self) => self.shutdown());
|
|
3107
3103
|
}
|
|
3108
|
-
|
|
3104
|
+
// Shared by drain, settle and autoclose; bad knobs throw at build.
|
|
3109
3105
|
_build_breaker(options) {
|
|
3110
3106
|
return new CircuitBreaker(
|
|
3111
3107
|
resolveCircuitBreakerConfig(options.circuitBreaker),
|
|
@@ -3117,7 +3113,7 @@ var Act = class {
|
|
|
3117
3113
|
}
|
|
3118
3114
|
);
|
|
3119
3115
|
}
|
|
3120
|
-
|
|
3116
|
+
// Apps that declare no lanes pass no lane filter to `claim`.
|
|
3121
3117
|
_build_drain_controllers(options, lanes, handle, handle_batch) {
|
|
3122
3118
|
const all_lanes = this._declared_lanes;
|
|
3123
3119
|
const only_set = options.onlyLanes?.length ? new Set(options.onlyLanes) : void 0;
|
|
@@ -3163,7 +3159,7 @@ var Act = class {
|
|
|
3163
3159
|
}
|
|
3164
3160
|
return controllers;
|
|
3165
3161
|
}
|
|
3166
|
-
|
|
3162
|
+
// One process can't see the cluster, so it reports its own lane gaps.
|
|
3167
3163
|
_advise_orphaned_lanes() {
|
|
3168
3164
|
const active = new Set(this._drain_controllers.keys());
|
|
3169
3165
|
const orphaned = this._declared_lanes.filter((name) => !active.has(name));
|
|
@@ -3173,7 +3169,7 @@ var Act = class {
|
|
|
3173
3169
|
`Act declared ${orphaned.length} orphaned lane(s) on this instance: ${list}. onlyLanes excludes them, so no DrainController claims their streams here \u2014 their reactions accumulate un-drained unless a peer worker deploys with these lanes in its onlyLanes. Ensure the cluster invariant holds: the union of every worker's onlyLanes must cover every declared lane. See docs/docs/guides/production-checklist.md \xA7 Sizing lanes.`
|
|
3174
3170
|
);
|
|
3175
3171
|
}
|
|
3176
|
-
|
|
3172
|
+
// Audit deps, built after the controllers so the lane set is final.
|
|
3177
3173
|
_build_audit_deps() {
|
|
3178
3174
|
return {
|
|
3179
3175
|
store,
|
|
@@ -3202,7 +3198,7 @@ var Act = class {
|
|
|
3202
3198
|
}
|
|
3203
3199
|
});
|
|
3204
3200
|
}
|
|
3205
|
-
|
|
3201
|
+
// Cold start: an idle deferred stream still fires on time after a restart.
|
|
3206
3202
|
async _seed_persisted_defers() {
|
|
3207
3203
|
const now = Date.now();
|
|
3208
3204
|
await walk_streams(store(), (pos) => {
|
|
@@ -3256,10 +3252,8 @@ var Act = class {
|
|
|
3256
3252
|
}
|
|
3257
3253
|
return this._shutdown_promise;
|
|
3258
3254
|
}
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
* default for none or 0, and for a running settle), capped.
|
|
3262
|
-
*/
|
|
3255
|
+
// The largest `leaseMillis` among lanes with a cycle in flight (the
|
|
3256
|
+
// default for none or 0, and for a running settle), capped.
|
|
3263
3257
|
_derive_grace_ms(running, settling) {
|
|
3264
3258
|
let max = settling ? DEFAULT_LEASE_MILLIS : 0;
|
|
3265
3259
|
for (const c of running)
|
|
@@ -3288,7 +3282,7 @@ var Act = class {
|
|
|
3288
3282
|
clearTimeout(timer);
|
|
3289
3283
|
}
|
|
3290
3284
|
}
|
|
3291
|
-
|
|
3285
|
+
// Failures are logged, never thrown: `notify` is a hint.
|
|
3292
3286
|
async _wire_notify(s, listen) {
|
|
3293
3287
|
if (!this._reactive) return void 0;
|
|
3294
3288
|
if (!s.notify) return void 0;
|
|
@@ -3360,6 +3354,10 @@ var Act = class {
|
|
|
3360
3354
|
if (!snapshots[0].patch) return snapshots;
|
|
3361
3355
|
this._wake(snapshots.map((s) => s.event.name));
|
|
3362
3356
|
this.emit("committed", snapshots);
|
|
3357
|
+
this._notify(
|
|
3358
|
+
`committed:${this.registry.actions[action2].name}`,
|
|
3359
|
+
snapshots
|
|
3360
|
+
);
|
|
3363
3361
|
return snapshots;
|
|
3364
3362
|
});
|
|
3365
3363
|
}
|
|
@@ -3505,28 +3503,26 @@ var Act = class {
|
|
|
3505
3503
|
return { fetched: [], leased: [], acked: [], blocked: [] };
|
|
3506
3504
|
return this._scoped(() => this._drain_all(options));
|
|
3507
3505
|
}
|
|
3508
|
-
|
|
3506
|
+
// Arms correlate and every lane; false on an app with no reactions.
|
|
3509
3507
|
_arm_all() {
|
|
3510
3508
|
if (!this._reactive) return false;
|
|
3511
3509
|
this._correlate.arm();
|
|
3512
3510
|
for (const c of this._drain_controllers.values()) c.arm();
|
|
3513
3511
|
return true;
|
|
3514
3512
|
}
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
* walks the pipeline itself (`autoSettle: false`).
|
|
3520
|
-
*/
|
|
3513
|
+
// Wakes what a change freed (a commit, a reset, an unblock, a restore,
|
|
3514
|
+
// a notification from another process): arms the lanes these events
|
|
3515
|
+
// react on, or every lane without names, and settles them unless the app
|
|
3516
|
+
// walks the pipeline itself (`autoSettle: false`).
|
|
3521
3517
|
_wake(names) {
|
|
3522
3518
|
const armed = names ? this._arm_for_event_names(names) : this._arm_all();
|
|
3523
3519
|
if (armed && this._auto_settle) this._schedule();
|
|
3524
3520
|
}
|
|
3525
|
-
|
|
3521
|
+
// Schedules a settle pass; writer-only instances (`drain: false`) skip it.
|
|
3526
3522
|
_schedule(options) {
|
|
3527
3523
|
if (this._drain) this._settle.schedule(options);
|
|
3528
3524
|
}
|
|
3529
|
-
|
|
3525
|
+
// Arms only the lanes these events react on; true when any was armed.
|
|
3530
3526
|
_arm_for_event_names(names) {
|
|
3531
3527
|
const to_arm = /* @__PURE__ */ new Set();
|
|
3532
3528
|
for (const name of names) {
|
|
@@ -3543,7 +3539,7 @@ var Act = class {
|
|
|
3543
3539
|
for (const lane of to_arm) this._drain_controllers.get(lane)?.arm();
|
|
3544
3540
|
return true;
|
|
3545
3541
|
}
|
|
3546
|
-
|
|
3542
|
+
// In parallel, so a slow lane never holds up a fast one.
|
|
3547
3543
|
async _drain_all(options) {
|
|
3548
3544
|
const merged = merge_drains(
|
|
3549
3545
|
await Promise.all(
|
|
@@ -3585,7 +3581,7 @@ var Act = class {
|
|
|
3585
3581
|
last_id: pass.last_id
|
|
3586
3582
|
};
|
|
3587
3583
|
}
|
|
3588
|
-
|
|
3584
|
+
// One correlate pass; arms every lane when it found work.
|
|
3589
3585
|
async _correlate_pass(limit, lease = false) {
|
|
3590
3586
|
if (!this._drain) return { kind: "idle", last_id: -1 };
|
|
3591
3587
|
return this._scoped(async () => {
|
|
@@ -3873,7 +3869,7 @@ var Act = class {
|
|
|
3873
3869
|
async prioritize(filter, priority) {
|
|
3874
3870
|
return this._scoped(() => store().prioritize(filter, priority));
|
|
3875
3871
|
}
|
|
3876
|
-
|
|
3872
|
+
// Shared by `close()` and reaction-requested closes.
|
|
3877
3873
|
async _run_close(targets) {
|
|
3878
3874
|
const close_actor = { id: "$close", name: "close" };
|
|
3879
3875
|
const result = await run_close_cycle(targets, {
|
|
@@ -4643,6 +4639,24 @@ function act() {
|
|
|
4643
4639
|
const fold_specs = [];
|
|
4644
4640
|
const lanes = [];
|
|
4645
4641
|
let _built = false;
|
|
4642
|
+
const advise_pii_types = () => {
|
|
4643
|
+
const fields = /* @__PURE__ */ new Set();
|
|
4644
|
+
for (const state2 of states.values()) {
|
|
4645
|
+
const shape = state2.state.shape ?? {};
|
|
4646
|
+
for (const [event, schema] of Object.entries(state2.events))
|
|
4647
|
+
for (const [field, field_schema] of Object.entries(
|
|
4648
|
+
pii_schemas(schema)
|
|
4649
|
+
)) {
|
|
4650
|
+
if (!reads_as_string(field_schema)) fields.add(`${event}.${field}`);
|
|
4651
|
+
if (shape[field] && !reads_as_string(shape[field]))
|
|
4652
|
+
fields.add(`${state2.name}.${field}`);
|
|
4653
|
+
}
|
|
4654
|
+
}
|
|
4655
|
+
if (fields.size > 0)
|
|
4656
|
+
log().warn(
|
|
4657
|
+
`Act has ${fields.size} sensitive field(s) whose type isn't a string: ${[...fields].join(", ")}. A caller who may not see one reads "[REDACTED]" or "[SHREDDED]" there instead, which its type doesn't allow. Declare sensitive fields as strings. See docs/docs/guides/sensitive-data.md.`
|
|
4658
|
+
);
|
|
4659
|
+
};
|
|
4646
4660
|
const read_wrap = (original) => {
|
|
4647
4661
|
const wrapped = async (events, stream) => {
|
|
4648
4662
|
const read = events.map((e) => _hr.get(e.name)?.(e) ?? e);
|
|
@@ -4781,6 +4795,7 @@ function act() {
|
|
|
4781
4795
|
for (const [name, gate] of built.query_readers) _qg.set(name, gate);
|
|
4782
4796
|
for (const [name, gate] of built.handler_readers) _hr.set(name, gate);
|
|
4783
4797
|
finalize_deprecations();
|
|
4798
|
+
advise_pii_types();
|
|
4784
4799
|
for (const state2 of states.values()) {
|
|
4785
4800
|
if (state2.disclose) _dp.set(state2.name, state2.disclose);
|
|
4786
4801
|
if (state2.autoclose) _ac.set(state2.name, state2.autoclose);
|
|
@@ -4811,6 +4826,12 @@ function act() {
|
|
|
4811
4826
|
};
|
|
4812
4827
|
return builder;
|
|
4813
4828
|
}
|
|
4829
|
+
function reads_as_string(schema) {
|
|
4830
|
+
const def = schema._zod.def;
|
|
4831
|
+
if (def.type === "string" || def.type === "transform") return true;
|
|
4832
|
+
if (def.out) return reads_as_string(def.out);
|
|
4833
|
+
return def.innerType ? reads_as_string(def.innerType) : false;
|
|
4834
|
+
}
|
|
4814
4835
|
|
|
4815
4836
|
// src/builders/projection-builder.ts
|
|
4816
4837
|
function _projection(target) {
|