logic-runtime-react-z 3.1.2 → 3.1.4

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,28 @@ 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
+ })
92
+ },
93
+ actions: {
94
+ add({ emit }) {
95
+ return (n: number) => emit("add", n)
96
+ }
76
97
  },
77
98
  })
78
99
 
@@ -111,124 +132,113 @@ computed: {
111
132
  - Reading `state.count` automatically tracks dependencies.
112
133
  - Computed values are cached and only re-evaluated when tracked dependencies change.
113
134
 
114
- ---
115
-
116
- ## ⚛️ React Integration (No Hooks Required)
117
135
 
118
- ### Define Logic (Framework-Agnostic)
119
-
120
- ```ts
121
- // counter.logic.ts
122
- import { createLogic, effect } from "logic-runtime-react-z"
136
+ ---
123
137
 
124
- export const counterLogic = createLogic({
125
- name: "counter",
138
+ ## ⚛️ React Integration
126
139
 
127
- state: {
128
- count: 1,
129
- loading: false,
130
- },
140
+ React is a thin adapter.
131
141
 
132
- computed: {
133
- double: ({ state }) => state.count * 2,
134
- triple: ({ state }) => state.count * 3,
135
- },
142
+ You have **2 integration styles**:
136
143
 
137
- intents: bus => {
138
- bus.on("inc", ({ setState }) => {
139
- setState(s => {
140
- s.count++
141
- })
142
- })
143
-
144
- bus.on<number>("add", ({ payload, setState }) => {
145
- setState(s => {
146
- s.count += payload
147
- })
148
- })
144
+ - `withLogic` Recommended
145
+ - `useLogic` Direct hook usage
149
146
 
150
- bus.on<number>("inc-async", async ({ payload, setState }) => {
151
- setState(s => {
152
- s.loading = true
153
- })
147
+ #### 🧩 Option 1 withLogic (Recommended)
154
148
 
155
- await new Promise(r => setTimeout(r, 1000))
149
+ Keeps view pure and declarative.
156
150
 
157
- setState(s => {
158
- s.count += payload
159
- s.loading = false
160
- })
161
- })
151
+ ```tsx
152
+ import { withLogic, LogicViewProps } from "logic-runtime-react-z"
153
+ import { counterLogic } from "./counter.logic"
162
154
 
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
- },
155
+ type CounterInjected =
156
+ LogicViewProps<typeof counterLogic>
171
157
 
172
- actions: {
173
- inc({ emit }) {
174
- return () => emit("inc")
175
- },
158
+ const CounterView = ({ state, actions, emit }: LogicViewProps) => {
159
+ // actions and emit => same emit
160
+ return (
161
+ <div>
162
+ <h2>Count: {state.count}</h2>
163
+ <p>Double: {state.double}</p>
164
+ <p>Triple: {state.triple}</p>
165
+
166
+ <button onClick={() => emit("inc")}>+</button>
167
+ <button onClick={() => emit("dec")}>-</button>
168
+ <button onClick={() => actions.add(10)}>+10 (action)</button>
169
+ <button onClick={() => emit("asyncInc")}>
170
+ {state.loading ? "Loading..." : "Async +"}
171
+ </button>
172
+ </div>
173
+ )
174
+ }
176
175
 
177
- add({ emit }) {
178
- return (n: number) => emit("add", n)
179
- },
176
+ // export default withLogic(counterLogic)(CounterView)
177
+ export const CounterPage = withLogic(counterLogic, CounterView)
178
+ ```
180
179
 
181
- incAsync({ emit }) {
182
- return (n: number) => emit("inc-async", n)
183
- },
184
- },
185
- })
180
+ <b> Why this is recommended?</b>
186
181
 
187
- ```
182
+ - View is fully testable
183
+ - No hooks inside view
184
+ - Logic can be reused outside React
185
+ - Clear separation of concerns
188
186
 
189
187
  ---
190
188
 
191
- ### Pure React View (Dumb View)
189
+ #### 🪝 Option 2 useLogic
190
+
191
+ Use directly inside a component.
192
192
 
193
193
  ```tsx
194
- import React from "react"
195
- import { withLogic } from "logic-runtime-react-z"
194
+ import { useLogic } from "logic-runtime-react-z"
196
195
  import { counterLogic } from "./counter.logic"
197
196
 
198
- function CounterView(props) {
199
- const { state, actions, emit } = props
197
+ export function Counter() {
198
+ const { state, actions, emit } = useLogic(counterLogic)
200
199
 
201
200
  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")
201
+ <div>
202
+ <h2>Count: {state.count}</h2>
203
+ <p>Double: {state.double}</p>
204
+ <p>Triple: {state.triple}</p>
205
+
206
+ <button onClick={() => emit("inc")}>+</button>
207
+ <button onClick={() => emit("dec")}>-</button>
208
+ <button onClick={() => emit("asyncInc")}>
209
+ {state.loading ? "Loading..." : "Async +"}
219
210
  </button>
220
211
  </div>
221
212
  )
222
213
  }
214
+ ```
223
215
 
224
- export const CounterPage = withLogic(counterLogic, CounterView)
216
+ Props are inferred when using useLogic, no manual generics required.
217
+
218
+ ---
219
+
220
+ ## 🌊 Async Support
221
+
222
+ Async logic is just another intent.
225
223
 
224
+ ```ts
225
+ bus.on("fetchUser", async ({ setState }) => {
226
+ setState(s => { s.loading = true })
227
+
228
+ const data = await api.getUser()
229
+
230
+ setState(s => {
231
+ s.user = data
232
+ s.loading = false
233
+ })
234
+ })
226
235
  ```
227
236
 
228
- Props are inferred when using withLogic, no manual generics required.
237
+ No special async API needed.
229
238
 
230
239
  ---
231
240
 
241
+
232
242
  ## 🧪 Backend Usage (Same Runtime)
233
243
 
234
244
  ```ts
@@ -274,134 +284,12 @@ async function run() {
274
284
  run()
275
285
  ```
276
286
 
277
- ✔ Same runtime, same behavior, no React involved.
278
- ✔ No React
279
- ✔ Replayable
287
+ ✔ Same runtime, same behavior.
288
+ ✔ No React dependency
289
+ ✔ Replayable execution
280
290
 
281
291
  ---
282
292
 
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
381
-
382
- ---
383
-
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
293
 
406
294
  ## 🧪 Unit Test Example
407
295
 
@@ -422,55 +310,85 @@ const logic = createLogic({
422
310
  },
423
311
  })
424
312
 
425
- const runtime = counterLogic.create()
313
+ const runtime = logic.create()
426
314
 
427
315
  await runtime.emit("set", 4)
428
316
  expect(runtime.computed.squared).toBe(16)
429
317
  ```
430
318
 
431
- ✔ Computed values are tested like plain data
432
-
433
319
  ---
434
320
 
435
321
  ## 🔍 Comparison
436
322
 
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) | | ⚠️ | ⚠️ | ⚠️ |
323
+ This is not about “better” — it's about architectural intent.
324
+
325
+ | Criteria | logic-runtime-react-z | Redux Toolkit | Zustand | Recoil | MobX |
326
+ |---------------------------------|------------------------------|----------------------|----------------|---------------|----------------|
327
+ | **Primary abstraction** | Intent runtime | Reducer store | Store | Atom graph | Observable |
328
+ | **Mental model** | Intent Behavior → State | Action Reducer | Mutate store | Atom graph | Reactive graph |
329
+ | **Single mutation entry** | ✅ | | | | |
330
+ | **Business logic isolation** | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ |
331
+ | **Built-in async orchestration**| | ⚠️ ||| |
332
+ | **Deterministic execution** | || ⚠️ | ⚠️ | ⚠️ |
333
+ | **Derived state built-in** | || ⚠️ || |
334
+ | **Headless runtime** | | ⚠️ | ⚠️ || ⚠️ |
335
+ | **Backend / worker ready** | | ⚠️ | ⚠️ | | |
336
+ | **Side-effect centralization** | ✅ | ⚠️ || ❌ | ⚠️ |
337
+ | **Devtools maturity** | ⚠️ | ✅ | ⚠️ | ⚠️ | ⚠️ |
338
+
339
+
340
+ <br />
341
+
342
+ ✅ Built-in / first-class
343
+ ⚠️ Possible / usage-dependent
344
+ ❌ Not built-in
451
345
 
346
+ ---
347
+
348
+ ### 🧠 Architectural Difference
349
+
350
+ Most state libraries focus on:
351
+
352
+ > **How state is stored and updated**
353
+
354
+ `logic-runtime-react-z` focuses on:
452
355
 
356
+ > **How behavior is orchestrated through intents**
453
357
 
454
- <b>⚠️ via selectors, not a true dependency graph. </b>
358
+ Redux/Zustand answer:
359
+ > "Where is my state and how do I change it?"
360
+
361
+ This runtime answers:
362
+ > "What behavior is triggered by this event, and how should it execute?"
455
363
 
456
364
  ---
457
365
 
458
- ## Why not Redux + RTK?
366
+ ### 🧭 Positioning Summary
367
+
368
+ - Redux → Structured state container
369
+ - Zustand → Lightweight mutable store
370
+ - Recoil → Declarative dependency graph
371
+ - MobX → Reactive observable system
372
+ - **logic-runtime-react-z → Intent-first behavior runtime**
373
+
374
+ ---
459
375
 
460
- Redux focuses on state transitions.
376
+ ### 🎯 When This Makes Sense
461
377
 
462
- logic-runtime-react-z models system behavior.
378
+ Choose this if you need:
463
379
 
464
- In Redux:
465
- - async flow is external (thunk/saga)
466
- - effects are not first-class
467
- - execution model depends on middleware setup
380
+ - Complex async flows
381
+ - Deterministic replayable behavior
382
+ - Logic shared between frontend & backend
383
+ - Strong separation between UI and domain behavior
384
+ - An explicit event-driven boundary
468
385
 
469
- In logic-runtime-react-z:
470
- - async orchestration is built-in
471
- - intent is the only entry point
472
- - execution order is guaranteed
386
+ Choose simpler state tools if:
473
387
 
388
+ - You mostly manage UI state
389
+ - You don’t need orchestration
390
+ - Your async flows are trivial
391
+ - Your team prefers mutable patterns
474
392
 
475
393
  ---
476
394
 
@@ -485,7 +403,7 @@ In logic-runtime-react-z:
485
403
 
486
404
  - Intents are processed sequentially
487
405
  - State mutations are isolated
488
- - Async effects follow declared strategies (takeLatest, debounce, etc.)
406
+ - Async effects can follow declared execution strategies.
489
407
  - Execution order is predictable
490
408
 
491
409
  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.4",
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>>;