intentx-solid 0.0.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 +263 -0
- package/build/index.cjs +1 -0
- package/build/index.d.ts +38 -0
- package/build/index.js +1 -0
- package/build/logic/bus.d.ts +4 -0
- package/build/logic/context.d.ts +10 -0
- package/build/logic/index.d.ts +4 -0
- package/build/logic/types.d.ts +14 -0
- package/build/logic/useLogic.d.ts +8 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
## π·β‘ intentx-solid
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/intentx-solid) 
|
|
4
|
+
|
|
5
|
+
<a href="https://codesandbox.io/p/devbox/5d4shj" target="_blank">LIVE EXAMPLE</a>
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
`intentx-solid` connects the headless **LogicRuntime engine** with Solidβs fine-grained reactive system.
|
|
10
|
+
|
|
11
|
+
It does not replace Solidβs state primitives.
|
|
12
|
+
It orchestrates business logic outside the component tree.
|
|
13
|
+
|
|
14
|
+
> It is a bridge between deterministic logic and Solidβs reactive UI.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## β¨ Why intentx-solid?
|
|
19
|
+
|
|
20
|
+
Use it when your UI starts to feel like business logic.
|
|
21
|
+
|
|
22
|
+
β
Complex async workflows
|
|
23
|
+
β
Intent-based architecture
|
|
24
|
+
β
Microfrontend communication
|
|
25
|
+
β
Testable business logic
|
|
26
|
+
β
Cross-framework runtime reuse
|
|
27
|
+
|
|
28
|
+
Avoid it when:
|
|
29
|
+
|
|
30
|
+
β You only need simple `createSignal`
|
|
31
|
+
β You want reducer-style state
|
|
32
|
+
β Your state is purely local UI
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## π§ Mental Model
|
|
37
|
+
```txt
|
|
38
|
+
UI Event
|
|
39
|
+
β
|
|
40
|
+
emit(intent)
|
|
41
|
+
β
|
|
42
|
+
intent handler
|
|
43
|
+
β
|
|
44
|
+
setState
|
|
45
|
+
β
|
|
46
|
+
computed re-evaluates
|
|
47
|
+
β
|
|
48
|
+
Solid store updates
|
|
49
|
+
β
|
|
50
|
+
Fine-grained reactivity updates UI
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## π¦ Installation
|
|
56
|
+
|
|
57
|
+
``` bash
|
|
58
|
+
npm install intentx-solid
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## π§© Core Logic (Framework-Agnostic)
|
|
64
|
+
|
|
65
|
+
``` ts
|
|
66
|
+
import { createLogic } from "intentx-runtime"
|
|
67
|
+
|
|
68
|
+
export const counterLogic = createLogic({
|
|
69
|
+
name: "counter",
|
|
70
|
+
|
|
71
|
+
state: {
|
|
72
|
+
count: 0
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
computed: {
|
|
76
|
+
double: ({ state }) => state.count * 2
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
actions: ({ setState }) => ({
|
|
80
|
+
inc() {
|
|
81
|
+
setState(d => {
|
|
82
|
+
d.count++
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## π Solid Adapter
|
|
92
|
+
|
|
93
|
+
``` ts
|
|
94
|
+
export { useLogic }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## π Usage
|
|
100
|
+
|
|
101
|
+
``` tsx
|
|
102
|
+
import { useLogic } from "intentx-solid"
|
|
103
|
+
import { counterLogic } from "./counter.logic"
|
|
104
|
+
|
|
105
|
+
export default function Counter() {
|
|
106
|
+
const counter = useLogic(counterLogic)
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<>
|
|
110
|
+
<button onClick={counter.actions.inc}>
|
|
111
|
+
{counter.store.count}
|
|
112
|
+
</button>
|
|
113
|
+
|
|
114
|
+
<p>Double: {counter.store.double}</p>
|
|
115
|
+
</>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
No wrapper components.
|
|
121
|
+
No providers required (unless you want shared context).
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## π¦ What `useLogic` Returns
|
|
126
|
+
|
|
127
|
+
``` ts
|
|
128
|
+
const counter = useLogic(counterLogic)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```txt
|
|
132
|
+
{
|
|
133
|
+
runtime,
|
|
134
|
+
store,
|
|
135
|
+
state,
|
|
136
|
+
actions,
|
|
137
|
+
emit
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
π₯ Important
|
|
142
|
+
|
|
143
|
+
- store is readonly
|
|
144
|
+
|
|
145
|
+
- Mutations must go through actions
|
|
146
|
+
|
|
147
|
+
- Solid reactivity remains fine-grained
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## π‘ Scoped Bus
|
|
152
|
+
|
|
153
|
+
``` ts
|
|
154
|
+
useLogic(logic, {
|
|
155
|
+
sharedBus: true
|
|
156
|
+
})
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Scoped:
|
|
160
|
+
|
|
161
|
+
``` ts
|
|
162
|
+
useLogic(logic, {
|
|
163
|
+
scope: "dashboard",
|
|
164
|
+
sharedBus: true
|
|
165
|
+
})
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Custom bus:
|
|
169
|
+
|
|
170
|
+
``` ts
|
|
171
|
+
import { createIntentBus } from "intentx-runtime"
|
|
172
|
+
|
|
173
|
+
const bus = createIntentBus()
|
|
174
|
+
|
|
175
|
+
useLogic(logic, {
|
|
176
|
+
bus
|
|
177
|
+
})
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## π§© Context API
|
|
183
|
+
|
|
184
|
+
Provide logic via Solid context:
|
|
185
|
+
|
|
186
|
+
``` ts
|
|
187
|
+
import { setLogicContext, useLogicContext } from "intentx-solid"
|
|
188
|
+
import { counterLogic } from "./counter.logic"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Provider:
|
|
192
|
+
|
|
193
|
+
``` tsx
|
|
194
|
+
const { Provider } = setLogicContext(
|
|
195
|
+
"counter",
|
|
196
|
+
counterLogic
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
export default function App() {
|
|
200
|
+
return (
|
|
201
|
+
<Provider>
|
|
202
|
+
<Child />
|
|
203
|
+
</Provider>
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Consume:
|
|
209
|
+
|
|
210
|
+
``` ts
|
|
211
|
+
const counter = useLogicContext("counter")
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## π SSR
|
|
217
|
+
|
|
218
|
+
- Runtime created during SSR
|
|
219
|
+
- Deterministic snapshot
|
|
220
|
+
- Hydration-safe
|
|
221
|
+
- No client-only hacks
|
|
222
|
+
- Server snapshot serializable
|
|
223
|
+
- Client rehydrates from deterministic state
|
|
224
|
+
|
|
225
|
+
Works with:
|
|
226
|
+
|
|
227
|
+
- SolidStart
|
|
228
|
+
- Node SSR
|
|
229
|
+
- Edge runtimes
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## π Comparison
|
|
234
|
+
|
|
235
|
+
| intentx-solid | Solid |
|
|
236
|
+
| ------------------- | ----------------------- |
|
|
237
|
+
| Intent-driven logic | Fine-grained reactivity |
|
|
238
|
+
| Deterministic state | Reactive DOM updates |
|
|
239
|
+
| Computed graph | Dependency tracking |
|
|
240
|
+
| Effects & async | Declarative components |
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
- UI consumes state.
|
|
244
|
+
- Logic lives outside components.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## π― Philosophy
|
|
249
|
+
|
|
250
|
+
Solid handles rendering.
|
|
251
|
+
|
|
252
|
+
intentx handles intent and state orchestration.
|
|
253
|
+
|
|
254
|
+
Together:
|
|
255
|
+
|
|
256
|
+
> Predictable business logic
|
|
257
|
+
> Ultra-fast fine-grained UI
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## π License
|
|
262
|
+
|
|
263
|
+
MIT
|
package/build/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var t=require("solid-js/store"),e=require("solid-js"),s="undefined"!=typeof document?document.currentScript:null;let n=0;function o(t){return Symbol(null!=t?t:"scope-"+ ++n)}const i={activeNode:null,nodes:new Set};let r=0;function c(t){const e={id:++r,type:t,deps:new Set};return i.nodes.add(e),e}function a(t,e){t.deps.add(e)}const d="undefined"==typeof globalThis||void 0===globalThis.__DEV__||globalThis.__DEV__,h={high:new Set,normal:new Set,low:new Set};let u=!1;function l(){u=!0;for(const t of["high","normal","low"])for(const e of h[t])h[t].delete(e),e();u=!1}function f(t,e="normal"){h[e].add(t),u||queueMicrotask(l)}const p=function(){const t={activeEffect:null,activeDeps:null},e=function(t,e){return function(s){let n=s;const o=new Set,r=d?c("signal"):null,h=()=>{var e;const s=t.activeEffect;if(s&&(o.add(s),null===(e=t.activeDeps)||void 0===e||e.add(o)),d&&r){const t=i.activeNode;t&&a(t,r)}return n};return h.set=(s,i="normal")=>{Object.is(s,n)||(n=s,o.forEach(s=>{s!==t.activeEffect&&e(s,i)}))},h.subscribe=t=>(o.add(t),()=>o.delete(t)),h}}(t,f),s=function(t,e){return function(s){let n,o=!0;const r=new Set,h=new Set,u=d?c("computed"):null,l=()=>{o||(o=!0,r.forEach(t=>e(t,"normal")))};return()=>{var e;const c=t.activeEffect;if(c&&(r.add(c),null===(e=t.activeDeps)||void 0===e||e.add(r)),o){for(const t of h)t.delete(l);h.clear();const e=t.activeEffect,r=t.activeDeps,c=d?i.activeNode:null;t.activeEffect=l,t.activeDeps=h,d&&u&&(i.activeNode=u);try{n=s(),o=!1}finally{t.activeEffect=e,t.activeDeps=r,d&&(i.activeNode=c)}}if(d&&u){const t=i.activeNode;t&&a(t,u)}return n}}}(t,f),n=function(t,e){return function(s,n="normal"){let o=!1;const r=new Set,a=d?c("effect"):null,h=()=>{if(o)return;for(const t of r)t.delete(h);r.clear();const e=d?i.activeNode:null;try{t.activeEffect=h,t.activeDeps=r,d&&a&&(i.activeNode=a),s()}finally{t.activeEffect=null,t.activeDeps=null,d&&(i.activeNode=e)}};return e(h,n),()=>{o=!0;for(const t of r)t.delete(h);r.clear()}}}(t,f);return{signal:e,createComputed:s,reactiveEffect:n,context:t}}(),m=p.signal,y=p.reactiveEffect;o("default");const g=function(t){const e=function(t){return function(e,s){const n=t(e),o=n.set;return n.set=(t,e="normal")=>{const i=n(),r=s?s(t,i):t;o(r,e)},n.update=(t,e="normal")=>{n.set(t(n()),e)},n}}(t);return function(t,s){var n;const o=null!==(n=null==s?void 0:s.equals)&&void 0!==n?n:Object.is;return e(t,(t,e)=>o(t,e)?e:t)}}(m);class b{constructor(){this.handlers={},this.effects={},this.middlewares=[],this.effectModes={},this.use=t=>{this.middlewares.push(t)},this.setEffectMode=(t,e)=>{this.effectModes[t]=e},this.effect=(t,e)=>{var s;((s=this.effects)[t]??(s[t]=[])).push(e)},this.on=(t,e)=>{var s;const n=(s=this.handlers)[t]??(s[t]=[]);return n.length>0?()=>{}:(n.push(e),()=>{const s=this.handlers[t];if(!s)return;const n=s.indexOf(e);0>n||s.splice(n,1),0===s.length&&delete this.handlers[t]})},this.emit=async(t,e)=>{const s=this.handlers[t]??[],n={context:e,effects:this.effects[t]??[],effectMode:this.effectModes[t]??"sequential"},o=this.middlewares.reduceRight((t,e)=>e(t),async t=>{for(const e of s)await e(t.context)});await o(n)},this.clear=()=>{this.handlers={},this.effects={},this.middlewares=[],this.effectModes={}}}}function w(t){return"function"==typeof structuredClone?structuredClone(t):JSON.parse(JSON.stringify(t))}function v(t){if(null===t||"object"!=typeof t)return t;Object.freeze(t);for(const e of Object.keys(t)){const s=t[e];s&&"object"==typeof s&&!Object.isFrozen(s)&&v(s)}return t}const S=void("undefined"==typeof document?require("url").pathToFileURL(__filename):s&&"SCRIPT"===s.tagName.toUpperCase()&&s.src||new URL("index.cjs",document.baseURI)),D="undefined"!=typeof globalThis&&void 0!==globalThis.process?globalThis.process?.env?.NODE_ENV:void 0,E=S?.DEV??(!!D&&"production"!==D);class k{constructor(t,e=o("logic"),s){this.computedAtoms={},this.subs=new Set,this.dirty=!0,this.isComputing=!1,this.isBatching=!1,this.destroyed=!1,this.computedKeys=new Set,this.computedDisposers=new Set,this.intentDisposers=new Set,this.errorHandlers=new Set,this.leadingLocks=new Set,this.throttleMap=new Map,this.destroy=()=>{this.destroyed||(this.destroyed=!0,this.subs.clear(),this.computedDisposers.forEach(t=>t()),this.computedDisposers.clear(),this.intentDisposers.forEach(t=>t()),this.intentDisposers.clear(),this.leadingLocks.clear(),this.throttleMap.clear(),this.errorHandlers.clear(),this.computedKeys.clear(),this.dirty=!0)},this.createStateAtoms=t=>{const e={};for(const s in t)e[s]=g(t[s]);return e},this.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 E?v(t):t},this.markDirty=()=>{this.destroyed||this.isBatching||(this.dirty=!0,this.subs.forEach(t=>t()))},this.createReactiveState=()=>new Proxy({},{get:(t,e)=>{const s=this.stateAtoms[e];return s?s():void 0}}),this.getSnapshot=()=>this.destroyed?this.snapshotCache??this.buildSnapshot():(this.dirty&&(this.snapshotCache=this.buildSnapshot(),this.dirty=!1),this.snapshotCache),this.subscribe=t=>this.destroyed?()=>{}:(this.subs.add(t),()=>this.subs.delete(t)),this.batch=t=>{if(!this.destroyed){this.isBatching=!0;try{t()}finally{this.isBatching=!1,this.markDirty()}}},this.onError=t=>(this.errorHandlers.add(t),()=>this.errorHandlers.delete(t)),this.getComputedKey=t=>this.computedAtoms[t](),this.getComputed=()=>{const t=this.getSnapshot(),e={};return this.computedKeys.forEach(s=>{e[s]=t[s]}),e},this.setStateInternal=t=>{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])},this.onIntent=(t,e)=>{const s=this.bus.on(t,e);return this.intentDisposers.add(s),()=>{s(),this.intentDisposers.delete(s)}},this.once=(t,e)=>{const s=this.onIntent(t,async t=>{s(),await e(t)})},this.takeLeading=(t,e)=>{this.onIntent(t,async s=>{if(!this.leadingLocks.has(t)){this.leadingLocks.add(t);try{await e(s)}finally{this.leadingLocks.delete(t)}}})},this.throttle=(t,e,s)=>{this.onIntent(t,async n=>{const o=Date.now();o-(this.throttleMap.get(t)??0)<e||(this.throttleMap.set(t,o),await s(n))})},this.useEffect=(t,e)=>{this.bus.effect(t,e)},this.emit=async(t,e)=>{if(this.destroyed)return;const s=new AbortController;try{await this.bus.emit(t,{payload:e,scope:this.scope,signal:s.signal,state:this.getSnapshot,setState:this.setStateInternal,emit:this.emit})}catch(s){this.errorHandlers.forEach(n=>n(s,{type:t,payload:e}))}},this.attachComputed=(t,e)=>{const s=g(void 0),n=this.createReactiveState();this.computedAtoms[t]=s,this.computedKeys.add(t);const o=()=>{this.destroyed||(this.isComputing=!0,s.set(e({state:n})),this.isComputing=!1)},i=y(o);this.computedDisposers.add(i),o();const r=s.subscribe(this.markDirty);this.computedDisposers.add(r)},this.scope=e,this.stateAtoms=this.createStateAtoms(t);for(const t in this.stateAtoms){const e=this.stateAtoms[t].subscribe(this.markDirty);this.computedDisposers.add(e)}s?this.bus=s:(this.bus=new b,this.bus.use(function(){const t=new Map,e=new Map;return s=>async n=>{await s(n);const{effects:o,effectMode:i,context:r}=n;if(!o.length)return;const c=o.map(s=>()=>(async s=>{const n=s.id;if("takeLatest"===s.strategy){t.get(n)?.abort();const e=new AbortController;return t.set(n,e),s.handler({...r,signal:e.signal})}return"debounce"===s.strategy?(clearTimeout(e.get(n)),new Promise(t=>{e.set(n,setTimeout(async()=>{await s.handler(r),t()},s.wait))})):s.handler(r)})(s));switch(i){case"parallel":await Promise.all(c.map(t=>t()));break;case"race":await Promise.race(c.map(t=>t()));break;case"allSettled":await Promise.allSettled(c.map(t=>t()));break;default:for(const t of c){const e=t();await e}}}}())),E&&(this.__debugId="runtime-"+Math.random().toString(36).slice(2))}get state(){return this.getSnapshot()}get computed(){const t={};return this.computedKeys.forEach(e=>{t[e]=this.computedAtoms[e]()}),t}}const C=()=>new b;let A=null;const x=new Map;function M(){return A||(A=C()),A}function L(t){return t?(x.has(t)||x.set(t,C()),x.get(t)):M()}const _="undefined"!=typeof window;function N(s,n){const i="string"==typeof n?.scope?o(n.scope):n?.scope,r=n?.bus??(n?.sharedBus?L("string"==typeof n?.scope?n.scope:void 0):void 0),c=r?s.create(i,r):s.create(i),[a,d]=t.createStore(c.getSnapshot());let h=()=>{};return _&&(h=c.subscribe(()=>{d(t.reconcile(c.getSnapshot()))}),e.onCleanup(()=>{h(),c.destroy?.()})),{runtime:c,store:a,state:a,actions:c.actions,emit:c.emit.bind(c)}}const j=e.createContext({});exports.createIntentBus=C,exports.createLogic=function(t){return{name:t.name,createShareBus(t,e){return this.create(t,e)},createIsolated(t){return this.create(t,void 0)},create(e,s){const n=new k(w(t.state),e,s);if(E&&!n.devtools){const e=function(t,e){const s=function(){let t=0,e=[];return{get records(){return e.slice()},record:function(s){e.push({...s,id:++t,state:w(s.state)})},replay:async function(t,s){const{from:n=0,to:o=1/0,scope:i}=s??{},r=e.filter(t=>!("emit"!==t.type||n>t.id||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}}}(),n=Symbol("devtools_wrapped");function o(){const s=e||t.scope;return s?"string"==typeof s?s:s.name??"anonymous":"global"}function i(){return"function"==typeof t.getSnapshot?t.getSnapshot():"function"==typeof t.state?t.state():void 0}return{timeline:s,wrap:function(){if(t[n])return;t[n]=!0;const e=t.emit.bind(t);t.emit=async(t,n)=>{s.record({type:"emit:start",intent:t,payload:n,scope:o(),state:i(),timestamp:Date.now()});try{await Promise.resolve(e(t,n))}catch(e){throw s.record({type:"emit:error",intent:t,payload:n,scope:o(),state:i(),timestamp:Date.now()}),e}s.record({type:"emit:end",intent:t,payload:n,scope:o(),state:i(),timestamp:Date.now()})}}}}(n,t.name??"logic");e.wrap(),n.devtools=e}if(t.computed)for(const e in t.computed)n.attachComputed(e,t.computed[e]);t.intents?.({on:n.onIntent,effect:(t,e)=>n.useEffect(t,e)});const o={};if(t.actions){const e=Object.keys(t.actions);for(const s of e)o[s]=(0,t.actions[s])({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"},s=(t={})=>{const n={...e,...t};return Object.assign(n,{takeLatest:()=>s({strategy:"takeLatest"}),debounce:t=>s({strategy:"debounce",wait:t}),blocking:()=>s({blocking:!0})})};return s()},exports.getGlobalBus=M,exports.getScopedBus=L,exports.setLogicContext=function(t,e,s){const n=N(e,s);return{Provider:function(e){return j.Provider({value:{[t]:n},get children(){return e.children}})},store:n}},exports.useLogic=N,exports.useLogicContext=function(t){const s=e.useContext(j);if(!s||!s[t])throw Error(`Logic "${t}" not found in context`);return s[t]};
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createIntentBus, LogicActions, LogicFactory, Scope } from 'intentx-runtime';
|
|
2
|
+
export { EffectMode, ExtractLogicTypes, IntentContext, LogicActions, LogicFactory, LogicRuntime, createIntentBus, createLogic, effect } from 'intentx-runtime';
|
|
3
|
+
import * as solid_js from 'solid-js';
|
|
4
|
+
|
|
5
|
+
type IntentBus = ReturnType<typeof createIntentBus>;
|
|
6
|
+
declare function getGlobalBus(): IntentBus;
|
|
7
|
+
declare function getScopedBus(scope?: string): IntentBus;
|
|
8
|
+
|
|
9
|
+
type ComputedDef<S> = Record<string, (context: {
|
|
10
|
+
state: Readonly<S>;
|
|
11
|
+
}) => any>;
|
|
12
|
+
type InferComputed<C> = {
|
|
13
|
+
[K in keyof C]: C[K] extends (...args: any) => infer R ? R : never;
|
|
14
|
+
};
|
|
15
|
+
type LogicInstance<S, C, A extends LogicActions> = {
|
|
16
|
+
runtime: any;
|
|
17
|
+
store: Readonly<S & InferComputed<C>>;
|
|
18
|
+
state: Readonly<S & InferComputed<C>>;
|
|
19
|
+
actions: A;
|
|
20
|
+
emit: (...args: any[]) => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
declare function useLogic<S extends object, C extends ComputedDef<S>, A extends LogicActions>(logic: LogicFactory<S, C, A>, options?: {
|
|
24
|
+
scope?: Scope | string;
|
|
25
|
+
sharedBus?: boolean;
|
|
26
|
+
bus?: ReturnType<typeof getScopedBus>;
|
|
27
|
+
}): LogicInstance<S, C, A>;
|
|
28
|
+
|
|
29
|
+
declare function setLogicContext<S extends object, C extends ComputedDef<S>, A extends LogicActions>(key: string, logic: LogicFactory<S, C, A>, options?: Parameters<typeof useLogic<S, C, A>>[1]): {
|
|
30
|
+
Provider: (props: {
|
|
31
|
+
children: any;
|
|
32
|
+
}) => solid_js.JSX.Element;
|
|
33
|
+
store: LogicInstance<S, C, A>;
|
|
34
|
+
};
|
|
35
|
+
declare function useLogicContext<T>(key: string): T;
|
|
36
|
+
|
|
37
|
+
export { getGlobalBus, getScopedBus, setLogicContext, useLogic, useLogicContext };
|
|
38
|
+
export type { ComputedDef, InferComputed, IntentBus, LogicInstance };
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createStore as t,reconcile as e}from"solid-js/store";import{onCleanup as s,createContext as n,useContext as o}from"solid-js";let i=0;function r(t){return Symbol(null!=t?t:"scope-"+ ++i)}const c={activeNode:null,nodes:new Set};let a=0;function h(t){const e={id:++a,type:t,deps:new Set};return c.nodes.add(e),e}function d(t,e){t.deps.add(e)}const u="undefined"==typeof globalThis||void 0===globalThis.__DEV__||globalThis.__DEV__,l={high:new Set,normal:new Set,low:new Set};let f=!1;function p(){f=!0;for(const t of["high","normal","low"])for(const e of l[t])l[t].delete(e),e();f=!1}function m(t,e="normal"){l[e].add(t),f||queueMicrotask(p)}const y=function(){const t={activeEffect:null,activeDeps:null},e=function(t,e){return function(s){let n=s;const o=new Set,i=u?h("signal"):null,r=()=>{var e;const s=t.activeEffect;if(s&&(o.add(s),null===(e=t.activeDeps)||void 0===e||e.add(o)),u&&i){const t=c.activeNode;t&&d(t,i)}return n};return r.set=(s,i="normal")=>{Object.is(s,n)||(n=s,o.forEach(s=>{s!==t.activeEffect&&e(s,i)}))},r.subscribe=t=>(o.add(t),()=>o.delete(t)),r}}(t,m),s=function(t,e){return function(s){let n,o=!0;const i=new Set,r=new Set,a=u?h("computed"):null,l=()=>{o||(o=!0,i.forEach(t=>e(t,"normal")))};return()=>{var e;const h=t.activeEffect;if(h&&(i.add(h),null===(e=t.activeDeps)||void 0===e||e.add(i)),o){for(const t of r)t.delete(l);r.clear();const e=t.activeEffect,i=t.activeDeps,h=u?c.activeNode:null;t.activeEffect=l,t.activeDeps=r,u&&a&&(c.activeNode=a);try{n=s(),o=!1}finally{t.activeEffect=e,t.activeDeps=i,u&&(c.activeNode=h)}}if(u&&a){const t=c.activeNode;t&&d(t,a)}return n}}}(t,m),n=function(t,e){return function(s,n="normal"){let o=!1;const i=new Set,r=u?h("effect"):null,a=()=>{if(o)return;for(const t of i)t.delete(a);i.clear();const e=u?c.activeNode:null;try{t.activeEffect=a,t.activeDeps=i,u&&r&&(c.activeNode=r),s()}finally{t.activeEffect=null,t.activeDeps=null,u&&(c.activeNode=e)}};return e(a,n),()=>{o=!0;for(const t of i)t.delete(a);i.clear()}}}(t,m);return{signal:e,createComputed:s,reactiveEffect:n,context:t}}(),g=y.signal,w=y.reactiveEffect;r("default");const b=function(t){const e=function(t){return function(e,s){const n=t(e),o=n.set;return n.set=(t,e="normal")=>{const i=n(),r=s?s(t,i):t;o(r,e)},n.update=(t,e="normal")=>{n.set(t(n()),e)},n}}(t);return function(t,s){var n;const o=null!==(n=null==s?void 0:s.equals)&&void 0!==n?n:Object.is;return e(t,(t,e)=>o(t,e)?e:t)}}(g);class v{constructor(){this.handlers={},this.effects={},this.middlewares=[],this.effectModes={},this.use=t=>{this.middlewares.push(t)},this.setEffectMode=(t,e)=>{this.effectModes[t]=e},this.effect=(t,e)=>{var s;((s=this.effects)[t]??(s[t]=[])).push(e)},this.on=(t,e)=>{var s;const n=(s=this.handlers)[t]??(s[t]=[]);return n.length>0?()=>{}:(n.push(e),()=>{const s=this.handlers[t];if(!s)return;const n=s.indexOf(e);0>n||s.splice(n,1),0===s.length&&delete this.handlers[t]})},this.emit=async(t,e)=>{const s=this.handlers[t]??[],n={context:e,effects:this.effects[t]??[],effectMode:this.effectModes[t]??"sequential"},o=this.middlewares.reduceRight((t,e)=>e(t),async t=>{for(const e of s)await e(t.context)});await o(n)},this.clear=()=>{this.handlers={},this.effects={},this.middlewares=[],this.effectModes={}}}}function S(t){return"function"==typeof structuredClone?structuredClone(t):JSON.parse(JSON.stringify(t))}function D(t){if(null===t||"object"!=typeof t)return t;Object.freeze(t);for(const e of Object.keys(t)){const s=t[e];s&&"object"==typeof s&&!Object.isFrozen(s)&&D(s)}return t}const E=void 0!==import.meta?import.meta.env:void 0,k="undefined"!=typeof globalThis&&void 0!==globalThis.process?globalThis.process?.env?.NODE_ENV:void 0,A=E?.DEV??(!!k&&"production"!==k);class M{constructor(t,e=r("logic"),s){this.computedAtoms={},this.subs=new Set,this.dirty=!0,this.isComputing=!1,this.isBatching=!1,this.destroyed=!1,this.computedKeys=new Set,this.computedDisposers=new Set,this.intentDisposers=new Set,this.errorHandlers=new Set,this.leadingLocks=new Set,this.throttleMap=new Map,this.destroy=()=>{this.destroyed||(this.destroyed=!0,this.subs.clear(),this.computedDisposers.forEach(t=>t()),this.computedDisposers.clear(),this.intentDisposers.forEach(t=>t()),this.intentDisposers.clear(),this.leadingLocks.clear(),this.throttleMap.clear(),this.errorHandlers.clear(),this.computedKeys.clear(),this.dirty=!0)},this.createStateAtoms=t=>{const e={};for(const s in t)e[s]=b(t[s]);return e},this.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 A?D(t):t},this.markDirty=()=>{this.destroyed||this.isBatching||(this.dirty=!0,this.subs.forEach(t=>t()))},this.createReactiveState=()=>new Proxy({},{get:(t,e)=>{const s=this.stateAtoms[e];return s?s():void 0}}),this.getSnapshot=()=>this.destroyed?this.snapshotCache??this.buildSnapshot():(this.dirty&&(this.snapshotCache=this.buildSnapshot(),this.dirty=!1),this.snapshotCache),this.subscribe=t=>this.destroyed?()=>{}:(this.subs.add(t),()=>this.subs.delete(t)),this.batch=t=>{if(!this.destroyed){this.isBatching=!0;try{t()}finally{this.isBatching=!1,this.markDirty()}}},this.onError=t=>(this.errorHandlers.add(t),()=>this.errorHandlers.delete(t)),this.getComputedKey=t=>this.computedAtoms[t](),this.getComputed=()=>{const t=this.getSnapshot(),e={};return this.computedKeys.forEach(s=>{e[s]=t[s]}),e},this.setStateInternal=t=>{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])},this.onIntent=(t,e)=>{const s=this.bus.on(t,e);return this.intentDisposers.add(s),()=>{s(),this.intentDisposers.delete(s)}},this.once=(t,e)=>{const s=this.onIntent(t,async t=>{s(),await e(t)})},this.takeLeading=(t,e)=>{this.onIntent(t,async s=>{if(!this.leadingLocks.has(t)){this.leadingLocks.add(t);try{await e(s)}finally{this.leadingLocks.delete(t)}}})},this.throttle=(t,e,s)=>{this.onIntent(t,async n=>{const o=Date.now();o-(this.throttleMap.get(t)??0)<e||(this.throttleMap.set(t,o),await s(n))})},this.useEffect=(t,e)=>{this.bus.effect(t,e)},this.emit=async(t,e)=>{if(this.destroyed)return;const s=new AbortController;try{await this.bus.emit(t,{payload:e,scope:this.scope,signal:s.signal,state:this.getSnapshot,setState:this.setStateInternal,emit:this.emit})}catch(s){this.errorHandlers.forEach(n=>n(s,{type:t,payload:e}))}},this.attachComputed=(t,e)=>{const s=b(void 0),n=this.createReactiveState();this.computedAtoms[t]=s,this.computedKeys.add(t);const o=()=>{this.destroyed||(this.isComputing=!0,s.set(e({state:n})),this.isComputing=!1)},i=w(o);this.computedDisposers.add(i),o();const r=s.subscribe(this.markDirty);this.computedDisposers.add(r)},this.scope=e,this.stateAtoms=this.createStateAtoms(t);for(const t in this.stateAtoms){const e=this.stateAtoms[t].subscribe(this.markDirty);this.computedDisposers.add(e)}s?this.bus=s:(this.bus=new v,this.bus.use(function(){const t=new Map,e=new Map;return s=>async n=>{await s(n);const{effects:o,effectMode:i,context:r}=n;if(!o.length)return;const c=o.map(s=>()=>(async s=>{const n=s.id;if("takeLatest"===s.strategy){t.get(n)?.abort();const e=new AbortController;return t.set(n,e),s.handler({...r,signal:e.signal})}return"debounce"===s.strategy?(clearTimeout(e.get(n)),new Promise(t=>{e.set(n,setTimeout(async()=>{await s.handler(r),t()},s.wait))})):s.handler(r)})(s));switch(i){case"parallel":await Promise.all(c.map(t=>t()));break;case"race":await Promise.race(c.map(t=>t()));break;case"allSettled":await Promise.allSettled(c.map(t=>t()));break;default:for(const t of c){const e=t();await e}}}}())),A&&(this.__debugId="runtime-"+Math.random().toString(36).slice(2))}get state(){return this.getSnapshot()}get computed(){const t={};return this.computedKeys.forEach(e=>{t[e]=this.computedAtoms[e]()}),t}}function C(t){const e={_kind:"effect",id:Symbol("effect"),handler:t,strategy:"default"},s=(t={})=>{const n={...e,...t};return Object.assign(n,{takeLatest:()=>s({strategy:"takeLatest"}),debounce:t=>s({strategy:"debounce",wait:t}),blocking:()=>s({blocking:!0})})};return s()}function N(t){return{name:t.name,createShareBus(t,e){return this.create(t,e)},createIsolated(t){return this.create(t,void 0)},create(e,s){const n=new M(S(t.state),e,s);if(A&&!n.devtools){const e=function(t,e){const s=function(){let t=0,e=[];return{get records(){return e.slice()},record:function(s){e.push({...s,id:++t,state:S(s.state)})},replay:async function(t,s){const{from:n=0,to:o=1/0,scope:i}=s??{},r=e.filter(t=>!("emit"!==t.type||n>t.id||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}}}(),n=Symbol("devtools_wrapped");function o(){const s=e||t.scope;return s?"string"==typeof s?s:s.name??"anonymous":"global"}function i(){return"function"==typeof t.getSnapshot?t.getSnapshot():"function"==typeof t.state?t.state():void 0}return{timeline:s,wrap:function(){if(t[n])return;t[n]=!0;const e=t.emit.bind(t);t.emit=async(t,n)=>{s.record({type:"emit:start",intent:t,payload:n,scope:o(),state:i(),timestamp:Date.now()});try{await Promise.resolve(e(t,n))}catch(e){throw s.record({type:"emit:error",intent:t,payload:n,scope:o(),state:i(),timestamp:Date.now()}),e}s.record({type:"emit:end",intent:t,payload:n,scope:o(),state:i(),timestamp:Date.now()})}}}}(n,t.name??"logic");e.wrap(),n.devtools=e}if(t.computed)for(const e in t.computed)n.attachComputed(e,t.computed[e]);t.intents?.({on:n.onIntent,effect:(t,e)=>n.useEffect(t,e)});const o={};if(t.actions){const e=Object.keys(t.actions);for(const s of e)o[s]=(0,t.actions[s])({emit:n.emit,getState:n.getSnapshot})}return n.actions=o,n}}}const _=()=>new v;let j=null;const L=new Map;function O(){return j||(j=_()),j}function I(t){return t?(L.has(t)||L.set(t,_()),L.get(t)):O()}const P="undefined"!=typeof window;function x(n,o){const i="string"==typeof o?.scope?r(o.scope):o?.scope,c=o?.bus??(o?.sharedBus?I("string"==typeof o?.scope?o.scope:void 0):void 0),a=c?n.create(i,c):n.create(i),[h,d]=t(a.getSnapshot());let u=()=>{};return P&&(u=a.subscribe(()=>{d(e(a.getSnapshot()))}),s(()=>{u(),a.destroy?.()})),{runtime:a,store:h,state:h,actions:a.actions,emit:a.emit.bind(a)}}const T=n({});function B(t,e,s){const n=x(e,s);return{Provider:function(e){return T.Provider({value:{[t]:n},get children(){return e.children}})},store:n}}function K(t){const e=o(T);if(!e||!e[t])throw Error(`Logic "${t}" not found in context`);return e[t]}export{_ as createIntentBus,N as createLogic,C as effect,O as getGlobalBus,I as getScopedBus,B as setLogicContext,x as useLogic,K as useLogicContext};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LogicFactory, LogicActions } from "intentx-runtime";
|
|
2
|
+
import { useLogic } from "./useLogic";
|
|
3
|
+
import type { ComputedDef } from "./types";
|
|
4
|
+
export declare function setLogicContext<S extends object, C extends ComputedDef<S>, A extends LogicActions>(key: string, logic: LogicFactory<S, C, A>, options?: Parameters<typeof useLogic<S, C, A>>[1]): {
|
|
5
|
+
Provider: (props: {
|
|
6
|
+
children: any;
|
|
7
|
+
}) => import("solid-js").JSX.Element;
|
|
8
|
+
store: import("./types").LogicInstance<S, C, A>;
|
|
9
|
+
};
|
|
10
|
+
export declare function useLogicContext<T>(key: string): T;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LogicActions } from "intentx-runtime";
|
|
2
|
+
export type ComputedDef<S> = Record<string, (context: {
|
|
3
|
+
state: Readonly<S>;
|
|
4
|
+
}) => any>;
|
|
5
|
+
export type InferComputed<C> = {
|
|
6
|
+
[K in keyof C]: C[K] extends (...args: any) => infer R ? R : never;
|
|
7
|
+
};
|
|
8
|
+
export type LogicInstance<S, C, A extends LogicActions> = {
|
|
9
|
+
runtime: any;
|
|
10
|
+
store: Readonly<S & InferComputed<C>>;
|
|
11
|
+
state: Readonly<S & InferComputed<C>>;
|
|
12
|
+
actions: A;
|
|
13
|
+
emit: (...args: any[]) => Promise<void>;
|
|
14
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Scope, LogicFactory, LogicActions } from "intentx-runtime";
|
|
2
|
+
import { getScopedBus } from "./bus";
|
|
3
|
+
import type { ComputedDef, LogicInstance } from "./types";
|
|
4
|
+
export declare function useLogic<S extends object, C extends ComputedDef<S>, A extends LogicActions>(logic: LogicFactory<S, C, A>, options?: {
|
|
5
|
+
scope?: Scope | string;
|
|
6
|
+
sharedBus?: boolean;
|
|
7
|
+
bus?: ReturnType<typeof getScopedBus>;
|
|
8
|
+
}): LogicInstance<S, C, A>;
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "intentx-solid",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Intent-driven logic adapter for SolidJS. Connects intentx-runtime with Solid's fine-grained reactivity.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "build/index.cjs",
|
|
7
|
+
"module": "build/index.js",
|
|
8
|
+
"types": "build/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./build/index.js",
|
|
12
|
+
"require": "./build/index.cjs",
|
|
13
|
+
"types": "./build/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"build"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "Delpi.Kye",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/delpikye-v/intentx-solid.git"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/delpikye-v/intentx-solid#readme",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/delpikye-v/intentx-solid/issues"
|
|
29
|
+
},
|
|
30
|
+
"funding": {
|
|
31
|
+
"type": "github",
|
|
32
|
+
"url": "https://github.com/sponsors/delpikye-v"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"solid",
|
|
36
|
+
"solidjs",
|
|
37
|
+
"state",
|
|
38
|
+
"state-management",
|
|
39
|
+
"logic",
|
|
40
|
+
"intent",
|
|
41
|
+
"event-driven",
|
|
42
|
+
"runtime",
|
|
43
|
+
"microfrontend",
|
|
44
|
+
"architecture"
|
|
45
|
+
],
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"solid-js": "^1.8.0"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"intentx-runtime": ">=0.2.2"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@rollup/plugin-commonjs": "^25.0.0",
|
|
57
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
58
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
59
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
60
|
+
"rollup": "^4.9.6",
|
|
61
|
+
"rollup-plugin-dts": "^6.3.0",
|
|
62
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
63
|
+
"rollup-plugin-typescript2": "^0.36.0",
|
|
64
|
+
"rimraf": "^5.0.5",
|
|
65
|
+
"tslib": "^2.6.2",
|
|
66
|
+
"typescript": "^5.3.3",
|
|
67
|
+
"unplugin-solid": "^1.0.0"
|
|
68
|
+
},
|
|
69
|
+
"scripts": {
|
|
70
|
+
"clean": "rimraf build",
|
|
71
|
+
"build": "rollup -c",
|
|
72
|
+
"cb": "npm run clean && npm run build"
|
|
73
|
+
}
|
|
74
|
+
}
|