@rotorsoft/act 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -564,6 +564,9 @@ process.once("unhandledRejection", async (arg) => {
564
564
  await disposeAndExit("ERROR");
565
565
  });
566
566
 
567
+ // src/act-builder.ts
568
+ import { ZodObject as ZodObject2 } from "zod";
569
+
567
570
  // src/act.ts
568
571
  import { randomUUID as randomUUID2 } from "crypto";
569
572
  import EventEmitter from "events";
@@ -811,47 +814,15 @@ var Act = class {
811
814
  this.emit("committed", snapshots);
812
815
  return snapshots;
813
816
  }
814
- /**
815
- * Loads the current state snapshot for a specific stream.
816
- *
817
- * Reconstructs the current state by replaying events from the event store.
818
- * Uses snapshots when available to optimize loading performance.
819
- *
820
- * @template SX - State schema type
821
- * @template EX - Event schemas type
822
- * @template AX - Action schemas type
823
- * @param state - The state definition to load
824
- * @param stream - The stream ID (state instance identifier)
825
- * @param callback - Optional callback invoked with the loaded snapshot
826
- * @returns The current state snapshot for the stream
827
- *
828
- * @example Load current state
829
- * ```typescript
830
- * const snapshot = await app.load(Counter, "counter-1");
831
- * console.log(snapshot.state.count); // Current count
832
- * console.log(snapshot.version); // Number of events applied
833
- * console.log(snapshot.patches); // Events since last snapshot
834
- * ```
835
- *
836
- * @example With callback
837
- * ```typescript
838
- * const snapshot = await app.load(User, "user-123", (snap) => {
839
- * console.log("Loaded user:", snap.state.name);
840
- * });
841
- * ```
842
- *
843
- * @example Load multiple states
844
- * ```typescript
845
- * const [user, account] = await Promise.all([
846
- * app.load(User, "user-123"),
847
- * app.load(BankAccount, "account-456")
848
- * ]);
849
- * ```
850
- *
851
- * @see {@link Snapshot} for snapshot structure
852
- */
853
- async load(state2, stream, callback) {
854
- const merged = this._states.get(state2.name) || state2;
817
+ async load(stateOrName, stream, callback) {
818
+ let merged;
819
+ if (typeof stateOrName === "string") {
820
+ const found = this._states.get(stateOrName);
821
+ if (!found) throw new Error(`State "${stateOrName}" not found`);
822
+ merged = found;
823
+ } else {
824
+ merged = this._states.get(stateOrName.name) || stateOrName;
825
+ }
855
826
  return await load(merged, stream, callback);
856
827
  }
857
828
  /**
@@ -1077,7 +1048,8 @@ var Act = class {
1077
1048
  );
1078
1049
  fetched.forEach(({ stream, lagging: lagging2, events }) => {
1079
1050
  const payloads = events.flatMap((event) => {
1080
- const register = this.registry.events[event.name] || [];
1051
+ const register = this.registry.events[event.name];
1052
+ if (!register) return [];
1081
1053
  return [...register.reactions.values()].filter((reaction) => {
1082
1054
  const resolved = typeof reaction.resolver === "function" ? reaction.resolver(event) : reaction.resolver;
1083
1055
  return resolved && resolved.target === stream;
@@ -1310,6 +1282,35 @@ var Act = class {
1310
1282
  };
1311
1283
 
1312
1284
  // src/act-builder.ts
1285
+ function baseTypeName(zodType) {
1286
+ let t = zodType;
1287
+ while (typeof t.unwrap === "function") {
1288
+ t = t.unwrap();
1289
+ }
1290
+ return t.constructor.name;
1291
+ }
1292
+ function mergeSchemas(existing, incoming, stateName) {
1293
+ if (existing instanceof ZodObject2 && incoming instanceof ZodObject2) {
1294
+ const existingShape = existing.shape;
1295
+ const incomingShape = incoming.shape;
1296
+ for (const key of Object.keys(incomingShape)) {
1297
+ if (key in existingShape) {
1298
+ const existingBase = baseTypeName(existingShape[key]);
1299
+ const incomingBase = baseTypeName(incomingShape[key]);
1300
+ if (existingBase !== incomingBase) {
1301
+ throw new Error(
1302
+ `Schema conflict in "${stateName}": key "${key}" has type "${existingBase}" but incoming partial declares "${incomingBase}"`
1303
+ );
1304
+ }
1305
+ }
1306
+ }
1307
+ return existing.extend(incomingShape);
1308
+ }
1309
+ return existing;
1310
+ }
1311
+ function mergeInits(existing, incoming) {
1312
+ return () => ({ ...existing(), ...incoming() });
1313
+ }
1313
1314
  var _this_ = ({ stream }) => ({
1314
1315
  source: stream,
1315
1316
  target: stream
@@ -1344,6 +1345,8 @@ function act(states = /* @__PURE__ */ new Map(), registry = {
1344
1345
  }
1345
1346
  const merged = {
1346
1347
  ...existing,
1348
+ state: mergeSchemas(existing.state, state2.state, state2.name),
1349
+ init: mergeInits(existing.init, state2.init),
1347
1350
  events: { ...existing.events, ...state2.events },
1348
1351
  actions: { ...existing.actions, ...state2.actions },
1349
1352
  patch: { ...existing.patch, ...state2.patch },