logic-runtime-react-z 3.1.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 +177 -159
- package/build/core/runtime.d.ts +20 -7
- package/build/index.cjs.js +1 -1
- package/build/index.d.ts +3 -1
- package/build/index.esm.js +1 -1
- package/build/logic/composeLogic.d.ts +15 -12
- package/build/logic/createLogic.d.ts +11 -16
- package/build/react/useActions.d.ts +4 -6
- package/build/react/useComputed.d.ts +6 -0
- package/build/react/useLogic.d.ts +6 -0
- package/build/react/useLogicSelector.d.ts +2 -2
- package/build/react/useRuntime.d.ts +4 -3
- package/build/react/withLogic.d.ts +5 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,15 +10,16 @@ A headless, deterministic, intent-driven runtime for frontend & backend logic.
|
|
|
10
10
|
React components stay pure. Business logic is fully testable, replayable, and framework-agnostic.
|
|
11
11
|
|
|
12
12
|
> **Intent is the only entry point.**
|
|
13
|
+
> **React is optional. createLogic is the product. Everything else is an adapter.**
|
|
13
14
|
|
|
14
15
|
---
|
|
15
16
|
|
|
16
17
|
## ✨ Why logic-runtime-react-z?
|
|
17
18
|
|
|
18
|
-
- No
|
|
19
|
+
- No business logic in React components
|
|
19
20
|
- Intent is the *only* entry point
|
|
20
21
|
- Predictable async flows
|
|
21
|
-
-
|
|
22
|
+
- Reactive computed graph with caching
|
|
22
23
|
- Headless & backend-friendly
|
|
23
24
|
- Deterministic testing & devtools replay
|
|
24
25
|
|
|
@@ -37,7 +38,7 @@ UI / HTTP / Queue / Cron
|
|
|
37
38
|
↓
|
|
38
39
|
mutate state
|
|
39
40
|
↓
|
|
40
|
-
computed / subscribers
|
|
41
|
+
computed (derived state) / subscribers
|
|
41
42
|
```
|
|
42
43
|
|
|
43
44
|
Think **events → behavior → state → derived state**.
|
|
@@ -75,23 +76,46 @@ const counterLogic = createLogic({
|
|
|
75
76
|
},
|
|
76
77
|
})
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
async function main() {
|
|
80
|
+
const runtime = counterLogic.create()
|
|
81
|
+
|
|
82
|
+
await runtime.emit("inc")
|
|
83
|
+
await runtime.emit("add", 5)
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
console.log(runtime.state.count)
|
|
86
|
+
}
|
|
82
87
|
|
|
83
|
-
|
|
88
|
+
main()
|
|
84
89
|
```
|
|
85
90
|
|
|
86
|
-
✔ No UI
|
|
87
|
-
✔ Fully testable
|
|
91
|
+
✔ No UI
|
|
92
|
+
✔ Fully testable
|
|
88
93
|
✔ Deterministic
|
|
89
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
|
+
|
|
90
114
|
---
|
|
91
115
|
|
|
92
|
-
## ⚛️ React Integration (No Hooks)
|
|
116
|
+
## ⚛️ React Integration (No Hooks Required)
|
|
93
117
|
|
|
94
|
-
### Define Logic
|
|
118
|
+
### Define Logic (Framework-Agnostic)
|
|
95
119
|
|
|
96
120
|
```ts
|
|
97
121
|
// counter.logic.ts
|
|
@@ -136,10 +160,11 @@ export const counterLogic = createLogic({
|
|
|
136
160
|
})
|
|
137
161
|
})
|
|
138
162
|
|
|
163
|
+
// effects = side-effects only (no state mutation)
|
|
139
164
|
bus.effect(
|
|
140
165
|
"inc-async",
|
|
141
166
|
effect(async ({ payload }) => {
|
|
142
|
-
console.log("effect run
|
|
167
|
+
console.log("effect run:", payload)
|
|
143
168
|
}).takeLatest()
|
|
144
169
|
)
|
|
145
170
|
},
|
|
@@ -158,26 +183,27 @@ export const counterLogic = createLogic({
|
|
|
158
183
|
},
|
|
159
184
|
},
|
|
160
185
|
})
|
|
186
|
+
|
|
161
187
|
```
|
|
162
188
|
|
|
163
189
|
---
|
|
164
190
|
|
|
165
|
-
### Pure React View (
|
|
191
|
+
### Pure React View (Dumb View)
|
|
166
192
|
|
|
167
193
|
```tsx
|
|
168
194
|
import React from "react"
|
|
169
195
|
import { withLogic } from "logic-runtime-react-z"
|
|
170
196
|
import { counterLogic } from "./counter.logic"
|
|
171
197
|
|
|
172
|
-
function CounterView(props
|
|
198
|
+
function CounterView(props) {
|
|
173
199
|
const { state, actions, emit } = props
|
|
174
200
|
|
|
175
201
|
return (
|
|
176
202
|
<div style={{ padding: 12 }}>
|
|
177
|
-
<div>Count: {state.triple}</div>
|
|
203
|
+
<div>Triple Count: {state.triple}</div>
|
|
178
204
|
|
|
179
|
-
<button onClick={actions.inc}>+1
|
|
180
|
-
<button onClick={() => actions.add(10)}>+10
|
|
205
|
+
<button onClick={actions.inc}>+1</button>
|
|
206
|
+
<button onClick={() => actions.add(10)}>+10</button>
|
|
181
207
|
|
|
182
208
|
<button
|
|
183
209
|
disabled={state.loading}
|
|
@@ -189,74 +215,93 @@ function CounterView(props: any) {
|
|
|
189
215
|
<hr />
|
|
190
216
|
|
|
191
217
|
<button onClick={() => emit("inc")}>
|
|
192
|
-
|
|
218
|
+
emit("inc")
|
|
193
219
|
</button>
|
|
194
220
|
</div>
|
|
195
221
|
)
|
|
196
222
|
}
|
|
197
223
|
|
|
198
|
-
export const CounterPage =
|
|
199
|
-
|
|
224
|
+
export const CounterPage = withLogic(counterLogic, CounterView)
|
|
225
|
+
|
|
200
226
|
```
|
|
201
227
|
|
|
202
|
-
✔ Props inferred
|
|
203
|
-
✔ No generics
|
|
204
|
-
✔ No interfaces
|
|
205
|
-
✔ View stays dumb
|
|
228
|
+
✔ Props are inferred when using withLogic, no manual generics required.
|
|
206
229
|
|
|
207
230
|
---
|
|
208
231
|
|
|
209
|
-
## 🧪 Backend Runtime
|
|
232
|
+
## 🧪 Backend Usage (Same Runtime)
|
|
210
233
|
|
|
211
234
|
```ts
|
|
212
|
-
import {
|
|
235
|
+
import { createLogic } from "logic-runtime-react-z"
|
|
213
236
|
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
237
|
+
const authLogic = createLogic({
|
|
238
|
+
state: {
|
|
239
|
+
user: null,
|
|
240
|
+
loading: false,
|
|
241
|
+
},
|
|
218
242
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
+
})
|
|
226
255
|
})
|
|
227
|
-
},
|
|
228
256
|
|
|
229
|
-
|
|
230
|
-
|
|
257
|
+
bus.on("logout", ({ setState }) => {
|
|
258
|
+
setState(s => {
|
|
259
|
+
s.user = null
|
|
260
|
+
})
|
|
261
|
+
})
|
|
231
262
|
},
|
|
232
263
|
})
|
|
233
264
|
|
|
234
|
-
|
|
235
|
-
|
|
265
|
+
async function run() {
|
|
266
|
+
const runtime = authLogic.create()
|
|
236
267
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
console.log(devtools.timeline.records)
|
|
268
|
+
await runtime.emit("login")
|
|
269
|
+
await runtime.emit("logout")
|
|
240
270
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
271
|
+
console.log(runtime.getSnapshot())
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
run()
|
|
245
275
|
```
|
|
246
276
|
|
|
247
|
-
✔ Same
|
|
277
|
+
✔ Same runtime, same behavior, no React involved.
|
|
248
278
|
✔ No React
|
|
249
279
|
✔ Replayable
|
|
250
|
-
✔ Devtools is backend-first.
|
|
251
280
|
|
|
252
281
|
---
|
|
253
282
|
|
|
254
|
-
## 🪝 Hooks
|
|
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.
|
|
255
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)
|
|
256
303
|
```ts
|
|
257
|
-
// useActions
|
|
258
304
|
import { useActions } from "logic-runtime-react-z"
|
|
259
|
-
import { counterLogic } from "./counter.logic"
|
|
260
305
|
|
|
261
306
|
function Buttons() {
|
|
262
307
|
const actions = useActions(counterLogic)
|
|
@@ -268,36 +313,72 @@ function Buttons() {
|
|
|
268
313
|
</>
|
|
269
314
|
)
|
|
270
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
|
+
}
|
|
271
337
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
338
|
+
function DoubleOnly() {
|
|
339
|
+
const double = useComputed(counterLogic, c => c.double)
|
|
340
|
+
return <div>{double}</div>
|
|
341
|
+
}
|
|
342
|
+
```
|
|
275
343
|
|
|
276
|
-
|
|
277
|
-
|
|
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(
|
|
278
352
|
counterLogic,
|
|
279
|
-
|
|
353
|
+
c => c.double
|
|
280
354
|
)
|
|
281
355
|
|
|
282
356
|
return <div>Double: {double}</div>
|
|
283
357
|
}
|
|
358
|
+
```
|
|
284
359
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
360
|
+
✔ Component re-renders only when double changes
|
|
361
|
+
✔ No extra dependencies
|
|
362
|
+
✔ Type-safe selector
|
|
288
363
|
|
|
289
|
-
|
|
290
|
-
|
|
364
|
+
#### useLogicSelector – State selector (Redux-like)
|
|
365
|
+
```ts
|
|
366
|
+
import { useLogicSelector } from "logic-runtime-react-z"
|
|
291
367
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
368
|
+
function CountLabel() {
|
|
369
|
+
const count = useLogicSelector(
|
|
370
|
+
counterLogic.create(),
|
|
371
|
+
state => state.count
|
|
296
372
|
)
|
|
297
|
-
}
|
|
298
373
|
|
|
374
|
+
return <span>{count}</span>
|
|
375
|
+
}
|
|
299
376
|
```
|
|
300
377
|
|
|
378
|
+
✔ Memoized selector
|
|
379
|
+
✔ Fine-grained subscriptions
|
|
380
|
+
✔ Familiar mental model
|
|
381
|
+
|
|
301
382
|
---
|
|
302
383
|
|
|
303
384
|
## 🧱 Composing Multiple Logic Modules
|
|
@@ -307,20 +388,16 @@ import { composeLogic } from "logic-runtime-react-z"
|
|
|
307
388
|
import { userLogic } from "./user.logic"
|
|
308
389
|
import { cartLogic } from "./cart.logic"
|
|
309
390
|
|
|
310
|
-
|
|
391
|
+
const app = composeLogic({
|
|
311
392
|
user: userLogic,
|
|
312
393
|
cart: cartLogic,
|
|
313
394
|
})
|
|
314
395
|
|
|
396
|
+
await app.emit("login")
|
|
315
397
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
await runtime.emit("user:login", credentials)
|
|
320
|
-
|
|
321
|
-
const snapshot = runtime.getSnapshot()
|
|
322
|
-
snapshot.user // user state
|
|
323
|
-
snapshot.cart // cart state
|
|
398
|
+
const state = app.getState()
|
|
399
|
+
state.user
|
|
400
|
+
state.cart
|
|
324
401
|
|
|
325
402
|
```
|
|
326
403
|
|
|
@@ -345,105 +422,46 @@ const logic = createLogic({
|
|
|
345
422
|
},
|
|
346
423
|
})
|
|
347
424
|
|
|
348
|
-
const runtime =
|
|
425
|
+
const runtime = counterLogic.create()
|
|
349
426
|
|
|
350
427
|
await runtime.emit("set", 4)
|
|
351
|
-
|
|
352
|
-
expect(runtime.state.squared).toBe(16)
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
---
|
|
356
|
-
|
|
357
|
-
## 🚫 Anti-patterns (What NOT to do)
|
|
358
|
-
|
|
359
|
-
### ❌ Business logic in React
|
|
360
|
-
|
|
361
|
-
```tsx
|
|
362
|
-
useEffect(() => {
|
|
363
|
-
fetchData()
|
|
364
|
-
}, [])
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
✅ Correct
|
|
368
|
-
|
|
369
|
-
```ts
|
|
370
|
-
emit("data:fetch")
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
### ❌ Mutating state directly
|
|
376
|
-
|
|
377
|
-
```ts
|
|
378
|
-
runtime.state.user.name = "admin"
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
✅ Correct
|
|
382
|
-
|
|
383
|
-
```ts
|
|
384
|
-
emit("update:user:name", "admin")
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
---
|
|
388
|
-
|
|
389
|
-
### ❌ Generic Redux-style intents
|
|
390
|
-
|
|
391
|
-
```ts
|
|
392
|
-
emit("SET_STATE", { loading: true })
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
✅ Correct
|
|
396
|
-
|
|
397
|
-
```ts
|
|
398
|
-
emit("login:start")
|
|
399
|
-
emit("login:success", user)
|
|
400
|
-
emit("login:failed", error)
|
|
428
|
+
expect(runtime.computed.squared).toBe(16)
|
|
401
429
|
```
|
|
402
430
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
## 🧩 When to Use This
|
|
406
|
-
|
|
407
|
-
- Complex async flows
|
|
408
|
-
- Shared logic across UI / backend
|
|
409
|
-
- Need deterministic tests
|
|
410
|
-
- Want to remove logic from React
|
|
411
|
-
|
|
412
|
-
## 🚫 When NOT to Use
|
|
413
|
-
|
|
414
|
-
- Simple local UI state
|
|
415
|
-
- Throwaway components
|
|
431
|
+
✔ Computed values are tested like plain data
|
|
416
432
|
|
|
417
433
|
---
|
|
418
434
|
|
|
419
|
-
## 🔍 Comparison
|
|
435
|
+
## 🔍 Comparison: Redux vs Zustand
|
|
420
436
|
|
|
421
437
|
| Capability / Library | logic-runtime-react-z | Redux | Zustand |
|
|
422
438
|
|--------------------------|:---------------------:|:-----:|:-------:|
|
|
423
439
|
| Intent-first model | ✅ | ❌ | ❌ |
|
|
424
440
|
| State-first model | ❌ | ✅ | ✅ |
|
|
425
441
|
| First-class effects | ✅ | ❌ | ❌ |
|
|
426
|
-
|
|
|
427
|
-
| Computed state graph | ✅ | ❌ | ⚠️ |
|
|
442
|
+
| Computed graph | ✅ | ❌ | ⚠️ |
|
|
428
443
|
| Deterministic execution | ✅ | ❌ | ❌ |
|
|
429
444
|
| Logic outside React | ✅ | ❌ | ❌ |
|
|
430
445
|
| Backend-safe | ✅ | ❌ | ❌ |
|
|
431
|
-
| Intent / effect tracing | ✅ | ❌ | ❌ |
|
|
432
|
-
| Centralized state store | ❌ | ✅ | ✅ |
|
|
433
|
-
| Easy global state | ⚠️ | ✅ | ✅ |
|
|
434
|
-
| Minimal boilerplate | ✅ | ❌ | ✅ |
|
|
435
446
|
|
|
436
|
-
```bash
|
|
437
|
-
Redux / Zustand:
|
|
438
|
-
UI → setState → store → re-render
|
|
439
447
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
448
|
+
##### ⚠️ via selectors, not a true dependency graph
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## 🧠 One-liner Takeaway
|
|
453
|
+
|
|
454
|
+
- Redux & Zustand manage **state**
|
|
455
|
+
- logic-runtime-react-z orchestrates **logic**
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
## 🧬 Determinism Guarantee
|
|
443
460
|
|
|
444
|
-
|
|
445
|
-
-
|
|
446
|
-
-
|
|
461
|
+
- Intents are processed sequentially
|
|
462
|
+
- State mutations are isolated
|
|
463
|
+
- Async flows are predictable
|
|
464
|
+
- Same inputs → same outputs
|
|
447
465
|
|
|
448
466
|
---
|
|
449
467
|
|
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"),
|
|
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
|
@@ -8,7 +8,9 @@ export type { LogicFactory, LogicActions, } from "./logic/createLogic";
|
|
|
8
8
|
export { composeLogic } from "./logic/composeLogic";
|
|
9
9
|
export { createBackendRuntime } from "./logic/createBackendRuntime";
|
|
10
10
|
export { withLogic } from "./react/withLogic";
|
|
11
|
-
export { useRuntime } from "./react/useRuntime";
|
|
12
11
|
export { useActions } from "./react/useActions";
|
|
12
|
+
export { useComputed } from "./react/useComputed";
|
|
13
|
+
export { useLogic } from "./react/useLogic";
|
|
13
14
|
export { useLogicSelector } from "./react/useLogicSelector";
|
|
15
|
+
export { useRuntime } from "./react/useRuntime";
|
|
14
16
|
export * from "./devtools";
|
package/build/index.esm.js
CHANGED
|
@@ -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.subs=new Set,this.bus=new l,this.dirty=!0,this.isComputing=!1,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.
|
|
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,18 +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
4
|
import type { LogicFactory } from "../logic/createLogic";
|
|
3
|
-
type
|
|
4
|
-
type
|
|
5
|
-
|
|
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;
|
|
6
10
|
};
|
|
7
|
-
type
|
|
8
|
-
[K in keyof M]:
|
|
11
|
+
type InferActions<M extends LogicMap> = {
|
|
12
|
+
[K in keyof M]: InferRuntime<M[K]> extends LogicRuntime<any, any, infer A> ? A : never;
|
|
9
13
|
};
|
|
10
|
-
export declare function composeLogic<M extends LogicMap>(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
};
|
|
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>;
|
|
17
20
|
};
|
|
18
21
|
export {};
|
|
@@ -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,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { LogicRuntime } from "../core/runtime";
|
|
3
|
-
export declare function useActions<A extends
|
|
4
|
-
|
|
5
|
-
}): A;
|
|
6
|
-
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,2 +1,2 @@
|
|
|
1
|
-
import { LogicRuntime } from "../core/runtime";
|
|
2
|
-
export declare function useLogicSelector<S extends object, R>(runtime: LogicRuntime<S>, selector: (state: Readonly<S
|
|
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,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.1.
|
|
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",
|