@rotorsoft/act 2.0.5 → 2.1.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.
Files changed (58) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/@types/adapter.d.ts +85 -0
  3. package/dist/@types/adapter.d.ts.map +1 -0
  4. package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
  5. package/dist/@types/config.d.ts +3 -9
  6. package/dist/@types/config.d.ts.map +1 -1
  7. package/dist/@types/deprecated.d.ts +57 -0
  8. package/dist/@types/deprecated.d.ts.map +1 -0
  9. package/dist/@types/index.d.ts +12 -9
  10. package/dist/@types/index.d.ts.map +1 -1
  11. package/dist/@types/internal/autoclose-reaction.d.ts.map +1 -1
  12. package/dist/@types/internal/close-cycle.d.ts.map +1 -1
  13. package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
  14. package/dist/@types/internal/drain-ops.d.ts.map +1 -1
  15. package/dist/@types/ports.d.ts +1 -3
  16. package/dist/@types/ports.d.ts.map +1 -1
  17. package/dist/@types/scoped.d.ts +1 -1
  18. package/dist/@types/sensitive.d.ts +6 -2
  19. package/dist/@types/sensitive.d.ts.map +1 -1
  20. package/dist/@types/types/index.d.ts +1 -1
  21. package/dist/@types/types/index.d.ts.map +1 -1
  22. package/dist/@types/types/ports.d.ts +4 -0
  23. package/dist/@types/types/ports.d.ts.map +1 -1
  24. package/dist/@types/types/schemas.d.ts +1 -1
  25. package/dist/@types/types/schemas.d.ts.map +1 -1
  26. package/dist/@types/utils.d.ts +0 -105
  27. package/dist/@types/utils.d.ts.map +1 -1
  28. package/dist/adapter.cjs +20 -0
  29. package/dist/adapter.cjs.map +1 -0
  30. package/dist/adapter.js +20 -0
  31. package/dist/adapter.js.map +1 -0
  32. package/dist/{chunk-VD4BLAY4.cjs → chunk-2377SSHX.cjs} +7 -3
  33. package/dist/chunk-2377SSHX.cjs.map +1 -0
  34. package/dist/{chunk-ESFICIG2.js → chunk-GWFLHWZV.js} +6 -2
  35. package/dist/{chunk-ESFICIG2.js.map → chunk-GWFLHWZV.js.map} +1 -1
  36. package/dist/chunk-HACJYR7Z.cjs +62 -0
  37. package/dist/chunk-HACJYR7Z.cjs.map +1 -0
  38. package/dist/{chunk-3JULRYQO.js → chunk-KXC4ILVY.js} +168 -227
  39. package/dist/chunk-KXC4ILVY.js.map +1 -0
  40. package/dist/chunk-SRZIVZIA.js +62 -0
  41. package/dist/chunk-SRZIVZIA.js.map +1 -0
  42. package/dist/{chunk-XW4EAUS6.cjs → chunk-VOVHDDET.cjs} +195 -254
  43. package/dist/chunk-VOVHDDET.cjs.map +1 -0
  44. package/dist/index.cjs +189 -160
  45. package/dist/index.cjs.map +1 -1
  46. package/dist/index.js +64 -35
  47. package/dist/index.js.map +1 -1
  48. package/dist/test/index.cjs +5 -4
  49. package/dist/test/index.cjs.map +1 -1
  50. package/dist/test/index.js +3 -2
  51. package/dist/test/index.js.map +1 -1
  52. package/dist/types/index.cjs +6 -2
  53. package/dist/types/index.cjs.map +1 -1
  54. package/dist/types/index.js +7 -3
  55. package/package.json +6 -1
  56. package/dist/chunk-3JULRYQO.js.map +0 -1
  57. package/dist/chunk-VD4BLAY4.cjs.map +0 -1
  58. package/dist/chunk-XW4EAUS6.cjs.map +0 -1
@@ -0,0 +1,62 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
2
+
3
+
4
+
5
+ var _chunk2377SSHXcjs = require('./chunk-2377SSHX.cjs');
6
+
7
+ // src/adapter.ts
8
+ function isStreamName(source, target) {
9
+ return source === target || !source.startsWith("^") && !source.endsWith("$");
10
+ }
11
+ function checkAppends(appends) {
12
+ const seen = /* @__PURE__ */ new Set();
13
+ for (const { stream, msgs } of appends) {
14
+ if (!msgs.length)
15
+ throw new Error(`commit: the append to "${stream}" has no events`);
16
+ if (seen.has(stream))
17
+ throw new Error(`commit: stream "${stream}" is named twice`);
18
+ seen.add(stream);
19
+ }
20
+ }
21
+ function concurrencyError(append, head) {
22
+ return new (0, _chunk2377SSHXcjs.ConcurrencyError)(
23
+ append.stream,
24
+ head,
25
+ append.msgs,
26
+ _nullishCoalesce(append.expectedVersion, () => ( -1))
27
+ );
28
+ }
29
+ function checkVersion(append, head) {
30
+ if (typeof append.expectedVersion === "number" && head !== append.expectedVersion)
31
+ throw concurrencyError(append, head);
32
+ }
33
+ function seedEvent(snapshot, meta) {
34
+ return {
35
+ name: snapshot !== void 0 ? _chunk2377SSHXcjs.SNAP_EVENT : _chunk2377SSHXcjs.TOMBSTONE_EVENT,
36
+ data: _nullishCoalesce(snapshot, () => ( {})),
37
+ meta: _nullishCoalesce(meta, () => ( { correlation: "", causation: {} }))
38
+ };
39
+ }
40
+ function fairSlots(lagging) {
41
+ return lagging >= 2 ? Math.max(1, Math.floor(lagging / 4)) : 0;
42
+ }
43
+ function parseNotification(raw) {
44
+ if (!raw || typeof raw !== "object") return void 0;
45
+ const { stream, events } = raw;
46
+ if (typeof stream !== "string" || !Array.isArray(events)) return void 0;
47
+ const kept = events.filter(
48
+ (e) => !!e && typeof e === "object" && typeof e.id === "number" && typeof e.name === "string"
49
+ );
50
+ return kept.length ? { stream, events: kept.map(({ id, name }) => ({ id, name })) } : void 0;
51
+ }
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+ exports.isStreamName = isStreamName; exports.checkAppends = checkAppends; exports.concurrencyError = concurrencyError; exports.checkVersion = checkVersion; exports.seedEvent = seedEvent; exports.fairSlots = fairSlots; exports.parseNotification = parseNotification;
62
+ //# sourceMappingURL=chunk-HACJYR7Z.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/act-root/act-root/libs/act/dist/chunk-HACJYR7Z.cjs","../src/adapter.ts"],"names":[],"mappings":"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","file":"/home/runner/work/act-root/act-root/libs/act/dist/chunk-HACJYR7Z.cjs","sourcesContent":[null,"/**\n * @packageDocumentation\n * @module act/adapter\n *\n * The rules a `Store` implementation calls, so each one lives once in core and\n * a third-party store can't drift from it. Each is a pure function of its\n * arguments. Import them by name, or as\n * `import * as adapter from \"@rotorsoft/act/adapter\"`. Writing a store:\n * https://rotorsoft.github.io/act-root/docs/guides/writing-a-store\n */\nimport {\n ConcurrencyError,\n type EventMeta,\n type Message,\n type Schema,\n type Schemas,\n SNAP_EVENT,\n type StoreNotification,\n TOMBSTONE_EVENT,\n} from \"./types/index.js\";\n\n/**\n * True when `source` is a stream's **name**, matched exactly. Only an anchored\n * source, one that starts with `^` or ends with `$`, is a **pattern** and gets\n * compiled as a RegExp. A name can hold any other character, so\n * `user+tag@example.com` and `order(1)` are names, and a pattern always says\n * that it is one.\n *\n * Pass the subscription's `target` too when it's known: a target reading itself\n * holds a stream's name, whatever characters that name has.\n *\n * The single source of truth for this across correlate (which decides what a\n * source marks), the drain fetch path, the close check, and the adapters, so\n * they all agree.\n *\n * @example\n * ```typescript\n * isStreamName(\"Board\"); // → true (exact lookup)\n * isStreamName(\"a+b\"); // → true (exact lookup)\n * isStreamName(\"^(A|B)$\"); // → false (compile as RegExp)\n * ```\n */\nexport function isStreamName(source: string, target?: string): boolean {\n return (\n source === target || (!source.startsWith(\"^\") && !source.endsWith(\"$\"))\n );\n}\n\n/**\n * What every store refuses in a `commit`: an append with no events, and a\n * stream named twice. In core so each adapter calls the one rule.\n */\nexport function checkAppends(\n appends: readonly {\n readonly stream: string;\n readonly msgs: readonly unknown[];\n }[]\n): void {\n const seen = new Set<string>();\n for (const { stream, msgs } of appends) {\n if (!msgs.length)\n throw new Error(`commit: the append to \"${stream}\" has no events`);\n if (seen.has(stream))\n throw new Error(`commit: stream \"${stream}\" is named twice`);\n seen.add(stream);\n }\n}\n\n/**\n * The error a stale append raises, given the head the store found. A writer\n * that named no `expectedVersion` reads as `-1`: only a race between the\n * version check and the insert gets one here.\n */\nexport function concurrencyError(\n append: {\n readonly stream: string;\n readonly msgs: readonly unknown[];\n readonly expectedVersion?: number;\n },\n head: number\n): ConcurrencyError {\n return new ConcurrencyError(\n append.stream,\n head,\n append.msgs as Message<Schemas, keyof Schemas>[],\n append.expectedVersion ?? -1\n );\n}\n\n/**\n * What every store refuses as a stale writer: an append whose\n * `expectedVersion` is not the stream's head. In core so each adapter calls\n * the one rule before it appends anything.\n */\nexport function checkVersion(\n append: {\n readonly stream: string;\n readonly msgs: readonly unknown[];\n readonly expectedVersion?: number;\n },\n head: number\n): void {\n if (\n typeof append.expectedVersion === \"number\" &&\n head !== append.expectedVersion\n )\n throw concurrencyError(append, head);\n}\n\n/**\n * The event a full `truncate` seeds a stream with at version 0: a snapshot\n * of the given state, or a tombstone when there is none.\n */\nexport function seedEvent(\n snapshot?: Schema,\n meta?: EventMeta\n): { name: string; data: Schema; meta: EventMeta } {\n return {\n name: snapshot !== undefined ? SNAP_EVENT : TOMBSTONE_EVENT,\n data: snapshot ?? {},\n meta: meta ?? { correlation: \"\", causation: {} },\n };\n}\n\n/**\n * How many of `lagging` claim slots ignore priority, so sustained high-priority\n * load can't starve a low-priority stream forever. Each store's `claim` calls\n * it, and the rule stays out of the `claim` signature.\n */\nexport function fairSlots(lagging: number): number {\n return lagging >= 2 ? Math.max(1, Math.floor(lagging / 4)) : 0;\n}\n\n/**\n * The commit notification in a payload a store or broker received, or\n * `undefined` when there is none: `stream` must be a string, and only\n * `{ id: number, name: string }` events are kept, stripped of anything else.\n * A payload with no such event is not a notification. In core so every\n * listener reads a foreign or version-skewed payload the same way.\n */\nexport function parseNotification(raw: unknown): StoreNotification | undefined {\n if (!raw || typeof raw !== \"object\") return undefined;\n const { stream, events } = raw as { stream?: unknown; events?: unknown };\n if (typeof stream !== \"string\" || !Array.isArray(events)) return undefined;\n const kept = events.filter(\n (e): e is { id: number; name: string } =>\n !!e &&\n typeof e === \"object\" &&\n typeof (e as { id?: unknown }).id === \"number\" &&\n typeof (e as { name?: unknown }).name === \"string\"\n );\n return kept.length\n ? { stream, events: kept.map(({ id, name }) => ({ id, name })) }\n : undefined;\n}\n"]}
@@ -1,12 +1,17 @@
1
1
  import {
2
- ConcurrencyError,
2
+ checkAppends,
3
+ checkVersion,
4
+ fairSlots,
5
+ seedEvent
6
+ } from "./chunk-SRZIVZIA.js";
7
+ import {
3
8
  DEFAULT_LANE,
9
+ DEFAULT_QUERY_STREAMS_LIMIT,
4
10
  Environments,
5
11
  LogLevels,
6
12
  SNAP_EVENT,
7
- TOMBSTONE_EVENT,
8
13
  ValidationError
9
- } from "./chunk-ESFICIG2.js";
14
+ } from "./chunk-GWFLHWZV.js";
10
15
 
11
16
  // src/adapters/console-logger.ts
12
17
  var LEVEL_VALUES = {
@@ -207,148 +212,6 @@ var InMemoryCache = class {
207
212
  import * as fs from "fs";
208
213
  import { z as z2 } from "zod";
209
214
 
210
- // src/internal/config.ts
211
- import { z } from "zod";
212
- var BackoffOptionsSchema = z.object({
213
- strategy: z.enum(["fixed", "linear", "exponential"]),
214
- baseMs: z.number().min(0),
215
- maxMs: z.number().gt(0).optional(),
216
- jitter: z.boolean().optional()
217
- });
218
- var DEFAULT_BACKOFF = {
219
- strategy: "fixed",
220
- baseMs: 1e4
221
- };
222
- var DEFAULT_MAX_RETRIES = 3;
223
- var DEFAULT_BLOCK_ON_ERROR = true;
224
- var ReactionOptionsSchema = z.object({
225
- blockOnError: z.boolean(),
226
- maxRetries: z.number().int().min(0),
227
- backoff: BackoffOptionsSchema.optional()
228
- });
229
- function resolveReactionConfig(options) {
230
- return ReactionOptionsSchema.parse(options);
231
- }
232
- var ActionOptionsSchema = z.object({
233
- maxRetries: z.number().int().min(0).optional(),
234
- backoff: BackoffOptionsSchema.optional()
235
- });
236
- function resolveActionConfig(options) {
237
- return ActionOptionsSchema.parse(options);
238
- }
239
- var LaneConfigSchema = z.object({
240
- name: z.string().min(1),
241
- leaseMillis: z.number().min(0).optional(),
242
- streamLimit: z.number().int().min(0).optional(),
243
- cycleMs: z.number().min(0).optional()
244
- });
245
- function resolveLaneConfig(options) {
246
- LaneConfigSchema.parse(options);
247
- return options;
248
- }
249
- var DEFAULT_STREAM_LIMIT = 10;
250
- var DEFAULT_EVENT_LIMIT = 10;
251
- var DEFAULT_LEASE_MILLIS = 1e4;
252
- var DrainOptionsSchema = z.object({
253
- streamLimit: z.number().int().min(0).optional(),
254
- eventLimit: z.number().int().min(0).optional(),
255
- leaseMillis: z.number().min(0).optional()
256
- });
257
- function resolveDrainConfig(options) {
258
- if (options === void 0) return void 0;
259
- DrainOptionsSchema.parse(options);
260
- return options;
261
- }
262
- var SettleOptionsSchema = DrainOptionsSchema.extend({
263
- debounceMs: z.number().min(0).optional(),
264
- // `maxPasses` defaults to Infinity (no cap) when omitted; a present value is
265
- // a non-negative integer — `0` is legal and means "run no passes".
266
- //
267
- // `Infinity` is accepted explicitly. It is the documented default
268
- // (`Act.settle`'s doc-comment and `SettleOptions.maxPasses` both name it),
269
- // and `settle.ts` destructures `maxPasses = Infinity`, so the one value the
270
- // docs advertise was the one value `z.number().int()` refused — Zod 4
271
- // rejects `±Infinity`, and an integer check cannot pass it either. Wrapper
272
- // code normalizing an optional cap (`maxPasses: opts.maxPasses ?? Infinity`)
273
- // is the natural way to hit it. Accepting it also honors this module's own
274
- // rule that a value which works today is never newly rejected.
275
- maxPasses: z.union([z.number().int().min(0), z.literal(Number.POSITIVE_INFINITY)]).optional()
276
- }).loose();
277
- function resolveSettleConfig(options) {
278
- if (options === void 0) return void 0;
279
- SettleOptionsSchema.parse(options);
280
- return options;
281
- }
282
- var MAX_SHUTDOWN_GRACE_MS = 3e4;
283
- var ShutdownOptionsSchema = z.object({
284
- // `0` is legal and is exactly today's behavior: stop scheduling and
285
- // return without waiting.
286
- graceMs: z.number().min(0).optional()
287
- }).loose();
288
- function resolveShutdownConfig(options) {
289
- if (options === void 0) return void 0;
290
- ShutdownOptionsSchema.parse(options);
291
- return options;
292
- }
293
- var ActOptionsSchema = z.object({
294
- maxSubscribedStreams: z.number().int().min(1).optional(),
295
- settleDebounceMs: z.number().int().min(0).optional(),
296
- autoSettle: z.boolean().optional()
297
- }).loose();
298
- function resolveActConfig(options) {
299
- if (options === void 0) return void 0;
300
- ActOptionsSchema.parse(options);
301
- return options;
302
- }
303
- var DEFAULT_AUTOCLOSE_WINDOW_TZ = "UTC";
304
- function is_valid_time_zone(tz) {
305
- try {
306
- new Intl.DateTimeFormat("en-US", { timeZone: tz });
307
- return true;
308
- } catch {
309
- return false;
310
- }
311
- }
312
- var AutocloseWindowSchema = z.object({
313
- start: z.number().int().min(0).max(23, { message: "autocloseWindow.start must be an hour in [0, 23]" }),
314
- end: z.number().int().min(0).max(23, { message: "autocloseWindow.end must be an hour in [0, 23]" }),
315
- timeZone: z.string().refine(is_valid_time_zone, {
316
- message: "autocloseWindow.timeZone must be a valid IANA time zone"
317
- }).default(DEFAULT_AUTOCLOSE_WINDOW_TZ)
318
- }).refine((w) => w.start !== w.end, {
319
- message: "autocloseWindow.start and end must differ \u2014 an empty window disables autoclose"
320
- });
321
- var AutocloseOptionsSchema = z.object({
322
- autocloseWindow: AutocloseWindowSchema.optional()
323
- });
324
- function resolveAutocloseConfig(options) {
325
- return AutocloseOptionsSchema.parse({
326
- autocloseWindow: options?.autocloseWindow
327
- });
328
- }
329
- var DEFAULT_CIRCUIT_FAILURE_THRESHOLD = 5;
330
- var DEFAULT_CIRCUIT_COOLDOWN_MS = 3e4;
331
- var CircuitBreakerOptionsSchema = z.object({
332
- failureThreshold: z.number().int().min(1).default(DEFAULT_CIRCUIT_FAILURE_THRESHOLD),
333
- cooldownMs: z.number().int().min(100).max(36e5).default(DEFAULT_CIRCUIT_COOLDOWN_MS)
334
- });
335
- var resolveCircuitBreakerConfig = (options) => CircuitBreakerOptionsSchema.parse(options ?? {});
336
- var DEFAULT_FOLD_FLUSH_EVERY = 1e3;
337
- var DEFAULT_MAX_CACHED_STATES = 1e4;
338
- var FoldOptionsSchema = z.object({
339
- flushEvery: z.number().int().min(1).default(DEFAULT_FOLD_FLUSH_EVERY),
340
- maxCachedStates: z.number().int().min(1).default(DEFAULT_MAX_CACHED_STATES)
341
- });
342
- function resolveFoldConfig(options) {
343
- return FoldOptionsSchema.parse(options);
344
- }
345
- function check_store(store3) {
346
- if (store3.commit.length === 4)
347
- throw new Error(
348
- "This store's commit takes (stream, msgs, meta, expectedVersion), the shape before @rotorsoft/act 2.0. Upgrade it, and every @rotorsoft/act-* package, together: https://rotorsoft.github.io/act-root/docs/guides/migrating-to-2.x"
349
- );
350
- }
351
-
352
215
  // src/utils.ts
353
216
  import { prettifyError, ZodError } from "zod";
354
217
  var validate = (target, payload, schema) => {
@@ -361,60 +224,9 @@ var validate = (target, payload, schema) => {
361
224
  throw new ValidationError(target, payload, error);
362
225
  }
363
226
  };
364
- var extend = (source, schema, target) => {
365
- const value = validate("config", source, schema);
366
- return { ...target, ...value };
367
- };
368
227
  async function sleep(ms) {
369
228
  return new Promise((resolve) => setTimeout(resolve, ms ?? config().sleepMs));
370
229
  }
371
- function is_literal_source(source, target) {
372
- return source === target || !source.startsWith("^") && !source.endsWith("$");
373
- }
374
- var ISO_8601 = /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.\d+)?(Z|[+-][0-2][0-9]:[0-5][0-9])?$/;
375
- var dateReviver = (_key, value) => typeof value === "string" && ISO_8601.test(value) ? new Date(value) : value;
376
- function check_appends(appends) {
377
- const seen = /* @__PURE__ */ new Set();
378
- for (const { stream, msgs } of appends) {
379
- if (!msgs.length)
380
- throw new Error(`commit: the append to "${stream}" has no events`);
381
- if (seen.has(stream))
382
- throw new Error(`commit: stream "${stream}" is named twice`);
383
- seen.add(stream);
384
- }
385
- }
386
- function concurrency_error(append, head) {
387
- return new ConcurrencyError(
388
- append.stream,
389
- head,
390
- append.msgs,
391
- append.expectedVersion ?? -1
392
- );
393
- }
394
- function throw_if_stale(append, head) {
395
- if (typeof append.expectedVersion === "number" && head !== append.expectedVersion)
396
- throw concurrency_error(append, head);
397
- }
398
- function seed_event(snapshot, meta) {
399
- return {
400
- name: snapshot !== void 0 ? SNAP_EVENT : TOMBSTONE_EVENT,
401
- data: snapshot ?? {},
402
- meta: meta ?? { correlation: "", causation: {} }
403
- };
404
- }
405
- function fair_slots(lagging) {
406
- return lagging >= 2 ? Math.max(1, Math.floor(lagging / 4)) : 0;
407
- }
408
- function notification_of(raw) {
409
- if (!raw || typeof raw !== "object") return void 0;
410
- const { stream, events } = raw;
411
- if (typeof stream !== "string" || !Array.isArray(events)) return void 0;
412
- const kept = events.filter(
413
- (e) => !!e && typeof e === "object" && typeof e.id === "number" && typeof e.name === "string"
414
- );
415
- return kept.length ? { stream, events: kept.map(({ id, name }) => ({ id, name })) } : void 0;
416
- }
417
- var DEFAULT_QUERY_STREAMS_LIMIT = 100;
418
230
 
419
231
  // src/adapters/in-memory-store.ts
420
232
  var InMemoryStream = class {
@@ -667,9 +479,9 @@ var InMemoryStore = class {
667
479
  }
668
480
  async commit(appends, meta) {
669
481
  await sleep();
670
- check_appends(appends);
482
+ checkAppends(appends);
671
483
  for (const append of appends)
672
- throw_if_stale(append, this._stream_versions.get(append.stream) ?? -1);
484
+ checkVersion(append, this._stream_versions.get(append.stream) ?? -1);
673
485
  const created = /* @__PURE__ */ new Date();
674
486
  return appends.flatMap(({ stream, msgs }) => {
675
487
  let version = this._stream_versions.get(stream) ?? -1;
@@ -697,7 +509,7 @@ var InMemoryStore = class {
697
509
  const available = [...this._streams.values()].filter(
698
510
  (s) => s.is_available && has_work(s) && (lane === void 0 || s.lane === lane)
699
511
  );
700
- const fair = fair_slots(lagging);
512
+ const fair = fairSlots(lagging);
701
513
  const by_priority = [...available].sort(
702
514
  (a, b) => b.priority - a.priority || a.at - b.at
703
515
  );
@@ -964,7 +776,7 @@ var InMemoryStore = class {
964
776
  stream,
965
777
  version: 0,
966
778
  created: /* @__PURE__ */ new Date(),
967
- ...seed_event(snapshot, meta)
779
+ ...seedEvent(snapshot, meta)
968
780
  };
969
781
  this._events.push(event);
970
782
  this._stream_versions.set(stream, 0);
@@ -1044,6 +856,148 @@ var run_disposers = async () => {
1044
856
  }
1045
857
  };
1046
858
 
859
+ // src/internal/config.ts
860
+ import { z } from "zod";
861
+ var BackoffOptionsSchema = z.object({
862
+ strategy: z.enum(["fixed", "linear", "exponential"]),
863
+ baseMs: z.number().min(0),
864
+ maxMs: z.number().gt(0).optional(),
865
+ jitter: z.boolean().optional()
866
+ });
867
+ var DEFAULT_BACKOFF = {
868
+ strategy: "fixed",
869
+ baseMs: 1e4
870
+ };
871
+ var DEFAULT_MAX_RETRIES = 3;
872
+ var DEFAULT_BLOCK_ON_ERROR = true;
873
+ var ReactionOptionsSchema = z.object({
874
+ blockOnError: z.boolean(),
875
+ maxRetries: z.number().int().min(0),
876
+ backoff: BackoffOptionsSchema.optional()
877
+ });
878
+ function resolveReactionConfig(options) {
879
+ return ReactionOptionsSchema.parse(options);
880
+ }
881
+ var ActionOptionsSchema = z.object({
882
+ maxRetries: z.number().int().min(0).optional(),
883
+ backoff: BackoffOptionsSchema.optional()
884
+ });
885
+ function resolveActionConfig(options) {
886
+ return ActionOptionsSchema.parse(options);
887
+ }
888
+ var LaneConfigSchema = z.object({
889
+ name: z.string().min(1),
890
+ leaseMillis: z.number().min(0).optional(),
891
+ streamLimit: z.number().int().min(0).optional(),
892
+ cycleMs: z.number().min(0).optional()
893
+ });
894
+ function resolveLaneConfig(options) {
895
+ LaneConfigSchema.parse(options);
896
+ return options;
897
+ }
898
+ var DEFAULT_STREAM_LIMIT = 10;
899
+ var DEFAULT_EVENT_LIMIT = 10;
900
+ var DEFAULT_LEASE_MILLIS = 1e4;
901
+ var DrainOptionsSchema = z.object({
902
+ streamLimit: z.number().int().min(0).optional(),
903
+ eventLimit: z.number().int().min(0).optional(),
904
+ leaseMillis: z.number().min(0).optional()
905
+ });
906
+ function resolveDrainConfig(options) {
907
+ if (options === void 0) return void 0;
908
+ DrainOptionsSchema.parse(options);
909
+ return options;
910
+ }
911
+ var SettleOptionsSchema = DrainOptionsSchema.extend({
912
+ debounceMs: z.number().min(0).optional(),
913
+ // `maxPasses` defaults to Infinity (no cap) when omitted; a present value is
914
+ // a non-negative integer — `0` is legal and means "run no passes".
915
+ //
916
+ // `Infinity` is accepted explicitly. It is the documented default
917
+ // (`Act.settle`'s doc-comment and `SettleOptions.maxPasses` both name it),
918
+ // and `settle.ts` destructures `maxPasses = Infinity`, so the one value the
919
+ // docs advertise was the one value `z.number().int()` refused — Zod 4
920
+ // rejects `±Infinity`, and an integer check cannot pass it either. Wrapper
921
+ // code normalizing an optional cap (`maxPasses: opts.maxPasses ?? Infinity`)
922
+ // is the natural way to hit it. Accepting it also honors this module's own
923
+ // rule that a value which works today is never newly rejected.
924
+ maxPasses: z.union([z.number().int().min(0), z.literal(Number.POSITIVE_INFINITY)]).optional()
925
+ }).loose();
926
+ function resolveSettleConfig(options) {
927
+ if (options === void 0) return void 0;
928
+ SettleOptionsSchema.parse(options);
929
+ return options;
930
+ }
931
+ var MAX_SHUTDOWN_GRACE_MS = 3e4;
932
+ var ShutdownOptionsSchema = z.object({
933
+ // `0` is legal and is exactly today's behavior: stop scheduling and
934
+ // return without waiting.
935
+ graceMs: z.number().min(0).optional()
936
+ }).loose();
937
+ function resolveShutdownConfig(options) {
938
+ if (options === void 0) return void 0;
939
+ ShutdownOptionsSchema.parse(options);
940
+ return options;
941
+ }
942
+ var ActOptionsSchema = z.object({
943
+ maxSubscribedStreams: z.number().int().min(1).optional(),
944
+ settleDebounceMs: z.number().int().min(0).optional(),
945
+ autoSettle: z.boolean().optional()
946
+ }).loose();
947
+ function resolveActConfig(options) {
948
+ if (options === void 0) return void 0;
949
+ ActOptionsSchema.parse(options);
950
+ return options;
951
+ }
952
+ var DEFAULT_AUTOCLOSE_WINDOW_TZ = "UTC";
953
+ function is_valid_time_zone(tz) {
954
+ try {
955
+ new Intl.DateTimeFormat("en-US", { timeZone: tz });
956
+ return true;
957
+ } catch {
958
+ return false;
959
+ }
960
+ }
961
+ var AutocloseWindowSchema = z.object({
962
+ start: z.number().int().min(0).max(23, { message: "autocloseWindow.start must be an hour in [0, 23]" }),
963
+ end: z.number().int().min(0).max(23, { message: "autocloseWindow.end must be an hour in [0, 23]" }),
964
+ timeZone: z.string().refine(is_valid_time_zone, {
965
+ message: "autocloseWindow.timeZone must be a valid IANA time zone"
966
+ }).default(DEFAULT_AUTOCLOSE_WINDOW_TZ)
967
+ }).refine((w) => w.start !== w.end, {
968
+ message: "autocloseWindow.start and end must differ \u2014 an empty window disables autoclose"
969
+ });
970
+ var AutocloseOptionsSchema = z.object({
971
+ autocloseWindow: AutocloseWindowSchema.optional()
972
+ });
973
+ function resolveAutocloseConfig(options) {
974
+ return AutocloseOptionsSchema.parse({
975
+ autocloseWindow: options?.autocloseWindow
976
+ });
977
+ }
978
+ var DEFAULT_CIRCUIT_FAILURE_THRESHOLD = 5;
979
+ var DEFAULT_CIRCUIT_COOLDOWN_MS = 3e4;
980
+ var CircuitBreakerOptionsSchema = z.object({
981
+ failureThreshold: z.number().int().min(1).default(DEFAULT_CIRCUIT_FAILURE_THRESHOLD),
982
+ cooldownMs: z.number().int().min(100).max(36e5).default(DEFAULT_CIRCUIT_COOLDOWN_MS)
983
+ });
984
+ var resolveCircuitBreakerConfig = (options) => CircuitBreakerOptionsSchema.parse(options ?? {});
985
+ var DEFAULT_FOLD_FLUSH_EVERY = 1e3;
986
+ var DEFAULT_MAX_CACHED_STATES = 1e4;
987
+ var FoldOptionsSchema = z.object({
988
+ flushEvery: z.number().int().min(1).default(DEFAULT_FOLD_FLUSH_EVERY),
989
+ maxCachedStates: z.number().int().min(1).default(DEFAULT_MAX_CACHED_STATES)
990
+ });
991
+ function resolveFoldConfig(options) {
992
+ return FoldOptionsSchema.parse(options);
993
+ }
994
+ function check_store(store3) {
995
+ if (store3.commit.length === 4)
996
+ throw new Error(
997
+ "This store's commit takes (stream, msgs, meta, expectedVersion), the shape before @rotorsoft/act 2.0. Upgrade it, and every @rotorsoft/act-* package, together: https://rotorsoft.github.io/act-root/docs/guides/migrating-to-2.x"
998
+ );
999
+ }
1000
+
1047
1001
  // src/scoped.ts
1048
1002
  import { AsyncLocalStorage } from "async_hooks";
1049
1003
  var scoped = new AsyncLocalStorage();
@@ -1106,7 +1060,7 @@ var _cache = port(function cache(adapter) {
1106
1060
  var cache2 = ((adapter) => {
1107
1061
  return current_ports()?.cache ?? _cache(adapter);
1108
1062
  });
1109
- var default_scope = () => DEFAULT_SCOPE;
1063
+ var unscoped_ports = () => DEFAULT_SCOPE;
1110
1064
  var DEFAULT_SCOPE = {
1111
1065
  get store() {
1112
1066
  return _store();
@@ -1136,7 +1090,7 @@ function dispose(disposer) {
1136
1090
  }
1137
1091
 
1138
1092
  // src/config.ts
1139
- var PackageSchema = z2.object({
1093
+ var package_schema = z2.object({
1140
1094
  name: z2.string().min(1),
1141
1095
  version: z2.string().min(1),
1142
1096
  description: z2.string().min(1).optional(),
@@ -1156,7 +1110,7 @@ var get_package = () => {
1156
1110
  name: FALLBACK_PACKAGE.name,
1157
1111
  version: FALLBACK_PACKAGE.version
1158
1112
  };
1159
- for (const [key, schema] of Object.entries(PackageSchema.shape)) {
1113
+ for (const [key, schema] of Object.entries(package_schema.shape)) {
1160
1114
  const field = schema.safeParse(raw?.[key]);
1161
1115
  if (field.success && field.data !== void 0) pkg2[key] = field.data;
1162
1116
  }
@@ -1167,7 +1121,7 @@ var get_package = () => {
1167
1121
  }
1168
1122
  };
1169
1123
  var pkg_load_error;
1170
- var BaseSchema = PackageSchema.extend({
1124
+ var BaseSchema = package_schema.extend({
1171
1125
  env: z2.enum(Environments),
1172
1126
  logLevel: z2.enum(LogLevels),
1173
1127
  logSingleLine: z2.boolean(),
@@ -1182,7 +1136,8 @@ var pkg = get_package();
1182
1136
  var _validated;
1183
1137
  var config = () => {
1184
1138
  if (!_validated) {
1185
- _validated = extend(
1139
+ _validated = validate(
1140
+ "config",
1186
1141
  { ...pkg, env, logLevel, logSingleLine, sleepMs },
1187
1142
  BaseSchema
1188
1143
  );
@@ -1196,14 +1151,17 @@ var config = () => {
1196
1151
  }
1197
1152
  return _validated;
1198
1153
  };
1199
- function resolveAutocloseConfig2(options) {
1200
- return resolveAutocloseConfig(options);
1201
- }
1202
1154
 
1203
1155
  export {
1204
1156
  ConsoleLogger,
1205
1157
  LruMap,
1206
1158
  InMemoryCache,
1159
+ package_schema,
1160
+ config,
1161
+ validate,
1162
+ sleep,
1163
+ InMemoryStore,
1164
+ register_weak_disposer,
1207
1165
  DEFAULT_BACKOFF,
1208
1166
  DEFAULT_MAX_RETRIES,
1209
1167
  DEFAULT_BLOCK_ON_ERROR,
@@ -1222,23 +1180,6 @@ export {
1222
1180
  resolveCircuitBreakerConfig,
1223
1181
  resolveFoldConfig,
1224
1182
  check_store,
1225
- PackageSchema,
1226
- config,
1227
- resolveAutocloseConfig2,
1228
- validate,
1229
- extend,
1230
- sleep,
1231
- is_literal_source,
1232
- dateReviver,
1233
- check_appends,
1234
- concurrency_error,
1235
- throw_if_stale,
1236
- seed_event,
1237
- fair_slots,
1238
- notification_of,
1239
- DEFAULT_QUERY_STREAMS_LIMIT,
1240
- InMemoryStore,
1241
- register_weak_disposer,
1242
1183
  make_run_scoped,
1243
1184
  current_autoclose_window,
1244
1185
  current_reacting,
@@ -1247,8 +1188,8 @@ export {
1247
1188
  log,
1248
1189
  store2 as store,
1249
1190
  cache2 as cache,
1250
- default_scope,
1191
+ unscoped_ports,
1251
1192
  disposeAndExit,
1252
1193
  dispose
1253
1194
  };
1254
- //# sourceMappingURL=chunk-3JULRYQO.js.map
1195
+ //# sourceMappingURL=chunk-KXC4ILVY.js.map