@rotorsoft/act 1.17.0 → 1.18.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/index.cjs CHANGED
@@ -43,6 +43,7 @@ __export(index_exports, {
43
43
  DEFAULT_LANE: () => DEFAULT_LANE,
44
44
  DEFAULT_MAX_SUBSCRIBED_STREAMS: () => DEFAULT_MAX_SUBSCRIBED_STREAMS,
45
45
  DEFAULT_SETTLE_DEBOUNCE_MS: () => DEFAULT_SETTLE_DEBOUNCE_MS,
46
+ DeferSignal: () => DeferSignal,
46
47
  Environments: () => Environments,
47
48
  Errors: () => Errors,
48
49
  EventMetaSchema: () => EventMetaSchema,
@@ -2130,13 +2131,258 @@ function classify_registry(registry, states) {
2130
2131
  };
2131
2132
  }
2132
2133
 
2133
- // src/internal/circuit-breaker.ts
2134
+ // src/internal/defer-config.ts
2134
2135
  var import_zod7 = require("zod");
2136
+
2137
+ // src/internal/defer-signal.ts
2138
+ var DeferSignal = class extends Error {
2139
+ /**
2140
+ * The unresolved schedule. The dispatcher turns this into an absolute
2141
+ * due-time by resolving it against the triggering event.
2142
+ */
2143
+ when;
2144
+ constructor(when) {
2145
+ super("reaction deferred");
2146
+ this.name = "DeferSignal";
2147
+ this.when = when;
2148
+ }
2149
+ };
2150
+
2151
+ // src/internal/defer-config.ts
2152
+ var DeferDurationSchema = import_zod7.z.object({
2153
+ days: import_zod7.z.number().positive().optional(),
2154
+ hours: import_zod7.z.number().positive().optional(),
2155
+ minutes: import_zod7.z.number().positive().optional()
2156
+ }).strict().refine((d) => d.days != null || d.hours != null || d.minutes != null, {
2157
+ message: "defer: a duration needs at least one of days, hours, or minutes"
2158
+ });
2159
+ var DeferWhenSchema = import_zod7.z.object({
2160
+ after: DeferDurationSchema.optional(),
2161
+ at: import_zod7.z.date().optional()
2162
+ }).strict().refine((w) => w.after === void 0 !== (w.at === void 0), {
2163
+ message: "defer: specify exactly one of `after` or `at`"
2164
+ });
2165
+ function duration_ms(d) {
2166
+ return (d.days ?? 0) * 864e5 + (d.hours ?? 0) * 36e5 + (d.minutes ?? 0) * 6e4;
2167
+ }
2168
+ function resolve_defer_at(when, event) {
2169
+ const parsed = DeferWhenSchema.parse(when);
2170
+ if (parsed.after) return event.created.getTime() + duration_ms(parsed.after);
2171
+ return parsed.at.getTime();
2172
+ }
2173
+ function assert_defer_when(when) {
2174
+ DeferWhenSchema.parse(when);
2175
+ }
2176
+ function make_deferred(handler, schedule) {
2177
+ const call = handler;
2178
+ const deferred = async (event, stream, app) => {
2179
+ const when = typeof schedule === "function" ? schedule(event) : schedule;
2180
+ if (Date.now() < resolve_defer_at(when, event)) throw new DeferSignal(when);
2181
+ return call(event, stream, app);
2182
+ };
2183
+ Object.defineProperty(deferred, "name", { value: handler.name });
2184
+ return deferred;
2185
+ }
2186
+
2187
+ // src/internal/merge.ts
2188
+ var import_zod8 = require("zod");
2189
+ function base_type_name(zodType) {
2190
+ let t = zodType;
2191
+ while (typeof t.unwrap === "function") {
2192
+ t = t.unwrap();
2193
+ }
2194
+ return t.constructor.name;
2195
+ }
2196
+ function merge_schemas(existing, incoming, state_name) {
2197
+ if (existing instanceof import_zod8.ZodObject && incoming instanceof import_zod8.ZodObject) {
2198
+ const existing_shape = existing.shape;
2199
+ const incoming_shape = incoming.shape;
2200
+ for (const key of Object.keys(incoming_shape)) {
2201
+ if (key in existing_shape) {
2202
+ const existing_base = base_type_name(existing_shape[key]);
2203
+ const incoming_base = base_type_name(incoming_shape[key]);
2204
+ if (existing_base !== incoming_base) {
2205
+ throw new Error(
2206
+ `Schema conflict in "${state_name}": key "${key}" has type "${existing_base}" but incoming partial declares "${incoming_base}"`
2207
+ );
2208
+ }
2209
+ }
2210
+ }
2211
+ return existing.extend(incoming_shape);
2212
+ }
2213
+ return existing;
2214
+ }
2215
+ function merge_inits(existing, incoming) {
2216
+ return () => ({ ...existing(), ...incoming() });
2217
+ }
2218
+ function register_state(state2, states, actions, events) {
2219
+ const existing = states.get(state2.name);
2220
+ if (existing) {
2221
+ merge_into_existing(state2, existing, states, actions, events);
2222
+ } else {
2223
+ register_new_state(state2, states, actions, events);
2224
+ }
2225
+ }
2226
+ function register_new_state(state2, states, actions, events) {
2227
+ states.set(state2.name, state2);
2228
+ for (const name of Object.keys(state2.actions)) {
2229
+ if (actions[name]) throw new Error(`Duplicate action "${name}"`);
2230
+ actions[name] = state2;
2231
+ }
2232
+ for (const name of Object.keys(state2.events)) {
2233
+ if (events[name]) throw new Error(`Duplicate event "${name}"`);
2234
+ events[name] = { schema: state2.events[name], reactions: /* @__PURE__ */ new Map() };
2235
+ }
2236
+ }
2237
+ function merge_into_existing(state2, existing, states, actions, events) {
2238
+ for (const name of Object.keys(state2.actions)) {
2239
+ if (existing.actions[name] === state2.actions[name]) continue;
2240
+ if (actions[name]) throw new Error(`Duplicate action "${name}"`);
2241
+ }
2242
+ for (const name of Object.keys(state2.events)) {
2243
+ if (existing.events[name] === state2.events[name]) continue;
2244
+ if (existing.events[name]) {
2245
+ throw new Error(
2246
+ `Event "${name}" in state "${state2.name}" is declared with different Zod schemas across slices. Cross-slice event schemas must reference the same instance \u2014 extract a shared schema (e.g. \`export const ${name} = z.object({ ... })\` in a shared module) and import it in every slice that declares it.`
2247
+ );
2248
+ }
2249
+ if (events[name]) throw new Error(`Duplicate event "${name}"`);
2250
+ }
2251
+ const merged_patch = merge_patches(existing.patch, state2.patch, state2.name);
2252
+ const merged = {
2253
+ ...existing,
2254
+ state: merge_schemas(existing.state, state2.state, state2.name),
2255
+ init: merge_inits(existing.init, state2.init),
2256
+ events: { ...existing.events, ...state2.events },
2257
+ actions: { ...existing.actions, ...state2.actions },
2258
+ patch: merged_patch,
2259
+ on: { ...existing.on, ...state2.on },
2260
+ given: { ...existing.given, ...state2.given },
2261
+ snap: state2.snap && existing.snap && state2.snap !== existing.snap ? (() => {
2262
+ throw new Error(
2263
+ `Duplicate snap strategy for state "${state2.name}"`
2264
+ );
2265
+ })() : state2.snap || existing.snap
2266
+ };
2267
+ states.set(state2.name, merged);
2268
+ for (const name of Object.keys(merged.actions)) {
2269
+ actions[name] = merged;
2270
+ }
2271
+ for (const name of Object.keys(state2.events)) {
2272
+ if (events[name]) continue;
2273
+ events[name] = { schema: state2.events[name], reactions: /* @__PURE__ */ new Map() };
2274
+ }
2275
+ }
2276
+ function merge_patches(existing, incoming, state_name) {
2277
+ const merged = { ...existing };
2278
+ for (const name of Object.keys(incoming)) {
2279
+ const existing_p = existing[name];
2280
+ const incoming_p = incoming[name];
2281
+ if (!existing_p) {
2282
+ merged[name] = incoming_p;
2283
+ continue;
2284
+ }
2285
+ const existing_is_default = existing_p._passthrough;
2286
+ const incoming_is_default = incoming_p._passthrough;
2287
+ if (!existing_is_default && !incoming_is_default && existing_p !== incoming_p) {
2288
+ throw new Error(
2289
+ `Duplicate custom patch for event "${name}" in state "${state_name}"`
2290
+ );
2291
+ }
2292
+ if (existing_is_default && !incoming_is_default) {
2293
+ merged[name] = incoming_p;
2294
+ }
2295
+ }
2296
+ return merged;
2297
+ }
2298
+ function merge_event_register(target, source) {
2299
+ for (const [event_name, source_reg] of Object.entries(source)) {
2300
+ const target_reg = target[event_name];
2301
+ if (!target_reg) continue;
2302
+ for (const [name, reaction] of source_reg.reactions) {
2303
+ const existing = target_reg.reactions.get(name);
2304
+ if (existing !== void 0 && existing !== reaction)
2305
+ throw new Error(
2306
+ `Duplicate reaction "${name}" for event "${event_name}". Reaction handlers are keyed by function name; rename one of them.`
2307
+ );
2308
+ target_reg.reactions.set(name, reaction);
2309
+ }
2310
+ }
2311
+ }
2312
+ function merge_projection(proj, events) {
2313
+ for (const event_name of Object.keys(proj.events)) {
2314
+ const proj_register = proj.events[event_name];
2315
+ const existing = events[event_name];
2316
+ if (!existing) {
2317
+ events[event_name] = {
2318
+ schema: proj_register.schema,
2319
+ reactions: new Map(proj_register.reactions)
2320
+ };
2321
+ } else {
2322
+ for (const [name, reaction] of proj_register.reactions) {
2323
+ let key = name;
2324
+ while (existing.reactions.has(key)) key = `${key}_p`;
2325
+ existing.reactions.set(key, reaction);
2326
+ }
2327
+ }
2328
+ }
2329
+ }
2330
+ var _this_ = ({ stream }) => ({
2331
+ source: stream,
2332
+ target: stream
2333
+ });
2334
+
2335
+ // src/internal/builder-utils.ts
2336
+ function register_lane(config2, lanes) {
2337
+ if (config2.name === DEFAULT_LANE)
2338
+ throw new Error(`Lane "${DEFAULT_LANE}" is reserved`);
2339
+ if (lanes.some((l) => l.name === config2.name))
2340
+ throw new Error(`Lane "${config2.name}" was already declared`);
2341
+ lanes.push(config2);
2342
+ }
2343
+ function reaction_on(event, events, builder) {
2344
+ const register = (handler, options, schedule) => {
2345
+ if (!handler.name)
2346
+ throw new Error(
2347
+ `Reaction handler for "${String(event)}" must be a named function`
2348
+ );
2349
+ if (events[event].reactions.has(handler.name))
2350
+ throw new Error(
2351
+ `Duplicate reaction "${handler.name}" for event "${String(event)}". Reaction handlers are keyed by function name; rename one of them.`
2352
+ );
2353
+ if (schedule && typeof schedule !== "function") assert_defer_when(schedule);
2354
+ const reaction = {
2355
+ handler: schedule ? make_deferred(handler, schedule) : handler,
2356
+ resolver: _this_,
2357
+ options: {
2358
+ blockOnError: options?.blockOnError ?? true,
2359
+ maxRetries: options?.maxRetries ?? 3,
2360
+ backoff: options?.backoff
2361
+ }
2362
+ };
2363
+ events[event].reactions.set(handler.name, reaction);
2364
+ return Object.assign(builder, {
2365
+ to(resolver) {
2366
+ reaction.resolver = typeof resolver === "string" ? { target: resolver } : resolver;
2367
+ return builder;
2368
+ }
2369
+ });
2370
+ };
2371
+ return {
2372
+ do: (handler, options) => register(handler, options),
2373
+ defer: (schedule) => ({
2374
+ do: (handler, options) => register(handler, options, schedule)
2375
+ })
2376
+ };
2377
+ }
2378
+
2379
+ // src/internal/circuit-breaker.ts
2380
+ var import_zod9 = require("zod");
2135
2381
  var DEFAULT_CIRCUIT_FAILURE_THRESHOLD = 5;
2136
2382
  var DEFAULT_CIRCUIT_COOLDOWN_MS = 3e4;
2137
- var CircuitBreakerOptionsSchema = import_zod7.z.object({
2138
- failureThreshold: import_zod7.z.number().int().min(1).default(DEFAULT_CIRCUIT_FAILURE_THRESHOLD),
2139
- cooldownMs: import_zod7.z.number().int().min(100).max(36e5).default(DEFAULT_CIRCUIT_COOLDOWN_MS)
2383
+ var CircuitBreakerOptionsSchema = import_zod9.z.object({
2384
+ failureThreshold: import_zod9.z.number().int().min(1).default(DEFAULT_CIRCUIT_FAILURE_THRESHOLD),
2385
+ cooldownMs: import_zod9.z.number().int().min(100).max(36e5).default(DEFAULT_CIRCUIT_COOLDOWN_MS)
2140
2386
  });
2141
2387
  var resolveCircuitBreakerConfig = (options) => CircuitBreakerOptionsSchema.parse(options ?? {});
2142
2388
  var CircuitBreaker = class {
@@ -2566,17 +2812,6 @@ function close_correlation(correlator, actor) {
2566
2812
  });
2567
2813
  }
2568
2814
 
2569
- // src/internal/defer-signal.ts
2570
- var DeferSignal = class extends Error {
2571
- /** Wall-clock time (ms since epoch) to re-visit the stream. */
2572
- defer_at;
2573
- constructor(defer_at) {
2574
- super("reaction deferred");
2575
- this.name = "DeferSignal";
2576
- this.defer_at = defer_at;
2577
- }
2578
- };
2579
-
2580
2815
  // src/internal/drain-cycle.ts
2581
2816
  var import_node_crypto2 = require("crypto");
2582
2817
 
@@ -3423,154 +3658,6 @@ var DrainController = class {
3423
3658
  }
3424
3659
  };
3425
3660
 
3426
- // src/internal/merge.ts
3427
- var import_zod8 = require("zod");
3428
- function base_type_name(zodType) {
3429
- let t = zodType;
3430
- while (typeof t.unwrap === "function") {
3431
- t = t.unwrap();
3432
- }
3433
- return t.constructor.name;
3434
- }
3435
- function merge_schemas(existing, incoming, state_name) {
3436
- if (existing instanceof import_zod8.ZodObject && incoming instanceof import_zod8.ZodObject) {
3437
- const existing_shape = existing.shape;
3438
- const incoming_shape = incoming.shape;
3439
- for (const key of Object.keys(incoming_shape)) {
3440
- if (key in existing_shape) {
3441
- const existing_base = base_type_name(existing_shape[key]);
3442
- const incoming_base = base_type_name(incoming_shape[key]);
3443
- if (existing_base !== incoming_base) {
3444
- throw new Error(
3445
- `Schema conflict in "${state_name}": key "${key}" has type "${existing_base}" but incoming partial declares "${incoming_base}"`
3446
- );
3447
- }
3448
- }
3449
- }
3450
- return existing.extend(incoming_shape);
3451
- }
3452
- return existing;
3453
- }
3454
- function merge_inits(existing, incoming) {
3455
- return () => ({ ...existing(), ...incoming() });
3456
- }
3457
- function register_state(state2, states, actions, events) {
3458
- const existing = states.get(state2.name);
3459
- if (existing) {
3460
- merge_into_existing(state2, existing, states, actions, events);
3461
- } else {
3462
- register_new_state(state2, states, actions, events);
3463
- }
3464
- }
3465
- function register_new_state(state2, states, actions, events) {
3466
- states.set(state2.name, state2);
3467
- for (const name of Object.keys(state2.actions)) {
3468
- if (actions[name]) throw new Error(`Duplicate action "${name}"`);
3469
- actions[name] = state2;
3470
- }
3471
- for (const name of Object.keys(state2.events)) {
3472
- if (events[name]) throw new Error(`Duplicate event "${name}"`);
3473
- events[name] = { schema: state2.events[name], reactions: /* @__PURE__ */ new Map() };
3474
- }
3475
- }
3476
- function merge_into_existing(state2, existing, states, actions, events) {
3477
- for (const name of Object.keys(state2.actions)) {
3478
- if (existing.actions[name] === state2.actions[name]) continue;
3479
- if (actions[name]) throw new Error(`Duplicate action "${name}"`);
3480
- }
3481
- for (const name of Object.keys(state2.events)) {
3482
- if (existing.events[name] === state2.events[name]) continue;
3483
- if (existing.events[name]) {
3484
- throw new Error(
3485
- `Event "${name}" in state "${state2.name}" is declared with different Zod schemas across slices. Cross-slice event schemas must reference the same instance \u2014 extract a shared schema (e.g. \`export const ${name} = z.object({ ... })\` in a shared module) and import it in every slice that declares it.`
3486
- );
3487
- }
3488
- if (events[name]) throw new Error(`Duplicate event "${name}"`);
3489
- }
3490
- const merged_patch = merge_patches(existing.patch, state2.patch, state2.name);
3491
- const merged = {
3492
- ...existing,
3493
- state: merge_schemas(existing.state, state2.state, state2.name),
3494
- init: merge_inits(existing.init, state2.init),
3495
- events: { ...existing.events, ...state2.events },
3496
- actions: { ...existing.actions, ...state2.actions },
3497
- patch: merged_patch,
3498
- on: { ...existing.on, ...state2.on },
3499
- given: { ...existing.given, ...state2.given },
3500
- snap: state2.snap && existing.snap && state2.snap !== existing.snap ? (() => {
3501
- throw new Error(
3502
- `Duplicate snap strategy for state "${state2.name}"`
3503
- );
3504
- })() : state2.snap || existing.snap
3505
- };
3506
- states.set(state2.name, merged);
3507
- for (const name of Object.keys(merged.actions)) {
3508
- actions[name] = merged;
3509
- }
3510
- for (const name of Object.keys(state2.events)) {
3511
- if (events[name]) continue;
3512
- events[name] = { schema: state2.events[name], reactions: /* @__PURE__ */ new Map() };
3513
- }
3514
- }
3515
- function merge_patches(existing, incoming, state_name) {
3516
- const merged = { ...existing };
3517
- for (const name of Object.keys(incoming)) {
3518
- const existing_p = existing[name];
3519
- const incoming_p = incoming[name];
3520
- if (!existing_p) {
3521
- merged[name] = incoming_p;
3522
- continue;
3523
- }
3524
- const existing_is_default = existing_p._passthrough;
3525
- const incoming_is_default = incoming_p._passthrough;
3526
- if (!existing_is_default && !incoming_is_default && existing_p !== incoming_p) {
3527
- throw new Error(
3528
- `Duplicate custom patch for event "${name}" in state "${state_name}"`
3529
- );
3530
- }
3531
- if (existing_is_default && !incoming_is_default) {
3532
- merged[name] = incoming_p;
3533
- }
3534
- }
3535
- return merged;
3536
- }
3537
- function merge_event_register(target, source) {
3538
- for (const [event_name, source_reg] of Object.entries(source)) {
3539
- const target_reg = target[event_name];
3540
- if (!target_reg) continue;
3541
- for (const [name, reaction] of source_reg.reactions) {
3542
- const existing = target_reg.reactions.get(name);
3543
- if (existing !== void 0 && existing !== reaction)
3544
- throw new Error(
3545
- `Duplicate reaction "${name}" for event "${event_name}". Reaction handlers are keyed by function name; rename one of them.`
3546
- );
3547
- target_reg.reactions.set(name, reaction);
3548
- }
3549
- }
3550
- }
3551
- function merge_projection(proj, events) {
3552
- for (const event_name of Object.keys(proj.events)) {
3553
- const proj_register = proj.events[event_name];
3554
- const existing = events[event_name];
3555
- if (!existing) {
3556
- events[event_name] = {
3557
- schema: proj_register.schema,
3558
- reactions: new Map(proj_register.reactions)
3559
- };
3560
- } else {
3561
- for (const [name, reaction] of proj_register.reactions) {
3562
- let key = name;
3563
- while (existing.reactions.has(key)) key = `${key}_p`;
3564
- existing.reactions.set(key, reaction);
3565
- }
3566
- }
3567
- }
3568
- }
3569
- var _this_ = ({ stream }) => ({
3570
- source: stream,
3571
- target: stream
3572
- });
3573
-
3574
3661
  // src/internal/reactions.ts
3575
3662
  function finalize(lease, handled, at, error, options, logger, failed_at) {
3576
3663
  if (!error) return { lease, handled, acked_at: at };
@@ -3627,7 +3714,12 @@ function build_handle(deps) {
3627
3714
  handled++;
3628
3715
  } catch (error) {
3629
3716
  if (error instanceof DeferSignal)
3630
- return { lease, handled, acked_at: at, defer: error.defer_at };
3717
+ return {
3718
+ lease,
3719
+ handled,
3720
+ acked_at: at,
3721
+ defer: resolve_defer_at(error.when, event)
3722
+ };
3631
3723
  if (error instanceof CloseSignal)
3632
3724
  return {
3633
3725
  lease,
@@ -3947,9 +4039,9 @@ var Act = class {
3947
4039
  const aggregate = event.stream;
3948
4040
  const config2 = this._autoclose_config;
3949
4041
  if (!in_autoclose_window(config2.autocloseWindow, /* @__PURE__ */ new Date()))
3950
- throw new DeferSignal(
3951
- Date.now() + config2.autocloseCycleMinutes * 6e4
3952
- );
4042
+ throw new DeferSignal({
4043
+ at: new Date(Date.now() + config2.autocloseCycleMinutes * 6e4)
4044
+ });
3953
4045
  const stats = await store2().query_stats([aggregate], {
3954
4046
  count: true,
3955
4047
  exclude: [TOMBSTONE_EVENT]
@@ -3967,7 +4059,9 @@ var Act = class {
3967
4059
  at: head.id
3968
4060
  });
3969
4061
  if (after_ms !== void 0)
3970
- throw new DeferSignal(head.created.getTime() + after_ms);
4062
+ throw new DeferSignal({
4063
+ at: new Date(head.created.getTime() + after_ms)
4064
+ });
3971
4065
  }
3972
4066
  };
3973
4067
  const key = `__autoclose_${st.name}`;
@@ -5068,41 +5162,10 @@ function act() {
5068
5162
  },
5069
5163
  withActor: () => builder,
5070
5164
  withLane: (config2) => {
5071
- if (config2.name === DEFAULT_LANE)
5072
- throw new Error(`Lane "${DEFAULT_LANE}" is reserved`);
5073
- if (lanes.some((l) => l.name === config2.name))
5074
- throw new Error(`Lane "${config2.name}" was already declared`);
5075
- lanes.push(config2);
5165
+ register_lane(config2, lanes);
5076
5166
  return builder;
5077
5167
  },
5078
- on: (event) => ({
5079
- do: (handler, options) => {
5080
- const reaction = {
5081
- handler,
5082
- resolver: _this_,
5083
- options: {
5084
- blockOnError: options?.blockOnError ?? true,
5085
- maxRetries: options?.maxRetries ?? 3,
5086
- backoff: options?.backoff
5087
- }
5088
- };
5089
- if (!handler.name)
5090
- throw new Error(
5091
- `Reaction handler for "${String(event)}" must be a named function`
5092
- );
5093
- if (registry.events[event].reactions.has(handler.name))
5094
- throw new Error(
5095
- `Duplicate reaction "${handler.name}" for event "${String(event)}". Reaction handlers are keyed by function name; rename one of them.`
5096
- );
5097
- registry.events[event].reactions.set(handler.name, reaction);
5098
- return Object.assign(builder, {
5099
- to(resolver) {
5100
- reaction.resolver = typeof resolver === "string" ? { target: resolver } : resolver;
5101
- return builder;
5102
- }
5103
- });
5104
- }
5105
- }),
5168
+ on: (event) => reaction_on(event, registry.events, builder),
5106
5169
  build: (options) => {
5107
5170
  if (!_built) {
5108
5171
  for (const proj of pending_projections) {
@@ -5267,41 +5330,10 @@ function slice() {
5267
5330
  return builder;
5268
5331
  },
5269
5332
  withLane: (config2) => {
5270
- if (config2.name === DEFAULT_LANE)
5271
- throw new Error(`Lane "${DEFAULT_LANE}" is reserved`);
5272
- if (lanes.some((l) => l.name === config2.name))
5273
- throw new Error(`Lane "${config2.name}" was already declared`);
5274
- lanes.push(config2);
5333
+ register_lane(config2, lanes);
5275
5334
  return builder;
5276
5335
  },
5277
- on: (event) => ({
5278
- do: (handler, options) => {
5279
- const reaction = {
5280
- handler,
5281
- resolver: _this_,
5282
- options: {
5283
- blockOnError: options?.blockOnError ?? true,
5284
- maxRetries: options?.maxRetries ?? 3,
5285
- backoff: options?.backoff
5286
- }
5287
- };
5288
- if (!handler.name)
5289
- throw new Error(
5290
- `Reaction handler for "${String(event)}" must be a named function`
5291
- );
5292
- if (events[event].reactions.has(handler.name))
5293
- throw new Error(
5294
- `Duplicate reaction "${handler.name}" for event "${String(event)}". Reaction handlers are keyed by function name; rename one of them.`
5295
- );
5296
- events[event].reactions.set(handler.name, reaction);
5297
- return Object.assign(builder, {
5298
- to(resolver) {
5299
- reaction.resolver = typeof resolver === "string" ? { target: resolver } : resolver;
5300
- return builder;
5301
- }
5302
- });
5303
- }
5304
- }),
5336
+ on: (event) => reaction_on(event, events, builder),
5305
5337
  build: () => ({
5306
5338
  _tag: "Slice",
5307
5339
  states,
@@ -5612,6 +5644,7 @@ function write_line(writer, line) {
5612
5644
  DEFAULT_LANE,
5613
5645
  DEFAULT_MAX_SUBSCRIBED_STREAMS,
5614
5646
  DEFAULT_SETTLE_DEBOUNCE_MS,
5647
+ DeferSignal,
5615
5648
  Environments,
5616
5649
  Errors,
5617
5650
  EventMetaSchema,