@rotorsoft/act 1.31.13 → 1.31.15
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 +2 -0
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/builders/event-builder.d.ts +11 -4
- package/dist/@types/builders/event-builder.d.ts.map +1 -1
- package/dist/@types/internal/circuit-breaker.d.ts +7 -0
- package/dist/@types/internal/circuit-breaker.d.ts.map +1 -1
- package/dist/@types/internal/date-reviver.d.ts +50 -0
- package/dist/@types/internal/date-reviver.d.ts.map +1 -0
- package/dist/@types/internal/drain-cycle.d.ts +3 -1
- package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
- package/dist/@types/internal/index.d.ts +1 -0
- package/dist/@types/internal/index.d.ts.map +1 -1
- package/dist/@types/internal/sensitive.d.ts +22 -4
- package/dist/@types/internal/sensitive.d.ts.map +1 -1
- package/dist/@types/ports.d.ts +19 -0
- package/dist/@types/ports.d.ts.map +1 -1
- package/dist/@types/scoped.d.ts +17 -5
- package/dist/@types/scoped.d.ts.map +1 -1
- package/dist/{chunk-D5MBFIKL.js → chunk-7IBF4FTQ.js} +16 -11
- package/dist/{chunk-D5MBFIKL.js.map → chunk-7IBF4FTQ.js.map} +1 -1
- package/dist/{chunk-IO2OOCOR.js → chunk-T2AT4N6B.js} +13 -3
- package/dist/{chunk-IO2OOCOR.js.map → chunk-T2AT4N6B.js.map} +1 -1
- package/dist/index.cjs +156 -85
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +133 -76
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.js +2 -2
- package/dist/types/index.cjs +14 -9
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.js +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
config,
|
|
13
13
|
current_reacting,
|
|
14
14
|
dateReviver,
|
|
15
|
+
default_scope,
|
|
15
16
|
dispose,
|
|
16
17
|
disposeAndExit,
|
|
17
18
|
extend,
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
sleep,
|
|
25
26
|
store,
|
|
26
27
|
validate
|
|
27
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-T2AT4N6B.js";
|
|
28
29
|
import {
|
|
29
30
|
ActorSchema,
|
|
30
31
|
CausationEventSchema,
|
|
@@ -45,13 +46,13 @@ import {
|
|
|
45
46
|
TargetSchema,
|
|
46
47
|
ValidationError,
|
|
47
48
|
ZodEmpty,
|
|
48
|
-
is_pii,
|
|
49
49
|
make_gate,
|
|
50
50
|
pii_fields,
|
|
51
|
+
pii_schemas,
|
|
51
52
|
pii_split,
|
|
52
53
|
pii_strip,
|
|
53
54
|
sensitive
|
|
54
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-7IBF4FTQ.js";
|
|
55
56
|
|
|
56
57
|
// src/signals.ts
|
|
57
58
|
process.once("SIGINT", async (arg) => {
|
|
@@ -916,6 +917,15 @@ var CircuitBreaker = class {
|
|
|
916
917
|
this._cooldown_ms = config2.cooldownMs;
|
|
917
918
|
this._hooks = hooks;
|
|
918
919
|
}
|
|
920
|
+
/**
|
|
921
|
+
* True when the store has failed at least once since the last pass that
|
|
922
|
+
* went all the way through. The breaker can still read "closed" here: it
|
|
923
|
+
* only opens after several failures in a row, so this catches the first
|
|
924
|
+
* one, which `state()` cannot.
|
|
925
|
+
*/
|
|
926
|
+
get failing() {
|
|
927
|
+
return this._failures > 0;
|
|
928
|
+
}
|
|
919
929
|
/** Current state given the wall-clock `now`. */
|
|
920
930
|
state(now) {
|
|
921
931
|
if (this._opened_at === void 0) return "closed";
|
|
@@ -1869,18 +1879,83 @@ function close_correlation(correlator, actor) {
|
|
|
1869
1879
|
});
|
|
1870
1880
|
}
|
|
1871
1881
|
|
|
1872
|
-
// src/internal/
|
|
1882
|
+
// src/internal/date-reviver.ts
|
|
1873
1883
|
import { z as z3 } from "zod";
|
|
1874
|
-
var
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1884
|
+
var def_of = (schema) => schema._zod?.def ?? schema.def;
|
|
1885
|
+
function variant_schema(schema) {
|
|
1886
|
+
const shape = def_of(schema)?.shape;
|
|
1887
|
+
if (!shape) {
|
|
1888
|
+
const dates = date_reviver_schema(schema);
|
|
1889
|
+
return { schema: dates ?? schema, dated: !!dates };
|
|
1890
|
+
}
|
|
1891
|
+
const next = {};
|
|
1892
|
+
let dated = false;
|
|
1893
|
+
for (const [key, field] of Object.entries(shape)) {
|
|
1894
|
+
const dates = date_reviver_schema(field);
|
|
1895
|
+
if (dates) dated = true;
|
|
1896
|
+
next[key] = (dates ?? field).optional();
|
|
1897
|
+
}
|
|
1898
|
+
return { schema: z3.looseObject(next), dated };
|
|
1899
|
+
}
|
|
1900
|
+
function date_reviver_schema(schema) {
|
|
1901
|
+
const def = def_of(schema);
|
|
1902
|
+
if (!def) return void 0;
|
|
1903
|
+
const inner = () => date_reviver_schema(def.innerType);
|
|
1904
|
+
switch (def.type) {
|
|
1905
|
+
case "date":
|
|
1906
|
+
return z3.coerce.date();
|
|
1907
|
+
case "object": {
|
|
1908
|
+
const shape = def.shape;
|
|
1909
|
+
if (!shape) return void 0;
|
|
1910
|
+
const dated = {};
|
|
1911
|
+
for (const [key, field] of Object.entries(shape)) {
|
|
1912
|
+
const dates = date_reviver_schema(field);
|
|
1913
|
+
if (dates) dated[key] = dates.optional();
|
|
1914
|
+
}
|
|
1915
|
+
return Object.keys(dated).length ? z3.looseObject(dated) : void 0;
|
|
1916
|
+
}
|
|
1917
|
+
case "array": {
|
|
1918
|
+
const element = date_reviver_schema(def.element);
|
|
1919
|
+
return element && z3.array(element);
|
|
1920
|
+
}
|
|
1921
|
+
case "tuple": {
|
|
1922
|
+
const items = def.items.map((i) => date_reviver_schema(i));
|
|
1923
|
+
return items.some(Boolean) ? z3.tuple(items.map((i) => i ?? z3.unknown())) : void 0;
|
|
1924
|
+
}
|
|
1925
|
+
case "record": {
|
|
1926
|
+
const value = date_reviver_schema(def.valueType);
|
|
1927
|
+
return value && z3.record(z3.string(), value);
|
|
1928
|
+
}
|
|
1929
|
+
case "union": {
|
|
1930
|
+
const variants = def.options.map(variant_schema);
|
|
1931
|
+
return variants.some((v) => v.dated) ? z3.union(variants.map((v) => v.schema)) : void 0;
|
|
1932
|
+
}
|
|
1933
|
+
case "nullable":
|
|
1934
|
+
return inner()?.nullable();
|
|
1935
|
+
case "optional":
|
|
1936
|
+
case "nonoptional":
|
|
1937
|
+
case "readonly":
|
|
1938
|
+
case "default":
|
|
1939
|
+
case "prefault":
|
|
1940
|
+
case "catch":
|
|
1941
|
+
return inner();
|
|
1942
|
+
default:
|
|
1943
|
+
return void 0;
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
// src/internal/defer-config.ts
|
|
1948
|
+
import { z as z4 } from "zod";
|
|
1949
|
+
var DeferDurationSchema = z4.object({
|
|
1950
|
+
days: z4.number().positive().optional(),
|
|
1951
|
+
hours: z4.number().positive().optional(),
|
|
1952
|
+
minutes: z4.number().positive().optional()
|
|
1878
1953
|
}).strict().refine((d) => d.days != null || d.hours != null || d.minutes != null, {
|
|
1879
1954
|
message: "defer: a duration needs at least one of days, hours, or minutes"
|
|
1880
1955
|
});
|
|
1881
|
-
var DeferWhenSchema =
|
|
1956
|
+
var DeferWhenSchema = z4.object({
|
|
1882
1957
|
after: DeferDurationSchema.optional(),
|
|
1883
|
-
at:
|
|
1958
|
+
at: z4.date().optional()
|
|
1884
1959
|
}).strict().refine((w) => w.after === void 0 !== (w.at === void 0), {
|
|
1885
1960
|
message: "defer: specify exactly one of `after` or `at`"
|
|
1886
1961
|
});
|
|
@@ -2623,10 +2698,10 @@ function trace_cycle(logger, leased, fetched, handled, acked, blocked) {
|
|
|
2623
2698
|
}
|
|
2624
2699
|
|
|
2625
2700
|
// src/internal/drain-cycle.ts
|
|
2626
|
-
function budget_exhausted(lease, options) {
|
|
2627
|
-
if (!options?.blockOnError || lease.retry <= options.maxRetries)
|
|
2701
|
+
function budget_exhausted(lease, options, store_failing) {
|
|
2702
|
+
if (store_failing || !options?.blockOnError || lease.retry <= options.maxRetries)
|
|
2628
2703
|
return void 0;
|
|
2629
|
-
const error = `Blocking ${lease.stream} after ${lease.retry} claims with no acknowledged progress \u2014 the
|
|
2704
|
+
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: raise leaseMillis for this handler, then unblock the stream.`;
|
|
2630
2705
|
log().error(error);
|
|
2631
2706
|
return { lease, handled: 0, acked_at: lease.at, error, block: true };
|
|
2632
2707
|
}
|
|
@@ -2637,7 +2712,7 @@ function warn_misrouted(seen, stream, handler, event) {
|
|
|
2637
2712
|
`Reaction "${handler}" on "${event}" resolved to target "${stream}", which a projection already serves. A target is served by one batch handler or one state projection, so this reaction can never run \u2014 and delivering to it would hand the projection an aggregate from another stream. Skipping it. The equivalent static \`.to({ target })\` is rejected at build; a dynamic resolver's target is only knowable here.`
|
|
2638
2713
|
);
|
|
2639
2714
|
}
|
|
2640
|
-
async function run_drain_cycle(ops, registry, batch_handlers, misrouted, handle, handle_batch, lagging, leading, eventLimit, leaseMillis, on_blocked, lane) {
|
|
2715
|
+
async function run_drain_cycle(ops, registry, batch_handlers, misrouted, store_failing, handle, handle_batch, lagging, leading, eventLimit, leaseMillis, on_blocked, lane) {
|
|
2641
2716
|
const leased = await ops.claim(
|
|
2642
2717
|
lagging,
|
|
2643
2718
|
leading,
|
|
@@ -2679,7 +2754,11 @@ async function run_drain_cycle(ops, registry, batch_handlers, misrouted, handle,
|
|
|
2679
2754
|
const entry = fetch_map.get(lease.stream);
|
|
2680
2755
|
const at = entry.fetch.events.at(-1)?.id || fetch_window_at;
|
|
2681
2756
|
const { payloads } = entry;
|
|
2682
|
-
const exhausted = budget_exhausted(
|
|
2757
|
+
const exhausted = budget_exhausted(
|
|
2758
|
+
lease,
|
|
2759
|
+
payloads[0]?.options,
|
|
2760
|
+
store_failing
|
|
2761
|
+
);
|
|
2683
2762
|
if (exhausted) return Promise.resolve(exhausted);
|
|
2684
2763
|
const batchHandler = batch_handlers.get(lease.stream);
|
|
2685
2764
|
if (batchHandler && payloads.length > 0) {
|
|
@@ -2851,6 +2930,7 @@ var DrainController = class {
|
|
|
2851
2930
|
this._deps.registry,
|
|
2852
2931
|
this._deps.batch_handlers,
|
|
2853
2932
|
this._misrouted,
|
|
2933
|
+
this._deps.breaker.failing,
|
|
2854
2934
|
this._deps.handle,
|
|
2855
2935
|
this._deps.handle_batch,
|
|
2856
2936
|
lagging,
|
|
@@ -3357,6 +3437,8 @@ var Act = class {
|
|
|
3357
3437
|
* per-Act ports (ACT-501). No-op when the Act is unscoped — so the singleton
|
|
3358
3438
|
* path keeps reading fresh `store()`/`cache()` per call, which matters for
|
|
3359
3439
|
* tests that dispose and re-seed mid-suite. */
|
|
3440
|
+
/** This Act's ports: its own bag, or the singleton adapters. */
|
|
3441
|
+
_ports;
|
|
3360
3442
|
_scoped;
|
|
3361
3443
|
/**
|
|
3362
3444
|
* Correlation-id generator for originating actions. Bound at
|
|
@@ -3435,7 +3517,8 @@ var Act = class {
|
|
|
3435
3517
|
this._batch_handlers = batch_handlers;
|
|
3436
3518
|
this._lanes = lanes;
|
|
3437
3519
|
validate_only_lanes(options, lanes);
|
|
3438
|
-
this.
|
|
3520
|
+
this._ports = options.scoped ?? default_scope();
|
|
3521
|
+
this._scoped = make_run_scoped(this._ports);
|
|
3439
3522
|
this._correlator = options.correlator ?? default_correlator;
|
|
3440
3523
|
this._es = build_es(this._logger, this._correlator, patch_fn);
|
|
3441
3524
|
this._cd = build_drain(this._logger);
|
|
@@ -3464,7 +3547,7 @@ var Act = class {
|
|
|
3464
3547
|
this._audit_deps = this._build_audit_deps();
|
|
3465
3548
|
this._correlate = this._build_correlate(options, classification);
|
|
3466
3549
|
this._settle = this._build_settle(options);
|
|
3467
|
-
this._notify_disposer = this._wire_notify(
|
|
3550
|
+
this._notify_disposer = this._wire_notify(this._ports.store);
|
|
3468
3551
|
register_weak_disposer(new WeakRef(this), (self) => self.shutdown());
|
|
3469
3552
|
}
|
|
3470
3553
|
/**
|
|
@@ -3713,13 +3796,13 @@ var Act = class {
|
|
|
3713
3796
|
this._shutdown_promise = (async () => {
|
|
3714
3797
|
this.stop_correlations();
|
|
3715
3798
|
await this._scoped(() => this._correlate.release_correlation());
|
|
3799
|
+
const disposer = await this._notify_disposer;
|
|
3800
|
+
if (disposer) await disposer();
|
|
3716
3801
|
this.stop_settling();
|
|
3717
3802
|
this._breaker.stop();
|
|
3718
3803
|
for (const c of this._drain_controllers.values()) c.stop();
|
|
3719
3804
|
await this._await_inflight(options?.graceMs);
|
|
3720
3805
|
this._emitter.removeAllListeners();
|
|
3721
|
-
const disposer = await this._notify_disposer;
|
|
3722
|
-
if (disposer) await disposer();
|
|
3723
3806
|
})();
|
|
3724
3807
|
}
|
|
3725
3808
|
return this._shutdown_promise;
|
|
@@ -4913,70 +4996,43 @@ function reaction_on(event, events, builder) {
|
|
|
4913
4996
|
}
|
|
4914
4997
|
|
|
4915
4998
|
// src/builders/event-builder.ts
|
|
4916
|
-
import { z as
|
|
4917
|
-
var def_of = (schema) => schema._zod?.def ?? schema.def;
|
|
4918
|
-
function to_read_schema(schema, found) {
|
|
4919
|
-
const def = def_of(schema);
|
|
4920
|
-
if (!def) return schema;
|
|
4921
|
-
switch (def.type) {
|
|
4922
|
-
case "date":
|
|
4923
|
-
found.date = true;
|
|
4924
|
-
return z4.coerce.date();
|
|
4925
|
-
case "object": {
|
|
4926
|
-
const shape = def.shape;
|
|
4927
|
-
if (!shape) return schema;
|
|
4928
|
-
const next = {};
|
|
4929
|
-
for (const [key, inner] of Object.entries(shape))
|
|
4930
|
-
next[key] = to_read_schema(inner, found);
|
|
4931
|
-
return z4.looseObject(next);
|
|
4932
|
-
}
|
|
4933
|
-
case "array":
|
|
4934
|
-
return z4.array(to_read_schema(def.element, found));
|
|
4935
|
-
case "record":
|
|
4936
|
-
return z4.record(
|
|
4937
|
-
z4.string(),
|
|
4938
|
-
to_read_schema(def.valueType, found)
|
|
4939
|
-
);
|
|
4940
|
-
case "union":
|
|
4941
|
-
return z4.union(
|
|
4942
|
-
def.options.map(
|
|
4943
|
-
(o) => to_read_schema(o, found)
|
|
4944
|
-
)
|
|
4945
|
-
);
|
|
4946
|
-
case "optional":
|
|
4947
|
-
return to_read_schema(def.innerType, found).optional();
|
|
4948
|
-
case "nullable":
|
|
4949
|
-
return to_read_schema(def.innerType, found).nullable();
|
|
4950
|
-
default:
|
|
4951
|
-
return schema;
|
|
4952
|
-
}
|
|
4953
|
-
}
|
|
4999
|
+
import { z as z5 } from "zod";
|
|
4954
5000
|
function event_tags(schema) {
|
|
4955
|
-
const
|
|
4956
|
-
const
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
const
|
|
4964
|
-
|
|
5001
|
+
const pii = pii_schemas(schema);
|
|
5002
|
+
const pii_dates = {};
|
|
5003
|
+
for (const [key, field] of Object.entries(pii)) {
|
|
5004
|
+
const dates = date_reviver_schema(field);
|
|
5005
|
+
if (dates) pii_dates[key] = dates.optional();
|
|
5006
|
+
}
|
|
5007
|
+
const data_reviver_schema = date_reviver_schema(schema);
|
|
5008
|
+
const revive = (schema2) => (data) => {
|
|
5009
|
+
const revived = schema2.safeParse(data);
|
|
5010
|
+
return revived.success ? revived.data : data;
|
|
4965
5011
|
};
|
|
4966
|
-
|
|
4967
|
-
const found = { date: false };
|
|
4968
|
-
const read_schema = to_read_schema(schema, found);
|
|
5012
|
+
const dated_pii = Object.keys(pii_dates).length > 0;
|
|
4969
5013
|
return {
|
|
4970
|
-
sensitive:
|
|
4971
|
-
|
|
5014
|
+
sensitive: Object.keys(pii),
|
|
5015
|
+
date_reviver: data_reviver_schema && revive(data_reviver_schema),
|
|
5016
|
+
pii_date_reviver: dated_pii ? revive(z5.looseObject(pii_dates)) : void 0
|
|
4972
5017
|
};
|
|
4973
5018
|
}
|
|
4974
5019
|
function make_event_reader(tags, disclosure, predicate = null) {
|
|
4975
|
-
const { sensitive: sensitive2,
|
|
4976
|
-
if (!
|
|
5020
|
+
const { sensitive: sensitive2, date_reviver, pii_date_reviver } = tags;
|
|
5021
|
+
if (!date_reviver && sensitive2.length === 0) return void 0;
|
|
4977
5022
|
const gate = sensitive2.length === 0 ? IDENTITY_GATE : disclosure === "strip" ? ((event) => pii_strip(event, sensitive2)) : make_gate(sensitive2, predicate);
|
|
4978
|
-
if (!
|
|
4979
|
-
|
|
5023
|
+
if (!date_reviver) return gate;
|
|
5024
|
+
const revive_pii = disclosure === "redact" && predicate ? pii_date_reviver : void 0;
|
|
5025
|
+
return ((event, actor) => {
|
|
5026
|
+
const pii = event.pii;
|
|
5027
|
+
return gate(
|
|
5028
|
+
{
|
|
5029
|
+
...event,
|
|
5030
|
+
data: date_reviver(event.data),
|
|
5031
|
+
...revive_pii && actor && pii != null ? { pii: revive_pii(pii) } : {}
|
|
5032
|
+
},
|
|
5033
|
+
actor
|
|
5034
|
+
);
|
|
5035
|
+
});
|
|
4980
5036
|
}
|
|
4981
5037
|
function build_events(registry, states, lanes, owners) {
|
|
4982
5038
|
const declared = /* @__PURE__ */ new Set([DEFAULT_LANE, ...lanes.map((l) => l.name)]);
|
|
@@ -5762,6 +5818,7 @@ export {
|
|
|
5762
5818
|
cache,
|
|
5763
5819
|
config,
|
|
5764
5820
|
dateReviver,
|
|
5821
|
+
default_scope,
|
|
5765
5822
|
dispose,
|
|
5766
5823
|
disposeAndExit,
|
|
5767
5824
|
extend,
|