@rotorsoft/act 0.42.0 → 0.44.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.
@@ -169,11 +169,14 @@ export type QueryStreamsResult = {
169
169
  readonly count: number;
170
170
  };
171
171
  /**
172
- * Filter for {@link Store.prioritize} bulk priority updates.
172
+ * Filter shape for bulk operations on registered streams. Used by
173
+ * {@link Store.prioritize}, {@link Store.reset}, and {@link Store.unblock}
174
+ * — anything that operates on a set of streams selected by pattern or
175
+ * exact match rather than enumerated by name.
173
176
  *
174
177
  * Same shape as {@link QueryStreams} but without pagination — bulk
175
- * UPDATEs don't paginate. Empty filter (`{}`) updates **every**
176
- * registered stream.
178
+ * UPDATEs don't paginate. Empty filter (`{}`) matches **every**
179
+ * registered stream; treat as a footgun and use sparingly.
177
180
  *
178
181
  * @property stream - Stream-name filter (regex by default; `stream_exact`
179
182
  * for equality).
@@ -184,7 +187,103 @@ export type QueryStreamsResult = {
184
187
  * @property blocked - Restrict to blocked / unblocked streams. Omit
185
188
  * for both.
186
189
  */
187
- export type PrioritizeFilter = Pick<QueryStreams, "stream" | "stream_exact" | "source" | "source_exact" | "blocked">;
190
+ export type StreamFilter = Pick<QueryStreams, "stream" | "stream_exact" | "source" | "source_exact" | "blocked">;
191
+ /**
192
+ * Alias of {@link StreamFilter}. Retained for backward compatibility
193
+ * with code that imports the filter by its prioritize-specific name.
194
+ * Prefer `StreamFilter` for new code.
195
+ */
196
+ export type PrioritizeFilter = StreamFilter;
197
+ /**
198
+ * Framework-internal event names — written by the runtime, not by user
199
+ * code. Snapshots are seeded by `truncate()`; tombstones by `close()`.
200
+ *
201
+ * Kept as a literal-string union here (rather than re-exported from
202
+ * `../ports.js` where the runtime constants live) so {@link QueryStatsOptions.exclude}
203
+ * can be type-checked without inducing a `types/` → `ports.ts` cycle.
204
+ * The runtime constants {@link "../ports.js".SNAP_EVENT | SNAP_EVENT} and
205
+ * {@link "../ports.js".TOMBSTONE_EVENT | TOMBSTONE_EVENT} (exported from
206
+ * `@rotorsoft/act`) are the typed source of truth; this union mirrors
207
+ * them at the type level.
208
+ */
209
+ export type FrameworkEventName = "__snapshot__" | "__tombstone__";
210
+ /**
211
+ * Union of all event names valid for a given schema set: user-declared
212
+ * event names plus the framework-internal markers. Used by
213
+ * {@link QueryStatsOptions.exclude} so callers can mix domain events and
214
+ * framework markers in the same filter list without `as string` casts
215
+ * or stringly-typed mistakes (e.g. `"__tombsotne__"` typos fail at
216
+ * compile time).
217
+ *
218
+ * @template E - Event schemas; defaults to {@link Schemas}.
219
+ */
220
+ export type EventName<E extends Schemas = Schemas> = (keyof E & string) | FrameworkEventName;
221
+ /**
222
+ * Per-stream aggregated stats returned by {@link Store.query_stats}.
223
+ *
224
+ * `head` and `tail` follow the **git-log convention**, not the Unix
225
+ * `head`/`tail` convention:
226
+ * - `head` — the **latest** event (highest id), always present.
227
+ * - `tail` — the **earliest** event (lowest id), opt-in via
228
+ * {@link QueryStatsOptions.tail}.
229
+ *
230
+ * @template E - Event schemas; defaults to {@link Schemas} when the caller
231
+ * does not narrow.
232
+ * @property head - Latest non-excluded event for the stream.
233
+ * @property tail - Earliest non-excluded event for the stream, when
234
+ * `options.tail` is true.
235
+ * @property count - Total non-excluded event count for the stream, when
236
+ * `options.count` is true.
237
+ * @property names - Sparse map of event name → count of events with
238
+ * that name, when `options.names` is true. Keys are typed as
239
+ * {@link EventName | EventName<E>} so typos on lookup
240
+ * (e.g. `stats.names?.["TicktOpened"]`) fail at compile time when the
241
+ * caller narrows `E`. Empty object never returned — a stream with no
242
+ * matching events is absent from the result map entirely.
243
+ */
244
+ export type StreamStats<E extends Schemas = Schemas> = {
245
+ readonly head: Committed<E, keyof E>;
246
+ readonly tail?: Committed<E, keyof E>;
247
+ readonly count?: number;
248
+ readonly names?: Readonly<Partial<Record<EventName<E>, number>>>;
249
+ };
250
+ /**
251
+ * Options for {@link Store.query_stats}. All stat fields default to
252
+ * `false` except `head`, which is always returned.
253
+ *
254
+ * **Cost model:** With no opt-in flags (or `tail` alone), each requested
255
+ * stat resolves via an index-backed lookup — O(K) cost where K is the
256
+ * number of matched streams. Setting `count` and/or `names` triggers a
257
+ * full event scan over the matched streams (O(N) where N is total events);
258
+ * both share the same scan and so requesting one is the same cost as
259
+ * requesting both.
260
+ *
261
+ * @template E - Event schemas; defaults to {@link Schemas}. When the caller
262
+ * narrows `E`, `exclude` is type-checked against the schema's event names
263
+ * — typos like `["TOMBSTON_EVENT"]` fail at compile time.
264
+ * @property tail - Include the earliest non-excluded event per stream.
265
+ * Cheap when alone (indexed); free when `count`/`names` also set
266
+ * (already scanning).
267
+ * @property count - Include the total non-excluded event count per stream.
268
+ * Triggers full scan.
269
+ * @property names - Include a `name → count` map per stream. Triggers
270
+ * full scan (shares cost with `count`).
271
+ * @property exclude - Event names to skip — e.g.
272
+ * `[TOMBSTONE_EVENT, SNAP_EVENT]` to ignore framework markers. Applies
273
+ * to all returned stats (head, tail, count, names) consistently.
274
+ * @property before - Time-travel cutoff: only consider events with
275
+ * `id < before`. Omitted = current state. Useful for "what did this
276
+ * stream look like at event N?" historical queries without changing
277
+ * the call shape. Cheap on both code paths (cheap-heads path narrows
278
+ * the index scan; full-scan path adds a `WHERE id < ?` predicate).
279
+ */
280
+ export type QueryStatsOptions<E extends Schemas = Schemas> = {
281
+ readonly tail?: boolean;
282
+ readonly count?: boolean;
283
+ readonly names?: boolean;
284
+ readonly exclude?: ReadonlyArray<EventName<E>>;
285
+ readonly before?: number;
286
+ };
188
287
  /**
189
288
  * Interface for event store implementations.
190
289
  *
@@ -440,14 +539,24 @@ export interface Store extends Disposable {
440
539
  * "needs drain" flag, so a settled `Act` instance will short-circuit and
441
540
  * skip the replay. `Act.reset()` wraps this and arms the flag.
442
541
  *
443
- * @param streams - Stream names to reset
542
+ * Accepts either an explicit list of stream names or a
543
+ * {@link StreamFilter} for bulk operations (e.g., "rebuild every
544
+ * blocked stream"). The filter form is the same shape used by
545
+ * {@link prioritize} and {@link query_streams}. An empty filter
546
+ * (`{}`) matches every registered stream — typically a footgun for
547
+ * `reset`; prefer narrower filters like `{ blocked: true }`.
548
+ *
549
+ * @param input - Stream names or a {@link StreamFilter}
444
550
  * @returns Count of streams that were actually reset
445
551
  *
446
552
  * @example
447
553
  * ```typescript
448
- * // Recommended
554
+ * // By name
449
555
  * await app.reset(["my-projection"]);
450
556
  *
557
+ * // By filter — rebuild every blocked stream in a projection family
558
+ * await app.reset({ stream: "^proj-orders-", blocked: true });
559
+ *
451
560
  * // Low-level (does NOT trigger replay on settled apps)
452
561
  * await store().reset(["my-projection"]);
453
562
  * ```
@@ -455,7 +564,60 @@ export interface Store extends Disposable {
455
564
  * @see {@link Act.reset} for the high-level rebuild API that wraps
456
565
  * this primitive and arms the orchestrator's drain flag
457
566
  */
458
- reset: (streams: string[]) => Promise<number>;
567
+ reset: (input: string[] | StreamFilter) => Promise<number>;
568
+ /**
569
+ * Clears the blocked flag on streams without replaying their history.
570
+ * Sets `blocked = false`, `retry_count = 0`, `error = null`, and
571
+ * clears any lease bookkeeping. The `at` watermark stays where it
572
+ * was — the stream resumes from the next event after the last
573
+ * successful ack, not from zero.
574
+ *
575
+ * The distinction from {@link reset} matters: `reset()` is for
576
+ * projection rebuilds (replay from event 0); `unblock()` is for
577
+ * recovering from a poison message after the operator fixes the
578
+ * underlying issue. Use `unblock()` when you don't want to re-process
579
+ * history.
580
+ *
581
+ * **Prefer `Act.unblock()` over calling this directly.** Like
582
+ * `reset()`, this primitive doesn't raise the orchestrator's internal
583
+ * "needs drain" flag — a settled `Act` instance will short-circuit and
584
+ * skip the resume. `Act.unblock()` wraps this and arms the flag.
585
+ *
586
+ * Only streams that were actually blocked at call time count toward
587
+ * the return value; already-unblocked streams and unknown stream
588
+ * names are silently skipped. The atomic single-statement update
589
+ * makes the call safe to issue concurrently with `claim()` — workers
590
+ * holding a `FOR UPDATE SKIP LOCKED` lock won't see partial state.
591
+ *
592
+ * Accepts either an explicit list of stream names or a
593
+ * {@link StreamFilter} for bulk recovery (e.g., "unblock every
594
+ * blocked order projection"). The `blocked = true` predicate is
595
+ * always applied — passing `blocked: false` in the filter matches
596
+ * nothing. An empty filter (`{}`) means "unblock everything that's
597
+ * blocked," which is a sane post-incident bulk recovery.
598
+ *
599
+ * @param input - Stream names or a {@link StreamFilter}
600
+ * @returns Count of streams that were actually flipped (were blocked)
601
+ *
602
+ * @example
603
+ * ```typescript
604
+ * // By name (single targeted recovery)
605
+ * await app.unblock(["webhooks-out-customer-42"]);
606
+ *
607
+ * // By filter — unblock every blocked stream in a family
608
+ * await app.unblock({ stream: "^webhooks-out-" });
609
+ *
610
+ * // Post-incident: unblock everything that's blocked
611
+ * await app.unblock({});
612
+ *
613
+ * // Low-level (does NOT trigger resume on settled apps)
614
+ * await store().unblock(["webhooks-out-customer-42"]);
615
+ * ```
616
+ *
617
+ * @see {@link Act.unblock} for the high-level recovery API
618
+ * @see {@link reset} for the rebuild-from-zero alternative
619
+ */
620
+ unblock: (input: string[] | StreamFilter) => Promise<number>;
459
621
  /**
460
622
  * Bulk-update the scheduling priority of streams matching a filter.
461
623
  *
@@ -495,7 +657,7 @@ export interface Store extends Disposable {
495
657
  * @see {@link Act.prioritize} for the orchestrator-level wrapper
496
658
  * @see {@link claim} for how priority biases stream scheduling
497
659
  */
498
- prioritize: (filter: PrioritizeFilter, priority: number) => Promise<number>;
660
+ prioritize: (filter: StreamFilter, priority: number) => Promise<number>;
499
661
  /**
500
662
  * Atomically truncates streams and seeds each with a final event.
501
663
  *
@@ -560,6 +722,110 @@ export interface Store extends Disposable {
560
722
  * ```
561
723
  */
562
724
  query_streams: (callback: (position: StreamPosition) => void, query?: QueryStreams) => Promise<QueryStreamsResult>;
725
+ /**
726
+ * Per-stream aggregated stats — single round trip per adapter.
727
+ *
728
+ * Returns the latest event (`head`) plus opt-in extras (`tail`, `count`,
729
+ * `names`) for each stream selected by `input`. Streams with no
730
+ * qualifying events are absent from the result map.
731
+ *
732
+ * **Cost model.** With no opt-in flags, the call uses an index-backed
733
+ * head lookup per stream — O(K) where K is the number of matched
734
+ * streams. `tail` alone stays in the cheap tier. Setting `count` and/or
735
+ * `names` triggers a full event scan over the matched streams (O(N)
736
+ * where N is total events); both stats share that scan, so requesting
737
+ * one or both is the same cost.
738
+ *
739
+ * **`input`.** Either an explicit `string[]` of stream names, or a
740
+ * narrow event-stream selector `{ stream?, stream_exact? }` for
741
+ * pattern-based or exact-name matching. **Subscription-level filters
742
+ * (`source`, `blocked`) are intentionally not accepted here** — they
743
+ * describe subscriptions, not events, and conflating the two would
744
+ * silently exclude unsubscribed event streams. For
745
+ * "stats for all blocked subscriptions" compose explicitly:
746
+ * `query_streams({blocked: true})` → collect names → `query_stats(names)`.
747
+ *
748
+ * **`head` vs `tail` naming.** Follows the git-log convention: `head`
749
+ * is the latest event (highest id), `tail` is the earliest (lowest id).
750
+ * This is the **opposite** of the Unix `head`/`tail` commands.
751
+ *
752
+ * **Framework markers.** Snapshots (`__snapshot__`) and tombstones
753
+ * (`__tombstone__`) are real events and are included by default —
754
+ * intentional, so schema-evolution tooling can count them. To exclude
755
+ * them, pass them in `options.exclude` (typed against {@link EventName})
756
+ * so typos are compile-time errors.
757
+ *
758
+ * **Snapshot counts come from `names`.** When `names: true` and snapshots
759
+ * are not in `exclude`, `result.names["__snapshot__"]` is the snapshot
760
+ * count for that stream — no separate field needed. Validates snapshot
761
+ * policy at scale: `names["__snapshot__"] / count` should match the
762
+ * configured snap predicate's expected ratio.
763
+ *
764
+ * **Time travel.** `options.before` narrows to events with `id < before`,
765
+ * answering "what did this stream look like at event N?" without
766
+ * special call shape.
767
+ *
768
+ * @example Cheap heads — close-cycle pattern (one round trip, no scan)
769
+ * ```typescript
770
+ * const stats = await store().query_stats(streams, {
771
+ * exclude: [TOMBSTONE_EVENT],
772
+ * });
773
+ * for (const [stream, { head }] of stats) {
774
+ * // head.id, head.version, head.name
775
+ * }
776
+ * ```
777
+ *
778
+ * @example Full stats — inspector / admin dashboard (one full scan)
779
+ * ```typescript
780
+ * const stats = await store().query_stats<MyEvents>(
781
+ * { stream: "^orders-" },
782
+ * { count: true, tail: true, names: true,
783
+ * exclude: [TOMBSTONE_EVENT] }
784
+ * );
785
+ * for (const [stream, s] of stats) {
786
+ * const snaps = s.names?.[SNAP_EVENT] ?? 0;
787
+ * const domain = (s.count ?? 0) - snaps;
788
+ * console.log(stream, { snaps, domain, tail: s.tail?.created });
789
+ * }
790
+ * ```
791
+ *
792
+ * @example Schema-evolution — surface deprecated events per stream
793
+ * ```typescript
794
+ * const stats = await store().query_stats<TicketEvents>(
795
+ * { stream: "^ticket-" },
796
+ * { names: true }
797
+ * );
798
+ * for (const [stream, { names = {} }] of stats) {
799
+ * if ((names["TicketOpened"] ?? 0) > 0) {
800
+ * console.log(`${stream}: ${names["TicketOpened"]} legacy events`);
801
+ * }
802
+ * }
803
+ * ```
804
+ *
805
+ * @example Time travel — stream state at a historical cutoff
806
+ * ```typescript
807
+ * const stats = await store().query_stats(["order-42"], {
808
+ * before: 100_000, // events up to (not including) id 100000
809
+ * tail: true,
810
+ * });
811
+ * const { head, tail } = stats.get("order-42") ?? {};
812
+ * // head = latest event with id < 100_000; tail = earliest in range
813
+ * ```
814
+ *
815
+ * @template E - Event schemas. Narrow at the call site to type-check
816
+ * `exclude` against your event names (typos fail at compile time).
817
+ *
818
+ * @param input - Stream names or a filter selecting the streams to stat.
819
+ * @param options - Opt-in stat fields, event-name exclusions, and
820
+ * time-travel cutoff. See {@link QueryStatsOptions}.
821
+ * @returns Map keyed by stream name. Streams with no qualifying events
822
+ * (after `exclude` and `before` are applied) are absent.
823
+ *
824
+ * @see {@link QueryStatsOptions} for the cost-aware option surface
825
+ * @see {@link StreamStats} for the per-stream result shape
826
+ * @see {@link EventName} for the typed exclude entries
827
+ */
828
+ query_stats: <E extends Schemas>(input: string[] | Pick<StreamFilter, "stream" | "stream_exact">, options?: QueryStatsOptions<E>) => Promise<Map<string, StreamStats<E>>>;
563
829
  /**
564
830
  * Optional cross-process commit notifications.
565
831
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../../src/types/ports.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../../src/types/ports.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ import {
3
3
  Environments,
4
4
  LogLevels,
5
5
  ValidationError
6
- } from "./chunk-AGWZY6YT.js";
6
+ } from "./chunk-VMX7RPTC.js";
7
7
 
8
8
  // src/adapters/console-logger.ts
9
9
  var LEVEL_VALUES = {
@@ -364,6 +364,20 @@ var InMemoryStream = class {
364
364
  this._leased_by = void 0;
365
365
  this._leased_until = void 0;
366
366
  }
367
+ /**
368
+ * Clear the blocked flag and lease bookkeeping without touching the
369
+ * watermark. Returns true if the stream was actually blocked (and is
370
+ * now flipped); false otherwise.
371
+ */
372
+ unblock() {
373
+ if (!this._blocked) return false;
374
+ this._blocked = false;
375
+ this._retry = -1;
376
+ this._error = "";
377
+ this._leased_by = void 0;
378
+ this._leased_until = void 0;
379
+ return true;
380
+ }
367
381
  };
368
382
  var InMemoryStore = class {
369
383
  // stored events
@@ -599,19 +613,81 @@ var InMemoryStore = class {
599
613
  return leases.map((l) => this._streams.get(l.stream)?.block(l, l.error)).filter((l) => !!l);
600
614
  }
601
615
  /**
602
- * Reset watermarks for the given streams to -1, clearing retry, blocked,
603
- * error, and lease state so they can be replayed from the beginning.
604
- * @param streams - Stream names to reset.
616
+ * Build a predicate from a {@link StreamFilter}. Compiled regexes are
617
+ * cached in the closure so callers can apply it across the streams
618
+ * map without re-compiling per iteration.
619
+ */
620
+ _filterPredicate(filter) {
621
+ const streamRe = filter.stream && !filter.stream_exact ? new RegExp(filter.stream) : void 0;
622
+ const sourceRe = filter.source && !filter.source_exact ? new RegExp(filter.source) : void 0;
623
+ return (s) => {
624
+ if (filter.stream !== void 0) {
625
+ if (filter.stream_exact ? s.stream !== filter.stream : !streamRe.test(s.stream))
626
+ return false;
627
+ }
628
+ if (filter.source !== void 0) {
629
+ if (s.source === void 0) return false;
630
+ if (filter.source_exact ? s.source !== filter.source : !sourceRe.test(s.source))
631
+ return false;
632
+ }
633
+ if (filter.blocked !== void 0 && s.blocked !== filter.blocked)
634
+ return false;
635
+ return true;
636
+ };
637
+ }
638
+ /**
639
+ * Reset watermarks to -1, clearing retry, blocked, error, and lease
640
+ * state so the matched streams can be replayed from the beginning.
641
+ * Accepts either an explicit list of names or a {@link StreamFilter}.
642
+ *
643
+ * @param input - Stream names or a filter selecting the streams to reset.
605
644
  * @returns Count of streams that were actually reset.
606
645
  */
607
- async reset(streams) {
646
+ async reset(input) {
608
647
  await sleep();
609
648
  let count = 0;
610
- for (const name of streams) {
611
- const s = this._streams.get(name);
612
- if (s) {
613
- s.reset();
614
- count++;
649
+ if (Array.isArray(input)) {
650
+ for (const name of input) {
651
+ const s = this._streams.get(name);
652
+ if (s) {
653
+ s.reset();
654
+ count++;
655
+ }
656
+ }
657
+ } else {
658
+ const matches = this._filterPredicate(input);
659
+ for (const s of this._streams.values()) {
660
+ if (matches(s)) {
661
+ s.reset();
662
+ count++;
663
+ }
664
+ }
665
+ }
666
+ return count;
667
+ }
668
+ /**
669
+ * Clear the blocked flag (and retry / error / lease) on the matched
670
+ * streams without touching the watermark. Streams that aren't blocked
671
+ * at call time are silently skipped. Accepts either an explicit list
672
+ * of names or a {@link StreamFilter}. The filter form always restricts
673
+ * to blocked streams — passing `blocked: false` matches nothing.
674
+ * See {@link Store.unblock}.
675
+ *
676
+ * @param input - Stream names or a filter selecting the streams to unblock.
677
+ * @returns Count of streams that were actually flipped (were blocked).
678
+ */
679
+ async unblock(input) {
680
+ await sleep();
681
+ let count = 0;
682
+ if (Array.isArray(input)) {
683
+ for (const name of input) {
684
+ const s = this._streams.get(name);
685
+ if (s?.unblock()) count++;
686
+ }
687
+ } else {
688
+ const matches = this._filterPredicate({ ...input, blocked: true });
689
+ for (const s of this._streams.values()) {
690
+ if (matches(s) && s.unblock()) count++;
615
691
  }
616
692
  }
617
693
  return count;
@@ -627,21 +703,10 @@ var InMemoryStore = class {
627
703
  */
628
704
  async prioritize(filter, priority) {
629
705
  await sleep();
630
- const streamRe = filter.stream && !filter.stream_exact ? new RegExp(filter.stream) : void 0;
631
- const sourceRe = filter.source && !filter.source_exact ? new RegExp(filter.source) : void 0;
706
+ const matches = this._filterPredicate(filter);
632
707
  let count = 0;
633
708
  for (const s of this._streams.values()) {
634
- if (filter.stream !== void 0) {
635
- if (filter.stream_exact ? s.stream !== filter.stream : !streamRe.test(s.stream))
636
- continue;
637
- }
638
- if (filter.source !== void 0) {
639
- if (s.source === void 0) continue;
640
- if (filter.source_exact ? s.source !== filter.source : !sourceRe.test(s.source))
641
- continue;
642
- }
643
- if (filter.blocked !== void 0 && s.blocked !== filter.blocked)
644
- continue;
709
+ if (!matches(s)) continue;
645
710
  if (s.priority !== priority) {
646
711
  s.setPriority(priority);
647
712
  count++;
@@ -693,6 +758,77 @@ var InMemoryStore = class {
693
758
  }
694
759
  return { maxEventId: this._events.length - 1, count };
695
760
  }
761
+ /**
762
+ * Per-stream aggregated stats — see {@link Store.query_stats}.
763
+ *
764
+ * Single forward scan over the in-memory event list, accumulating per
765
+ * stream. The "cheap heads" cost tier from durable adapters doesn't
766
+ * apply here (InMemory has no indexes); correctness is the goal, perf
767
+ * is a non-issue.
768
+ *
769
+ * Scope rules:
770
+ * - Array `input` — explicit stream names, regardless of subscription.
771
+ * - Filter `input` — `stream`/`stream_exact` match against event-bearing
772
+ * stream names; `source`/`source_exact`/`blocked` require a
773
+ * corresponding subscription in `_streams` (those are subscription
774
+ * concepts, not event concepts). Empty filter `{}` matches every
775
+ * event-bearing stream.
776
+ */
777
+ async query_stats(input, options) {
778
+ await sleep();
779
+ const exclude = new Set(options?.exclude ?? []);
780
+ const wantTail = options?.tail ?? false;
781
+ const wantCount = options?.count ?? false;
782
+ const wantNames = options?.names ?? false;
783
+ const before = options?.before;
784
+ const arrayTargets = Array.isArray(input) ? new Set(input) : null;
785
+ const filter = Array.isArray(input) ? null : input;
786
+ const streamRe = filter?.stream && !filter.stream_exact ? new RegExp(filter.stream) : void 0;
787
+ const scopeCache = /* @__PURE__ */ new Map();
788
+ const inScope = (stream) => {
789
+ const cached = scopeCache.get(stream);
790
+ if (cached !== void 0) return cached;
791
+ let ok = true;
792
+ if (arrayTargets) {
793
+ ok = arrayTargets.has(stream);
794
+ } else if (filter?.stream !== void 0) {
795
+ ok = filter.stream_exact ? stream === filter.stream : (
796
+ // biome-ignore lint/style/noNonNullAssertion: streamRe set when stream is regex
797
+ streamRe.test(stream)
798
+ );
799
+ }
800
+ scopeCache.set(stream, ok);
801
+ return ok;
802
+ };
803
+ const acc = /* @__PURE__ */ new Map();
804
+ for (const e of this._events) {
805
+ if (before !== void 0 && e.id >= before) continue;
806
+ if (!inScope(e.stream)) continue;
807
+ if (exclude.has(e.name)) continue;
808
+ let a = acc.get(e.stream);
809
+ if (!a) {
810
+ a = { head: e, count: 0 };
811
+ if (wantTail) a.tail = e;
812
+ if (wantNames) a.names = {};
813
+ acc.set(e.stream, a);
814
+ }
815
+ a.head = e;
816
+ a.count++;
817
+ if (wantNames) {
818
+ const n = String(e.name);
819
+ a.names[n] = (a.names[n] ?? 0) + 1;
820
+ }
821
+ }
822
+ const out = /* @__PURE__ */ new Map();
823
+ for (const [stream, a] of acc) {
824
+ const stats = { head: a.head };
825
+ if (wantTail) stats.tail = a.tail;
826
+ if (wantCount) stats.count = a.count;
827
+ if (wantNames) stats.names = a.names;
828
+ out.set(stream, stats);
829
+ }
830
+ return out;
831
+ }
696
832
  /**
697
833
  * Atomically truncates streams and seeds each with a snapshot or tombstone.
698
834
  * @param targets - Streams to truncate with optional snapshot state and meta.
@@ -874,4 +1010,4 @@ export {
874
1010
  SNAP_EVENT,
875
1011
  TOMBSTONE_EVENT
876
1012
  };
877
- //# sourceMappingURL=chunk-M5YFKVRV.js.map
1013
+ //# sourceMappingURL=chunk-LKRNWD7C.js.map