@rotorsoft/act 0.9.0 → 0.10.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
@@ -1361,6 +1361,70 @@ var _this_ = ({ stream }) => ({
1361
1361
  });
1362
1362
  var _void_ = () => void 0;
1363
1363
 
1364
+ // src/projection-builder.ts
1365
+ function isProjection(x) {
1366
+ return x != null && x._tag === "Projection";
1367
+ }
1368
+ function projection(target, events = {}) {
1369
+ const defaultResolver = target ? { target } : void 0;
1370
+ const builder = {
1371
+ on: (entry) => {
1372
+ const keys = Object.keys(entry);
1373
+ if (keys.length !== 1) throw new Error(".on() requires exactly one key");
1374
+ const event = keys[0];
1375
+ const schema = entry[event];
1376
+ if (!(event in events)) {
1377
+ events[event] = {
1378
+ schema,
1379
+ reactions: /* @__PURE__ */ new Map()
1380
+ };
1381
+ }
1382
+ return {
1383
+ do: (handler) => {
1384
+ const reaction = {
1385
+ handler,
1386
+ resolver: defaultResolver ?? _this_,
1387
+ options: {
1388
+ blockOnError: true,
1389
+ maxRetries: 3
1390
+ }
1391
+ };
1392
+ const register = events[event];
1393
+ const name = handler.name || `${event}_${register.reactions.size}`;
1394
+ register.reactions.set(name, reaction);
1395
+ const nextBuilder = projection(
1396
+ target,
1397
+ events
1398
+ );
1399
+ return {
1400
+ ...nextBuilder,
1401
+ to(resolver) {
1402
+ register.reactions.set(name, {
1403
+ ...reaction,
1404
+ resolver: typeof resolver === "string" ? { target: resolver } : resolver
1405
+ });
1406
+ return nextBuilder;
1407
+ },
1408
+ void() {
1409
+ register.reactions.set(name, {
1410
+ ...reaction,
1411
+ resolver: _void_
1412
+ });
1413
+ return nextBuilder;
1414
+ }
1415
+ };
1416
+ }
1417
+ };
1418
+ },
1419
+ build: () => ({
1420
+ _tag: "Projection",
1421
+ events
1422
+ }),
1423
+ events
1424
+ };
1425
+ return builder;
1426
+ }
1427
+
1364
1428
  // src/slice-builder.ts
1365
1429
  function isSlice(x) {
1366
1430
  return x != null && x._tag === "Slice";
@@ -1419,6 +1483,25 @@ function act(states = /* @__PURE__ */ new Map(), registry = {
1419
1483
  }) {
1420
1484
  const builder = {
1421
1485
  with: ((input) => {
1486
+ if (isProjection(input)) {
1487
+ for (const eventName of Object.keys(input.events)) {
1488
+ const projRegister = input.events[eventName];
1489
+ const existing = registry.events[eventName];
1490
+ if (!existing) {
1491
+ registry.events[eventName] = {
1492
+ schema: projRegister.schema,
1493
+ reactions: new Map(projRegister.reactions)
1494
+ };
1495
+ } else {
1496
+ for (const [name, reaction] of projRegister.reactions) {
1497
+ let key = name;
1498
+ while (existing.reactions.has(key)) key = `${key}_p`;
1499
+ existing.reactions.set(key, reaction);
1500
+ }
1501
+ }
1502
+ }
1503
+ return act(states, registry);
1504
+ }
1422
1505
  if (isSlice(input)) {
1423
1506
  for (const s of input.states.values()) {
1424
1507
  registerState(s, states, registry.actions, registry.events);
@@ -1504,7 +1587,11 @@ function state(name, state2) {
1504
1587
  }
1505
1588
  function action_builder(state2) {
1506
1589
  return {
1507
- on(action2, schema) {
1590
+ on(entry) {
1591
+ const keys = Object.keys(entry);
1592
+ if (keys.length !== 1) throw new Error(".on() requires exactly one key");
1593
+ const action2 = keys[0];
1594
+ const schema = entry[action2];
1508
1595
  if (action2 in state2.actions)
1509
1596
  throw new Error(`Duplicate action "${action2}"`);
1510
1597
  const actions = { ...state2.actions, [action2]: schema };
@@ -1557,10 +1644,12 @@ export {
1557
1644
  dispose,
1558
1645
  disposeAndExit,
1559
1646
  extend,
1647
+ isProjection,
1560
1648
  isSlice,
1561
1649
  logger,
1562
1650
  patch,
1563
1651
  port,
1652
+ projection,
1564
1653
  sleep,
1565
1654
  slice,
1566
1655
  state,