logic-runtime-react-z 3.1.4 → 3.1.6

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/README.md CHANGED
@@ -130,8 +130,6 @@ computed: {
130
130
 
131
131
  - `state` inside `computed` is **reactive**.
132
132
  - Reading `state.count` automatically tracks dependencies.
133
- - Computed values are cached and only re-evaluated when tracked dependencies change.
134
-
135
133
 
136
134
  ---
137
135
 
@@ -149,14 +147,17 @@ You have **2 integration styles**:
149
147
  Keeps view pure and declarative.
150
148
 
151
149
  ```tsx
150
+ // full see: LIVE EXAMPLE
152
151
  import { withLogic, LogicViewProps } from "logic-runtime-react-z"
153
152
  import { counterLogic } from "./counter.logic"
154
153
 
154
+ interface MyProps {}
155
+
155
156
  type CounterInjected =
156
- LogicViewProps<typeof counterLogic>
157
+ LogicViewProps<typeof counterLogic> & MyProps
157
158
 
158
159
  const CounterView = ({ state, actions, emit }: LogicViewProps) => {
159
- // actions and emit => same emit
160
+ // actions and emit => same emit (update state)
160
161
  return (
161
162
  <div>
162
163
  <h2>Count: {state.count}</h2>
@@ -278,7 +279,7 @@ async function run() {
278
279
  await runtime.emit("login")
279
280
  await runtime.emit("logout")
280
281
 
281
- console.log(runtime.getSnapshot())
282
+ console.log(runtime.state)
282
283
  }
283
284
 
284
285
  run()
@@ -313,7 +314,7 @@ const logic = createLogic({
313
314
  const runtime = logic.create()
314
315
 
315
316
  await runtime.emit("set", 4)
316
- expect(runtime.computed.squared).toBe(16)
317
+ expect(runtime.state.squared).toBe(16)
317
318
  ```
318
319
 
319
320
  ---
@@ -355,10 +356,10 @@ Most state libraries focus on:
355
356
 
356
357
  > **How behavior is orchestrated through intents**
357
358
 
358
- Redux/Zustand answer:
359
+ Redux/Zustand:
359
360
  > "Where is my state and how do I change it?"
360
361
 
361
- This runtime answers:
362
+ This runtime:
362
363
  > "What behavior is triggered by this event, and how should it execute?"
363
364
 
364
365
  ---
@@ -410,6 +411,12 @@ Given the same intent sequence, the resulting state is reproducible.
410
411
 
411
412
  ---
412
413
 
414
+ ## 🔗 Multiple Logic Communication
415
+
416
+ 💡 Multiple logic instances should communicate through a shared event bus (e.g. eventbus-z) — not direct calls — to preserve intent boundaries and deterministic execution.
417
+
418
+ ---
419
+
413
420
  ## 📐 Architecture Diagram (High-level)
414
421
 
415
422
  ```bash
@@ -1,5 +1,5 @@
1
- import type { Atom } from "chrono-state-z/build/core/atom";
2
1
  import { Scope } from "intentx-core-z";
2
+ import type { Atom } from "chrono-state-z";
3
3
  import { EffectDef } from "./effect";
4
4
  export type AtomAccessor<T> = Atom<T>;
5
5
  export type ComputedDef<S> = Record<string, (context: {
@@ -1 +1 @@
1
- "use strict";var t=require("chrono-state-z"),e=require("intentx-core-z"),s=require("react/jsx-runtime");function n(t){var e=Object.create(null);return t&&Object.keys(t).forEach(function(s){if("default"!==s){var n=Object.getOwnPropertyDescriptor(t,s);Object.defineProperty(e,s,n.get?n:{enumerable:!0,get:function(){return t[s]}})}}),e.default=t,Object.freeze(e)}var o=n(require("react"));class i{constructor(){this.handlers={},this.effects={},this.middlewares=[]}use(t){this.middlewares.push(t)}effect(t,e){var s,n;(null!==(s=(n=this.effects)[t])&&void 0!==s?s:n[t]=[]).push(e)}on(t,e){var s,n;const o=this.handlers[t];o&&o.length>0?console.warn(`[IntentBus] Duplicate intent handler "${t}" detected. Only the first handler will be used.`):(null!==(s=(n=this.handlers)[t])&&void 0!==s?s:n[t]=[]).push(e)}async emit(t,e){var s,n;const o=null!==(s=this.handlers[t])&&void 0!==s?s:[],i=null!==(n=this.effects[t])&&void 0!==n?n:[],r=(a=this.middlewares,c=async t=>{t.effects=i;for(const e of o)await e(t)},a.reduceRight((t,e)=>e(t),c));var a,c;await r(e)}}class r{constructor(t,s=e.createScope("logic")){this.computedAtoms={},this.subs=new Set,this.bus=new i,this.dirty=!0,this.isComputing=!1,this.computedKeys=new Set,this.markDirty=()=>{this.dirty=!0,this.subs.forEach(t=>t())},this.getSnapshot=()=>(this.dirty&&(this.snapshotCache=this.buildSnapshot(),this.dirty=!1),this.snapshotCache),this.subscribe=t=>(this.subs.add(t),()=>this.subs.delete(t)),this.onIntent=(t,e)=>{this.bus.on(t,e)},this.emit=async(t,e)=>{const s=new AbortController;await this.bus.emit(t,{payload:e,scope:this.scope,signal:s.signal,state:this.getSnapshot,setState:t=>this.setStateInternal(t),emit:this.emit})},this.scope=s,this.stateAtoms=this.createStateAtoms(t);for(const t in this.stateAtoms)this.stateAtoms[t].subscribe(this.markDirty);this.bus.use(function(){const t=new Map,e=new Map;return s=>async n=>{var o;const i=n.effects;if(!(null==i?void 0:i.length))return s(n);for(const s of i){const i=s.id;if("takeLatest"===s.strategy){null===(o=t.get(i))||void 0===o||o.abort();const e=new AbortController;t.set(i,e),await s.handler({...n,signal:e.signal})}else"debounce"===s.strategy?(clearTimeout(e.get(i)),e.set(i,setTimeout(()=>s.handler(n),s.wait))):await s.handler(n)}await s(n)}}())}createStateAtoms(e){const s={};for(const n in e)s[n]=t.atom(e[n]);return s}buildSnapshot(){const t={};for(const e in this.stateAtoms)t[e]=this.stateAtoms[e]();for(const e in this.computedAtoms)t[e]=this.computedAtoms[e]();return t}createReactiveState(){return new Proxy({},{get:(t,e)=>{const s=this.stateAtoms[e];return s?s():void 0}})}get state(){return this.getSnapshot()}get computed(){const t={};return this.computedKeys.forEach(e=>{t[e]=this.computedAtoms[e]()}),t}getComputedKey(t){return this.computedAtoms[t]()}getComputed(t){const e={};return this.computedKeys.forEach(s=>{e[s]=t[s]}),e}setStateInternal(t){this.isComputing&&console.warn("[logic-runtime] setState() called inside computed()");const e={};for(const t in this.stateAtoms)e[t]=this.stateAtoms[t]();t(e);for(const t in this.stateAtoms)e[t]!==this.stateAtoms[t]()&&this.stateAtoms[t].set(e[t])}useEffect(t,e){this.bus.effect(t,e)}attachComputed(e,s){const n=t.atom(void 0),o=this.createReactiveState();this.computedAtoms[e]=n,this.computedKeys.add(e);const i=()=>{this.isComputing=!0,n.set(s({state:o})),this.isComputing=!1};t.effect(i),i(),n.subscribe(this.markDirty)}}function a(t){const e=function(){let t=0,e=[];return{get records(){return e.slice()},record:function(s){e.push({...s,id:++t,state:structuredClone(s.state)})},replay:async function(t,s){const{from:n=0,to:o=1/0,scope:i}=null!=s?s:{},r=e.filter(t=>"emit"===t.type&&t.id>=n&&t.id<=o&&(!i||t.scope===i));for(const e of r){const s=t(e.intent,e.payload);s instanceof Promise&&await s}},clear:function(){e=[],t=0}}}();function s(){return"string"==typeof t.scope?t.scope:t.scope.name}return{timeline:e,wrap:function(){const n=t.emit.bind(t);t.emit=async(o,i)=>{e.record({type:"emit:start",intent:o,payload:i,scope:s(),state:t.getSnapshot(),timestamp:Date.now()});try{const t=n(o,i);t instanceof Promise&&await t}finally{e.record({type:"emit:end",intent:o,payload:i,scope:s(),state:t.getSnapshot(),timestamp:Date.now()})}}}}}Object.defineProperty(exports,"createSelector",{enumerable:!0,get:function(){return t.createSelector}}),exports.LogicRuntime=r,exports.attachDevtools=a,exports.createBackendRuntime=function(t){var s,n;let o=structuredClone(t);const i=()=>o,r=t=>{o={...o,...t}},c=e.createScope("backend");async function u(t,e){await l.emit(t,e,c)}const l=e.createIntentBus(t=>{const e=new AbortController;return{scope:c,payload:t,signal:e.signal,get state(){return i()},setState(){throw new Error("setState is not allowed in backend runtime")},emit:u}}),h={state:i,reset:()=>{o=structuredClone(t)},emit:u,registerIntents:function(t){for(const e in t){const s=t[e];l.on(e,async(t,e)=>{var n;const o={get state(){return i()},signal:null!==(n=t.signal)&&void 0!==n?n:(new AbortController).signal,set:r,emit:u};await s(o)},c)}},onIntent:l.on,effect:l.effect};if("production"!==(null===(n=null===(s=null===globalThis||void 0===globalThis?void 0:globalThis.process)||void 0===s?void 0:s.env)||void 0===n?void 0:n.NODE_ENV)){const t=a(h);t.wrap(h),h.devtools=t}return h},exports.createLogic=function(t){return{name:t.name,create(e){var s;const n=new r(structuredClone(t.state),e);if(t.computed)for(const e in t.computed)n.attachComputed(e,t.computed[e]);null===(s=t.intents)||void 0===s||s.call(t,{on:n.onIntent,effect:n.useEffect.bind(n)});const o={};if(t.actions){const e=Object.keys(t.actions);for(const s of e){const e=t.actions[s];o[s]=e({emit:n.emit,getState:n.getSnapshot})}}return n.actions=o,n}}},exports.effect=function(t){const e={_kind:"effect",id:Symbol("effect"),handler:t,strategy:"default",wait:0};return{...e,takeLatest(){return e.strategy="takeLatest",this},debounce(t){return e.strategy="debounce",e.wait=t,this}}},exports.useLogic=function(t,s){const n=o.useRef(null);n.current||(n.current=t.create("string"==typeof s?e.createScope(s):s));const i=n.current,r=o.useSyncExternalStore(i.subscribe,i.getSnapshot,i.getSnapshot),a=o.useCallback((t,e)=>i.emit(t,e),[i]),c=i.actions;return o.useMemo(()=>({state:r,actions:c,emit:a}),[r,c,a])},exports.withLogic=function(t,n,i){var r,a;const c=r=>{const a=o.useRef(null);a.current||(a.current=t.create("string"==typeof i?e.createScope(i):i));const c=a.current,u=o.useSyncExternalStore(c.subscribe,c.getSnapshot,c.getSnapshot),l=o.useCallback((t,e)=>c.emit(t,e),[c]),h=o.useMemo(()=>({state:u,actions:c.actions,emit:l}),[u,l,c]);return s.jsx(n,{...r,...h})};return c.displayName=`withLogic(${null!==(a=null!==(r=n.displayName)&&void 0!==r?r:n.name)&&void 0!==a?a:"View"})`,c};
1
+ "use strict";var t=require("chrono-state-z"),e=require("intentx-core-z"),s=require("react/jsx-runtime");function n(t){var e=Object.create(null);return t&&Object.keys(t).forEach(function(s){if("default"!==s){var n=Object.getOwnPropertyDescriptor(t,s);Object.defineProperty(e,s,n.get?n:{enumerable:!0,get:function(){return t[s]}})}}),e.default=t,Object.freeze(e)}var o,i,r=n(require("react"));class a{constructor(){this.handlers={},this.effects={},this.middlewares=[]}use(t){this.middlewares.push(t)}effect(t,e){var s,n;(null!==(s=(n=this.effects)[t])&&void 0!==s?s:n[t]=[]).push(e)}on(t,e){var s,n;const o=this.handlers[t];o&&o.length>0?console.warn(`[IntentBus] Duplicate intent handler "${t}" detected. Only the first handler will be used.`):(null!==(s=(n=this.handlers)[t])&&void 0!==s?s:n[t]=[]).push(e)}async emit(t,e){var s,n;const o=null!==(s=this.handlers[t])&&void 0!==s?s:[],i=null!==(n=this.effects[t])&&void 0!==n?n:[],r=(a=this.middlewares,c=async t=>{t.effects=i;for(const e of o)await e(t)},a.reduceRight((t,e)=>e(t),c));var a,c;await r(e)}}class c{constructor(t,s=e.createScope("logic")){this.computedAtoms={},this.subs=new Set,this.bus=new a,this.dirty=!0,this.isComputing=!1,this.computedKeys=new Set,this.markDirty=()=>{this.dirty=!0,this.subs.forEach(t=>t())},this.getSnapshot=()=>(this.dirty&&(this.snapshotCache=this.buildSnapshot(),this.dirty=!1),this.snapshotCache),this.subscribe=t=>(this.subs.add(t),()=>this.subs.delete(t)),this.onIntent=(t,e)=>{this.bus.on(t,e)},this.emit=async(t,e)=>{const s=new AbortController;await this.bus.emit(t,{payload:e,scope:this.scope,signal:s.signal,state:this.getSnapshot,setState:t=>this.setStateInternal(t),emit:this.emit})},this.scope=s,this.stateAtoms=this.createStateAtoms(t);for(const t in this.stateAtoms)this.stateAtoms[t].subscribe(this.markDirty);this.bus.use(function(){const t=new Map,e=new Map;return s=>async n=>{var o;const i=n.effects;if(!(null==i?void 0:i.length))return s(n);for(const s of i){const i=s.id;if("takeLatest"===s.strategy){null===(o=t.get(i))||void 0===o||o.abort();const e=new AbortController;t.set(i,e),await s.handler({...n,signal:e.signal})}else"debounce"===s.strategy?(clearTimeout(e.get(i)),e.set(i,setTimeout(()=>s.handler(n),s.wait))):await s.handler(n)}await s(n)}}())}createStateAtoms(e){const s={};for(const n in e)s[n]=t.atom(e[n]);return s}buildSnapshot(){const t={};for(const e in this.stateAtoms)t[e]=this.stateAtoms[e]();for(const e in this.computedAtoms)t[e]=this.computedAtoms[e]();return t}createReactiveState(){return new Proxy({},{get:(t,e)=>{const s=this.stateAtoms[e];return s?s():void 0}})}get state(){return this.getSnapshot()}get computed(){const t={};return this.computedKeys.forEach(e=>{t[e]=this.computedAtoms[e]()}),t}getComputedKey(t){return this.computedAtoms[t]()}getComputed(t){const e={};return this.computedKeys.forEach(s=>{e[s]=t[s]}),e}setStateInternal(t){this.isComputing&&console.warn("[logic-runtime] setState() called inside computed()");const e={};for(const t in this.stateAtoms)e[t]=this.stateAtoms[t]();t(e);for(const t in this.stateAtoms)e[t]!==this.stateAtoms[t]()&&this.stateAtoms[t].set(e[t])}useEffect(t,e){this.bus.effect(t,e)}attachComputed(e,s){const n=t.atom(void 0),o=this.createReactiveState();this.computedAtoms[e]=n,this.computedKeys.add(e);const i=()=>{this.isComputing=!0,n.set(s({state:o})),this.isComputing=!1};t.effect(i),i(),n.subscribe(this.markDirty)}}function u(t){const e=function(){let t=0,e=[];return{get records(){return e.slice()},record:function(s){e.push({...s,id:++t,state:structuredClone(s.state)})},replay:async function(t,s){const{from:n=0,to:o=1/0,scope:i}=null!=s?s:{},r=e.filter(t=>"emit"===t.type&&t.id>=n&&t.id<=o&&(!i||t.scope===i));for(const e of r){const s=t(e.intent,e.payload);s instanceof Promise&&await s}},clear:function(){e=[],t=0}}}();function s(){return"string"==typeof t.scope?t.scope:t.scope.name}return{timeline:e,wrap:function(){const n=t.emit.bind(t);t.emit=async(o,i)=>{e.record({type:"emit:start",intent:o,payload:i,scope:s(),state:t.getSnapshot(),timestamp:Date.now()});try{const t=n(o,i);t instanceof Promise&&await t}finally{e.record({type:"emit:end",intent:o,payload:i,scope:s(),state:t.getSnapshot(),timestamp:Date.now()})}}}}}const l="production"!==(null===(i=null===(o=null===globalThis||void 0===globalThis?void 0:globalThis.process)||void 0===o?void 0:o.env)||void 0===i?void 0:i.NODE_ENV);Object.defineProperty(exports,"createSelector",{enumerable:!0,get:function(){return t.createSelector}}),exports.LogicRuntime=c,exports.attachDevtools=u,exports.createBackendRuntime=function(t){let s=structuredClone(t);const n=()=>s,o=t=>{s={...s,...t}},i=e.createScope("backend");async function r(t,e){await a.emit(t,e,i)}const a=e.createIntentBus(t=>{const e=new AbortController;return{scope:i,payload:t,signal:e.signal,get state(){return n()},setState(){throw new Error("setState is not allowed in backend runtime")},emit:r}}),c={state:n,reset:()=>{s=structuredClone(t)},emit:r,registerIntents:function(t){for(const e in t){const s=t[e];a.on(e,async(t,e)=>{var i;const a={get state(){return n()},signal:null!==(i=t.signal)&&void 0!==i?i:(new AbortController).signal,set:o,emit:r};await s(a)},i)}},onIntent:a.on,effect:a.effect};if(l){const t=u(c);t.wrap(c),c.devtools=t}return c},exports.createLogic=function(t){return{name:t.name,create(e){var s,n;const o=new c(structuredClone(t.state),e);if(t.computed)for(const e in t.computed)o.attachComputed(e,t.computed[e]);null===(s=t.intents)||void 0===s||s.call(t,{on:o.onIntent,effect:o.useEffect.bind(o)});const i={};if(t.actions){const e=Object.keys(t.actions);for(const s of e){const e=t.actions[s];i[s]=e({emit:o.emit,getState:o.getSnapshot})}}return o.actions=i,null===(n=t.bootstrap)||void 0===n||n.call(t,{runtime:o,emit:o.emit,getState:o.getSnapshot}),o}}},exports.effect=function(t){const e={_kind:"effect",id:Symbol("effect"),handler:t,strategy:"default",wait:0};return{...e,takeLatest(){return e.strategy="takeLatest",this},debounce(t){return e.strategy="debounce",e.wait=t,this}}},exports.useLogic=function(t,s){const n=r.useRef(null);n.current||(n.current=t.create("string"==typeof s?e.createScope(s):s));const o=n.current,i=r.useSyncExternalStore(o.subscribe,o.getSnapshot,o.getSnapshot),a=r.useCallback((t,e)=>o.emit(t,e),[o]),c=o.actions;return r.useMemo(()=>({state:i,actions:c,emit:a}),[i,c,a])},exports.withLogic=function(t,n,o){var i,a;const c=i=>{const a=r.useRef(null);a.current||(a.current=t.create("string"==typeof o?e.createScope(o):o));const c=a.current,u=r.useSyncExternalStore(c.subscribe,c.getSnapshot,c.getSnapshot),l=r.useCallback((t,e)=>c.emit(t,e),[c]),h=r.useMemo(()=>({state:u,actions:c.actions,emit:l}),[u,l,c]);return s.jsx(n,{...i,...h})};return c.displayName=`withLogic(${null!==(a=null!==(i=n.displayName)&&void 0!==i?i:n.name)&&void 0!==a?a:"View"})`,c};
@@ -1 +1 @@
1
- import{atom as t,effect as e}from"chrono-state-z";export{createSelector}from"chrono-state-z";import{createScope as s,createIntentBus as n}from"intentx-core-z";import{jsx as o}from"react/jsx-runtime";import*as i from"react";class a{constructor(){this.handlers={},this.effects={},this.middlewares=[]}use(t){this.middlewares.push(t)}effect(t,e){var s,n;(null!==(s=(n=this.effects)[t])&&void 0!==s?s:n[t]=[]).push(e)}on(t,e){var s,n;const o=this.handlers[t];o&&o.length>0?console.warn(`[IntentBus] Duplicate intent handler "${t}" detected. Only the first handler will be used.`):(null!==(s=(n=this.handlers)[t])&&void 0!==s?s:n[t]=[]).push(e)}async emit(t,e){var s,n;const o=null!==(s=this.handlers[t])&&void 0!==s?s:[],i=null!==(n=this.effects[t])&&void 0!==n?n:[],a=(r=this.middlewares,c=async t=>{t.effects=i;for(const e of o)await e(t)},r.reduceRight((t,e)=>e(t),c));var r,c;await a(e)}}class r{constructor(t,e=s("logic")){this.computedAtoms={},this.subs=new Set,this.bus=new a,this.dirty=!0,this.isComputing=!1,this.computedKeys=new Set,this.markDirty=()=>{this.dirty=!0,this.subs.forEach(t=>t())},this.getSnapshot=()=>(this.dirty&&(this.snapshotCache=this.buildSnapshot(),this.dirty=!1),this.snapshotCache),this.subscribe=t=>(this.subs.add(t),()=>this.subs.delete(t)),this.onIntent=(t,e)=>{this.bus.on(t,e)},this.emit=async(t,e)=>{const s=new AbortController;await this.bus.emit(t,{payload:e,scope:this.scope,signal:s.signal,state:this.getSnapshot,setState:t=>this.setStateInternal(t),emit:this.emit})},this.scope=e,this.stateAtoms=this.createStateAtoms(t);for(const t in this.stateAtoms)this.stateAtoms[t].subscribe(this.markDirty);this.bus.use(function(){const t=new Map,e=new Map;return s=>async n=>{var o;const i=n.effects;if(!(null==i?void 0:i.length))return s(n);for(const s of i){const i=s.id;if("takeLatest"===s.strategy){null===(o=t.get(i))||void 0===o||o.abort();const e=new AbortController;t.set(i,e),await s.handler({...n,signal:e.signal})}else"debounce"===s.strategy?(clearTimeout(e.get(i)),e.set(i,setTimeout(()=>s.handler(n),s.wait))):await s.handler(n)}await s(n)}}())}createStateAtoms(e){const s={};for(const n in e)s[n]=t(e[n]);return s}buildSnapshot(){const t={};for(const e in this.stateAtoms)t[e]=this.stateAtoms[e]();for(const e in this.computedAtoms)t[e]=this.computedAtoms[e]();return t}createReactiveState(){return new Proxy({},{get:(t,e)=>{const s=this.stateAtoms[e];return s?s():void 0}})}get state(){return this.getSnapshot()}get computed(){const t={};return this.computedKeys.forEach(e=>{t[e]=this.computedAtoms[e]()}),t}getComputedKey(t){return this.computedAtoms[t]()}getComputed(t){const e={};return this.computedKeys.forEach(s=>{e[s]=t[s]}),e}setStateInternal(t){this.isComputing&&console.warn("[logic-runtime] setState() called inside computed()");const e={};for(const t in this.stateAtoms)e[t]=this.stateAtoms[t]();t(e);for(const t in this.stateAtoms)e[t]!==this.stateAtoms[t]()&&this.stateAtoms[t].set(e[t])}useEffect(t,e){this.bus.effect(t,e)}attachComputed(s,n){const o=t(void 0),i=this.createReactiveState();this.computedAtoms[s]=o,this.computedKeys.add(s);const a=()=>{this.isComputing=!0,o.set(n({state:i})),this.isComputing=!1};e(a),a(),o.subscribe(this.markDirty)}}function c(t){const e={_kind:"effect",id:Symbol("effect"),handler:t,strategy:"default",wait:0};return{...e,takeLatest(){return e.strategy="takeLatest",this},debounce(t){return e.strategy="debounce",e.wait=t,this}}}function u(t){return{name:t.name,create(e){var s;const n=new r(structuredClone(t.state),e);if(t.computed)for(const e in t.computed)n.attachComputed(e,t.computed[e]);null===(s=t.intents)||void 0===s||s.call(t,{on:n.onIntent,effect:n.useEffect.bind(n)});const o={};if(t.actions){const e=Object.keys(t.actions);for(const s of e){const e=t.actions[s];o[s]=e({emit:n.emit,getState:n.getSnapshot})}}return n.actions=o,n}}}function l(t){const e=function(){let t=0,e=[];return{get records(){return e.slice()},record:function(s){e.push({...s,id:++t,state:structuredClone(s.state)})},replay:async function(t,s){const{from:n=0,to:o=1/0,scope:i}=null!=s?s:{},a=e.filter(t=>"emit"===t.type&&t.id>=n&&t.id<=o&&(!i||t.scope===i));for(const e of a){const s=t(e.intent,e.payload);s instanceof Promise&&await s}},clear:function(){e=[],t=0}}}();function s(){return"string"==typeof t.scope?t.scope:t.scope.name}return{timeline:e,wrap:function(){const n=t.emit.bind(t);t.emit=async(o,i)=>{e.record({type:"emit:start",intent:o,payload:i,scope:s(),state:t.getSnapshot(),timestamp:Date.now()});try{const t=n(o,i);t instanceof Promise&&await t}finally{e.record({type:"emit:end",intent:o,payload:i,scope:s(),state:t.getSnapshot(),timestamp:Date.now()})}}}}}function h(t){var e,o;let i=structuredClone(t);const a=()=>i,r=t=>{i={...i,...t}},c=s("backend");async function u(t,e){await h.emit(t,e,c)}const h=n(t=>{const e=new AbortController;return{scope:c,payload:t,signal:e.signal,get state(){return a()},setState(){throw new Error("setState is not allowed in backend runtime")},emit:u}});const d={state:a,reset:()=>{i=structuredClone(t)},emit:u,registerIntents:function(t){for(const e in t){const s=t[e];h.on(e,async(t,e)=>{var n;const o={get state(){return a()},signal:null!==(n=t.signal)&&void 0!==n?n:(new AbortController).signal,set:r,emit:u};await s(o)},c)}},onIntent:h.on,effect:h.effect};if("production"!==(null===(o=null===(e=null===globalThis||void 0===globalThis?void 0:globalThis.process)||void 0===e?void 0:e.env)||void 0===o?void 0:o.NODE_ENV)){const t=l(d);t.wrap(d),d.devtools=t}return d}function d(t,e,n){var a,r;const c=a=>{const r=i.useRef(null);r.current||(r.current=t.create("string"==typeof n?s(n):n));const c=r.current,u=i.useSyncExternalStore(c.subscribe,c.getSnapshot,c.getSnapshot),l=i.useCallback((t,e)=>c.emit(t,e),[c]),h=i.useMemo(()=>({state:u,actions:c.actions,emit:l}),[u,l,c]);return o(e,{...a,...h})};return c.displayName=`withLogic(${null!==(r=null!==(a=e.displayName)&&void 0!==a?a:e.name)&&void 0!==r?r:"View"})`,c}function m(t,e){const n=i.useRef(null);n.current||(n.current=t.create("string"==typeof e?s(e):e));const o=n.current,a=i.useSyncExternalStore(o.subscribe,o.getSnapshot,o.getSnapshot),r=i.useCallback((t,e)=>o.emit(t,e),[o]),c=o.actions;return i.useMemo(()=>({state:a,actions:c,emit:r}),[a,c,r])}export{r as LogicRuntime,l as attachDevtools,h as createBackendRuntime,u as createLogic,c as effect,m as useLogic,d as withLogic};
1
+ import{atom as t,effect as e}from"chrono-state-z";export{createSelector}from"chrono-state-z";import{createScope as s,createIntentBus as n}from"intentx-core-z";import{jsx as o}from"react/jsx-runtime";import*as i from"react";class a{constructor(){this.handlers={},this.effects={},this.middlewares=[]}use(t){this.middlewares.push(t)}effect(t,e){var s,n;(null!==(s=(n=this.effects)[t])&&void 0!==s?s:n[t]=[]).push(e)}on(t,e){var s,n;const o=this.handlers[t];o&&o.length>0?console.warn(`[IntentBus] Duplicate intent handler "${t}" detected. Only the first handler will be used.`):(null!==(s=(n=this.handlers)[t])&&void 0!==s?s:n[t]=[]).push(e)}async emit(t,e){var s,n;const o=null!==(s=this.handlers[t])&&void 0!==s?s:[],i=null!==(n=this.effects[t])&&void 0!==n?n:[],a=(r=this.middlewares,c=async t=>{t.effects=i;for(const e of o)await e(t)},r.reduceRight((t,e)=>e(t),c));var r,c;await a(e)}}class r{constructor(t,e=s("logic")){this.computedAtoms={},this.subs=new Set,this.bus=new a,this.dirty=!0,this.isComputing=!1,this.computedKeys=new Set,this.markDirty=()=>{this.dirty=!0,this.subs.forEach(t=>t())},this.getSnapshot=()=>(this.dirty&&(this.snapshotCache=this.buildSnapshot(),this.dirty=!1),this.snapshotCache),this.subscribe=t=>(this.subs.add(t),()=>this.subs.delete(t)),this.onIntent=(t,e)=>{this.bus.on(t,e)},this.emit=async(t,e)=>{const s=new AbortController;await this.bus.emit(t,{payload:e,scope:this.scope,signal:s.signal,state:this.getSnapshot,setState:t=>this.setStateInternal(t),emit:this.emit})},this.scope=e,this.stateAtoms=this.createStateAtoms(t);for(const t in this.stateAtoms)this.stateAtoms[t].subscribe(this.markDirty);this.bus.use(function(){const t=new Map,e=new Map;return s=>async n=>{var o;const i=n.effects;if(!(null==i?void 0:i.length))return s(n);for(const s of i){const i=s.id;if("takeLatest"===s.strategy){null===(o=t.get(i))||void 0===o||o.abort();const e=new AbortController;t.set(i,e),await s.handler({...n,signal:e.signal})}else"debounce"===s.strategy?(clearTimeout(e.get(i)),e.set(i,setTimeout(()=>s.handler(n),s.wait))):await s.handler(n)}await s(n)}}())}createStateAtoms(e){const s={};for(const n in e)s[n]=t(e[n]);return s}buildSnapshot(){const t={};for(const e in this.stateAtoms)t[e]=this.stateAtoms[e]();for(const e in this.computedAtoms)t[e]=this.computedAtoms[e]();return t}createReactiveState(){return new Proxy({},{get:(t,e)=>{const s=this.stateAtoms[e];return s?s():void 0}})}get state(){return this.getSnapshot()}get computed(){const t={};return this.computedKeys.forEach(e=>{t[e]=this.computedAtoms[e]()}),t}getComputedKey(t){return this.computedAtoms[t]()}getComputed(t){const e={};return this.computedKeys.forEach(s=>{e[s]=t[s]}),e}setStateInternal(t){this.isComputing&&console.warn("[logic-runtime] setState() called inside computed()");const e={};for(const t in this.stateAtoms)e[t]=this.stateAtoms[t]();t(e);for(const t in this.stateAtoms)e[t]!==this.stateAtoms[t]()&&this.stateAtoms[t].set(e[t])}useEffect(t,e){this.bus.effect(t,e)}attachComputed(s,n){const o=t(void 0),i=this.createReactiveState();this.computedAtoms[s]=o,this.computedKeys.add(s);const a=()=>{this.isComputing=!0,o.set(n({state:i})),this.isComputing=!1};e(a),a(),o.subscribe(this.markDirty)}}function c(t){const e={_kind:"effect",id:Symbol("effect"),handler:t,strategy:"default",wait:0};return{...e,takeLatest(){return e.strategy="takeLatest",this},debounce(t){return e.strategy="debounce",e.wait=t,this}}}function u(t){return{name:t.name,create(e){var s,n;const o=new r(structuredClone(t.state),e);if(t.computed)for(const e in t.computed)o.attachComputed(e,t.computed[e]);null===(s=t.intents)||void 0===s||s.call(t,{on:o.onIntent,effect:o.useEffect.bind(o)});const i={};if(t.actions){const e=Object.keys(t.actions);for(const s of e){const e=t.actions[s];i[s]=e({emit:o.emit,getState:o.getSnapshot})}}return o.actions=i,null===(n=t.bootstrap)||void 0===n||n.call(t,{runtime:o,emit:o.emit,getState:o.getSnapshot}),o}}}function l(t){const e=function(){let t=0,e=[];return{get records(){return e.slice()},record:function(s){e.push({...s,id:++t,state:structuredClone(s.state)})},replay:async function(t,s){const{from:n=0,to:o=1/0,scope:i}=null!=s?s:{},a=e.filter(t=>"emit"===t.type&&t.id>=n&&t.id<=o&&(!i||t.scope===i));for(const e of a){const s=t(e.intent,e.payload);s instanceof Promise&&await s}},clear:function(){e=[],t=0}}}();function s(){return"string"==typeof t.scope?t.scope:t.scope.name}return{timeline:e,wrap:function(){const n=t.emit.bind(t);t.emit=async(o,i)=>{e.record({type:"emit:start",intent:o,payload:i,scope:s(),state:t.getSnapshot(),timestamp:Date.now()});try{const t=n(o,i);t instanceof Promise&&await t}finally{e.record({type:"emit:end",intent:o,payload:i,scope:s(),state:t.getSnapshot(),timestamp:Date.now()})}}}}}var h,d;const m="production"!==(null===(d=null===(h=null===globalThis||void 0===globalThis?void 0:globalThis.process)||void 0===h?void 0:h.env)||void 0===d?void 0:d.NODE_ENV);function f(t){let e=structuredClone(t);const o=()=>e,i=t=>{e={...e,...t}},a=s("backend");async function r(t,e){await c.emit(t,e,a)}const c=n(t=>{const e=new AbortController;return{scope:a,payload:t,signal:e.signal,get state(){return o()},setState(){throw new Error("setState is not allowed in backend runtime")},emit:r}});const u={state:o,reset:()=>{e=structuredClone(t)},emit:r,registerIntents:function(t){for(const e in t){const s=t[e];c.on(e,async(t,e)=>{var n;const a={get state(){return o()},signal:null!==(n=t.signal)&&void 0!==n?n:(new AbortController).signal,set:i,emit:r};await s(a)},a)}},onIntent:c.on,effect:c.effect};if(m){const t=l(u);t.wrap(u),u.devtools=t}return u}function p(t,e,n){var a,r;const c=a=>{const r=i.useRef(null);r.current||(r.current=t.create("string"==typeof n?s(n):n));const c=r.current,u=i.useSyncExternalStore(c.subscribe,c.getSnapshot,c.getSnapshot),l=i.useCallback((t,e)=>c.emit(t,e),[c]),h=i.useMemo(()=>({state:u,actions:c.actions,emit:l}),[u,l,c]);return o(e,{...a,...h})};return c.displayName=`withLogic(${null!==(r=null!==(a=e.displayName)&&void 0!==a?a:e.name)&&void 0!==r?r:"View"})`,c}function g(t,e){const n=i.useRef(null);n.current||(n.current=t.create("string"==typeof e?s(e):e));const o=n.current,a=i.useSyncExternalStore(o.subscribe,o.getSnapshot,o.getSnapshot),r=i.useCallback((t,e)=>o.emit(t,e),[o]),c=o.actions;return i.useMemo(()=>({state:a,actions:c,emit:r}),[a,c,r])}export{r as LogicRuntime,l as attachDevtools,f as createBackendRuntime,u as createLogic,c as effect,g as useLogic,p as withLogic};
@@ -17,12 +17,17 @@ export declare function createLogic<S extends object, C extends ComputedDef<S>,
17
17
  }) => (...args: any[]) => any>>(config: {
18
18
  name?: string;
19
19
  state: S;
20
- computed: C;
20
+ computed?: C;
21
21
  intents?: (bus: {
22
22
  on: LogicRuntime<S, C, any>["onIntent"];
23
23
  effect: (type: string, eff: EffectDef) => void;
24
24
  }) => void;
25
25
  actions: ActionsDef;
26
+ bootstrap?: (context: {
27
+ runtime: LogicRuntime<S, C, any>;
28
+ emit: LogicRuntime<S, C, any>["emit"];
29
+ getState: LogicRuntime<S, C, any>["getSnapshot"];
30
+ }) => void | Promise<void>;
26
31
  }): LogicFactory<S, C, {
27
32
  [K in keyof ActionsDef]: ReturnType<ActionsDef[K]>;
28
33
  }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "logic-runtime-react-z",
3
- "version": "3.1.4",
3
+ "version": "3.1.6",
4
4
  "description": "Intent-first business logic runtime. Deterministic, headless, and framework-agnostic.",
5
5
  "license": "MIT",
6
6
  "author": "Delpi.Kye",
@@ -75,7 +75,7 @@
75
75
  "typescript": "^5.3.3"
76
76
  },
77
77
  "dependencies": {
78
- "chrono-state-z": "^2.1.0",
79
- "intentx-core-z": "^2.1.0"
78
+ "chrono-state-z": "^2.2.1",
79
+ "intentx-core-z": "^2.2.1"
80
80
  }
81
81
  }