logic-runtime-react-z 3.1.2 → 3.1.3

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
@@ -4,13 +4,12 @@
4
4
 
5
5
  <a href="https://codesandbox.io/p/sandbox/jnd992" target="_blank">LIVE EXAMPLE</a>
6
6
 
7
- **Intent-first business logic runtime**: React is a **view** logic lives **elsewhere**.
7
+ **Intent-First Business Logic Runtime.**. React is a view layer. Business logic lives elsewhere.
8
8
 
9
- A headless, deterministic, intent-driven runtime for frontend & backend logic.
10
- React components stay pure. Business logic is fully testable, replayable, and framework-agnostic.
9
+ A headless, deterministic, intent-driven runtime for frontend and backend systems.
11
10
 
12
- > **Intent is the only entry point.**
13
- > **React is optional. `createLogic` is the product. Everything else is an adapter.**
11
+ > **Intent is the only entry point. Logic is deterministic.**
12
+ > **React is optional** `createLogic` is the product; everything else is an adapter.
14
13
 
15
14
  ---
16
15
 
@@ -59,7 +58,7 @@ npm install logic-runtime-react-z
59
58
  import { createLogic } from "logic-runtime-react-z"
60
59
 
61
60
  const counterLogic = createLogic({
62
- state: { count: 0 },
61
+ state: { count: 0, loading: false },
63
62
 
64
63
  intents: bus => {
65
64
  bus.on("inc", ({ setState }) => {
@@ -73,6 +72,23 @@ const counterLogic = createLogic({
73
72
  s.count += payload
74
73
  })
75
74
  })
75
+
76
+ bus.on("dec", ({ setState }) => {
77
+ setState(s => {
78
+ s.count--
79
+ })
80
+ })
81
+
82
+ bus.on("asyncInc", async ({ setState }) => {
83
+ setState(s => { s.loading = true })
84
+
85
+ await new Promise(r => setTimeout(r, 1000))
86
+
87
+ setState(s => {
88
+ s.count++
89
+ s.loading = false
90
+ })
91
+ })
76
92
  },
77
93
  })
78
94
 
@@ -111,124 +127,111 @@ computed: {
111
127
  - Reading `state.count` automatically tracks dependencies.
112
128
  - Computed values are cached and only re-evaluated when tracked dependencies change.
113
129
 
114
- ---
115
-
116
- ## ⚛️ React Integration (No Hooks Required)
117
-
118
- ### Define Logic (Framework-Agnostic)
119
-
120
- ```ts
121
- // counter.logic.ts
122
- import { createLogic, effect } from "logic-runtime-react-z"
123
130
 
124
- export const counterLogic = createLogic({
125
- name: "counter",
131
+ ---
126
132
 
127
- state: {
128
- count: 1,
129
- loading: false,
130
- },
133
+ ## ⚛️ React Integration
131
134
 
132
- computed: {
133
- double: ({ state }) => state.count * 2,
134
- triple: ({ state }) => state.count * 3,
135
- },
135
+ React is a thin adapter.
136
136
 
137
- intents: bus => {
138
- bus.on("inc", ({ setState }) => {
139
- setState(s => {
140
- s.count++
141
- })
142
- })
137
+ You have **2 integration styles**:
143
138
 
144
- bus.on<number>("add", ({ payload, setState }) => {
145
- setState(s => {
146
- s.count += payload
147
- })
148
- })
139
+ - `withLogic` Recommended
140
+ - `useLogic` → Direct hook usage
149
141
 
150
- bus.on<number>("inc-async", async ({ payload, setState }) => {
151
- setState(s => {
152
- s.loading = true
153
- })
142
+ #### 🧩 Option 1 withLogic (Recommended)
154
143
 
155
- await new Promise(r => setTimeout(r, 1000))
144
+ Keeps view pure and declarative.
156
145
 
157
- setState(s => {
158
- s.count += payload
159
- s.loading = false
160
- })
161
- })
146
+ ```tsx
147
+ import { withLogic, LogicViewProps } from "logic-runtime-react-z"
148
+ import { counterLogic } from "./counter.logic"
162
149
 
163
- // effects = side-effects only (no state mutation)
164
- bus.effect(
165
- "inc-async",
166
- effect(async ({ payload }) => {
167
- console.log("effect run:", payload)
168
- }).takeLatest()
169
- )
170
- },
150
+ type CounterInjected =
151
+ LogicViewProps<typeof counterLogic>
171
152
 
172
- actions: {
173
- inc({ emit }) {
174
- return () => emit("inc")
175
- },
153
+ const CounterView = ({ state, computed, intent }: LogicViewProps) => {
154
+ return (
155
+ <div>
156
+ <h2>Count: {state.count}</h2>
157
+ <p>Double: {computed.double}</p>
158
+ <p>Triple: {computed.triple}</p>
159
+
160
+ <button onClick={() => intent("inc")}>+</button>
161
+ <button onClick={() => intent("dec")}>-</button>
162
+ <button onClick={() => intent("asyncInc")}>
163
+ {state.loading ? "Loading..." : "Async +"}
164
+ </button>
165
+ </div>
166
+ )
167
+ }
176
168
 
177
- add({ emit }) {
178
- return (n: number) => emit("add", n)
179
- },
169
+ // export default withLogic(counterLogic)(CounterView)
170
+ export const CounterPage = withLogic(counterLogic, CounterView)
171
+ ```
180
172
 
181
- incAsync({ emit }) {
182
- return (n: number) => emit("inc-async", n)
183
- },
184
- },
185
- })
173
+ <b> Why this is recommended?</b>
186
174
 
187
- ```
175
+ - View is fully testable
176
+ - No hooks inside view
177
+ - Logic can be reused outside React
178
+ - Clear separation of concerns
188
179
 
189
180
  ---
190
181
 
191
- ### Pure React View (Dumb View)
182
+ #### 🪝 Option 2 useLogic
183
+
184
+ Use directly inside a component.
192
185
 
193
186
  ```tsx
194
- import React from "react"
195
- import { withLogic } from "logic-runtime-react-z"
187
+ import { useLogic } from "logic-runtime-react-z"
196
188
  import { counterLogic } from "./counter.logic"
197
189
 
198
- function CounterView(props) {
199
- const { state, actions, emit } = props
190
+ export function Counter() {
191
+ const { state, computed, intent } = useLogic(counterLogic)
200
192
 
201
193
  return (
202
- <div style={{ padding: 12 }}>
203
- <div>Triple Count: {state.triple}</div>
204
-
205
- <button onClick={actions.inc}>+1</button>
206
- <button onClick={() => actions.add(10)}>+10</button>
207
-
208
- <button
209
- disabled={state.loading}
210
- onClick={() => actions.incAsync(5)}
211
- >
212
- Async +5
213
- </button>
214
-
215
- <hr />
216
-
217
- <button onClick={() => emit("inc")}>
218
- emit("inc")
194
+ <div>
195
+ <h2>Count: {state.count}</h2>
196
+ <p>Double: {computed.double}</p>
197
+ <p>Triple: {computed.triple}</p>
198
+
199
+ <button onClick={() => intent("inc")}>+</button>
200
+ <button onClick={() => intent("dec")}>-</button>
201
+ <button onClick={() => intent("asyncInc")}>
202
+ {state.loading ? "Loading..." : "Async +"}
219
203
  </button>
220
204
  </div>
221
205
  )
222
206
  }
207
+ ```
223
208
 
224
- export const CounterPage = withLogic(counterLogic, CounterView)
209
+ Props are inferred when using useLogic, no manual generics required.
210
+
211
+ ---
212
+
213
+ ## 🌊 Async Support
214
+
215
+ Async logic is just another intent.
216
+
217
+ ```ts
218
+ bus.on("fetchUser", async ({ setState }) => {
219
+ setState(s => { s.loading = true })
220
+
221
+ const data = await api.getUser()
225
222
 
223
+ setState(s => {
224
+ s.user = data
225
+ s.loading = false
226
+ })
227
+ })
226
228
  ```
227
229
 
228
- Props are inferred when using withLogic, no manual generics required.
230
+ No special async API needed.
229
231
 
230
232
  ---
231
233
 
234
+
232
235
  ## 🧪 Backend Usage (Same Runtime)
233
236
 
234
237
  ```ts
@@ -274,134 +277,12 @@ async function run() {
274
277
  run()
275
278
  ```
276
279
 
277
- ✔ Same runtime, same behavior, no React involved.
278
- ✔ No React
279
- ✔ Replayable
280
-
281
- ---
282
-
283
- ## 🪝 Hooks Examples (Optional, Thin Adapters)
284
-
285
- Hooks are optional convenience layers on top of the same logic runtime.
286
- They do not own state, they only subscribe to it.
287
-
288
- #### useRuntime – full snapshot
289
- ```ts
290
- import { useRuntime } from "logic-runtime-react-z"
291
-
292
- function Debug() {
293
- const snapshot = useRuntime(counterLogic)
294
- return <pre>{JSON.stringify(snapshot, null, 2)}</pre>
295
- }
296
- ```
297
-
298
- ✔ Subscribes to full snapshot
299
- ✔ Includes state + computed
300
- ✔ Read-only
301
-
302
- #### useActions – actions only (no re-render)
303
- ```ts
304
- import { useActions } from "logic-runtime-react-z"
305
-
306
- function Buttons() {
307
- const actions = useActions(counterLogic)
308
-
309
- return (
310
- <>
311
- <button onClick={actions.inc}>+1</button>
312
- <button onClick={() => actions.add(5)}>+5</button>
313
- </>
314
- )
315
- }
316
- ```
317
-
318
-
319
- ✔ No re-render on state change
320
- ✔ Fully inferred action types
321
- ✔ Ideal for buttons / handlers
322
-
323
- #### useComputed – Subscribe to computed values
324
- ```ts
325
- import { useComputed } from "logic-runtime-react-z"
326
-
327
- function Stats() {
328
- const { double, triple } = useComputed(counterLogic)
329
-
330
- return (
331
- <>
332
- <div>Double: {double}</div>
333
- <div>Triple: {triple}</div>
334
- </>
335
- )
336
- }
337
-
338
- function DoubleOnly() {
339
- const double = useComputed(counterLogic, c => c.double)
340
- return <div>{double}</div>
341
- }
342
- ```
343
-
344
- ✔ Only derived data
345
- ✔ Cached & reactive
346
- ✔ No state mutation possible
347
-
348
- #### useComputed with selector (recommended)
349
- ```ts
350
- function DoubleOnly() {
351
- const double = useComputed(
352
- counterLogic,
353
- c => c.double
354
- )
355
-
356
- return <div>Double: {double}</div>
357
- }
358
- ```
359
-
360
- ✔ Component re-renders only when double changes
361
- ✔ No extra dependencies
362
- ✔ Type-safe selector
363
-
364
- #### useLogicSelector – State selector (Redux-like)
365
- ```ts
366
- import { useLogicSelector } from "logic-runtime-react-z"
367
-
368
- function CountLabel() {
369
- const count = useLogicSelector(
370
- counterLogic,
371
- state => state.count
372
- )
373
-
374
- return <span>{count}</span>
375
- }
376
- ```
377
-
378
- ✔ Memoized selector
379
- ✔ Fine-grained subscriptions
380
- ✔ Familiar mental model
280
+ ✔ Same runtime, same behavior.
281
+ ✔ No React dependency
282
+ ✔ Replayable execution
381
283
 
382
284
  ---
383
285
 
384
- ## 🧱 Composing Multiple Logic Modules
385
-
386
- ```ts
387
- import { composeLogic } from "logic-runtime-react-z"
388
- import { userLogic } from "./user.logic"
389
- import { cartLogic } from "./cart.logic"
390
-
391
- const app = composeLogic({
392
- user: userLogic,
393
- cart: cartLogic,
394
- })
395
-
396
- await app.emit("login")
397
-
398
- const state = app.getState()
399
- state.user
400
- state.cart
401
-
402
- ```
403
-
404
- ---
405
286
 
406
287
  ## 🧪 Unit Test Example
407
288
 
@@ -422,55 +303,85 @@ const logic = createLogic({
422
303
  },
423
304
  })
424
305
 
425
- const runtime = counterLogic.create()
306
+ const runtime = logic.create()
426
307
 
427
308
  await runtime.emit("set", 4)
428
309
  expect(runtime.computed.squared).toBe(16)
429
310
  ```
430
311
 
431
- ✔ Computed values are tested like plain data
432
-
433
312
  ---
434
313
 
435
314
  ## 🔍 Comparison
436
315
 
437
- | Criteria | logic-runtime-react-z | Redux | Zustand | Recoil | MobX |
438
- | ----------------------------------------- | :---------------------: | :------------------: | :-------------------: | :----------------------------: | :-------------------------: |
439
- | **Intent-first model** ||| | ⚠️ | ⚠️ |
440
- | **State-first model** | ❌ | ✅ | ✅ | ✅ | ✅ |
441
- | **First-class effect orchestration** | (built-in) | ⚠️ (via middleware) | ⚠️ (via middleware) | ⚠️ (selectors + async helpers) | ⚠️ (actions + reactions) |
442
- | **Fine-grained derived state (computed)** | (reactive & cached) | ❌ | ⚠️ (simple selectors) | (dependency graph) | ⚠️ (observable derivations) |
443
- | **Predictable execution semantics** | 🔁 intent queue/rules | 👍 sync + middleware | 👍 sync | 👍 sync | 👍 sync |
444
- | **Async control strategies built-in** | ✅ takeLatest / debounce | ❌ | ❌ | ❌ | ❌ |
445
- | **Logic outside React** | | ⚠️ | ⚠️ | ⚠️ | ⚠️ |
446
- | **Framework-agnostic** | |||||
447
- | **Backend-ready usage** | | ⚠️ | ⚠️ | ⚠️ | ⚠️ |
448
- | **Type-inferred actions** | | ⚠️ | ⚠️ | ⚠️ | ⚠️ |
449
- | **Minimal re-render strategies** | selectors/hooks | selectors | selectors | atoms/selectors | global observables |
450
- | **Devtools ecosystem** | ⚠️ (nascent) | | ⚠️ | ⚠️ | ⚠️ |
316
+ This is not about “better” — it's about architectural intent.
317
+
318
+ | Criteria | logic-runtime-react-z | Redux Toolkit | Zustand | Recoil | MobX |
319
+ |---------------------------------|------------------------------|----------------------|----------------|---------------|----------------|
320
+ | **Primary abstraction** | Intent runtime | Reducer store | Store | Atom graph | Observable |
321
+ | **Mental model** | Intent Behavior → State | Action Reducer | Mutate store | Atom graph | Reactive graph |
322
+ | **Single mutation entry** | ✅ | | | | |
323
+ | **Business logic isolation** | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ |
324
+ | **Built-in async orchestration**| | ⚠️ ||| |
325
+ | **Deterministic execution** | || ⚠️ | ⚠️ | ⚠️ |
326
+ | **Derived state built-in** | || ⚠️ || |
327
+ | **Headless runtime** | | ⚠️ | ⚠️ || ⚠️ |
328
+ | **Backend / worker ready** | | ⚠️ | ⚠️ | | |
329
+ | **Side-effect centralization** | ✅ | ⚠️ || ❌ | ⚠️ |
330
+ | **Devtools maturity** | ⚠️ | ✅ | ⚠️ | ⚠️ | ⚠️ |
331
+
332
+
333
+ <br />
334
+
335
+ ✅ Built-in / first-class
336
+ ⚠️ Possible / usage-dependent
337
+ ❌ Not built-in
451
338
 
339
+ ---
340
+
341
+ ### 🧠 Architectural Difference
342
+
343
+ Most state libraries focus on:
344
+
345
+ > **How state is stored and updated**
346
+
347
+ `logic-runtime-react-z` focuses on:
452
348
 
349
+ > **How behavior is orchestrated through intents**
453
350
 
454
- <b>⚠️ via selectors, not a true dependency graph. </b>
351
+ Redux/Zustand answer:
352
+ > "Where is my state and how do I change it?"
353
+
354
+ This runtime answers:
355
+ > "What behavior is triggered by this event, and how should it execute?"
455
356
 
456
357
  ---
457
358
 
458
- ## Why not Redux + RTK?
359
+ ### 🧭 Positioning Summary
360
+
361
+ - Redux → Structured state container
362
+ - Zustand → Lightweight mutable store
363
+ - Recoil → Declarative dependency graph
364
+ - MobX → Reactive observable system
365
+ - **logic-runtime-react-z → Intent-first behavior runtime**
366
+
367
+ ---
459
368
 
460
- Redux focuses on state transitions.
369
+ ### 🎯 When This Makes Sense
461
370
 
462
- logic-runtime-react-z models system behavior.
371
+ Choose this if you need:
463
372
 
464
- In Redux:
465
- - async flow is external (thunk/saga)
466
- - effects are not first-class
467
- - execution model depends on middleware setup
373
+ - Complex async flows
374
+ - Deterministic replayable behavior
375
+ - Logic shared between frontend & backend
376
+ - Strong separation between UI and domain behavior
377
+ - An explicit event-driven boundary
468
378
 
469
- In logic-runtime-react-z:
470
- - async orchestration is built-in
471
- - intent is the only entry point
472
- - execution order is guaranteed
379
+ Choose simpler state tools if:
473
380
 
381
+ - You mostly manage UI state
382
+ - You don’t need orchestration
383
+ - Your async flows are trivial
384
+ - Your team prefers mutable patterns
474
385
 
475
386
  ---
476
387
 
@@ -485,7 +396,7 @@ In logic-runtime-react-z:
485
396
 
486
397
  - Intents are processed sequentially
487
398
  - State mutations are isolated
488
- - Async effects follow declared strategies (takeLatest, debounce, etc.)
399
+ - Async effects can follow declared execution strategies.
489
400
  - Execution order is predictable
490
401
 
491
402
  Given the same intent sequence, the resulting state is reproducible.
@@ -1 +1 @@
1
- "use strict";var t=require("chrono-state-z"),e=require("intentx-core-z"),s=require("react/jsx-runtime"),n=require("react");function o(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 r=o(n);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:[],r=null!==(n=this.effects[t])&&void 0!==n?n:[],i=(c=this.middlewares,a=async t=>{t.effects=r;for(const e of o)await e(t)},c.reduceRight((t,e)=>e(t),a));var c,a;await i(e)}}class c{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 r=n.effects;if(!(null==r?void 0:r.length))return s(n);for(const s of r){const r=s.id;if("takeLatest"===s.strategy){null===(o=t.get(r))||void 0===o||o.abort();const e=new AbortController;t.set(r,e),await s.handler({...n,signal:e.signal})}else"debounce"===s.strategy?(clearTimeout(e.get(r)),e.set(r,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),t.effect(()=>{this.isComputing=!0,n.set(s({state:o})),this.isComputing=!1}),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:r}=null!=s?s:{},i=e.filter(t=>"emit"===t.type&&t.id>=n&&t.id<=o&&(!r||t.scope===r));for(const e of i){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,r)=>{e.record({type:"emit:start",intent:o,payload:r,scope:s(),state:t.getSnapshot(),timestamp:Date.now()});try{const t=n(o,r);t instanceof Promise&&await t}finally{e.record({type:"emit:end",intent:o,payload:r,scope:s(),state:t.getSnapshot(),timestamp:Date.now()})}}}}}function u(t){var s;const o=n.useRef(null),r=t&&"function"==typeof t.subscribe&&"function"==typeof t.getSnapshot?t:null!==(s=o.current)&&void 0!==s?s:o.current=t.create(e.createScope("react"));return n.useSyncExternalStore(r.subscribe,r.getSnapshot,r.getSnapshot)}Object.defineProperty(exports,"createSelector",{enumerable:!0,get:function(){return t.createSelector}}),exports.LogicRuntime=c,exports.attachDevtools=a,exports.composeLogic=function(t){const s=e.createScope("logic"),n={};for(const e in t)n[e]=t[e].create(s);const o={};for(const t in n)o[t]=n[t].actions;return{scope:s,runtimes:n,emit:async(t,e)=>{await Promise.all(Object.values(n).map(s=>s.emit(t,e)))},actions:o,getState:()=>{const t={};for(const e in n)t[e]=n[e].state;return t}}},exports.createBackendRuntime=function(t){var s,n;let o=structuredClone(t);const r=()=>o,i=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 r()},setState(){throw new Error("setState is not allowed in backend runtime")},emit:u}}),h={state:r,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 r()},signal:null!==(n=t.signal)&&void 0!==n?n:(new AbortController).signal,set:i,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 c(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)for(const e in t.actions)o[e]=t.actions[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.useActions=function(t){return(t instanceof c?t:u(t).__runtime).actions},exports.useComputed=function(e,s){const o=e instanceof c?e:u(e).__runtime;if(!s)return n.useSyncExternalStore(o.subscribe,()=>o.getComputed(o.getSnapshot()),()=>o.getComputed(o.getSnapshot()));const r=n.useMemo(()=>t.createSelector(s),[s]);return n.useSyncExternalStore(o.subscribe,()=>r(o.getComputed(o.getSnapshot())),()=>r(o.getComputed(o.getSnapshot())))},exports.useLogic=function(t){const e=n.useSyncExternalStore(t.subscribe,t.getSnapshot,t.getSnapshot);return{state:e,computed:t.getComputed(e),actions:t.actions}},exports.useLogicSelector=function(e,s){const o=n.useMemo(()=>t.createSelector(s),[s]);return n.useSyncExternalStore(e.subscribe,()=>o(e.getSnapshot()),()=>o(e.getSnapshot()))},exports.useRuntime=u,exports.withLogic=function(t,n,o){var i,c;const a=i=>{const c=r.useRef(null);c.current||(c.current=t.create("string"==typeof o?e.createScope(o):o));const a=c.current,u=r.useSyncExternalStore(a.subscribe,a.getSnapshot,a.getSnapshot),l=r.useCallback((t,e)=>a.emit(t,e),[a]),h=r.useMemo(()=>({state:u,actions:a.actions,emit:l}),[u,l,a]);return s.jsx(n,{...i,...h})};return a.displayName=`withLogic(${null!==(c=null!==(i=n.displayName)&&void 0!==i?i:n.name)&&void 0!==c?c:"View"})`,a};
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};
package/build/index.d.ts CHANGED
@@ -5,12 +5,8 @@ export { effect } from "./core/effect";
5
5
  export type { IntentMiddleware, IntentNext, } from "./core/middleware";
6
6
  export { createLogic } from "./logic/createLogic";
7
7
  export type { LogicFactory, LogicActions, } from "./logic/createLogic";
8
- export { composeLogic } from "./logic/composeLogic";
9
8
  export { createBackendRuntime } from "./logic/createBackendRuntime";
10
9
  export { withLogic } from "./react/withLogic";
11
- export { useActions } from "./react/useActions";
12
- export { useComputed } from "./react/useComputed";
10
+ export type { LogicViewProps } from "./react/withLogic";
13
11
  export { useLogic } from "./react/useLogic";
14
- export { useLogicSelector } from "./react/useLogicSelector";
15
- export { useRuntime } from "./react/useRuntime";
16
12
  export * from "./devtools";
@@ -1 +1 @@
1
- import{atom as t,effect as e,createSelector as s}from"chrono-state-z";export{createSelector}from"chrono-state-z";import{createScope as n,createIntentBus as o}from"intentx-core-z";import{jsx as i}from"react/jsx-runtime";import*as r from"react";import{useRef as a,useSyncExternalStore as c,useMemo as u}from"react";class l{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 h{constructor(t,e=n("logic")){this.computedAtoms={},this.subs=new Set,this.bus=new l,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),e(()=>{this.isComputing=!0,o.set(n({state:i})),this.isComputing=!1}),o.subscribe(this.markDirty)}}function m(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 d(t){return{name:t.name,create(e){var s;const n=new h(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)for(const e in t.actions)o[e]=t.actions[e]({emit:n.emit,getState:n.getSnapshot});return n.actions=o,n}}}function p(t){const e=n("logic"),s={};for(const n in t)s[n]=t[n].create(e);const o={};for(const t in s)o[t]=s[t].actions;return{scope:e,runtimes:s,emit:async(t,e)=>{await Promise.all(Object.values(s).map(s=>s.emit(t,e)))},actions:o,getState:()=>{const t={};for(const e in s)t[e]=s[e].state;return t}}}function f(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()})}}}}}function g(t){var e,s;let i=structuredClone(t);const r=()=>i,a=t=>{i={...i,...t}},c=n("backend");async function u(t,e){await l.emit(t,e,c)}const l=o(t=>{const e=new AbortController;return{scope:c,payload:t,signal:e.signal,get state(){return r()},setState(){throw new Error("setState is not allowed in backend runtime")},emit:u}});const h={state:r,reset:()=>{i=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 r()},signal:null!==(n=t.signal)&&void 0!==n?n:(new AbortController).signal,set:a,emit:u};await s(o)},c)}},onIntent:l.on,effect:l.effect};if("production"!==(null===(s=null===(e=null===globalThis||void 0===globalThis?void 0:globalThis.process)||void 0===e?void 0:e.env)||void 0===s?void 0:s.NODE_ENV)){const t=f(h);t.wrap(h),h.devtools=t}return h}function b(t,e,s){var o,a;const c=o=>{const a=r.useRef(null);a.current||(a.current=t.create("string"==typeof s?n(s):s));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 i(e,{...o,...h})};return c.displayName=`withLogic(${null!==(a=null!==(o=e.displayName)&&void 0!==o?o:e.name)&&void 0!==a?a:"View"})`,c}function y(t){var e;const s=a(null),o=t&&"function"==typeof t.subscribe&&"function"==typeof t.getSnapshot?t:null!==(e=s.current)&&void 0!==e?e:s.current=t.create(n("react"));return c(o.subscribe,o.getSnapshot,o.getSnapshot)}function w(t){return(t instanceof h?t:y(t).__runtime).actions}function S(t,e){const n=t instanceof h?t:y(t).__runtime;if(!e)return c(n.subscribe,()=>n.getComputed(n.getSnapshot()),()=>n.getComputed(n.getSnapshot()));const o=u(()=>s(e),[e]);return c(n.subscribe,()=>o(n.getComputed(n.getSnapshot())),()=>o(n.getComputed(n.getSnapshot())))}function v(t){const e=c(t.subscribe,t.getSnapshot,t.getSnapshot);return{state:e,computed:t.getComputed(e),actions:t.actions}}function C(t,e){const n=u(()=>s(e),[e]);return c(t.subscribe,()=>n(t.getSnapshot()),()=>n(t.getSnapshot()))}export{h as LogicRuntime,f as attachDevtools,p as composeLogic,g as createBackendRuntime,d as createLogic,m as effect,w as useActions,S as useComputed,v as useLogic,C as useLogicSelector,y as useRuntime,b 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;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};
@@ -6,18 +6,23 @@ export type LogicFactory<S extends object, C extends ComputedDef<S>, A extends L
6
6
  name?: string;
7
7
  create(scope?: Scope): LogicRuntime<S, C, A>;
8
8
  };
9
- export declare function createLogic<S extends object, C extends ComputedDef<S> = {}, A extends LogicActions = {}>(config: {
9
+ export type ExtractLogicTypes<T> = T extends LogicFactory<infer S, infer C, infer A> ? {
10
+ state: Readonly<S & InferComputed<C>>;
11
+ actions: A;
12
+ emit: (intent: string, payload?: any) => Promise<void>;
13
+ } : never;
14
+ export declare function createLogic<S extends object, C extends ComputedDef<S>, ActionsDef extends Record<string, (context: {
15
+ emit: LogicRuntime<S, C, any>["emit"];
16
+ getState: () => Readonly<S & InferComputed<C>>;
17
+ }) => (...args: any[]) => any>>(config: {
10
18
  name?: string;
11
19
  state: S;
12
- computed?: C;
20
+ computed: C;
13
21
  intents?: (bus: {
14
- on: LogicRuntime<S, C, A>["onIntent"];
22
+ on: LogicRuntime<S, C, any>["onIntent"];
15
23
  effect: (type: string, eff: EffectDef) => void;
16
24
  }) => void;
17
- actions?: {
18
- [K in keyof A]: (context: {
19
- emit: LogicRuntime<S, C, A>["emit"];
20
- getState: () => Readonly<S & InferComputed<C>>;
21
- }) => A[K];
22
- };
23
- }): LogicFactory<S, C, A>;
25
+ actions: ActionsDef;
26
+ }): LogicFactory<S, C, {
27
+ [K in keyof ActionsDef]: ReturnType<ActionsDef[K]>;
28
+ }>;
@@ -1,6 +1,8 @@
1
- import { LogicRuntime, InferComputed } from "../core/runtime";
2
- export declare function useLogic<S extends object, C extends Record<string, any>, A extends Record<string, any>>(runtime: LogicRuntime<S, C, A>): {
3
- state: Readonly<S & InferComputed<C>>;
4
- computed: Readonly<InferComputed<C>>;
1
+ import { Scope } from "intentx-core-z";
2
+ import type { LogicActions, LogicFactory } from "../logic/createLogic";
3
+ import type { ComputedDef } from "../core/runtime";
4
+ export declare function useLogic<S extends object, C extends ComputedDef<S>, A extends LogicActions>(logic: LogicFactory<S, C, A>, scope?: Scope | string): {
5
+ state: Readonly<S & import("../core/runtime").InferComputed<C>>;
5
6
  actions: A;
7
+ emit: (intent: string, payload?: any) => Promise<void>;
6
8
  };
@@ -1,11 +1,12 @@
1
1
  import * as React from "react";
2
2
  import { Scope } from "intentx-core-z";
3
- import type { LogicActions, LogicFactory } from "../logic/createLogic";
3
+ import type { ExtractLogicTypes, LogicActions, LogicFactory } from "../logic/createLogic";
4
4
  import type { ComputedDef, InferComputed } from "../core/runtime";
5
5
  type InjectedProps<S extends object, C extends ComputedDef<S>, A extends LogicActions> = {
6
6
  state: Readonly<S & InferComputed<C>>;
7
7
  actions: A;
8
8
  emit: (intent: string, payload?: any) => Promise<void>;
9
9
  };
10
+ export type LogicViewProps<T extends LogicFactory<any, any, any>> = ExtractLogicTypes<T>;
10
11
  export declare function withLogic<S extends object, C extends ComputedDef<S>, A extends LogicActions, P extends object>(logic: LogicFactory<S, C, A>, View: React.ComponentType<P & InjectedProps<S, C, A>>, scope?: Scope | string): React.FC<Omit<P, keyof InjectedProps<S, C, A>>>;
11
12
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "logic-runtime-react-z",
3
- "version": "3.1.2",
3
+ "version": "3.1.3",
4
4
  "description": "Intent-first business logic runtime. Deterministic, headless, and framework-agnostic.",
5
5
  "license": "MIT",
6
6
  "author": "Delpi.Kye",
@@ -14,16 +14,6 @@
14
14
  "types": "./build/index.d.ts",
15
15
  "import": "./build/index.esm.js",
16
16
  "require": "./build/index.cjs.js"
17
- },
18
- "./react": {
19
- "types": "./build/react/index.d.ts",
20
- "import": "./build/react/index.esm.js",
21
- "require": "./build/react/index.cjs.js"
22
- },
23
- "./devtools": {
24
- "types": "./build/devtools/index.d.ts",
25
- "import": "./build/devtools/index.esm.js",
26
- "require": "./build/devtools/index.cjs.js"
27
17
  }
28
18
  },
29
19
  "files": [
@@ -1,21 +0,0 @@
1
- import { Scope } from "intentx-core-z";
2
- import type { ComputedDef, InferComputed } from "../core/runtime";
3
- import { LogicRuntime } from "../core/runtime";
4
- import type { LogicFactory } from "../logic/createLogic";
5
- type AnyLogicFactory = LogicFactory<any, ComputedDef<any>, any>;
6
- type LogicMap = Record<string, AnyLogicFactory>;
7
- type InferRuntime<L> = L extends LogicFactory<infer S, infer C, infer A> ? LogicRuntime<S, C, A> : never;
8
- type InferState<M extends LogicMap> = {
9
- [K in keyof M]: InferRuntime<M[K]> extends LogicRuntime<infer S, infer C, any> ? Readonly<S & InferComputed<C>> : never;
10
- };
11
- type InferActions<M extends LogicMap> = {
12
- [K in keyof M]: InferRuntime<M[K]> extends LogicRuntime<any, any, infer A> ? A : never;
13
- };
14
- export declare function composeLogic<M extends LogicMap>(map: M): {
15
- scope: Scope;
16
- runtimes: { [K in keyof M]: InferRuntime<M[K]>; };
17
- emit: <P = any>(type: string, payload?: P) => Promise<void>;
18
- actions: InferActions<M>;
19
- getState: () => InferState<M>;
20
- };
21
- export {};
@@ -1,4 +0,0 @@
1
- import { LogicFactory, LogicActions } from "../logic/createLogic";
2
- import { LogicRuntime, ComputedDef } from "../core/runtime";
3
- export declare function useActions<A extends LogicActions>(runtime: LogicRuntime<any, any, A>): A;
4
- export declare function useActions<S extends object, C extends ComputedDef<S>, A extends LogicActions>(logic: LogicFactory<S, C, A>): A;
@@ -1,6 +0,0 @@
1
- import { LogicFactory } from "../logic/createLogic";
2
- import { LogicRuntime, ComputedDef, InferComputed } from "../core/runtime";
3
- export declare function useComputed<S extends object, C extends ComputedDef<S>>(runtime: LogicRuntime<S, C, any>): Readonly<InferComputed<C>>;
4
- export declare function useComputed<S extends object, C extends ComputedDef<S>, R>(runtime: LogicRuntime<S, C, any>, selector: (computed: Readonly<InferComputed<C>>) => R): R;
5
- export declare function useComputed<S extends object, C extends ComputedDef<S>, A extends Record<string, any>>(logic: LogicFactory<S, C, A>): Readonly<InferComputed<C>>;
6
- export declare function useComputed<S extends object, C extends ComputedDef<S>, A extends Record<string, any>, R>(logic: LogicFactory<S, C, A>, selector: (computed: Readonly<InferComputed<C>>) => R): R;
@@ -1,2 +0,0 @@
1
- import { LogicRuntime, InferComputed } from "../core/runtime";
2
- export declare function useLogicSelector<S extends object, C extends Record<string, any>, R>(runtime: LogicRuntime<S, C, any>, selector: (state: Readonly<S & InferComputed<C>>) => R): R;
@@ -1,5 +0,0 @@
1
- import type { ComputedDef, InferComputed } from "../core/runtime";
2
- import { LogicRuntime } from "../core/runtime";
3
- import type { LogicFactory } from "../logic/createLogic";
4
- export declare function useRuntime<S extends object, C extends ComputedDef<S>, A extends Record<string, any>>(runtime: LogicRuntime<S, C, A>): Readonly<S & InferComputed<C>>;
5
- export declare function useRuntime<S extends object, C extends ComputedDef<S>, A extends Record<string, any>>(logic: LogicFactory<S, C, A>): Readonly<S & InferComputed<C>>;