@playfast/reform 0.0.1

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.
Files changed (204) hide show
  1. package/README.md +64 -0
  2. package/dist/cjs/boundary/boundary.js +86 -0
  3. package/dist/cjs/calc/asyncCalc.js +128 -0
  4. package/dist/cjs/calc/asyncData.js +37 -0
  5. package/dist/cjs/calc/calc.js +58 -0
  6. package/dist/cjs/calc/calcFamily.js +127 -0
  7. package/dist/cjs/channel/channel.js +142 -0
  8. package/dist/cjs/compose/composition.js +50 -0
  9. package/dist/cjs/compose/host.js +8 -0
  10. package/dist/cjs/compose/props.js +14 -0
  11. package/dist/cjs/compose/provide.js +30 -0
  12. package/dist/cjs/compose/slot.js +27 -0
  13. package/dist/cjs/compose/ui.js +61 -0
  14. package/dist/cjs/definition/definition.js +46 -0
  15. package/dist/cjs/event/event.js +36 -0
  16. package/dist/cjs/event/eventGroup.js +7 -0
  17. package/dist/cjs/feature/feature.js +102 -0
  18. package/dist/cjs/index.js +116 -0
  19. package/dist/cjs/internal/capture.js +14 -0
  20. package/dist/cjs/internal/ctx.js +2 -0
  21. package/dist/cjs/internal/errors.js +62 -0
  22. package/dist/cjs/internal/inspect.js +36 -0
  23. package/dist/cjs/internal/queryDriver.js +138 -0
  24. package/dist/cjs/internal/reuse.js +71 -0
  25. package/dist/cjs/internal/scheduler.js +73 -0
  26. package/dist/cjs/internal/seeds.js +19 -0
  27. package/dist/cjs/internal/sources.js +61 -0
  28. package/dist/cjs/internal/store.js +77 -0
  29. package/dist/cjs/internal/track.js +22 -0
  30. package/dist/cjs/package.json +4 -0
  31. package/dist/cjs/procedure/procedure.js +52 -0
  32. package/dist/cjs/reducer/reducer.js +64 -0
  33. package/dist/cjs/remote/remoteState.js +307 -0
  34. package/dist/cjs/runtime/bus.js +25 -0
  35. package/dist/cjs/runtime/loop.js +119 -0
  36. package/dist/cjs/scene/scene.js +36 -0
  37. package/dist/cjs/state/state.js +47 -0
  38. package/dist/cjs/state/stateFamily.js +101 -0
  39. package/dist/cjs/state/stateGroup.js +47 -0
  40. package/dist/cjs/state/token.js +23 -0
  41. package/dist/cjs/ui/node.js +2 -0
  42. package/dist/cjs/ui/trigger.js +2 -0
  43. package/dist/dts/boundary/boundary.d.ts +72 -0
  44. package/dist/dts/boundary/boundary.d.ts.map +1 -0
  45. package/dist/dts/calc/asyncCalc.d.ts +91 -0
  46. package/dist/dts/calc/asyncCalc.d.ts.map +1 -0
  47. package/dist/dts/calc/asyncData.d.ts +55 -0
  48. package/dist/dts/calc/asyncData.d.ts.map +1 -0
  49. package/dist/dts/calc/calc.d.ts +57 -0
  50. package/dist/dts/calc/calc.d.ts.map +1 -0
  51. package/dist/dts/calc/calcFamily.d.ts +57 -0
  52. package/dist/dts/calc/calcFamily.d.ts.map +1 -0
  53. package/dist/dts/channel/channel.d.ts +115 -0
  54. package/dist/dts/channel/channel.d.ts.map +1 -0
  55. package/dist/dts/compose/composition.d.ts +72 -0
  56. package/dist/dts/compose/composition.d.ts.map +1 -0
  57. package/dist/dts/compose/host.d.ts +17 -0
  58. package/dist/dts/compose/host.d.ts.map +1 -0
  59. package/dist/dts/compose/props.d.ts +13 -0
  60. package/dist/dts/compose/props.d.ts.map +1 -0
  61. package/dist/dts/compose/provide.d.ts +22 -0
  62. package/dist/dts/compose/provide.d.ts.map +1 -0
  63. package/dist/dts/compose/slot.d.ts +49 -0
  64. package/dist/dts/compose/slot.d.ts.map +1 -0
  65. package/dist/dts/compose/ui.d.ts +50 -0
  66. package/dist/dts/compose/ui.d.ts.map +1 -0
  67. package/dist/dts/definition/definition.d.ts +33 -0
  68. package/dist/dts/definition/definition.d.ts.map +1 -0
  69. package/dist/dts/event/event.d.ts +33 -0
  70. package/dist/dts/event/event.d.ts.map +1 -0
  71. package/dist/dts/event/eventGroup.d.ts +9 -0
  72. package/dist/dts/event/eventGroup.d.ts.map +1 -0
  73. package/dist/dts/feature/feature.d.ts +220 -0
  74. package/dist/dts/feature/feature.d.ts.map +1 -0
  75. package/dist/dts/index.d.ts +43 -0
  76. package/dist/dts/index.d.ts.map +1 -0
  77. package/dist/dts/internal/capture.d.ts +28 -0
  78. package/dist/dts/internal/capture.d.ts.map +1 -0
  79. package/dist/dts/internal/ctx.d.ts +12 -0
  80. package/dist/dts/internal/ctx.d.ts.map +1 -0
  81. package/dist/dts/internal/errors.d.ts +69 -0
  82. package/dist/dts/internal/errors.d.ts.map +1 -0
  83. package/dist/dts/internal/inspect.d.ts +17 -0
  84. package/dist/dts/internal/inspect.d.ts.map +1 -0
  85. package/dist/dts/internal/queryDriver.d.ts +65 -0
  86. package/dist/dts/internal/queryDriver.d.ts.map +1 -0
  87. package/dist/dts/internal/reuse.d.ts +10 -0
  88. package/dist/dts/internal/reuse.d.ts.map +1 -0
  89. package/dist/dts/internal/scheduler.d.ts +47 -0
  90. package/dist/dts/internal/scheduler.d.ts.map +1 -0
  91. package/dist/dts/internal/seeds.d.ts +17 -0
  92. package/dist/dts/internal/seeds.d.ts.map +1 -0
  93. package/dist/dts/internal/sources.d.ts +39 -0
  94. package/dist/dts/internal/sources.d.ts.map +1 -0
  95. package/dist/dts/internal/store.d.ts +47 -0
  96. package/dist/dts/internal/store.d.ts.map +1 -0
  97. package/dist/dts/internal/track.d.ts +33 -0
  98. package/dist/dts/internal/track.d.ts.map +1 -0
  99. package/dist/dts/procedure/procedure.d.ts +40 -0
  100. package/dist/dts/procedure/procedure.d.ts.map +1 -0
  101. package/dist/dts/reducer/reducer.d.ts +44 -0
  102. package/dist/dts/reducer/reducer.d.ts.map +1 -0
  103. package/dist/dts/remote/remoteState.d.ts +119 -0
  104. package/dist/dts/remote/remoteState.d.ts.map +1 -0
  105. package/dist/dts/runtime/bus.d.ts +27 -0
  106. package/dist/dts/runtime/bus.d.ts.map +1 -0
  107. package/dist/dts/runtime/loop.d.ts +45 -0
  108. package/dist/dts/runtime/loop.d.ts.map +1 -0
  109. package/dist/dts/scene/scene.d.ts +44 -0
  110. package/dist/dts/scene/scene.d.ts.map +1 -0
  111. package/dist/dts/state/state.d.ts +37 -0
  112. package/dist/dts/state/state.d.ts.map +1 -0
  113. package/dist/dts/state/stateFamily.d.ts +79 -0
  114. package/dist/dts/state/stateFamily.d.ts.map +1 -0
  115. package/dist/dts/state/stateGroup.d.ts +36 -0
  116. package/dist/dts/state/stateGroup.d.ts.map +1 -0
  117. package/dist/dts/state/token.d.ts +30 -0
  118. package/dist/dts/state/token.d.ts.map +1 -0
  119. package/dist/dts/ui/node.d.ts +9 -0
  120. package/dist/dts/ui/node.d.ts.map +1 -0
  121. package/dist/dts/ui/trigger.d.ts +7 -0
  122. package/dist/dts/ui/trigger.d.ts.map +1 -0
  123. package/dist/esm/boundary/boundary.js +83 -0
  124. package/dist/esm/boundary/boundary.js.map +1 -0
  125. package/dist/esm/calc/asyncCalc.js +95 -0
  126. package/dist/esm/calc/asyncCalc.js.map +1 -0
  127. package/dist/esm/calc/asyncData.js +34 -0
  128. package/dist/esm/calc/asyncData.js.map +1 -0
  129. package/dist/esm/calc/calc.js +58 -0
  130. package/dist/esm/calc/calc.js.map +1 -0
  131. package/dist/esm/calc/calcFamily.js +124 -0
  132. package/dist/esm/calc/calcFamily.js.map +1 -0
  133. package/dist/esm/channel/channel.js +136 -0
  134. package/dist/esm/channel/channel.js.map +1 -0
  135. package/dist/esm/compose/composition.js +46 -0
  136. package/dist/esm/compose/composition.js.map +1 -0
  137. package/dist/esm/compose/host.js +5 -0
  138. package/dist/esm/compose/host.js.map +1 -0
  139. package/dist/esm/compose/props.js +11 -0
  140. package/dist/esm/compose/props.js.map +1 -0
  141. package/dist/esm/compose/provide.js +28 -0
  142. package/dist/esm/compose/provide.js.map +1 -0
  143. package/dist/esm/compose/slot.js +23 -0
  144. package/dist/esm/compose/slot.js.map +1 -0
  145. package/dist/esm/compose/ui.js +57 -0
  146. package/dist/esm/compose/ui.js.map +1 -0
  147. package/dist/esm/definition/definition.js +42 -0
  148. package/dist/esm/definition/definition.js.map +1 -0
  149. package/dist/esm/event/event.js +30 -0
  150. package/dist/esm/event/event.js.map +1 -0
  151. package/dist/esm/event/eventGroup.js +4 -0
  152. package/dist/esm/event/eventGroup.js.map +1 -0
  153. package/dist/esm/feature/feature.js +98 -0
  154. package/dist/esm/feature/feature.js.map +1 -0
  155. package/dist/esm/index.js +45 -0
  156. package/dist/esm/index.js.map +1 -0
  157. package/dist/esm/internal/capture.js +11 -0
  158. package/dist/esm/internal/capture.js.map +1 -0
  159. package/dist/esm/internal/ctx.js +2 -0
  160. package/dist/esm/internal/ctx.js.map +1 -0
  161. package/dist/esm/internal/errors.js +54 -0
  162. package/dist/esm/internal/errors.js.map +1 -0
  163. package/dist/esm/internal/inspect.js +32 -0
  164. package/dist/esm/internal/inspect.js.map +1 -0
  165. package/dist/esm/internal/queryDriver.js +134 -0
  166. package/dist/esm/internal/queryDriver.js.map +1 -0
  167. package/dist/esm/internal/reuse.js +68 -0
  168. package/dist/esm/internal/reuse.js.map +1 -0
  169. package/dist/esm/internal/scheduler.js +69 -0
  170. package/dist/esm/internal/scheduler.js.map +1 -0
  171. package/dist/esm/internal/seeds.js +17 -0
  172. package/dist/esm/internal/seeds.js.map +1 -0
  173. package/dist/esm/internal/sources.js +59 -0
  174. package/dist/esm/internal/sources.js.map +1 -0
  175. package/dist/esm/internal/store.js +73 -0
  176. package/dist/esm/internal/store.js.map +1 -0
  177. package/dist/esm/internal/track.js +18 -0
  178. package/dist/esm/internal/track.js.map +1 -0
  179. package/dist/esm/package.json +4 -0
  180. package/dist/esm/procedure/procedure.js +50 -0
  181. package/dist/esm/procedure/procedure.js.map +1 -0
  182. package/dist/esm/reducer/reducer.js +63 -0
  183. package/dist/esm/reducer/reducer.js.map +1 -0
  184. package/dist/esm/remote/remoteState.js +270 -0
  185. package/dist/esm/remote/remoteState.js.map +1 -0
  186. package/dist/esm/runtime/bus.js +20 -0
  187. package/dist/esm/runtime/bus.js.map +1 -0
  188. package/dist/esm/runtime/loop.js +116 -0
  189. package/dist/esm/runtime/loop.js.map +1 -0
  190. package/dist/esm/scene/scene.js +31 -0
  191. package/dist/esm/scene/scene.js.map +1 -0
  192. package/dist/esm/state/state.js +43 -0
  193. package/dist/esm/state/state.js.map +1 -0
  194. package/dist/esm/state/stateFamily.js +96 -0
  195. package/dist/esm/state/stateFamily.js.map +1 -0
  196. package/dist/esm/state/stateGroup.js +46 -0
  197. package/dist/esm/state/stateGroup.js.map +1 -0
  198. package/dist/esm/state/token.js +20 -0
  199. package/dist/esm/state/token.js.map +1 -0
  200. package/dist/esm/ui/node.js +2 -0
  201. package/dist/esm/ui/node.js.map +1 -0
  202. package/dist/esm/ui/trigger.js +2 -0
  203. package/dist/esm/ui/trigger.js.map +1 -0
  204. package/package.json +33 -0
@@ -0,0 +1,68 @@
1
+ import { Equal } from 'effect';
2
+ // Structural sharing for recomputed calc outputs: reconcile a fresh output
3
+ // against the previous one, substituting previous nodes wherever value equality
4
+ // holds, so identities only move where values moved. Downstream memo boundaries
5
+ // (React subtrees keyed on object identity) then skip everything that didn't
6
+ // change. Referentially transparent: the result is value-equal to `next` — only
7
+ // identities shift toward `previous` — and neither argument is mutated, so the
8
+ // pass composes with the framework's Equal-based invalidation untouched.
9
+ // Bounds the walk; calc outputs are shallow plain data by framework convention.
10
+ const maxDepth = 16;
11
+ const isPlainRecord = (v) => typeof v === 'object' &&
12
+ v !== null &&
13
+ (Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);
14
+ const go = (prev, next, depth) => {
15
+ if (Object.is(prev, next))
16
+ return prev;
17
+ // Data/Schema classes implement Equal+Hash: substitute wholesale on value
18
+ // equality. Plain objects/arrays fall through (their Equal is referential).
19
+ if (Equal.equals(prev, next))
20
+ return prev;
21
+ if (depth <= 0)
22
+ return next;
23
+ if (Array.isArray(prev) && Array.isArray(next)) {
24
+ const out = next.map((item, i) => (i < prev.length ? go(prev[i], item, depth - 1) : item));
25
+ return prev.length === next.length && out.every((v, i) => Object.is(v, prev[i]))
26
+ ? prev
27
+ : out;
28
+ }
29
+ if (isPlainRecord(prev) && isPlainRecord(next)) {
30
+ const keys = Object.keys(next);
31
+ const out = {};
32
+ for (const key of keys)
33
+ out[key] = key in prev ? go(prev[key], next[key], depth - 1) : next[key];
34
+ const allPrev = keys.length === Object.keys(prev).length &&
35
+ keys.every((key) => key in prev && Object.is(out[key], prev[key]));
36
+ return allPrev ? prev : out;
37
+ }
38
+ // Data/Schema class instances that DIFFER still get walked: their Equal is
39
+ // fieldwise over own enumerable fields, so a reconstruction over reconciled
40
+ // fields (same prototype; the constructor is bypassed, but every leaf is a
41
+ // validated value out of `prev` or `next`) stays value-equal to `next` while
42
+ // unchanged children — e.g. one untouched element inside a class-typed
43
+ // container — keep their `prev` identity.
44
+ if (Equal.isEqual(prev) &&
45
+ Equal.isEqual(next) &&
46
+ Object.getPrototypeOf(prev) === Object.getPrototypeOf(next)) {
47
+ const prevFields = Object.fromEntries(Object.entries(prev));
48
+ const nextFields = Object.entries(next);
49
+ const out = {};
50
+ for (const [key, value] of nextFields)
51
+ out[key] = key in prevFields ? go(prevFields[key], value, depth - 1) : value;
52
+ const allPrev = nextFields.length === Object.keys(prevFields).length &&
53
+ nextFields.every(([key]) => key in prevFields && Object.is(out[key], prevFields[key]));
54
+ return allPrev ? prev : Object.assign(Object.create(Object.getPrototypeOf(next)), out);
55
+ }
56
+ // Class instances without Equal (Date, Map, …) are opaque leaves.
57
+ return next;
58
+ };
59
+ /**
60
+ * Substitute `previous` nodes into `next` wherever they are value-equal. The
61
+ * walker only ever returns `previous`, `next`, or a key/index-wise
62
+ * reconstruction of `next` whose every leaf came from one of them, so the
63
+ * result is value-equal to `next` and the type is preserved by construction —
64
+ * the single cast below is that argument, in the style of `wireSources` /
65
+ * `narrowStore`.
66
+ */
67
+ export const reuse = (previous, next) => go(previous, next, maxDepth);
68
+ //# sourceMappingURL=reuse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reuse.js","sourceRoot":"","sources":["../../../src/internal/reuse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { Context, Effect, Layer, MutableRef, Option } from 'effect';
2
+ export const makeScheduler = () => {
3
+ const pending = new Set();
4
+ const armed = MutableRef.make(false);
5
+ const flush = () => {
6
+ MutableRef.set(armed, false);
7
+ // Drain to a fixpoint within ONE microtask. A derived store's `onChange`
8
+ // re-schedules during the pass (it is itself a listener of its upstream), so
9
+ // resolving the whole dependency graph here — instead of re-arming a fresh
10
+ // microtask per layer — collapses a depth-N propagation into a single flush
11
+ // and wakes each leaf subscriber once at its final value. Converges because
12
+ // a derived store schedules only when its output actually moves (Equal).
13
+ while (pending.size > 0) {
14
+ const due = [...pending];
15
+ pending.clear();
16
+ for (const listener of due) {
17
+ // One listener's throw (a defect in a user calc body) must not abandon
18
+ // the rest of the flush; surface it to the host's global handler on a
19
+ // fresh microtask instead of unwinding this loop.
20
+ try {
21
+ listener();
22
+ }
23
+ catch (error) {
24
+ queueMicrotask(() => {
25
+ throw error;
26
+ });
27
+ }
28
+ }
29
+ }
30
+ };
31
+ const schedule = (listeners) => {
32
+ for (const listener of listeners)
33
+ pending.add(listener);
34
+ if (pending.size > 0 && !MutableRef.get(armed)) {
35
+ MutableRef.set(armed, true);
36
+ queueMicrotask(flush);
37
+ }
38
+ };
39
+ return { schedule };
40
+ };
41
+ /**
42
+ * The process-wide scheduler, used by any store created outside a runtime that
43
+ * provides its own `Notifications`. Fine for a single client app (microtask
44
+ * ordering is global anyway); a runtime that needs isolation — concurrent SSR,
45
+ * multiple mounted roots — provides `Notifications` upstream of its stores.
46
+ */
47
+ export const defaultScheduler = makeScheduler();
48
+ /**
49
+ * Optional per-runtime scheduler. When a runtime provides it upstream of its
50
+ * state/calc layers, those stores coalesce on it instead of the global default,
51
+ * isolating their notification timing from other runtimes in the same process.
52
+ */
53
+ export class Notifications extends Context.Tag('reform/Notifications')() {
54
+ }
55
+ /**
56
+ * A fresh per-runtime scheduler. Merged into `Engine`, so a runtime that wires
57
+ * its state/calc layers *downstream* of `Engine` gets isolated notification
58
+ * timing; the common sibling wiring falls back to `defaultScheduler` (still
59
+ * correct, just process-shared).
60
+ */
61
+ export const notificationsLayer = Layer.sync(Notifications, makeScheduler);
62
+ /**
63
+ * Resolve the scheduler a store should use: the runtime's `Notifications` if one
64
+ * is in context, else the global default. Uses `serviceOption` so it imposes no
65
+ * hard requirement — a store layer wired as a sibling of the runtime (the common
66
+ * pattern) simply falls back to the default.
67
+ */
68
+ export const resolveScheduler = Effect.map(Effect.serviceOption(Notifications), Option.getOrElse(() => defaultScheduler));
69
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../../src/internal/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAiBnE,MAAM,CAAC,MAAM,aAAa,GAAG,GAAc,EAAE;IAC3C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAc,CAAA;IACrC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAEpC,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAC5B,yEAAyE;QACzE,6EAA6E;QAC7E,2EAA2E;QAC3E,4EAA4E;QAC5E,4EAA4E;QAC5E,yEAAyE;QACzE,OAAO,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,CAAC,GAAG,OAAO,CAAC,CAAA;YACxB,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,KAAK,MAAM,QAAQ,IAAI,GAAG,EAAE,CAAC;gBAC3B,uEAAuE;gBACvE,sEAAsE;gBACtE,kDAAkD;gBAClD,IAAI,CAAC;oBACH,QAAQ,EAAE,CAAA;gBACZ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,cAAc,CAAC,GAAG,EAAE;wBAClB,MAAM,KAAK,CAAA;oBACb,CAAC,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAA;IAED,MAAM,QAAQ,GAAG,CAAC,SAA+B,EAAE,EAAE;QACnD,KAAK,MAAM,QAAQ,IAAI,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACvD,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/C,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;YAC3B,cAAc,CAAC,KAAK,CAAC,CAAA;QACvB,CAAC;IACH,CAAC,CAAA;IAED,OAAO,EAAE,QAAQ,EAAE,CAAA;AACrB,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAc,aAAa,EAAE,CAAA;AAE1D;;;;GAIG;AACH,MAAM,OAAO,aAAc,SAAQ,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,EAA4B;CAAG;AAErG;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA+B,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;AAEtG;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA6B,MAAM,CAAC,GAAG,CAClE,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,EACnC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,CACzC,CAAA"}
@@ -0,0 +1,17 @@
1
+ import { FiberRef, GlobalValue } from 'effect';
2
+ /**
3
+ * The sanctioned tooling/test seam for seeding CLOSED scenes. A scene's layers
4
+ * are pre-composed (each state group seeds its own live store), so an outer
5
+ * layer cannot override an inner store — but a FiberRef set via
6
+ * `Layer.locally(ref, value)(layer)` IS visible inside the construction effects
7
+ * of nested layers. `State.live` consults this ref at store-construction time:
8
+ * if the state's member name is present, the (schema-validated) value replaces
9
+ * the authored seed; otherwise the authored seed wins.
10
+ *
11
+ * Empty by default — production wiring never touches it. The dev-tool inspector
12
+ * (`Scene.seedScene`) and proofs are the only intended writers. `globalValue`
13
+ * keeps a single ref instance even if the module is loaded twice (duplicated
14
+ * bundles, HMR), so the writer and the reader always agree.
15
+ */
16
+ export const CurrentSeedOverrides = GlobalValue.globalValue(Symbol.for('reform/CurrentSeedOverrides'), () => FiberRef.unsafeMake({}));
17
+ //# sourceMappingURL=seeds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seeds.js","sourceRoot":"","sources":["../../../src/internal/seeds.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AAE9C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAC/B,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,6BAA6B,CAAC,EAAE,GAAG,EAAE,CACtE,QAAQ,CAAC,UAAU,CAAoC,EAAE,CAAC,CAC3D,CAAA"}
@@ -0,0 +1,59 @@
1
+ import { Effect, Equal, Predicate } from 'effect';
2
+ import {} from '../state/token.js';
3
+ import {} from './store.js';
4
+ /**
5
+ * The runtime key an input contributes to the inputs object. Prefer the
6
+ * explicit `manifest.name` — the string handed to `make` — over the structural
7
+ * `name`: a `Calc`/`AsyncCalc` *class* satisfies `Source` through its static
8
+ * `name`, and a user subclass declaration (`class Feed extends Calc.make(…)`)
9
+ * defines its OWN `name` from the class binding, shadowing the explicit one.
10
+ * That binding is what minifiers rename, so keying the snapshot by `input.name`
11
+ * made every subclassed calc input `undefined` in production builds (and would
12
+ * silently mis-key in dev whenever the binding differs from the `make` name —
13
+ * the type-level key, `SourceName<S>`, is always the `make` string). The
14
+ * manifest is inherited through the static prototype chain and never shadowed.
15
+ * `StateToken`s carry no manifest; their `name` is an instance field holding
16
+ * the explicit member key, so the fallback is always the declared string.
17
+ */
18
+ const inputKey = (input) => Predicate.hasProperty(input, 'manifest') &&
19
+ Predicate.isRecord(input.manifest) &&
20
+ Predicate.isString(input.manifest.name)
21
+ ? input.manifest.name
22
+ : input.name;
23
+ /** Element-wise value equality of two invalidation keys. */
24
+ export const sameKey = (a, b) => a.length === b.length && a.every((value, i) => Equal.equals(value, b[i]));
25
+ /**
26
+ * Read each input's backing store and return the shared sensing surface. The
27
+ * caller owns lifecycle: register the `subscribe` result's unsubscribe as a
28
+ * scope finalizer (both live bodies run under `Layer.scoped`).
29
+ */
30
+ export const wireSources = (inputs, invalidateBy) => Effect.gen(function* () {
31
+ const sources = [];
32
+ for (const input of inputs)
33
+ sources.push(yield* input.store);
34
+ const snapshot = () => {
35
+ const args = {};
36
+ inputs.forEach((input, i) => {
37
+ // `noUncheckedIndexedAccess`: `sources` is built 1:1 with `inputs`, but
38
+ // guard the index so the read is honestly total.
39
+ const source = sources[i];
40
+ if (source !== undefined)
41
+ args[inputKey(input)] = source.getSnapshot();
42
+ });
43
+ return args;
44
+ };
45
+ const keyOf = (args) => invalidateBy ? invalidateBy(args) : Object.values(args);
46
+ const subscribe = (listener) => {
47
+ const unsubscribes = sources.map((source) => source.subscribe(listener));
48
+ return () => {
49
+ for (const unsubscribe of unsubscribes)
50
+ unsubscribe();
51
+ };
52
+ };
53
+ return { snapshot, keyOf, subscribe };
54
+ // Yielding each `input.store` (a `Context.Tag<Store<unknown>>`) widens the
55
+ // inferred requirement to `Store<unknown>`; restate the precise per-input
56
+ // `InputStores<Inputs>` union the signature promises. This is the single
57
+ // place that cast lives — `Calc.live`/`AsyncCalc.live` inherit it.
58
+ });
59
+ //# sourceMappingURL=sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.js","sourceRoot":"","sources":["../../../src/internal/sources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAC/D,OAAO,EAAqD,MAAM,gBAAgB,CAAA;AAClF,OAAO,EAAc,MAAM,SAAS,CAAA;AA8BpC;;;;;;;;;;;;;GAaG;AACH,MAAM,QAAQ,GAAG,CAAC,KAAgB,EAAU,EAAE,CAC5C,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC;IACxC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;IAClC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;IACrC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI;IACrB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAA;AAEhB,4DAA4D;AAC5D,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAyB,EAAE,CAAyB,EAAW,EAAE,CACvF,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAY3E;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,MAAc,EACd,YAAmC,EAC8B,EAAE,CACnE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,OAAO,GAA0B,EAAE,CAAA;IACzC,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAE5D,MAAM,QAAQ,GAAG,GAAyB,EAAE;QAC1C,MAAM,IAAI,GAA4B,EAAE,CAAA;QACxC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;YAC1B,wEAAwE;YACxE,iDAAiD;YACjD,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;YACzB,IAAI,MAAM,KAAK,SAAS;gBAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,CAAA;QACxE,CAAC,CAAC,CAAA;QACF,OAAO,IAA4B,CAAA;IACrC,CAAC,CAAA;IACD,MAAM,KAAK,GAAG,CAAC,IAA0B,EAA0B,EAAE,CACnE,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACzD,MAAM,SAAS,GAAG,CAAC,QAAoB,EAAgB,EAAE;QACvD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;QACxE,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,WAAW,IAAI,YAAY;gBAAE,WAAW,EAAE,CAAA;QACvD,CAAC,CAAA;IACH,CAAC,CAAA;IACD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,CAAA;IACrC,2EAA2E;IAC3E,0EAA0E;IAC1E,yEAAyE;IACzE,mEAAmE;AACrE,CAAC,CAAoE,CAAA"}
@@ -0,0 +1,73 @@
1
+ import { Equal, MutableRef } from 'effect';
2
+ import { inspectable } from './inspect.js';
3
+ import { defaultScheduler } from './scheduler.js';
4
+ export const makeStore = (initial, scheduler = defaultScheduler) => {
5
+ // The store is a mutable reactive slot by design, so its value lives in a
6
+ // `MutableRef` we update in place (no reassigned binding).
7
+ const value = MutableRef.make(initial);
8
+ const version = MutableRef.make(0);
9
+ const listeners = new Set();
10
+ return {
11
+ get: () => MutableRef.get(value),
12
+ getSnapshot: () => MutableRef.get(value),
13
+ getVersion: () => MutableRef.get(version),
14
+ set: (next) => {
15
+ if (Equal.equals(MutableRef.get(value), next))
16
+ return;
17
+ MutableRef.set(value, next);
18
+ MutableRef.update(version, (n) => n + 1);
19
+ scheduler.schedule(listeners);
20
+ },
21
+ subscribe: (listener) => {
22
+ listeners.add(listener);
23
+ return () => {
24
+ listeners.delete(listener);
25
+ };
26
+ },
27
+ ...inspectable(() => ({ _id: 'reform/Store', value: MutableRef.get(value) })),
28
+ };
29
+ };
30
+ /**
31
+ * A read-only `Store` whose value is computed from upstream sources.
32
+ *
33
+ * Reads are pull-fresh: `get`/`getSnapshot` call `compute` directly, so a
34
+ * headless snapshot always reflects the current source state without waiting for
35
+ * a notification (`compute` must memoize so an unchanged read returns a stable
36
+ * reference — `useSyncExternalStore` requires it). *Notifications*, by contrast,
37
+ * run through the same coalescing scheduler as `makeStore`: an upstream change
38
+ * recomputes once and wakes subscribers only when the output actually moves (by
39
+ * `Equal.equals`), so every store kind shares one notification timing. `set` is
40
+ * a no-op — the only writer is the upstream subscription.
41
+ */
42
+ export const makeDerivedStore = (compute, subscribeUpstream, scheduler = defaultScheduler) => {
43
+ const listeners = new Set();
44
+ const version = MutableRef.make(0);
45
+ // The last output we notified against — tracked only here, never touched by
46
+ // reads, so a `get` racing ahead of `onChange` can't suppress a notification.
47
+ const seen = MutableRef.make({ value: compute() });
48
+ const onChange = () => {
49
+ const previous = MutableRef.get(seen);
50
+ const next = compute();
51
+ MutableRef.set(seen, { value: next });
52
+ if (previous === undefined || !Equal.equals(previous.value, next)) {
53
+ MutableRef.update(version, (n) => n + 1);
54
+ scheduler.schedule(listeners);
55
+ }
56
+ };
57
+ const unsubscribe = subscribeUpstream(onChange);
58
+ const store = {
59
+ get: compute,
60
+ getSnapshot: compute,
61
+ getVersion: () => MutableRef.get(version),
62
+ set: () => { },
63
+ subscribe: (listener) => {
64
+ listeners.add(listener);
65
+ return () => {
66
+ listeners.delete(listener);
67
+ };
68
+ },
69
+ ...inspectable(() => ({ _id: 'reform/Store', value: compute() })),
70
+ };
71
+ return { store, unsubscribe };
72
+ };
73
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/internal/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { Context, Effect, Option } from 'effect';
2
+ /**
3
+ * The active render's dependency tracker (D5). Present only while a composition
4
+ * is rendering under `@reform/react`; absent in procedures and headless reads.
5
+ */
6
+ export class CurrentTracker extends Context.Tag('reform/Tracker')() {
7
+ }
8
+ /**
9
+ * Read a store's current snapshot and, if a tracker is active, record the store
10
+ * as a dependency of the current render. One read API, two behaviors by context
11
+ * (D5): inside a render it subscribes the slice; elsewhere it just snapshots.
12
+ */
13
+ export const readTracked = (store) => Effect.map(Effect.serviceOption(CurrentTracker), (tracker) => {
14
+ if (Option.isSome(tracker))
15
+ tracker.value.add(store);
16
+ return store.getSnapshot();
17
+ });
18
+ //# sourceMappingURL=track.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track.js","sourceRoot":"","sources":["../../../src/internal/track.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAqBhD;;;GAGG;AACH,MAAM,OAAO,cAAe,SAAQ,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAA2B;CAAG;AAE/F;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAI,KAAe,EAAoB,EAAE,CAClE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE;IAC3D,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;QAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACpD,OAAO,KAAK,CAAC,WAAW,EAAE,CAAA;AAC5B,CAAC,CAAC,CAAA"}
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "module",
3
+ "sideEffects": []
4
+ }
@@ -0,0 +1,50 @@
1
+ import { Effect, Layer } from 'effect';
2
+ import { Procedures } from '../channel/channel.js';
3
+ import { definitionClass } from '../definition/definition.js';
4
+ import {} from '../event/event.js';
5
+ import {} from '../internal/ctx.js';
6
+ import { Bus, narrowHandled } from '../runtime/bus.js';
7
+ /**
8
+ * A cross-event-loop flow. The *definition* declares its trigger events and the
9
+ * channel it runs on; the *implementation* is the effectful body. Procedures no
10
+ * longer subscribe to the bus themselves — the single drain loop routes events
11
+ * to the channel, which runs the registered bodies under its policy.
12
+ */
13
+ export const make = (name, config) => definitionClass({
14
+ manifest: { kind: 'Procedure', name },
15
+ events: config.events,
16
+ channel: config.channel,
17
+ });
18
+ /**
19
+ * Register the flow body into its channel. The body may read state and dispatch
20
+ * events, but never writes state (the core invariant); its context requirements
21
+ * (RPC clients, etc.) are captured here so the channel fiber can run it with no
22
+ * outstanding R.
23
+ */
24
+ export const live = (procedure, body) => {
25
+ const name = procedure.manifest.name;
26
+ const channelName = procedure.channel.manifest.name;
27
+ const handles = new Set(procedure.events.map((e) => e.tag));
28
+ // Scoped registration (see `Reducer.live`): an eager procedure's scope is the
29
+ // root runtime's, so behavior is unchanged; a lazy feature's procedure registers
30
+ // on mount and unregisters on unmount, so it stops running and is reclaimed.
31
+ return Layer.scopedDiscard(Effect.gen(function* () {
32
+ const procedures = yield* Procedures;
33
+ if (procedures.entries.some((e) => e.name === name)) {
34
+ yield* Effect.logWarning(`reform: duplicate procedure name '${name}' registered`);
35
+ }
36
+ // Snapshot the body's full context (Bus + RPC clients) so `run` is total.
37
+ const runtime = yield* Effect.runtime();
38
+ const entry = {
39
+ name,
40
+ channelName,
41
+ // The channel only routes events whose tag is in `handles`, so at runtime
42
+ // `event` is always one of `Events`; `narrowHandled` restores the body's
43
+ // declared event union from the erased `Tagged` envelope.
44
+ handles,
45
+ run: (event) => Effect.provide(Effect.gen(() => body(narrowHandled(event))), runtime),
46
+ };
47
+ yield* Effect.acquireRelease(Effect.sync(() => procedures.register(entry)), () => Effect.sync(() => procedures.unregister(entry)));
48
+ }));
49
+ };
50
+ //# sourceMappingURL=procedure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"procedure.js","sourceRoot":"","sources":["../../../src/procedure/procedure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAEtC,OAAO,EAA0C,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACvF,OAAO,EAAiB,eAAe,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,EAAiC,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAAY,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAwBnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,IAAY,EACZ,MAA+B,EACP,EAAE,CAC1B,eAAe,CAAyB;IACtC,QAAQ,EAAE,EAAE,IAAI,EAAE,WAAoB,EAAE,IAAI,EAA8B;IAC1E,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,OAAO,EAAE,MAAM,CAAC,OAAO;CACxB,CAAC,CAAA;AAEJ;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAKlB,SAAiC,EACjC,IAAuE,EACf,EAAE;IAC1D,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAA;IACpC,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAA;IACnD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAC3D,8EAA8E;IAC9E,iFAAiF;IACjF,6EAA6E;IAC7E,OAAO,KAAK,CAAC,aAAa,CACxB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,UAAU,CAAA;QACpC,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACpD,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,qCAAqC,IAAI,cAAc,CAAC,CAAA;QACnF,CAAC;QACD,0EAA0E;QAC1E,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,EAAkB,CAAA;QACvD,MAAM,KAAK,GAAmB;YAC5B,IAAI;YACJ,WAAW;YACX,0EAA0E;YAC1E,yEAAyE;YACzE,0DAA0D;YAC1D,OAAO;YACP,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;SACtF,CAAA;QACD,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,CAC/E,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAChD,CAAA;IACH,CAAC,CAAC,CACH,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,63 @@
1
+ import { Effect, Layer } from 'effect';
2
+ import { definitionClass } from '../definition/definition.js';
3
+ import { AsyncReducer } from '../internal/errors.js';
4
+ import {} from '../event/event.js';
5
+ import {} from '../state/state.js';
6
+ import { Tombstone, } from '../state/stateFamily.js';
7
+ import { narrowHandled } from '../runtime/bus.js';
8
+ import { Reducers } from '../runtime/loop.js';
9
+ export function make(name, config) {
10
+ return definitionClass({
11
+ manifest: { kind: 'Reducer', name },
12
+ config,
13
+ handles: new Set(config.events.map((e) => e.tag)),
14
+ });
15
+ }
16
+ /** Reject an accidentally-async fold up front: a reducer must be a pure sync write. */
17
+ const sync = (value) => {
18
+ // Loose `!= null` so a reducer returning `undefined` doesn't crash the guard.
19
+ if (value != null && typeof value.then === 'function') {
20
+ throw new AsyncReducer();
21
+ }
22
+ return value;
23
+ };
24
+ export function live(reducer, fold) {
25
+ const { config, handles } = reducer;
26
+ const name = reducer.manifest.name;
27
+ // Scoped registration: register on build, unregister on scope close. For an eager
28
+ // app the scope is the root runtime's (closes only at dispose), so behavior is
29
+ // unchanged; for a lazy feature the scope is the feature's, so unmount removes the
30
+ // entry — it stops folding and is reclaimed instead of leaking onto a dead store.
31
+ return Layer.scopedDiscard(Effect.gen(function* () {
32
+ const reducers = yield* Reducers;
33
+ if (reducers.entries.some((e) => e.name === name)) {
34
+ yield* Effect.logWarning(`reform: duplicate reducer name '${name}' registered`);
35
+ }
36
+ const entry = yield* Effect.gen(function* () {
37
+ if ('family' in config) {
38
+ const family = yield* config.family.store;
39
+ return {
40
+ name,
41
+ handles,
42
+ apply: (event) => {
43
+ // The loop only invokes `apply` for events in `handles`, so `event`
44
+ // is one of this reducer's declared events; `narrowHandled` restores
45
+ // that typed view from the erased `Tagged` envelope `keyOf` is fed.
46
+ const key = config.keyOf(narrowHandled(event));
47
+ const next = fold(family.at(key).get(), event);
48
+ // A fold may return the eviction sentinel to drop the key's store
49
+ // (bounding an otherwise-unbounded family) instead of a new value.
50
+ if (next === Tombstone)
51
+ family.forget(key);
52
+ else
53
+ family.at(key).set(sync(next));
54
+ },
55
+ };
56
+ }
57
+ const store = yield* config.states[0].store;
58
+ return { name, handles, apply: (event) => store.set(sync(fold(store.get(), event))) };
59
+ });
60
+ yield* Effect.acquireRelease(Effect.sync(() => reducers.register(entry)), () => Effect.sync(() => reducers.unregister(entry)));
61
+ }));
62
+ }
63
+ //# sourceMappingURL=reducer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reducer.js","sourceRoot":"","sources":["../../../src/reducer/reducer.ts"],"names":[],"mappings":"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"}