logic-runtime-react-z 3.0.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -139
- package/build/core/runtime.d.ts +20 -7
- package/build/index.cjs.js +1 -1
- package/build/index.d.ts +8 -4
- package/build/index.esm.js +1 -1
- package/build/logic/composeLogic.d.ts +16 -11
- package/build/logic/createBackendRuntime.d.ts +3 -3
- package/build/logic/createLogic.d.ts +11 -16
- package/build/react/useActions.d.ts +4 -5
- package/build/react/useComputed.d.ts +6 -0
- package/build/react/useLogic.d.ts +6 -0
- package/build/react/useLogicSelector.d.ts +2 -0
- package/build/react/useRuntime.d.ts +4 -3
- package/build/react/withLogic.d.ts +5 -4
- package/package.json +3 -7
- package/build/react/selector.d.ts +0 -1
- package/build/react/useSelector.d.ts +0 -2
package/README.md
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 🧩 logic-runtime-react-z
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/logic-runtime-react-z) 
|
|
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
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
11
|
|
|
10
|
-
>
|
|
11
|
-
> React
|
|
12
|
+
> **Intent is the only entry point.**
|
|
13
|
+
> **React is optional. createLogic is the product. Everything else is an adapter.**
|
|
12
14
|
|
|
13
15
|
---
|
|
14
16
|
|
|
15
|
-
## ✨ logic-runtime-react-z?
|
|
17
|
+
## ✨ Why logic-runtime-react-z?
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- No React hooks in views
|
|
19
|
+
- No business logic in React components
|
|
20
20
|
- Intent is the *only* entry point
|
|
21
21
|
- Predictable async flows
|
|
22
|
-
-
|
|
22
|
+
- Reactive computed graph with caching
|
|
23
23
|
- Headless & backend-friendly
|
|
24
24
|
- Deterministic testing & devtools replay
|
|
25
25
|
|
|
@@ -38,7 +38,7 @@ UI / HTTP / Queue / Cron
|
|
|
38
38
|
↓
|
|
39
39
|
mutate state
|
|
40
40
|
↓
|
|
41
|
-
computed / subscribers
|
|
41
|
+
computed (derived state) / subscribers
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
Think **events → behavior → state → derived state**.
|
|
@@ -76,23 +76,46 @@ const counterLogic = createLogic({
|
|
|
76
76
|
},
|
|
77
77
|
})
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
async function main() {
|
|
80
|
+
const runtime = counterLogic.create()
|
|
80
81
|
|
|
81
|
-
await runtime.emit("inc")
|
|
82
|
-
await runtime.emit("add", 5)
|
|
82
|
+
await runtime.emit("inc")
|
|
83
|
+
await runtime.emit("add", 5)
|
|
84
|
+
|
|
85
|
+
console.log(runtime.state.count)
|
|
86
|
+
}
|
|
83
87
|
|
|
84
|
-
|
|
88
|
+
main()
|
|
85
89
|
```
|
|
86
90
|
|
|
87
|
-
✔ No UI
|
|
88
|
-
✔ Fully testable
|
|
91
|
+
✔ No UI
|
|
92
|
+
✔ Fully testable
|
|
89
93
|
✔ Deterministic
|
|
90
94
|
|
|
95
|
+
> 💡 This is the core usage.
|
|
96
|
+
> createLogic() + runtime.emit() already gives you state, computed and effects.
|
|
97
|
+
> React integration is just a convenience layer on top of this runtime.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 🧠 Computed State
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
computed: {
|
|
105
|
+
double: ({ state }) => state.count * 2,
|
|
106
|
+
triple: ({ state }) => state.count * 3,
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- `state` inside `computed` is **reactive**.
|
|
111
|
+
- Reading `state.count` automatically tracks dependencies.
|
|
112
|
+
- Computed values are cached and only re-evaluated when tracked dependencies change.
|
|
113
|
+
|
|
91
114
|
---
|
|
92
115
|
|
|
93
|
-
## ⚛️ React Integration (
|
|
116
|
+
## ⚛️ React Integration (No Hooks Required)
|
|
94
117
|
|
|
95
|
-
### Define Logic
|
|
118
|
+
### Define Logic (Framework-Agnostic)
|
|
96
119
|
|
|
97
120
|
```ts
|
|
98
121
|
// counter.logic.ts
|
|
@@ -108,7 +131,7 @@ export const counterLogic = createLogic({
|
|
|
108
131
|
|
|
109
132
|
computed: {
|
|
110
133
|
double: ({ state }) => state.count * 2,
|
|
111
|
-
|
|
134
|
+
triple: ({ state }) => state.count * 3,
|
|
112
135
|
},
|
|
113
136
|
|
|
114
137
|
intents: bus => {
|
|
@@ -137,10 +160,11 @@ export const counterLogic = createLogic({
|
|
|
137
160
|
})
|
|
138
161
|
})
|
|
139
162
|
|
|
163
|
+
// effects = side-effects only (no state mutation)
|
|
140
164
|
bus.effect(
|
|
141
165
|
"inc-async",
|
|
142
166
|
effect(async ({ payload }) => {
|
|
143
|
-
console.log("effect run
|
|
167
|
+
console.log("effect run:", payload)
|
|
144
168
|
}).takeLatest()
|
|
145
169
|
)
|
|
146
170
|
},
|
|
@@ -159,26 +183,27 @@ export const counterLogic = createLogic({
|
|
|
159
183
|
},
|
|
160
184
|
},
|
|
161
185
|
})
|
|
186
|
+
|
|
162
187
|
```
|
|
163
188
|
|
|
164
189
|
---
|
|
165
190
|
|
|
166
|
-
### Pure React View (
|
|
191
|
+
### Pure React View (Dumb View)
|
|
167
192
|
|
|
168
193
|
```tsx
|
|
169
194
|
import React from "react"
|
|
170
195
|
import { withLogic } from "logic-runtime-react-z"
|
|
171
196
|
import { counterLogic } from "./counter.logic"
|
|
172
197
|
|
|
173
|
-
function CounterView(props
|
|
198
|
+
function CounterView(props) {
|
|
174
199
|
const { state, actions, emit } = props
|
|
175
200
|
|
|
176
201
|
return (
|
|
177
202
|
<div style={{ padding: 12 }}>
|
|
178
|
-
<div>Count: {state.
|
|
203
|
+
<div>Triple Count: {state.triple}</div>
|
|
179
204
|
|
|
180
|
-
<button onClick={actions.inc}>+1
|
|
181
|
-
<button onClick={() => actions.add(10)}>+10
|
|
205
|
+
<button onClick={actions.inc}>+1</button>
|
|
206
|
+
<button onClick={() => actions.add(10)}>+10</button>
|
|
182
207
|
|
|
183
208
|
<button
|
|
184
209
|
disabled={state.loading}
|
|
@@ -190,74 +215,93 @@ function CounterView(props: any) {
|
|
|
190
215
|
<hr />
|
|
191
216
|
|
|
192
217
|
<button onClick={() => emit("inc")}>
|
|
193
|
-
|
|
218
|
+
emit("inc")
|
|
194
219
|
</button>
|
|
195
220
|
</div>
|
|
196
221
|
)
|
|
197
222
|
}
|
|
198
223
|
|
|
199
|
-
export const CounterPage =
|
|
200
|
-
|
|
224
|
+
export const CounterPage = withLogic(counterLogic, CounterView)
|
|
225
|
+
|
|
201
226
|
```
|
|
202
227
|
|
|
203
|
-
✔ Props inferred
|
|
204
|
-
✔ No generics
|
|
205
|
-
✔ No interfaces
|
|
206
|
-
✔ View stays dumb
|
|
228
|
+
✔ Props are inferred when using withLogic, no manual generics required.
|
|
207
229
|
|
|
208
230
|
---
|
|
209
231
|
|
|
210
|
-
## 🧪 Backend Runtime
|
|
232
|
+
## 🧪 Backend Usage (Same Runtime)
|
|
211
233
|
|
|
212
234
|
```ts
|
|
213
|
-
import {
|
|
235
|
+
import { createLogic } from "logic-runtime-react-z"
|
|
214
236
|
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
237
|
+
const authLogic = createLogic({
|
|
238
|
+
state: {
|
|
239
|
+
user: null,
|
|
240
|
+
loading: false,
|
|
241
|
+
},
|
|
219
242
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
243
|
+
intents: bus => {
|
|
244
|
+
bus.on("login", async ({ setState }) => {
|
|
245
|
+
setState(s => {
|
|
246
|
+
s.loading = true
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
await new Promise(r => setTimeout(r, 500))
|
|
250
|
+
|
|
251
|
+
setState(s => {
|
|
252
|
+
s.user = { name: "Alice" }
|
|
253
|
+
s.loading = false
|
|
254
|
+
})
|
|
227
255
|
})
|
|
228
|
-
},
|
|
229
256
|
|
|
230
|
-
|
|
231
|
-
|
|
257
|
+
bus.on("logout", ({ setState }) => {
|
|
258
|
+
setState(s => {
|
|
259
|
+
s.user = null
|
|
260
|
+
})
|
|
261
|
+
})
|
|
232
262
|
},
|
|
233
263
|
})
|
|
234
264
|
|
|
235
|
-
|
|
236
|
-
|
|
265
|
+
async function run() {
|
|
266
|
+
const runtime = authLogic.create()
|
|
237
267
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
console.log(devtools.timeline.records)
|
|
268
|
+
await runtime.emit("login")
|
|
269
|
+
await runtime.emit("logout")
|
|
241
270
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
271
|
+
console.log(runtime.getSnapshot())
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
run()
|
|
246
275
|
```
|
|
247
276
|
|
|
248
|
-
✔ Same
|
|
277
|
+
✔ Same runtime, same behavior, no React involved.
|
|
249
278
|
✔ No React
|
|
250
279
|
✔ Replayable
|
|
251
|
-
✔ Devtools is backend-first.
|
|
252
280
|
|
|
253
281
|
---
|
|
254
282
|
|
|
255
|
-
## 🪝 Hooks
|
|
283
|
+
## 🪝 Hooks Examples (Optional, Thin Adapters)
|
|
256
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)
|
|
257
303
|
```ts
|
|
258
|
-
// useActions
|
|
259
304
|
import { useActions } from "logic-runtime-react-z"
|
|
260
|
-
import { counterLogic } from "./counter.logic"
|
|
261
305
|
|
|
262
306
|
function Buttons() {
|
|
263
307
|
const actions = useActions(counterLogic)
|
|
@@ -269,36 +313,72 @@ function Buttons() {
|
|
|
269
313
|
</>
|
|
270
314
|
)
|
|
271
315
|
}
|
|
316
|
+
```
|
|
272
317
|
|
|
273
|
-
// useSelector
|
|
274
|
-
import { useSelector } from "logic-runtime-react-z"
|
|
275
|
-
import { counterLogic } from "./counter.logic"
|
|
276
318
|
|
|
277
|
-
|
|
278
|
-
|
|
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(
|
|
279
352
|
counterLogic,
|
|
280
|
-
|
|
353
|
+
c => c.double
|
|
281
354
|
)
|
|
282
355
|
|
|
283
356
|
return <div>Double: {double}</div>
|
|
284
357
|
}
|
|
358
|
+
```
|
|
285
359
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
360
|
+
✔ Component re-renders only when double changes
|
|
361
|
+
✔ No extra dependencies
|
|
362
|
+
✔ Type-safe selector
|
|
289
363
|
|
|
290
|
-
|
|
291
|
-
|
|
364
|
+
#### useLogicSelector – State selector (Redux-like)
|
|
365
|
+
```ts
|
|
366
|
+
import { useLogicSelector } from "logic-runtime-react-z"
|
|
292
367
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
368
|
+
function CountLabel() {
|
|
369
|
+
const count = useLogicSelector(
|
|
370
|
+
counterLogic.create(),
|
|
371
|
+
state => state.count
|
|
297
372
|
)
|
|
298
|
-
}
|
|
299
373
|
|
|
374
|
+
return <span>{count}</span>
|
|
375
|
+
}
|
|
300
376
|
```
|
|
301
377
|
|
|
378
|
+
✔ Memoized selector
|
|
379
|
+
✔ Fine-grained subscriptions
|
|
380
|
+
✔ Familiar mental model
|
|
381
|
+
|
|
302
382
|
---
|
|
303
383
|
|
|
304
384
|
## 🧱 Composing Multiple Logic Modules
|
|
@@ -308,20 +388,16 @@ import { composeLogic } from "logic-runtime-react-z"
|
|
|
308
388
|
import { userLogic } from "./user.logic"
|
|
309
389
|
import { cartLogic } from "./cart.logic"
|
|
310
390
|
|
|
311
|
-
|
|
391
|
+
const app = composeLogic({
|
|
312
392
|
user: userLogic,
|
|
313
393
|
cart: cartLogic,
|
|
314
394
|
})
|
|
315
395
|
|
|
396
|
+
await app.emit("login")
|
|
316
397
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
await runtime.emit("user:login", credentials)
|
|
321
|
-
|
|
322
|
-
const snapshot = runtime.getSnapshot()
|
|
323
|
-
snapshot.user // user state
|
|
324
|
-
snapshot.cart // cart state
|
|
398
|
+
const state = app.getState()
|
|
399
|
+
state.user
|
|
400
|
+
state.cart
|
|
325
401
|
|
|
326
402
|
```
|
|
327
403
|
|
|
@@ -346,77 +422,49 @@ const logic = createLogic({
|
|
|
346
422
|
},
|
|
347
423
|
})
|
|
348
424
|
|
|
349
|
-
const runtime =
|
|
425
|
+
const runtime = counterLogic.create()
|
|
350
426
|
|
|
351
427
|
await runtime.emit("set", 4)
|
|
352
|
-
|
|
353
|
-
expect(runtime.state.squared).toBe(16)
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
---
|
|
357
|
-
|
|
358
|
-
## 🚫 Anti-patterns (What NOT to do)
|
|
359
|
-
|
|
360
|
-
### ❌ Business logic in React
|
|
361
|
-
|
|
362
|
-
```tsx
|
|
363
|
-
useEffect(() => {
|
|
364
|
-
fetchData()
|
|
365
|
-
}, [])
|
|
428
|
+
expect(runtime.computed.squared).toBe(16)
|
|
366
429
|
```
|
|
367
430
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
```ts
|
|
371
|
-
emit("data:fetch")
|
|
372
|
-
```
|
|
431
|
+
✔ Computed values are tested like plain data
|
|
373
432
|
|
|
374
433
|
---
|
|
375
434
|
|
|
376
|
-
|
|
435
|
+
## 🔍 Comparison: Redux vs Zustand
|
|
377
436
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
437
|
+
| Capability / Library | logic-runtime-react-z | Redux | Zustand |
|
|
438
|
+
|--------------------------|:---------------------:|:-----:|:-------:|
|
|
439
|
+
| Intent-first model | ✅ | ❌ | ❌ |
|
|
440
|
+
| State-first model | ❌ | ✅ | ✅ |
|
|
441
|
+
| First-class effects | ✅ | ❌ | ❌ |
|
|
442
|
+
| Computed graph | ✅ | ❌ | ⚠️ |
|
|
443
|
+
| Deterministic execution | ✅ | ❌ | ❌ |
|
|
444
|
+
| Logic outside React | ✅ | ❌ | ❌ |
|
|
445
|
+
| Backend-safe | ✅ | ❌ | ❌ |
|
|
381
446
|
|
|
382
|
-
✅ Correct
|
|
383
447
|
|
|
384
|
-
|
|
385
|
-
emit("update:user:name", "admin")
|
|
386
|
-
```
|
|
448
|
+
##### ⚠️ via selectors, not a true dependency graph
|
|
387
449
|
|
|
388
450
|
---
|
|
389
451
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
```ts
|
|
393
|
-
emit("SET_STATE", { loading: true })
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
✅ Correct
|
|
452
|
+
## 🧠 One-liner Takeaway
|
|
397
453
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
emit("login:success", user)
|
|
401
|
-
emit("login:failed", error)
|
|
402
|
-
```
|
|
454
|
+
- Redux & Zustand manage **state**
|
|
455
|
+
- logic-runtime-react-z orchestrates **logic**
|
|
403
456
|
|
|
404
457
|
---
|
|
405
458
|
|
|
406
|
-
##
|
|
407
|
-
|
|
408
|
-
- Complex async flows
|
|
409
|
-
- Shared logic across UI / backend
|
|
410
|
-
- Need deterministic tests
|
|
411
|
-
- Want to remove logic from React
|
|
412
|
-
|
|
413
|
-
## 🚫 When NOT to Use
|
|
459
|
+
## 🧬 Determinism Guarantee
|
|
414
460
|
|
|
415
|
-
-
|
|
416
|
-
-
|
|
461
|
+
- Intents are processed sequentially
|
|
462
|
+
- State mutations are isolated
|
|
463
|
+
- Async flows are predictable
|
|
464
|
+
- Same inputs → same outputs
|
|
417
465
|
|
|
418
466
|
---
|
|
419
467
|
|
|
420
|
-
##
|
|
468
|
+
## License
|
|
421
469
|
|
|
422
|
-
MIT
|
|
470
|
+
MIT
|
package/build/core/runtime.d.ts
CHANGED
|
@@ -1,26 +1,39 @@
|
|
|
1
|
-
import { Atom } from "chrono-state-z/build/core/atom";
|
|
1
|
+
import type { Atom } from "chrono-state-z/build/core/atom";
|
|
2
2
|
import { Scope } from "intentx-core-z";
|
|
3
3
|
import { EffectDef } from "./effect";
|
|
4
4
|
export type AtomAccessor<T> = Atom<T>;
|
|
5
|
-
export
|
|
5
|
+
export type ComputedDef<S> = Record<string, (context: {
|
|
6
|
+
state: Readonly<S>;
|
|
7
|
+
}) => any>;
|
|
8
|
+
export type InferComputed<C> = {
|
|
9
|
+
[K in keyof C]: C[K] extends (...args: any[]) => infer R ? R : never;
|
|
10
|
+
};
|
|
11
|
+
export declare class LogicRuntime<S extends object, C extends ComputedDef<S>, A extends Record<string, any>> {
|
|
6
12
|
readonly scope: Scope;
|
|
7
|
-
private
|
|
13
|
+
private stateAtoms;
|
|
14
|
+
private computedAtoms;
|
|
8
15
|
private subs;
|
|
9
16
|
private bus;
|
|
10
17
|
private snapshotCache;
|
|
11
18
|
private dirty;
|
|
12
19
|
private isComputing;
|
|
20
|
+
private computedKeys;
|
|
13
21
|
actions: A;
|
|
14
22
|
constructor(initial: S, scope?: Scope);
|
|
15
|
-
private
|
|
23
|
+
private createStateAtoms;
|
|
16
24
|
private buildSnapshot;
|
|
17
25
|
private markDirty;
|
|
18
|
-
|
|
26
|
+
private createReactiveState;
|
|
27
|
+
getSnapshot: () => Readonly<S & InferComputed<C>>;
|
|
19
28
|
subscribe: (fn: () => void) => () => boolean;
|
|
29
|
+
get state(): Readonly<S & InferComputed<C>>;
|
|
30
|
+
get computed(): Readonly<InferComputed<C>>;
|
|
31
|
+
getComputedKey<K extends keyof InferComputed<C>>(key: K): InferComputed<C>[K];
|
|
32
|
+
getComputed(snapshot: Readonly<S & InferComputed<C>>): Readonly<InferComputed<C>>;
|
|
20
33
|
private setStateInternal;
|
|
21
34
|
onIntent: <P = any>(type: string, handler: (context: {
|
|
22
35
|
payload: P;
|
|
23
|
-
state: () => Readonly<S
|
|
36
|
+
state: () => Readonly<S & InferComputed<C>>;
|
|
24
37
|
scope: Scope;
|
|
25
38
|
signal: AbortSignal;
|
|
26
39
|
setState(fn: (draft: S) => void): void;
|
|
@@ -28,5 +41,5 @@ export declare class LogicRuntime<S extends object, A extends Record<string, any
|
|
|
28
41
|
}) => any) => void;
|
|
29
42
|
useEffect(type: string, eff: EffectDef): void;
|
|
30
43
|
emit: <P = any>(type: string, payload?: P) => Promise<void>;
|
|
31
|
-
attachComputed<K extends string
|
|
44
|
+
attachComputed<K extends keyof C & string>(key: K, compute: C[K]): void;
|
|
32
45
|
}
|
package/build/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var t=require("chrono-state-z"),e=require("intentx-core-z"),s=require("react"),n=require("react
|
|
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.handler.toString();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",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};
|
package/build/index.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
export { createSelector } from "chrono-state-z";
|
|
1
2
|
export { LogicRuntime } from "./core/runtime";
|
|
3
|
+
export type { AtomAccessor } from "./core/runtime";
|
|
2
4
|
export { effect } from "./core/effect";
|
|
5
|
+
export type { IntentMiddleware, IntentNext, } from "./core/middleware";
|
|
3
6
|
export { createLogic } from "./logic/createLogic";
|
|
4
|
-
export type { LogicFactory } from "./logic/createLogic";
|
|
7
|
+
export type { LogicFactory, LogicActions, } from "./logic/createLogic";
|
|
5
8
|
export { composeLogic } from "./logic/composeLogic";
|
|
6
9
|
export { createBackendRuntime } from "./logic/createBackendRuntime";
|
|
7
|
-
export {
|
|
10
|
+
export { withLogic } from "./react/withLogic";
|
|
8
11
|
export { useActions } from "./react/useActions";
|
|
12
|
+
export { useComputed } from "./react/useComputed";
|
|
13
|
+
export { useLogic } from "./react/useLogic";
|
|
14
|
+
export { useLogicSelector } from "./react/useLogicSelector";
|
|
9
15
|
export { useRuntime } from "./react/useRuntime";
|
|
10
|
-
export { useSelector } from "./react/useSelector";
|
|
11
|
-
export { withLogic } from "./react/withLogic";
|
|
12
16
|
export * from "./devtools";
|
package/build/index.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{atom as t,effect as e}from"chrono-state-z";import{createScope as
|
|
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.handler.toString();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",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,16 +1,21 @@
|
|
|
1
|
+
import { Scope } from "intentx-core-z";
|
|
2
|
+
import type { ComputedDef, InferComputed } from "../core/runtime";
|
|
1
3
|
import { LogicRuntime } from "../core/runtime";
|
|
2
|
-
type LogicFactory
|
|
3
|
-
|
|
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;
|
|
4
10
|
};
|
|
5
|
-
type LogicMap =
|
|
6
|
-
|
|
7
|
-
[K in keyof M]: ReturnType<M[K]["create"]> extends LogicRuntime<infer S extends object, any> ? Readonly<S> : never;
|
|
11
|
+
type InferActions<M extends LogicMap> = {
|
|
12
|
+
[K in keyof M]: InferRuntime<M[K]> extends LogicRuntime<any, any, infer A> ? A : never;
|
|
8
13
|
};
|
|
9
|
-
export declare function composeLogic<M extends LogicMap>(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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>;
|
|
15
20
|
};
|
|
16
21
|
export {};
|
|
@@ -8,10 +8,10 @@ export type BackendContext<S> = {
|
|
|
8
8
|
export type BackendIntent<S> = (context: BackendContext<S>) => void | Promise<void>;
|
|
9
9
|
export type BackendIntents<S> = Record<string, BackendIntent<S>>;
|
|
10
10
|
export declare function createBackendRuntime<S extends object>(initial: S): {
|
|
11
|
-
state: () => S
|
|
11
|
+
state: () => Readonly<S>;
|
|
12
12
|
reset: () => void;
|
|
13
13
|
emit: (intent: string, payload?: any) => Promise<void>;
|
|
14
14
|
registerIntents: (intents: BackendIntents<S>) => void;
|
|
15
|
-
onIntent: (type: string,
|
|
16
|
-
effect: (type: string, fx: import("intentx-core-z/build/intent/
|
|
15
|
+
onIntent: (type: string, h: import("intentx-core-z").IntentHandler<S>, scope?: Scope) => () => void;
|
|
16
|
+
effect: (type: string, fx: import("intentx-core-z/build/intent/types").IntentEffect<S>, scope?: Scope) => () => void;
|
|
17
17
|
};
|
|
@@ -1,28 +1,23 @@
|
|
|
1
1
|
import { Scope } from "intentx-core-z";
|
|
2
|
-
import { LogicRuntime } from "../core/runtime";
|
|
2
|
+
import { LogicRuntime, ComputedDef, InferComputed } from "../core/runtime";
|
|
3
3
|
import { EffectDef } from "../core/effect";
|
|
4
|
-
type ComputedFactory<S> = (context: {
|
|
5
|
-
state: Readonly<S>;
|
|
6
|
-
}) => any;
|
|
7
|
-
type ActionFactory<S extends object, Fn extends (...args: any[]) => any> = (context: {
|
|
8
|
-
emit: LogicRuntime<S, any>["emit"];
|
|
9
|
-
getState: () => Readonly<S>;
|
|
10
|
-
}) => Fn;
|
|
11
4
|
export type LogicActions = Record<string, (...args: any[]) => any>;
|
|
12
|
-
export type LogicFactory<S extends object, A extends LogicActions> = {
|
|
5
|
+
export type LogicFactory<S extends object, C extends ComputedDef<S>, A extends LogicActions> = {
|
|
13
6
|
name?: string;
|
|
14
|
-
create(scope?: Scope): LogicRuntime<S, A>;
|
|
7
|
+
create(scope?: Scope): LogicRuntime<S, C, A>;
|
|
15
8
|
};
|
|
16
|
-
export declare function createLogic<S extends object, A extends LogicActions>(config: {
|
|
9
|
+
export declare function createLogic<S extends object, C extends ComputedDef<S> = {}, A extends LogicActions = {}>(config: {
|
|
17
10
|
name?: string;
|
|
18
11
|
state: S;
|
|
19
|
-
computed?:
|
|
12
|
+
computed?: C;
|
|
20
13
|
intents?: (bus: {
|
|
21
|
-
on: LogicRuntime<S>["onIntent"];
|
|
14
|
+
on: LogicRuntime<S, C, A>["onIntent"];
|
|
22
15
|
effect: (type: string, eff: EffectDef) => void;
|
|
23
16
|
}) => void;
|
|
24
17
|
actions?: {
|
|
25
|
-
[K in keyof A]:
|
|
18
|
+
[K in keyof A]: (context: {
|
|
19
|
+
emit: LogicRuntime<S, C, A>["emit"];
|
|
20
|
+
getState: () => Readonly<S & InferComputed<C>>;
|
|
21
|
+
}) => A[K];
|
|
26
22
|
};
|
|
27
|
-
}): LogicFactory<S, A>;
|
|
28
|
-
export {};
|
|
23
|
+
}): LogicFactory<S, C, A>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export declare function useActions<S extends object, A extends LogicActions>(logic: LogicFactory<S, A>): A;
|
|
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;
|
|
@@ -0,0 +1,6 @@
|
|
|
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;
|
|
@@ -0,0 +1,6 @@
|
|
|
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>>;
|
|
5
|
+
actions: A;
|
|
6
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
+
import type { ComputedDef, InferComputed } from "../core/runtime";
|
|
1
2
|
import { LogicRuntime } from "../core/runtime";
|
|
2
|
-
import { LogicFactory } from "../logic/createLogic";
|
|
3
|
-
export declare function useRuntime<S extends object
|
|
4
|
-
export declare function useRuntime<S extends object, A extends Record<string, any>>(logic: LogicFactory<S, A>): Readonly<S
|
|
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>>;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Scope } from "intentx-core-z";
|
|
3
|
-
import { LogicActions, LogicFactory } from "../logic/createLogic";
|
|
4
|
-
type
|
|
5
|
-
|
|
3
|
+
import type { LogicActions, LogicFactory } from "../logic/createLogic";
|
|
4
|
+
import type { ComputedDef, InferComputed } from "../core/runtime";
|
|
5
|
+
type InjectedProps<S extends object, C extends ComputedDef<S>, A extends LogicActions> = {
|
|
6
|
+
state: Readonly<S & InferComputed<C>>;
|
|
6
7
|
actions: A;
|
|
7
8
|
emit: (intent: string, payload?: any) => Promise<void>;
|
|
8
9
|
};
|
|
9
|
-
export declare function withLogic<S extends object, A extends LogicActions, P extends object>(logic: LogicFactory<S, A>, View: React.ComponentType<P & InjectedProps<S, A>>, scope?: Scope | string): React.FC<Omit<P, keyof InjectedProps<S, A>>>;
|
|
10
|
+
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>>>;
|
|
10
11
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "logic-runtime-react-z",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.1",
|
|
4
4
|
"description": "Intent-first business logic runtime. Headless and backend-friendly. Deterministic state, computed graph, and orchestrated async effects. React is just a view layer.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Delpi.Kye",
|
|
@@ -47,21 +47,17 @@
|
|
|
47
47
|
"intent-runtime",
|
|
48
48
|
"business-logic",
|
|
49
49
|
"logic-runtime",
|
|
50
|
-
|
|
51
50
|
"headless",
|
|
52
51
|
"backend-friendly",
|
|
53
52
|
"ui-agnostic",
|
|
54
|
-
|
|
55
53
|
"react",
|
|
56
54
|
"react-architecture",
|
|
57
55
|
"no-hooks",
|
|
58
56
|
"external-store",
|
|
59
|
-
|
|
60
57
|
"computed-state",
|
|
61
58
|
"derived-state",
|
|
62
59
|
"async-effects",
|
|
63
60
|
"takeLatest",
|
|
64
|
-
|
|
65
61
|
"state-management"
|
|
66
62
|
],
|
|
67
63
|
"peerDependencies": {
|
|
@@ -84,7 +80,7 @@
|
|
|
84
80
|
"typescript": "^5.3.3"
|
|
85
81
|
},
|
|
86
82
|
"dependencies": {
|
|
87
|
-
"chrono-state-z": "^2.0
|
|
88
|
-
"intentx-core-z": "^1.0
|
|
83
|
+
"chrono-state-z": "^2.1.0",
|
|
84
|
+
"intentx-core-z": "^2.1.0"
|
|
89
85
|
}
|
|
90
86
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function createSelector<T, R>(select: (state: T) => R, isEqual?: (value1: any, value2: any) => boolean): (state: T) => R;
|