@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.
Files changed (33) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/@types/act.d.ts +2 -0
  3. package/dist/@types/act.d.ts.map +1 -1
  4. package/dist/@types/builders/event-builder.d.ts +11 -4
  5. package/dist/@types/builders/event-builder.d.ts.map +1 -1
  6. package/dist/@types/internal/circuit-breaker.d.ts +7 -0
  7. package/dist/@types/internal/circuit-breaker.d.ts.map +1 -1
  8. package/dist/@types/internal/date-reviver.d.ts +50 -0
  9. package/dist/@types/internal/date-reviver.d.ts.map +1 -0
  10. package/dist/@types/internal/drain-cycle.d.ts +3 -1
  11. package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
  12. package/dist/@types/internal/index.d.ts +1 -0
  13. package/dist/@types/internal/index.d.ts.map +1 -1
  14. package/dist/@types/internal/sensitive.d.ts +22 -4
  15. package/dist/@types/internal/sensitive.d.ts.map +1 -1
  16. package/dist/@types/ports.d.ts +19 -0
  17. package/dist/@types/ports.d.ts.map +1 -1
  18. package/dist/@types/scoped.d.ts +17 -5
  19. package/dist/@types/scoped.d.ts.map +1 -1
  20. package/dist/{chunk-D5MBFIKL.js → chunk-7IBF4FTQ.js} +16 -11
  21. package/dist/{chunk-D5MBFIKL.js.map → chunk-7IBF4FTQ.js.map} +1 -1
  22. package/dist/{chunk-IO2OOCOR.js → chunk-T2AT4N6B.js} +13 -3
  23. package/dist/{chunk-IO2OOCOR.js.map → chunk-T2AT4N6B.js.map} +1 -1
  24. package/dist/index.cjs +156 -85
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.js +133 -76
  27. package/dist/index.js.map +1 -1
  28. package/dist/test/index.cjs.map +1 -1
  29. package/dist/test/index.js +2 -2
  30. package/dist/types/index.cjs +14 -9
  31. package/dist/types/index.cjs.map +1 -1
  32. package/dist/types/index.js +1 -1
  33. 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-IO2OOCOR.js";
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-D5MBFIKL.js";
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/defer-config.ts
1882
+ // src/internal/date-reviver.ts
1873
1883
  import { z as z3 } from "zod";
1874
- var DeferDurationSchema = z3.object({
1875
- days: z3.number().positive().optional(),
1876
- hours: z3.number().positive().optional(),
1877
- minutes: z3.number().positive().optional()
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 = z3.object({
1956
+ var DeferWhenSchema = z4.object({
1882
1957
  after: DeferDurationSchema.optional(),
1883
- at: z3.date().optional()
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 lease was lost on every attempt, so the retry budget (${options.maxRetries}) was spent without the handler ever reporting an error. Raise leaseMillis for this handler, then unblock the stream.`;
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(lease, payloads[0]?.options);
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._scoped = make_run_scoped(options.scoped);
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(options.scoped?.store ?? store());
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 z4 } from "zod";
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 sensitive2 = [];
4956
- const collect = (node) => {
4957
- const shape = def_of(node)?.shape;
4958
- if (shape) {
4959
- for (const key of Object.keys(shape))
4960
- if (is_pii(shape[key])) sensitive2.push(key);
4961
- return;
4962
- }
4963
- const options = node.options;
4964
- if (Array.isArray(options)) for (const option of options) collect(option);
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
- collect(schema);
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: [...new Set(sensitive2)],
4971
- parse: found.date ? (data) => read_schema.parse(data) : void 0
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, parse: parse2 } = tags;
4976
- if (!parse2 && sensitive2.length === 0) return void 0;
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 (!parse2) return gate;
4979
- return ((event, actor) => gate({ ...event, data: parse2(event.data) }, actor));
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,