@rotorsoft/act 0.7.0 → 0.9.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/.tsbuildinfo +1 -1
- package/dist/@types/act-builder.d.ts +35 -223
- package/dist/@types/act-builder.d.ts.map +1 -1
- package/dist/@types/act.d.ts +13 -10
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/index.d.ts +1 -0
- package/dist/@types/index.d.ts.map +1 -1
- package/dist/@types/merge.d.ts +38 -0
- package/dist/@types/merge.d.ts.map +1 -0
- package/dist/@types/slice-builder.d.ts +107 -0
- package/dist/@types/slice-builder.d.ts.map +1 -0
- package/dist/@types/state-builder.d.ts +9 -9
- package/dist/@types/state-builder.d.ts.map +1 -1
- package/dist/@types/types/action.d.ts +47 -2
- package/dist/@types/types/action.d.ts.map +1 -1
- package/dist/@types/types/reaction.d.ts +1 -1
- package/dist/@types/types/reaction.d.ts.map +1 -1
- package/dist/index.cjs +165 -108
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +163 -108
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -804,54 +804,21 @@ var Act = class {
|
|
|
804
804
|
action2,
|
|
805
805
|
target,
|
|
806
806
|
payload,
|
|
807
|
-
// @ts-expect-error type lost
|
|
808
807
|
reactingTo,
|
|
809
808
|
skipValidation
|
|
810
809
|
);
|
|
811
810
|
this.emit("committed", snapshots);
|
|
812
811
|
return snapshots;
|
|
813
812
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
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;
|
|
813
|
+
async load(stateOrName, stream, callback) {
|
|
814
|
+
let merged;
|
|
815
|
+
if (typeof stateOrName === "string") {
|
|
816
|
+
const found = this._states.get(stateOrName);
|
|
817
|
+
if (!found) throw new Error(`State "${stateOrName}" not found`);
|
|
818
|
+
merged = found;
|
|
819
|
+
} else {
|
|
820
|
+
merged = this._states.get(stateOrName.name) || stateOrName;
|
|
821
|
+
}
|
|
855
822
|
return await load(merged, stream, callback);
|
|
856
823
|
}
|
|
857
824
|
/**
|
|
@@ -964,7 +931,7 @@ var Act = class {
|
|
|
964
931
|
for (const payload of payloads) {
|
|
965
932
|
const { event, handler, options } = payload;
|
|
966
933
|
try {
|
|
967
|
-
await handler(event, stream);
|
|
934
|
+
await handler(event, stream, this);
|
|
968
935
|
at = event.id;
|
|
969
936
|
handled++;
|
|
970
937
|
} catch (error) {
|
|
@@ -1077,7 +1044,8 @@ var Act = class {
|
|
|
1077
1044
|
);
|
|
1078
1045
|
fetched.forEach(({ stream, lagging: lagging2, events }) => {
|
|
1079
1046
|
const payloads = events.flatMap((event) => {
|
|
1080
|
-
const register = this.registry.events[event.name]
|
|
1047
|
+
const register = this.registry.events[event.name];
|
|
1048
|
+
if (!register) return [];
|
|
1081
1049
|
return [...register.reactions.values()].filter((reaction) => {
|
|
1082
1050
|
const resolved = typeof reaction.resolver === "function" ? reaction.resolver(event) : reaction.resolver;
|
|
1083
1051
|
return resolved && resolved.target === stream;
|
|
@@ -1092,7 +1060,6 @@ var Act = class {
|
|
|
1092
1060
|
retry: 0,
|
|
1093
1061
|
lagging: lagging2
|
|
1094
1062
|
},
|
|
1095
|
-
// @ts-expect-error indexed by key
|
|
1096
1063
|
payloads
|
|
1097
1064
|
});
|
|
1098
1065
|
});
|
|
@@ -1309,79 +1276,164 @@ var Act = class {
|
|
|
1309
1276
|
}
|
|
1310
1277
|
};
|
|
1311
1278
|
|
|
1312
|
-
// src/
|
|
1279
|
+
// src/merge.ts
|
|
1280
|
+
import { ZodObject as ZodObject2 } from "zod";
|
|
1281
|
+
function baseTypeName(zodType) {
|
|
1282
|
+
let t = zodType;
|
|
1283
|
+
while (typeof t.unwrap === "function") {
|
|
1284
|
+
t = t.unwrap();
|
|
1285
|
+
}
|
|
1286
|
+
return t.constructor.name;
|
|
1287
|
+
}
|
|
1288
|
+
function mergeSchemas(existing, incoming, stateName) {
|
|
1289
|
+
if (existing instanceof ZodObject2 && incoming instanceof ZodObject2) {
|
|
1290
|
+
const existingShape = existing.shape;
|
|
1291
|
+
const incomingShape = incoming.shape;
|
|
1292
|
+
for (const key of Object.keys(incomingShape)) {
|
|
1293
|
+
if (key in existingShape) {
|
|
1294
|
+
const existingBase = baseTypeName(existingShape[key]);
|
|
1295
|
+
const incomingBase = baseTypeName(incomingShape[key]);
|
|
1296
|
+
if (existingBase !== incomingBase) {
|
|
1297
|
+
throw new Error(
|
|
1298
|
+
`Schema conflict in "${stateName}": key "${key}" has type "${existingBase}" but incoming partial declares "${incomingBase}"`
|
|
1299
|
+
);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
return existing.extend(incomingShape);
|
|
1304
|
+
}
|
|
1305
|
+
return existing;
|
|
1306
|
+
}
|
|
1307
|
+
function mergeInits(existing, incoming) {
|
|
1308
|
+
return () => ({ ...existing(), ...incoming() });
|
|
1309
|
+
}
|
|
1310
|
+
function registerState(state2, states, actions, events) {
|
|
1311
|
+
if (states.has(state2.name)) {
|
|
1312
|
+
const existing = states.get(state2.name);
|
|
1313
|
+
for (const name of Object.keys(state2.actions)) {
|
|
1314
|
+
if (existing.actions[name] === state2.actions[name]) continue;
|
|
1315
|
+
if (actions[name]) throw new Error(`Duplicate action "${name}"`);
|
|
1316
|
+
}
|
|
1317
|
+
for (const name of Object.keys(state2.events)) {
|
|
1318
|
+
if (existing.events[name] === state2.events[name]) continue;
|
|
1319
|
+
if (events[name]) throw new Error(`Duplicate event "${name}"`);
|
|
1320
|
+
}
|
|
1321
|
+
const merged = {
|
|
1322
|
+
...existing,
|
|
1323
|
+
state: mergeSchemas(existing.state, state2.state, state2.name),
|
|
1324
|
+
init: mergeInits(existing.init, state2.init),
|
|
1325
|
+
events: { ...existing.events, ...state2.events },
|
|
1326
|
+
actions: { ...existing.actions, ...state2.actions },
|
|
1327
|
+
patch: { ...existing.patch, ...state2.patch },
|
|
1328
|
+
on: { ...existing.on, ...state2.on },
|
|
1329
|
+
given: { ...existing.given, ...state2.given },
|
|
1330
|
+
snap: state2.snap || existing.snap
|
|
1331
|
+
};
|
|
1332
|
+
states.set(state2.name, merged);
|
|
1333
|
+
for (const name of Object.keys(merged.actions)) {
|
|
1334
|
+
actions[name] = merged;
|
|
1335
|
+
}
|
|
1336
|
+
for (const name of Object.keys(state2.events)) {
|
|
1337
|
+
if (events[name]) continue;
|
|
1338
|
+
events[name] = {
|
|
1339
|
+
schema: state2.events[name],
|
|
1340
|
+
reactions: /* @__PURE__ */ new Map()
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
} else {
|
|
1344
|
+
states.set(state2.name, state2);
|
|
1345
|
+
for (const name of Object.keys(state2.actions)) {
|
|
1346
|
+
if (actions[name]) throw new Error(`Duplicate action "${name}"`);
|
|
1347
|
+
actions[name] = state2;
|
|
1348
|
+
}
|
|
1349
|
+
for (const name of Object.keys(state2.events)) {
|
|
1350
|
+
if (events[name]) throw new Error(`Duplicate event "${name}"`);
|
|
1351
|
+
events[name] = {
|
|
1352
|
+
schema: state2.events[name],
|
|
1353
|
+
reactions: /* @__PURE__ */ new Map()
|
|
1354
|
+
};
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1313
1358
|
var _this_ = ({ stream }) => ({
|
|
1314
1359
|
source: stream,
|
|
1315
1360
|
target: stream
|
|
1316
1361
|
});
|
|
1317
1362
|
var _void_ = () => void 0;
|
|
1363
|
+
|
|
1364
|
+
// src/slice-builder.ts
|
|
1365
|
+
function isSlice(x) {
|
|
1366
|
+
return x != null && x._tag === "Slice";
|
|
1367
|
+
}
|
|
1368
|
+
function slice(states = /* @__PURE__ */ new Map(), actions = {}, events = {}) {
|
|
1369
|
+
const builder = {
|
|
1370
|
+
with: (state2) => {
|
|
1371
|
+
registerState(state2, states, actions, events);
|
|
1372
|
+
return slice(states, actions, events);
|
|
1373
|
+
},
|
|
1374
|
+
on: (event) => ({
|
|
1375
|
+
do: (handler, options) => {
|
|
1376
|
+
const reaction = {
|
|
1377
|
+
handler,
|
|
1378
|
+
resolver: _this_,
|
|
1379
|
+
options: {
|
|
1380
|
+
blockOnError: options?.blockOnError ?? true,
|
|
1381
|
+
maxRetries: options?.maxRetries ?? 3
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
const name = handler.name || `${String(event)}_${events[event].reactions.size}`;
|
|
1385
|
+
events[event].reactions.set(name, reaction);
|
|
1386
|
+
return {
|
|
1387
|
+
...builder,
|
|
1388
|
+
to(resolver) {
|
|
1389
|
+
events[event].reactions.set(name, {
|
|
1390
|
+
...reaction,
|
|
1391
|
+
resolver: typeof resolver === "string" ? { target: resolver } : resolver
|
|
1392
|
+
});
|
|
1393
|
+
return builder;
|
|
1394
|
+
},
|
|
1395
|
+
void() {
|
|
1396
|
+
events[event].reactions.set(name, {
|
|
1397
|
+
...reaction,
|
|
1398
|
+
resolver: _void_
|
|
1399
|
+
});
|
|
1400
|
+
return builder;
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
}),
|
|
1405
|
+
build: () => ({
|
|
1406
|
+
_tag: "Slice",
|
|
1407
|
+
states,
|
|
1408
|
+
events
|
|
1409
|
+
}),
|
|
1410
|
+
events
|
|
1411
|
+
};
|
|
1412
|
+
return builder;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
// src/act-builder.ts
|
|
1318
1416
|
function act(states = /* @__PURE__ */ new Map(), registry = {
|
|
1319
1417
|
actions: {},
|
|
1320
1418
|
events: {}
|
|
1321
1419
|
}) {
|
|
1322
1420
|
const builder = {
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
*
|
|
1328
|
-
* @template SX The type of state
|
|
1329
|
-
* @template EX The type of events
|
|
1330
|
-
* @template AX The type of actions
|
|
1331
|
-
* @param state The state to add
|
|
1332
|
-
* @returns The builder
|
|
1333
|
-
*/
|
|
1334
|
-
with: (state2) => {
|
|
1335
|
-
if (states.has(state2.name)) {
|
|
1336
|
-
const existing = states.get(state2.name);
|
|
1337
|
-
for (const name of Object.keys(state2.actions)) {
|
|
1338
|
-
if (registry.actions[name])
|
|
1339
|
-
throw new Error(`Duplicate action "${name}"`);
|
|
1421
|
+
with: ((input) => {
|
|
1422
|
+
if (isSlice(input)) {
|
|
1423
|
+
for (const s of input.states.values()) {
|
|
1424
|
+
registerState(s, states, registry.actions, registry.events);
|
|
1340
1425
|
}
|
|
1341
|
-
for (const
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
...existing,
|
|
1347
|
-
events: { ...existing.events, ...state2.events },
|
|
1348
|
-
actions: { ...existing.actions, ...state2.actions },
|
|
1349
|
-
patch: { ...existing.patch, ...state2.patch },
|
|
1350
|
-
on: { ...existing.on, ...state2.on },
|
|
1351
|
-
given: { ...existing.given, ...state2.given },
|
|
1352
|
-
snap: state2.snap || existing.snap
|
|
1353
|
-
};
|
|
1354
|
-
states.set(state2.name, merged);
|
|
1355
|
-
for (const name of Object.keys(merged.actions)) {
|
|
1356
|
-
registry.actions[name] = merged;
|
|
1357
|
-
}
|
|
1358
|
-
for (const name of Object.keys(state2.events)) {
|
|
1359
|
-
registry.events[name] = {
|
|
1360
|
-
schema: state2.events[name],
|
|
1361
|
-
reactions: /* @__PURE__ */ new Map()
|
|
1362
|
-
};
|
|
1363
|
-
}
|
|
1364
|
-
} else {
|
|
1365
|
-
states.set(state2.name, state2);
|
|
1366
|
-
for (const name of Object.keys(state2.actions)) {
|
|
1367
|
-
if (registry.actions[name])
|
|
1368
|
-
throw new Error(`Duplicate action "${name}"`);
|
|
1369
|
-
registry.actions[name] = state2;
|
|
1370
|
-
}
|
|
1371
|
-
for (const name of Object.keys(state2.events)) {
|
|
1372
|
-
if (registry.events[name])
|
|
1373
|
-
throw new Error(`Duplicate event "${name}"`);
|
|
1374
|
-
registry.events[name] = {
|
|
1375
|
-
schema: state2.events[name],
|
|
1376
|
-
reactions: /* @__PURE__ */ new Map()
|
|
1377
|
-
};
|
|
1426
|
+
for (const eventName of Object.keys(input.events)) {
|
|
1427
|
+
const sliceRegister = input.events[eventName];
|
|
1428
|
+
for (const [name, reaction] of sliceRegister.reactions) {
|
|
1429
|
+
registry.events[eventName].reactions.set(name, reaction);
|
|
1430
|
+
}
|
|
1378
1431
|
}
|
|
1432
|
+
return act(states, registry);
|
|
1379
1433
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
);
|
|
1384
|
-
},
|
|
1434
|
+
registerState(input, states, registry.actions, registry.events);
|
|
1435
|
+
return act(states, registry);
|
|
1436
|
+
}),
|
|
1385
1437
|
/**
|
|
1386
1438
|
* Adds a reaction to an event.
|
|
1387
1439
|
*
|
|
@@ -1399,18 +1451,19 @@ function act(states = /* @__PURE__ */ new Map(), registry = {
|
|
|
1399
1451
|
maxRetries: options?.maxRetries ?? 3
|
|
1400
1452
|
}
|
|
1401
1453
|
};
|
|
1402
|
-
registry.events[event].reactions.
|
|
1454
|
+
const name = handler.name || `${String(event)}_${registry.events[event].reactions.size}`;
|
|
1455
|
+
registry.events[event].reactions.set(name, reaction);
|
|
1403
1456
|
return {
|
|
1404
1457
|
...builder,
|
|
1405
1458
|
to(resolver) {
|
|
1406
|
-
registry.events[event].reactions.set(
|
|
1459
|
+
registry.events[event].reactions.set(name, {
|
|
1407
1460
|
...reaction,
|
|
1408
1461
|
resolver: typeof resolver === "string" ? { target: resolver } : resolver
|
|
1409
1462
|
});
|
|
1410
1463
|
return builder;
|
|
1411
1464
|
},
|
|
1412
1465
|
void() {
|
|
1413
|
-
registry.events[event].reactions.set(
|
|
1466
|
+
registry.events[event].reactions.set(name, {
|
|
1414
1467
|
...reaction,
|
|
1415
1468
|
resolver: _void_
|
|
1416
1469
|
});
|
|
@@ -1504,10 +1557,12 @@ export {
|
|
|
1504
1557
|
dispose,
|
|
1505
1558
|
disposeAndExit,
|
|
1506
1559
|
extend,
|
|
1560
|
+
isSlice,
|
|
1507
1561
|
logger,
|
|
1508
1562
|
patch,
|
|
1509
1563
|
port,
|
|
1510
1564
|
sleep,
|
|
1565
|
+
slice,
|
|
1511
1566
|
state,
|
|
1512
1567
|
store,
|
|
1513
1568
|
validate
|