@rotorsoft/act 1.23.5 → 1.23.7

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 (35) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/@types/act.d.ts.map +1 -1
  3. package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
  4. package/dist/@types/builders/act-builder.d.ts.map +1 -1
  5. package/dist/@types/builders/state-builder.d.ts.map +1 -1
  6. package/dist/@types/internal/autoclose-reaction.d.ts +1 -1
  7. package/dist/@types/internal/autoclose-reaction.d.ts.map +1 -1
  8. package/dist/@types/internal/autoclose-window.d.ts +66 -0
  9. package/dist/@types/internal/autoclose-window.d.ts.map +1 -0
  10. package/dist/@types/internal/backoff.d.ts.map +1 -1
  11. package/dist/@types/internal/builder-utils.d.ts.map +1 -1
  12. package/dist/@types/internal/circuit-breaker.d.ts +1 -19
  13. package/dist/@types/internal/circuit-breaker.d.ts.map +1 -1
  14. package/dist/@types/internal/config.d.ts +139 -0
  15. package/dist/@types/internal/config.d.ts.map +1 -0
  16. package/dist/@types/internal/event-sourcing.d.ts.map +1 -1
  17. package/dist/@types/internal/index.d.ts +4 -3
  18. package/dist/@types/internal/index.d.ts.map +1 -1
  19. package/dist/@types/internal/projection-fold.d.ts +2 -11
  20. package/dist/@types/internal/projection-fold.d.ts.map +1 -1
  21. package/dist/@types/types/action.d.ts +14 -3
  22. package/dist/@types/types/action.d.ts.map +1 -1
  23. package/dist/{chunk-DORIRU2I.js → chunk-C7H3GARW.js} +14 -11
  24. package/dist/chunk-C7H3GARW.js.map +1 -0
  25. package/dist/index.cjs +200 -118
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.js +188 -109
  28. package/dist/index.js.map +1 -1
  29. package/dist/test/index.cjs +13 -10
  30. package/dist/test/index.cjs.map +1 -1
  31. package/dist/test/index.js +1 -1
  32. package/package.json +2 -2
  33. package/dist/@types/internal/autoclose-config.d.ts +0 -142
  34. package/dist/@types/internal/autoclose-config.d.ts.map +0 -1
  35. package/dist/chunk-DORIRU2I.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -907,7 +907,18 @@ var InMemoryStore = class {
907
907
  async query(callback, query) {
908
908
  await sleep();
909
909
  let count = 0;
910
+ let floor_index = -1;
911
+ if (query?.with_snaps && query.stream_exact && query.stream !== void 0 && query.after === void 0) {
912
+ for (let j = this._events.length - 1; j >= 0; j--) {
913
+ const e = this._events[j];
914
+ if (e.stream === query.stream && e.name === SNAP_EVENT) {
915
+ floor_index = j;
916
+ break;
917
+ }
918
+ }
919
+ }
910
920
  if (query?.backward) {
921
+ const floor_id = floor_index >= 0 ? this._events[floor_index].id : -1;
911
922
  let i = (query?.before !== void 0 ? this._first_index_after(query.before - 1) : this._events.length) - 1;
912
923
  while (i >= 0) {
913
924
  const e = this._events[i--];
@@ -915,6 +926,7 @@ var InMemoryStore = class {
915
926
  if (query?.created_before && e.created >= query.created_before)
916
927
  continue;
917
928
  if (query.after !== void 0 && e.id <= query.after) break;
929
+ if (floor_id >= 0 && e.id < floor_id) break;
918
930
  if (query.created_after && e.created <= query.created_after) continue;
919
931
  await Promise.resolve(
920
932
  callback(this._with_pii(e))
@@ -923,16 +935,7 @@ var InMemoryStore = class {
923
935
  if (query?.limit && count >= query.limit) break;
924
936
  }
925
937
  } else {
926
- let i = this._first_index_after(query?.after ?? -1);
927
- if (query?.with_snaps && query.stream_exact && query.stream !== void 0 && query.after === void 0 && query.created_before === void 0 && query.created_after === void 0) {
928
- for (let j = this._events.length - 1; j >= 0; j--) {
929
- const e = this._events[j];
930
- if (e.stream === query.stream && e.name === SNAP_EVENT) {
931
- i = j;
932
- break;
933
- }
934
- }
935
- }
938
+ let i = floor_index >= 0 ? floor_index : this._first_index_after(query?.after ?? -1);
936
939
  while (i < this._events.length) {
937
940
  const e = this._events[i++];
938
941
  if (query && !this.in_query(query, e)) continue;
@@ -2041,84 +2044,8 @@ var PASS_FACTORIES = {
2041
2044
  "clock-anomalies": make_clock_anomalies_pass
2042
2045
  };
2043
2046
 
2044
- // src/internal/autoclose-config.ts
2045
- var import_zod5 = require("zod");
2046
- var DEFAULT_AUTOCLOSE_CYCLE_MINUTES = 720;
2047
- var DEFAULT_CLOSE_BATCH_SIZE = 64;
2048
- var DEFAULT_CLOSE_YIELD_MS = 0;
2049
- var DEFAULT_AUTOCLOSE_WINDOW_TZ = "UTC";
2050
- function is_valid_time_zone(tz) {
2051
- try {
2052
- new Intl.DateTimeFormat("en-US", { timeZone: tz });
2053
- return true;
2054
- } catch {
2055
- return false;
2056
- }
2057
- }
2058
- var AutocloseWindowSchema = import_zod5.z.object({
2059
- start: import_zod5.z.number().int().min(0).max(23, { message: "autocloseWindow.start must be an hour in [0, 23]" }),
2060
- end: import_zod5.z.number().int().min(0).max(23, { message: "autocloseWindow.end must be an hour in [0, 23]" }),
2061
- timeZone: import_zod5.z.string().refine(is_valid_time_zone, {
2062
- message: "autocloseWindow.timeZone must be a valid IANA time zone"
2063
- }).default(DEFAULT_AUTOCLOSE_WINDOW_TZ)
2064
- }).refine((w) => w.start !== w.end, {
2065
- message: "autocloseWindow.start and end must differ \u2014 an empty window disables autoclose"
2066
- });
2067
- var AutocloseOptionsSchema = import_zod5.z.object({
2068
- autocloseCycleMinutes: import_zod5.z.number().int().min(1).max(1440).default(DEFAULT_AUTOCLOSE_CYCLE_MINUTES),
2069
- closeBatchSize: import_zod5.z.number().int().min(1).max(1024).default(DEFAULT_CLOSE_BATCH_SIZE),
2070
- closeYieldMs: import_zod5.z.number().min(0).max(1e3).default(DEFAULT_CLOSE_YIELD_MS),
2071
- closeOnError: import_zod5.z.boolean().default(false),
2072
- autocloseWindow: AutocloseWindowSchema.optional()
2073
- });
2074
- function resolveAutocloseConfig(options) {
2075
- return AutocloseOptionsSchema.parse({
2076
- autocloseCycleMinutes: options?.autocloseCycleMinutes,
2077
- closeBatchSize: options?.closeBatchSize,
2078
- closeYieldMs: options?.closeYieldMs,
2079
- closeOnError: options?.closeOnError,
2080
- autocloseWindow: options?.autocloseWindow
2081
- });
2082
- }
2083
- function hour_in_zone(now, timeZone) {
2084
- const parts = new Intl.DateTimeFormat("en-US", {
2085
- timeZone,
2086
- hour: "2-digit",
2087
- hourCycle: "h23"
2088
- }).formatToParts(now);
2089
- return Number(parts.find((p) => p.type === "hour")?.value);
2090
- }
2091
- function hour_in_range(hour, start, end) {
2092
- return start < end ? hour >= start && hour < end : hour >= start || hour < end;
2093
- }
2094
- function is_dst_gap_open(now, timeZone, start) {
2095
- const hour = hour_in_zone(now, timeZone);
2096
- if (hour <= start) return false;
2097
- const prev = hour_in_zone(new Date(now.getTime() - 36e5), timeZone);
2098
- return prev === start - 1 && hour === start + 1;
2099
- }
2100
- function in_autoclose_window(window, now) {
2101
- if (!window) return true;
2102
- const hour = hour_in_zone(now, window.timeZone);
2103
- return hour_in_range(hour, window.start, window.end) || is_dst_gap_open(now, window.timeZone, window.start);
2104
- }
2105
- function next_window_open(window, now) {
2106
- const start_ms = now.getTime();
2107
- for (let h = 0; h <= 48; h++) {
2108
- const candidate = new Date(start_ms + h * 36e5);
2109
- if (hour_in_zone(candidate, window.timeZone) === window.start)
2110
- return candidate;
2111
- const boundary = new Date(
2112
- candidate.getTime() - candidate.getTime() % 36e5
2113
- );
2114
- if (is_dst_gap_open(boundary, window.timeZone, window.start))
2115
- return boundary;
2116
- }
2117
- return new Date(start_ms + 864e5);
2118
- }
2119
-
2120
2047
  // src/internal/autoclose-policy.ts
2121
- var import_zod6 = require("zod");
2048
+ var import_zod5 = require("zod");
2122
2049
  var DAY_MS = 864e5;
2123
2050
  var MIN_AFTER_DAYS = 1 / 1440;
2124
2051
  var MIN_KEEP_DAYS = 1;
@@ -2128,21 +2055,21 @@ function days_after(date, days) {
2128
2055
  function days_before_now(days) {
2129
2056
  return new Date(Date.now() - days * DAY_MS);
2130
2057
  }
2131
- var window_schema = (field, min_days, floor) => import_zod6.z.object({
2132
- days: import_zod6.z.number({ message: `autocloses: ${field}.days must be a number` }).positive(`autocloses: ${field}.days must be > 0`)
2058
+ var window_schema = (field, min_days, floor) => import_zod5.z.object({
2059
+ days: import_zod5.z.number({ message: `autocloses: ${field}.days must be a number` }).positive(`autocloses: ${field}.days must be > 0`)
2133
2060
  }).refine((o) => o.days >= min_days, {
2134
2061
  message: `autocloses: ${field} resolves to < ${floor}, which is too short to be a meaningful retention window`
2135
2062
  });
2136
2063
  var AfterSchema = window_schema("after", MIN_AFTER_DAYS, "one minute");
2137
2064
  var KeepSchema = window_schema("keep", MIN_KEEP_DAYS, "one day");
2138
- var IsSchema = import_zod6.z.union([
2139
- import_zod6.z.string().min(1, "autocloses: is must be a non-empty event name"),
2140
- import_zod6.z.array(
2141
- import_zod6.z.string().min(1, "autocloses: is entries must be non-empty event names")
2065
+ var IsSchema = import_zod5.z.union([
2066
+ import_zod5.z.string().min(1, "autocloses: is must be a non-empty event name"),
2067
+ import_zod5.z.array(
2068
+ import_zod5.z.string().min(1, "autocloses: is entries must be non-empty event names")
2142
2069
  ).min(1, "autocloses: is must include at least one event name").readonly()
2143
2070
  ]);
2144
- var ReachesSchema = import_zod6.z.number({ message: "autocloses: reaches must be a number" }).int("autocloses: reaches must be an integer").min(1, "autocloses: reaches must be >= 1");
2145
- var OrBlockSchema = import_zod6.z.object({
2071
+ var ReachesSchema = import_zod5.z.number({ message: "autocloses: reaches must be a number" }).int("autocloses: reaches must be an integer").min(1, "autocloses: reaches must be >= 1");
2072
+ var OrBlockSchema = import_zod5.z.object({
2146
2073
  after: AfterSchema.optional(),
2147
2074
  is: IsSchema.optional(),
2148
2075
  reaches: ReachesSchema.optional()
@@ -2152,7 +2079,7 @@ var OrBlockSchema = import_zod6.z.object({
2152
2079
  message: "autocloses: `or` block must include at least one of after / is / reaches"
2153
2080
  }
2154
2081
  );
2155
- var AutoclosePolicySchema = import_zod6.z.object({
2082
+ var AutoclosePolicySchema = import_zod5.z.object({
2156
2083
  after: AfterSchema.optional(),
2157
2084
  is: IsSchema.optional(),
2158
2085
  reaches: ReachesSchema.optional(),
@@ -2208,6 +2135,44 @@ function compile_autoclose_policy(options) {
2208
2135
  };
2209
2136
  }
2210
2137
 
2138
+ // src/internal/autoclose-window.ts
2139
+ function hour_in_zone(now, timeZone) {
2140
+ const parts = new Intl.DateTimeFormat("en-US", {
2141
+ timeZone,
2142
+ hour: "2-digit",
2143
+ hourCycle: "h23"
2144
+ }).formatToParts(now);
2145
+ return Number(parts.find((p) => p.type === "hour")?.value);
2146
+ }
2147
+ function hour_in_range(hour, start, end) {
2148
+ return start < end ? hour >= start && hour < end : hour >= start || hour < end;
2149
+ }
2150
+ function is_dst_gap_open(now, timeZone, start) {
2151
+ const hour = hour_in_zone(now, timeZone);
2152
+ if (hour <= start) return false;
2153
+ const prev = hour_in_zone(new Date(now.getTime() - 36e5), timeZone);
2154
+ return prev === start - 1 && hour === start + 1;
2155
+ }
2156
+ function in_autoclose_window(window, now) {
2157
+ if (!window) return true;
2158
+ const hour = hour_in_zone(now, window.timeZone);
2159
+ return hour_in_range(hour, window.start, window.end) || is_dst_gap_open(now, window.timeZone, window.start);
2160
+ }
2161
+ function next_window_open(window, now) {
2162
+ const start_ms = now.getTime();
2163
+ for (let h = 0; h <= 48; h++) {
2164
+ const candidate = new Date(start_ms + h * 36e5);
2165
+ if (hour_in_zone(candidate, window.timeZone) === window.start)
2166
+ return candidate;
2167
+ const boundary = new Date(
2168
+ candidate.getTime() - candidate.getTime() % 36e5
2169
+ );
2170
+ if (is_dst_gap_open(boundary, window.timeZone, window.start))
2171
+ return boundary;
2172
+ }
2173
+ return new Date(start_ms + 864e5);
2174
+ }
2175
+
2211
2176
  // src/internal/close-signal.ts
2212
2177
  var CloseSignal = class extends Error {
2213
2178
  /**
@@ -2388,6 +2353,123 @@ function classify_registry(registry, states) {
2388
2353
  };
2389
2354
  }
2390
2355
 
2356
+ // src/internal/config.ts
2357
+ var import_zod6 = require("zod");
2358
+ var BackoffOptionsSchema = import_zod6.z.object({
2359
+ strategy: import_zod6.z.enum(["fixed", "linear", "exponential"]),
2360
+ baseMs: import_zod6.z.number().min(0),
2361
+ maxMs: import_zod6.z.number().gt(0).optional(),
2362
+ jitter: import_zod6.z.boolean().optional()
2363
+ });
2364
+ var ReactionOptionsSchema = import_zod6.z.object({
2365
+ blockOnError: import_zod6.z.boolean(),
2366
+ maxRetries: import_zod6.z.number().int().min(0),
2367
+ backoff: BackoffOptionsSchema.optional()
2368
+ });
2369
+ function resolveReactionConfig(options) {
2370
+ return ReactionOptionsSchema.parse(options);
2371
+ }
2372
+ var ActionOptionsSchema = import_zod6.z.object({
2373
+ maxRetries: import_zod6.z.number().int().min(0).optional(),
2374
+ backoff: BackoffOptionsSchema.optional()
2375
+ });
2376
+ function resolveActionConfig(options) {
2377
+ return ActionOptionsSchema.parse(options);
2378
+ }
2379
+ var LaneConfigSchema = import_zod6.z.object({
2380
+ name: import_zod6.z.string().min(1),
2381
+ leaseMillis: import_zod6.z.number().min(0).optional(),
2382
+ streamLimit: import_zod6.z.number().int().min(0).optional(),
2383
+ cycleMs: import_zod6.z.number().min(0).optional()
2384
+ });
2385
+ function resolveLaneConfig(options) {
2386
+ LaneConfigSchema.parse(options);
2387
+ return options;
2388
+ }
2389
+ var DrainOptionsSchema = import_zod6.z.object({
2390
+ streamLimit: import_zod6.z.number().int().min(0).optional(),
2391
+ eventLimit: import_zod6.z.number().int().min(0).optional(),
2392
+ leaseMillis: import_zod6.z.number().min(0).optional()
2393
+ });
2394
+ function resolveDrainConfig(options) {
2395
+ if (options === void 0) return void 0;
2396
+ DrainOptionsSchema.parse(options);
2397
+ return options;
2398
+ }
2399
+ var SettleOptionsSchema = DrainOptionsSchema.extend({
2400
+ debounceMs: import_zod6.z.number().min(0).optional(),
2401
+ // `maxPasses` defaults to Infinity (no cap) when omitted; a present value is
2402
+ // a non-negative integer — `0` is legal and means "run no passes".
2403
+ maxPasses: import_zod6.z.number().int().min(0).optional()
2404
+ }).loose();
2405
+ function resolveSettleConfig(options) {
2406
+ if (options === void 0) return void 0;
2407
+ SettleOptionsSchema.parse(options);
2408
+ return options;
2409
+ }
2410
+ var ActOptionsSchema = import_zod6.z.object({
2411
+ maxSubscribedStreams: import_zod6.z.number().int().min(1).optional(),
2412
+ settleDebounceMs: import_zod6.z.number().int().min(0).optional()
2413
+ }).loose();
2414
+ function resolveActConfig(options) {
2415
+ if (options === void 0) return void 0;
2416
+ ActOptionsSchema.parse(options);
2417
+ return options;
2418
+ }
2419
+ var DEFAULT_AUTOCLOSE_CYCLE_MINUTES = 720;
2420
+ var DEFAULT_CLOSE_BATCH_SIZE = 64;
2421
+ var DEFAULT_CLOSE_YIELD_MS = 0;
2422
+ var DEFAULT_AUTOCLOSE_WINDOW_TZ = "UTC";
2423
+ function is_valid_time_zone(tz) {
2424
+ try {
2425
+ new Intl.DateTimeFormat("en-US", { timeZone: tz });
2426
+ return true;
2427
+ } catch {
2428
+ return false;
2429
+ }
2430
+ }
2431
+ var AutocloseWindowSchema = import_zod6.z.object({
2432
+ start: import_zod6.z.number().int().min(0).max(23, { message: "autocloseWindow.start must be an hour in [0, 23]" }),
2433
+ end: import_zod6.z.number().int().min(0).max(23, { message: "autocloseWindow.end must be an hour in [0, 23]" }),
2434
+ timeZone: import_zod6.z.string().refine(is_valid_time_zone, {
2435
+ message: "autocloseWindow.timeZone must be a valid IANA time zone"
2436
+ }).default(DEFAULT_AUTOCLOSE_WINDOW_TZ)
2437
+ }).refine((w) => w.start !== w.end, {
2438
+ message: "autocloseWindow.start and end must differ \u2014 an empty window disables autoclose"
2439
+ });
2440
+ var AutocloseOptionsSchema = import_zod6.z.object({
2441
+ autocloseCycleMinutes: import_zod6.z.number().int().min(1).max(1440).default(DEFAULT_AUTOCLOSE_CYCLE_MINUTES),
2442
+ closeBatchSize: import_zod6.z.number().int().min(1).max(1024).default(DEFAULT_CLOSE_BATCH_SIZE),
2443
+ closeYieldMs: import_zod6.z.number().min(0).max(1e3).default(DEFAULT_CLOSE_YIELD_MS),
2444
+ closeOnError: import_zod6.z.boolean().default(false),
2445
+ autocloseWindow: AutocloseWindowSchema.optional()
2446
+ });
2447
+ function resolveAutocloseConfig(options) {
2448
+ return AutocloseOptionsSchema.parse({
2449
+ autocloseCycleMinutes: options?.autocloseCycleMinutes,
2450
+ closeBatchSize: options?.closeBatchSize,
2451
+ closeYieldMs: options?.closeYieldMs,
2452
+ closeOnError: options?.closeOnError,
2453
+ autocloseWindow: options?.autocloseWindow
2454
+ });
2455
+ }
2456
+ var DEFAULT_CIRCUIT_FAILURE_THRESHOLD = 5;
2457
+ var DEFAULT_CIRCUIT_COOLDOWN_MS = 3e4;
2458
+ var CircuitBreakerOptionsSchema = import_zod6.z.object({
2459
+ failureThreshold: import_zod6.z.number().int().min(1).default(DEFAULT_CIRCUIT_FAILURE_THRESHOLD),
2460
+ cooldownMs: import_zod6.z.number().int().min(100).max(36e5).default(DEFAULT_CIRCUIT_COOLDOWN_MS)
2461
+ });
2462
+ var resolveCircuitBreakerConfig = (options) => CircuitBreakerOptionsSchema.parse(options ?? {});
2463
+ var DEFAULT_FOLD_FLUSH_EVERY = 1e3;
2464
+ var DEFAULT_MAX_CACHED_STATES = 1e4;
2465
+ var FoldOptionsSchema = import_zod6.z.object({
2466
+ flushEvery: import_zod6.z.number().int().min(1).default(DEFAULT_FOLD_FLUSH_EVERY),
2467
+ maxCachedStates: import_zod6.z.number().int().min(1).default(DEFAULT_MAX_CACHED_STATES)
2468
+ });
2469
+ function resolveFoldConfig(options) {
2470
+ return FoldOptionsSchema.parse(options);
2471
+ }
2472
+
2391
2473
  // src/internal/defer-config.ts
2392
2474
  var import_zod7 = require("zod");
2393
2475
  var DeferDurationSchema = import_zod7.z.object({
@@ -2595,11 +2677,14 @@ function reaction_on(event, events, builder) {
2595
2677
  const reaction = {
2596
2678
  handler: schedule ? make_deferred(handler, schedule) : handler,
2597
2679
  resolver: _this_,
2598
- options: {
2680
+ // #1269: validate the whole bag at the declaration site so a bad
2681
+ // `maxRetries`/`backoff`/`blockOnError` throws ZodError at build,
2682
+ // not a NaN gate on the first retry.
2683
+ options: resolveReactionConfig({
2599
2684
  blockOnError: options?.blockOnError ?? true,
2600
2685
  maxRetries: options?.maxRetries ?? 3,
2601
2686
  backoff: options?.backoff
2602
- }
2687
+ })
2603
2688
  };
2604
2689
  events[event].reactions.set(handler.name, reaction);
2605
2690
  return Object.assign(builder, {
@@ -2618,14 +2703,6 @@ function reaction_on(event, events, builder) {
2618
2703
  }
2619
2704
 
2620
2705
  // src/internal/circuit-breaker.ts
2621
- var import_zod9 = require("zod");
2622
- var DEFAULT_CIRCUIT_FAILURE_THRESHOLD = 5;
2623
- var DEFAULT_CIRCUIT_COOLDOWN_MS = 3e4;
2624
- var CircuitBreakerOptionsSchema = import_zod9.z.object({
2625
- failureThreshold: import_zod9.z.number().int().min(1).default(DEFAULT_CIRCUIT_FAILURE_THRESHOLD),
2626
- cooldownMs: import_zod9.z.number().int().min(100).max(36e5).default(DEFAULT_CIRCUIT_COOLDOWN_MS)
2627
- });
2628
- var resolveCircuitBreakerConfig = (options) => CircuitBreakerOptionsSchema.parse(options ?? {});
2629
2706
  var CircuitBreaker = class {
2630
2707
  _failures = 0;
2631
2708
  _opened_at;
@@ -3293,6 +3370,10 @@ function compute_backoff_delay(retry, opts) {
3293
3370
  delay = opts.baseMs * 2 ** r;
3294
3371
  if (opts.maxMs !== void 0) delay = Math.min(delay, opts.maxMs);
3295
3372
  break;
3373
+ default: {
3374
+ const _never = opts.strategy;
3375
+ throw new Error(`unknown backoff strategy: ${String(_never)}`);
3376
+ }
3296
3377
  }
3297
3378
  if (opts.jitter) delay = delay * (0.5 + Math.random());
3298
3379
  return Math.max(0, Math.floor(delay));
@@ -3503,7 +3584,14 @@ async function load(me, target, callback, patch_fn = bare_patch) {
3503
3584
  {
3504
3585
  stream,
3505
3586
  stream_exact: true,
3506
- ...cached ? { after: cached.event_id } : { with_snaps: true, ...asOf }
3587
+ // The snapshot resume floor is a current-state optimization: it only
3588
+ // holds when the load has no window of its own. `time_travel` already
3589
+ // captures that (any `asOf` bound set), so request `with_snaps` only for
3590
+ // a non-time-travel cold load — a bounded load full-scans real events
3591
+ // under its `asOf` filter. This is the single floor-eligibility decision
3592
+ // for the whole system; the stores apply the floor whenever asked and
3593
+ // never re-derive it (RFC 1274). The warm path resumes from `after`.
3594
+ ...cached ? { after: cached.event_id } : { ...time_travel ? {} : { with_snaps: true }, ...asOf }
3507
3595
  }
3508
3596
  );
3509
3597
  const head_is_tombstone = event?.name === TOMBSTONE_EVENT;
@@ -4042,16 +4130,6 @@ var DrainController = class {
4042
4130
  };
4043
4131
 
4044
4132
  // src/internal/projection-fold.ts
4045
- var import_zod10 = require("zod");
4046
- var DEFAULT_FOLD_FLUSH_EVERY = 1e3;
4047
- var DEFAULT_MAX_CACHED_STATES = 1e4;
4048
- var FoldOptionsSchema = import_zod10.z.object({
4049
- flushEvery: import_zod10.z.number().int().min(1).default(DEFAULT_FOLD_FLUSH_EVERY),
4050
- maxCachedStates: import_zod10.z.number().int().min(1).default(DEFAULT_MAX_CACHED_STATES)
4051
- });
4052
- function resolveFoldConfig(options) {
4053
- return FoldOptionsSchema.parse(options);
4054
- }
4055
4133
  function make_fold_handler(me, flush, config2, patch_fn = bare_patch) {
4056
4134
  const cache3 = /* @__PURE__ */ new Map();
4057
4135
  const row = ({ dirty: _, ...row2 }) => row2;
@@ -5078,6 +5156,7 @@ var Act = class {
5078
5156
  * @see {@link start_correlations} for automatic correlation
5079
5157
  */
5080
5158
  async drain(options = {}) {
5159
+ resolveDrainConfig(options);
5081
5160
  if (!this._drain)
5082
5161
  return { fetched: [], leased: [], acked: [], blocked: [] };
5083
5162
  return this._scoped(() => this._drain_all(options));
@@ -5640,6 +5719,7 @@ var Act = class {
5640
5719
  * @see {@link correlate} for manual correlation
5641
5720
  */
5642
5721
  settle(options = {}) {
5722
+ resolveSettleConfig(options);
5643
5723
  if (!this._drain) return;
5644
5724
  this._settle.schedule(options);
5645
5725
  }
@@ -5760,11 +5840,12 @@ function act() {
5760
5840
  },
5761
5841
  withActor: () => builder,
5762
5842
  withLane: (config2) => {
5763
- register_lane(config2, lanes);
5843
+ register_lane(resolveLaneConfig(config2), lanes);
5764
5844
  return builder;
5765
5845
  },
5766
5846
  on: (event) => reaction_on(event, registry.events, builder),
5767
5847
  build: (options) => {
5848
+ resolveActConfig(options);
5768
5849
  const patch_fn = options?.validateFoldedState === true ? validating_patch : bare_patch;
5769
5850
  if (!_built) {
5770
5851
  for (const proj of pending_projections) {
@@ -6081,6 +6162,7 @@ function action_builder(state2) {
6081
6162
  throw new Error(`Duplicate action "${action2}"`);
6082
6163
  internal.actions[action2] = schema;
6083
6164
  if (options) {
6165
+ resolveActionConfig(options);
6084
6166
  internal.options ??= {};
6085
6167
  internal.options[action2] = options;
6086
6168
  }