@rotorsoft/act 1.19.0 → 1.20.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.
@@ -9,6 +9,7 @@
9
9
  * actions, and are pure side-effect handlers routed to a named stream.
10
10
  */
11
11
  import type { ZodType } from "zod";
12
+ import { type FoldConfig } from "../internal/index.js";
12
13
  import type { BatchHandler, CacheEntry, Committed, EventRegister, FoldOptions, ReactionResolver, Schema, Schemas, State } from "../types/index.js";
13
14
  /**
14
15
  * A self-contained projection grouping read-model update handlers.
@@ -21,6 +22,45 @@ export type Projection<TEvents extends Schemas> = {
21
22
  readonly events: EventRegister<TEvents>;
22
23
  readonly target?: string;
23
24
  readonly batchHandler?: BatchHandler<TEvents>;
25
+ /**
26
+ * State-fold spec from `.of()`. The builder only records intent — the
27
+ * orchestrator resolves the REGISTRY-MERGED full state at
28
+ * `act().build()` and synthesizes the batch handler there, so the
29
+ * fold always covers every reducer of the state, including partials
30
+ * merged by slices the projection never saw.
31
+ * @internal
32
+ */
33
+ readonly fold?: {
34
+ readonly name: string;
35
+ readonly flush: (rows: ReadonlyArray<CacheEntry<any>>) => Promise<void>;
36
+ readonly config: FoldConfig;
37
+ };
38
+ };
39
+ /**
40
+ * The `.of()` continuation: state projections flush the cache layer
41
+ * outward — the rows ARE the streams' {@link CacheEntry} values, one
42
+ * per dirty stream per flush round. Must be an idempotent upsert keyed
43
+ * on `stream` (guard with `event_id` for order safety when a rebuild
44
+ * races a live worker).
45
+ */
46
+ type FoldFlush<TState extends Schema, TE extends Schemas> = {
47
+ flush: (handler: (rows: ReadonlyArray<CacheEntry<TState>>) => Promise<void>) => {
48
+ build: () => Projection<TE>;
49
+ };
50
+ };
51
+ /**
52
+ * `.of()` accepts the partials of ONE state (same name, enforced at the
53
+ * type level via `TName`) purely for typing and event registration —
54
+ * the fold itself always runs on the registry-merged full state,
55
+ * resolved at `act().build()`. Passing every partial is required: the
56
+ * orchestrator validates completeness at build and throws on missing
57
+ * events.
58
+ */
59
+ type OfSignatures = {
60
+ <TS1 extends Schema, TE1 extends Schemas, TA1 extends Schemas, TN extends string>(s1: State<TS1, TE1, TA1, TN>, options?: FoldOptions): FoldFlush<TS1, TE1>;
61
+ <TS1 extends Schema, TE1 extends Schemas, TA1 extends Schemas, TS2 extends Schema, TE2 extends Schemas, TA2 extends Schemas, TN extends string>(s1: State<TS1, TE1, TA1, TN>, s2: State<TS2, TE2, TA2, TN>, options?: FoldOptions): FoldFlush<TS1 & TS2, TE1 & TE2>;
62
+ <TS1 extends Schema, TE1 extends Schemas, TA1 extends Schemas, TS2 extends Schema, TE2 extends Schemas, TA2 extends Schemas, TS3 extends Schema, TE3 extends Schemas, TA3 extends Schemas, TN extends string>(s1: State<TS1, TE1, TA1, TN>, s2: State<TS2, TE2, TA2, TN>, s3: State<TS3, TE3, TA3, TN>, options?: FoldOptions): FoldFlush<TS1 & TS2 & TS3, TE1 & TE2 & TE3>;
63
+ <TS1 extends Schema, TE1 extends Schemas, TA1 extends Schemas, TS2 extends Schema, TE2 extends Schemas, TA2 extends Schemas, TS3 extends Schema, TE3 extends Schemas, TA3 extends Schemas, TS4 extends Schema, TE4 extends Schemas, TA4 extends Schemas, TN extends string>(s1: State<TS1, TE1, TA1, TN>, s2: State<TS2, TE2, TA2, TN>, s3: State<TS3, TE3, TA3, TN>, s4: State<TS4, TE4, TA4, TN>, options?: FoldOptions): FoldFlush<TS1 & TS2 & TS3 & TS4, TE1 & TE2 & TE3 & TE4>;
24
64
  };
25
65
  /** Helper: a single-key record mapping an event name to its Zod schema. */
26
66
  type EventEntry<TKey extends string = string, TData extends Schema = Schema> = {
@@ -99,18 +139,7 @@ export type ProjectionBuilder<TEvents extends Schemas, TTarget extends string |
99
139
  * `.build()` — a projection either folds a state or declares
100
140
  * handlers, never both.
101
141
  */
102
- of: <TState extends Schema, TE extends Schemas, TA extends Schemas>(state: State<TState, TE, TA>, options?: FoldOptions) => {
103
- /**
104
- * The sink: state projections flush the cache layer outward —
105
- * the rows ARE the streams' {@link CacheEntry} values, one per
106
- * dirty stream per flush round. Must be an idempotent upsert
107
- * keyed on `stream` (guard with `event_id` for order safety
108
- * when a rebuild races a live worker).
109
- */
110
- flush: (handler: (rows: ReadonlyArray<CacheEntry<TState>>) => Promise<void>) => {
111
- build: () => Projection<TE>;
112
- };
113
- };
142
+ of: OfSignatures;
114
143
  } : {}) : {});
115
144
  /**
116
145
  * Creates a new projection builder with a static target stream.
@@ -1 +1 @@
1
- {"version":3,"file":"projection-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/projection-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"projection-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/projection-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACnC,OAAO,EAEL,KAAK,UAAU,EAEhB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,SAAS,EACT,aAAa,EACb,WAAW,EAEX,gBAAgB,EAChB,MAAM,EACN,OAAO,EACP,KAAK,EACN,MAAM,mBAAmB,CAAC;AAE3B;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,OAAO,SAAS,OAAO,IAAI;IAChD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAC9C;;;;;;;OAOG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACxE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;KAC7B,CAAC;CACH,CAAC;AAEF;;;;;;GAMG;AACH,KAAK,SAAS,CAAC,MAAM,SAAS,MAAM,EAAE,EAAE,SAAS,OAAO,IAAI;IAC1D,KAAK,EAAE,CACL,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,KAChE;QACH,KAAK,EAAE,MAAM,UAAU,CAAC,EAAE,CAAC,CAAC;KAC7B,CAAC;CACH,CAAC;AAEF;;;;;;;GAOG;AACH,KAAK,YAAY,GAAG;IAClB,CACE,GAAG,SAAS,MAAM,EAClB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,OAAO,EACnB,EAAE,SAAS,MAAM,EAEjB,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAC5B,OAAO,CAAC,EAAE,WAAW,GACpB,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACvB,CACE,GAAG,SAAS,MAAM,EAClB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,MAAM,EAClB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,OAAO,EACnB,EAAE,SAAS,MAAM,EAEjB,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAC5B,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAC5B,OAAO,CAAC,EAAE,WAAW,GACpB,SAAS,CAAC,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;IACnC,CACE,GAAG,SAAS,MAAM,EAClB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,MAAM,EAClB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,MAAM,EAClB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,OAAO,EACnB,EAAE,SAAS,MAAM,EAEjB,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAC5B,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAC5B,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAC5B,OAAO,CAAC,EAAE,WAAW,GACpB,SAAS,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;IAC/C,CACE,GAAG,SAAS,MAAM,EAClB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,MAAM,EAClB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,MAAM,EAClB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,MAAM,EAClB,GAAG,SAAS,OAAO,EACnB,GAAG,SAAS,OAAO,EACnB,EAAE,SAAS,MAAM,EAEjB,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAC5B,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAC5B,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAC5B,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAC5B,OAAO,CAAC,EAAE,WAAW,GACpB,SAAS,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;CAC5D,CAAC;AAEF,2EAA2E;AAC3E,KAAK,UAAU,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI;KAC5E,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;CAC5B,CAAC;AAEF,iEAAiE;AACjE,KAAK,QAAQ,CACX,OAAO,SAAS,OAAO,EACvB,IAAI,SAAS,MAAM,EACnB,KAAK,SAAS,MAAM,EACpB,OAAO,SAAS,MAAM,GAAG,SAAS,GAAG,SAAS,IAC5C,iBAAiB,CAAC,OAAO,GAAG;KAAG,CAAC,IAAI,IAAI,GAAG,KAAK;CAAE,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG;IACvE,EAAE,EAAE,CACF,QAAQ,EAAE,gBAAgB,CAAC,OAAO,GAAG;SAAG,CAAC,IAAI,IAAI,GAAG,KAAK;KAAE,EAAE,IAAI,CAAC,GAAG,MAAM,KACxE,iBAAiB,CAAC,OAAO,GAAG;SAAG,CAAC,IAAI,IAAI,GAAG,KAAK;KAAE,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;CACzE,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,CAC3B,OAAO,SAAS,OAAO,EACvB,OAAO,SAAS,MAAM,GAAG,SAAS,GAAG,SAAS,EAC9C,YAAY,SAAS,OAAO,GAAG,KAAK,IAClC;IACF;;;;;;OAMG;IACH,EAAE,EAAE,CAAC,IAAI,SAAS,MAAM,EAAE,KAAK,SAAS,MAAM,EAC5C,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,KAC3B;QACH,EAAE,EAAE,CACF,OAAO,EAAE,CACP,KAAK,EAAE,SAAS,CAAC,OAAO,GAAG;aAAG,CAAC,IAAI,IAAI,GAAG,KAAK;SAAE,EAAE,IAAI,CAAC,EACxD,MAAM,EAAE,MAAM,KACX,OAAO,CAAC,IAAI,CAAC,KACf,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;KAC9C,CAAC;IACF;;OAEG;IACH,KAAK,EAAE,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;IACjC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CACzC,GAAG,CAAC,OAAO,SAAS,MAAM,GACvB;IACE;;;;;;;;;OASG;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,KAAK;QACzC,KAAK,EAAE,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;KAClC,CAAC;CACH,GAAG,CAAC,YAAY,SAAS,KAAK,GAC3B;IACE;;;;;;;;;;;;;;;;OAgBG;IACH,EAAE,EAAE,YAAY,CAAC;CAClB,GAED,EAAE,CAAC,GAEP,EAAE,CAAC,CAAC;AAsNR;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,SAAS,OAAO,GAAG,EAAE,EACrD,MAAM,EAAE,MAAM,GACb,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AACtC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,SAAS,OAAO,GAAG,EAAE,EACrD,MAAM,CAAC,EAAE,SAAS,GACjB,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC"}
@@ -46,7 +46,7 @@ export interface EsOps {
46
46
  * @example
47
47
  * await snap(snapshot);
48
48
  */
49
- export declare function snap<TState extends Schema, TEvents extends Schemas>(snapshot: Snapshot<TState, TEvents>): Promise<void>;
49
+ export declare function snap<TState extends Schema, TEvents extends Schemas>(snapshot: Snapshot<TState, TEvents>): Promise<Committed<TEvents, keyof TEvents> | undefined>;
50
50
  /**
51
51
  * Commits a tombstone event with optimistic concurrency, returning the
52
52
  * committed record on success or `undefined` if the stream moved past
@@ -1 +1 @@
1
- {"version":3,"file":"event-sourcing.d.ts","sourceRoot":"","sources":["../../../src/internal/event-sourcing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event-sourcing.d.ts","sourceRoot":"","sources":["../../../src/internal/event-sourcing.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -3024,7 +3024,7 @@ var DEFAULT_BATCH = 500;
3024
3024
  async function snap(snapshot) {
3025
3025
  const { id, stream, name, meta, version } = snapshot.event;
3026
3026
  try {
3027
- await store2().commit(
3027
+ const [committed] = await store2().commit(
3028
3028
  stream,
3029
3029
  [{ name: SNAP_EVENT, data: snapshot.state }],
3030
3030
  {
@@ -3034,6 +3034,7 @@ async function snap(snapshot) {
3034
3034
  version
3035
3035
  // IMPORTANT! - state events are committed right after the snapshot event
3036
3036
  );
3037
+ return committed;
3037
3038
  } catch (error) {
3038
3039
  const reason = error instanceof Error ? error.message : String(error);
3039
3040
  log().warn(
@@ -3246,7 +3247,7 @@ async function action(me, action2, target, payload, options) {
3246
3247
  const snapshot = await load(me, { stream, actor: target.actor });
3247
3248
  if (snapshot.event?.name === TOMBSTONE_EVENT)
3248
3249
  throw new StreamClosedError(stream);
3249
- const expected = expectedVersion ?? snapshot.event?.version;
3250
+ const expected = expectedVersion ?? (snapshot.version >= 0 ? snapshot.version : void 0);
3250
3251
  if (me.given) {
3251
3252
  const invariants = me.given[action2] || [];
3252
3253
  invariants.forEach(({ valid: valid2, description }) => {
@@ -3328,18 +3329,22 @@ async function action(me, action2, target, payload, options) {
3328
3329
  };
3329
3330
  });
3330
3331
  const last = snapshots.at(-1);
3331
- const snapped = me.snap?.(last);
3332
+ const contiguous = committed[0].version === snapshot.version + 1;
3333
+ const snapped = contiguous && me.snap?.(last);
3334
+ const snap_event = snapped ? await snap(last) : void 0;
3332
3335
  if (!me.pii_aware) {
3333
- cache2().set(stream, {
3334
- stream,
3335
- state: last.state,
3336
- version: last.event.version,
3337
- event_id: last.event.id,
3338
- patches: snapped ? 0 : last.patches,
3339
- snaps: snapped ? last.snaps + 1 : last.snaps
3340
- }).catch((err) => log().error(err));
3336
+ if (contiguous)
3337
+ cache2().set(stream, {
3338
+ stream,
3339
+ state: last.state,
3340
+ version: snap_event?.version ?? last.event.version,
3341
+ event_id: snap_event?.id ?? last.event.id,
3342
+ patches: snap_event ? 0 : last.patches,
3343
+ snaps: snap_event ? last.snaps + 1 : last.snaps
3344
+ }).catch((err) => log().error(err));
3345
+ else
3346
+ cache2().invalidate(stream).catch((err) => log().error(err));
3341
3347
  }
3342
- if (snapped) void snap(last);
3343
3348
  return snapshots;
3344
3349
  } catch (error) {
3345
3350
  if (!(error instanceof ConcurrencyError)) throw error;
@@ -5208,6 +5213,7 @@ function act() {
5208
5213
  autoclose_archiver: (state_name) => _aa.get(state_name) ?? null
5209
5214
  };
5210
5215
  const pending_projections = [];
5216
+ const fold_projections = [];
5211
5217
  const batch_handlers = /* @__PURE__ */ new Map();
5212
5218
  const lanes = [];
5213
5219
  let _built = false;
@@ -5273,6 +5279,8 @@ function act() {
5273
5279
  withProjection: (proj) => {
5274
5280
  merge_projection(proj, registry.events);
5275
5281
  register_batch_handler(proj, batch_handlers);
5282
+ if (proj.fold)
5283
+ fold_projections.push(proj);
5276
5284
  return builder;
5277
5285
  },
5278
5286
  withActor: () => builder,
@@ -5286,6 +5294,26 @@ function act() {
5286
5294
  for (const proj of pending_projections) {
5287
5295
  merge_projection(proj, registry.events);
5288
5296
  register_batch_handler(proj, batch_handlers);
5297
+ if (proj.fold) fold_projections.push(proj);
5298
+ }
5299
+ for (const proj of fold_projections) {
5300
+ const fold = proj.fold;
5301
+ const merged = states.get(fold.name);
5302
+ if (!merged)
5303
+ throw new Error(
5304
+ `State projection "${proj.target}" folds "${fold.name}", which is not registered \u2014 add it via withState/withSlice before build()`
5305
+ );
5306
+ const missing = Object.keys(merged.events).filter(
5307
+ (event_name) => !(event_name in proj.events)
5308
+ );
5309
+ if (missing.length > 0)
5310
+ throw new Error(
5311
+ `State projection "${proj.target}" of "${fold.name}" is missing events ${missing.join(", ")} \u2014 pass every partial of the state to .of()`
5312
+ );
5313
+ batch_handlers.set(
5314
+ proj.target,
5315
+ make_fold_handler(merged, fold.flush, fold.config)
5316
+ );
5289
5317
  }
5290
5318
  finalize_deprecations();
5291
5319
  validate_lane_references(registry, lanes);
@@ -5428,39 +5456,52 @@ function _projection(target) {
5428
5456
  batchHandler: handler
5429
5457
  })
5430
5458
  }),
5431
- of: (state2, options = {}) => {
5459
+ of: (...args) => {
5432
5460
  if (Object.keys(events).length > 0)
5433
5461
  throw new Error(
5434
5462
  `Projection "${target}" mixes .of() with .on() handlers \u2014 a projection either folds a state or declares handlers, never both`
5435
5463
  );
5464
+ const is_state = (a) => !!a && typeof a.init === "function";
5465
+ const partials = args.filter(is_state);
5466
+ const options = args.find((a) => !is_state(a)) ?? {};
5467
+ if (partials.length === 0)
5468
+ throw new Error(`Projection "${target}" .of() requires a state`);
5469
+ const name = partials[0].name;
5470
+ for (const partial of partials)
5471
+ if (partial.name !== name)
5472
+ throw new Error(
5473
+ `Projection "${target}" .of() partials must share one state name \u2014 got "${name}" and "${partial.name}"`
5474
+ );
5436
5475
  const config2 = resolveFoldConfig(options);
5437
5476
  const fold_events = {};
5438
- for (const [name, schema] of Object.entries(state2.events)) {
5439
- const noop2 = {
5440
- [`${target}_fold`]: async () => {
5441
- }
5442
- }[`${target}_fold`];
5443
- fold_events[name] = {
5444
- schema,
5445
- reactions: /* @__PURE__ */ new Map([
5446
- [
5447
- `${target}_fold`,
5448
- {
5449
- handler: noop2,
5450
- resolver: { target },
5451
- options: { blockOnError: true, maxRetries: 3 }
5452
- }
5453
- ]
5454
- ])
5455
- };
5456
- }
5477
+ for (const partial of partials)
5478
+ for (const [event_name, schema] of Object.entries(partial.events)) {
5479
+ if (event_name in fold_events) continue;
5480
+ const noop2 = {
5481
+ [`${target}_fold`]: async () => {
5482
+ }
5483
+ }[`${target}_fold`];
5484
+ fold_events[event_name] = {
5485
+ schema,
5486
+ reactions: /* @__PURE__ */ new Map([
5487
+ [
5488
+ `${target}_fold`,
5489
+ {
5490
+ handler: noop2,
5491
+ resolver: { target },
5492
+ options: { blockOnError: true, maxRetries: 3 }
5493
+ }
5494
+ ]
5495
+ ])
5496
+ };
5497
+ }
5457
5498
  return {
5458
5499
  flush: (handler) => ({
5459
5500
  build: () => ({
5460
5501
  _tag: "Projection",
5461
5502
  events: fold_events,
5462
5503
  target,
5463
- batchHandler: make_fold_handler(state2, handler, config2)
5504
+ fold: { name, flush: handler, config: config2 }
5464
5505
  })
5465
5506
  })
5466
5507
  };