intentx-solid 0.0.20 → 0.2.0
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 +101 -18
- package/build/index.cjs +1 -1
- package/build/index.d.ts +9 -14
- package/build/index.js +1 -1
- package/build/logic/context.d.ts +4 -5
- package/build/logic/types.d.ts +2 -8
- package/build/logic/useLogic.d.ts +7 -6
- package/package.json +23 -9
package/README.md
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
`intentx-solid`
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
`intentx-solid` is an architectural layer for Solid.
|
|
10
|
+
It enforces a strict separation between:
|
|
11
|
+
- Business Logic (deterministic runtime)
|
|
12
|
+
- UI Rendering (fine-grained reactivity)
|
|
13
13
|
|
|
14
14
|
> It is a bridge between deterministic logic and Solid’s reactive UI.
|
|
15
15
|
|
|
@@ -63,7 +63,7 @@ npm install intentx-solid
|
|
|
63
63
|
## 🧩 Core Logic (Framework-Agnostic)
|
|
64
64
|
|
|
65
65
|
``` ts
|
|
66
|
-
import { createLogic } from "intentx-
|
|
66
|
+
import { createLogic } from "intentx-solid"
|
|
67
67
|
|
|
68
68
|
export const counterLogic = createLogic({
|
|
69
69
|
name: "counter",
|
|
@@ -168,7 +168,7 @@ useLogic(logic, {
|
|
|
168
168
|
Custom bus:
|
|
169
169
|
|
|
170
170
|
``` ts
|
|
171
|
-
import { createIntentBus } from "intentx-
|
|
171
|
+
import { createIntentBus } from "intentx-solid"
|
|
172
172
|
|
|
173
173
|
const bus = createIntentBus()
|
|
174
174
|
|
|
@@ -230,14 +230,31 @@ Works with:
|
|
|
230
230
|
|
|
231
231
|
---
|
|
232
232
|
|
|
233
|
+
## 🧪 Testability Upgrade
|
|
234
|
+
|
|
235
|
+
Without rendering anything:
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
const runtime = counterLogic.create()
|
|
239
|
+
|
|
240
|
+
runtime.actions.inc()
|
|
241
|
+
expect(runtime.state.count).toBe(1)
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
That is the real split.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
233
249
|
## 🔍 Comparison
|
|
234
250
|
|
|
235
|
-
| intentx-solid
|
|
236
|
-
|
|
|
237
|
-
|
|
|
238
|
-
|
|
|
239
|
-
|
|
|
240
|
-
|
|
|
251
|
+
| Criteria | Solid only | intentx-solid |
|
|
252
|
+
| ---------------------- | ----------- | ------------- |
|
|
253
|
+
| Local UI state | ✅ | ❌ Overkill |
|
|
254
|
+
| Async orchestration | ⚠️ Manual | ✅ Built-in |
|
|
255
|
+
| Cross-runtime reuse | ❌ | ✅ |
|
|
256
|
+
| Deterministic snapshot | ❌ | ✅ |
|
|
257
|
+
|
|
241
258
|
|
|
242
259
|
|
|
243
260
|
- UI consumes state.
|
|
@@ -245,16 +262,82 @@ Works with:
|
|
|
245
262
|
|
|
246
263
|
---
|
|
247
264
|
|
|
248
|
-
##
|
|
265
|
+
## 🔥 What This Library Actually Does
|
|
266
|
+
|
|
267
|
+
<b>It separates business logic from UI completely.</b>
|
|
268
|
+
|
|
269
|
+
Without this split:
|
|
270
|
+
|
|
271
|
+
- Components start holding async workflows
|
|
272
|
+
- Event chains become implicit
|
|
273
|
+
- State transitions become coupled to rendering
|
|
274
|
+
- Testing requires rendering components
|
|
275
|
+
|
|
276
|
+
With intentx-solid:
|
|
277
|
+
|
|
278
|
+
- Logic lives outside the component tree
|
|
279
|
+
- UI becomes a pure consumer
|
|
280
|
+
- Async workflows are deterministic
|
|
281
|
+
- Runtime can be reused in Node, SSR, microfrontends
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## 🧩 Architectural Boundary
|
|
286
|
+
|
|
287
|
+
<b>Solid owns:</b>
|
|
288
|
+
|
|
289
|
+
- Signals
|
|
290
|
+
- Reactivity
|
|
291
|
+
- DOM updates
|
|
292
|
+
- Rendering lifecycle
|
|
293
|
+
|
|
294
|
+
<b>intentx owns:</b>
|
|
295
|
+
|
|
296
|
+
- State machine
|
|
297
|
+
- Intent routing
|
|
298
|
+
- Async orchestration
|
|
299
|
+
- Computed graph
|
|
300
|
+
- Cross-runtime communication
|
|
301
|
+
|
|
302
|
+
This is not about replacing `createSignal`.
|
|
303
|
+
|
|
304
|
+
It is about preventing this:
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
// ❌ Business logic leaking into UI
|
|
308
|
+
createEffect(async () => {
|
|
309
|
+
if (userId()) {
|
|
310
|
+
const data = await fetchUser(userId())
|
|
311
|
+
setUser(data)
|
|
312
|
+
}
|
|
313
|
+
})
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
And moving it here:
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
// ✅ Logic outside UI
|
|
320
|
+
actions: ({ setState }) => ({
|
|
321
|
+
async loadUser(id: string) {
|
|
322
|
+
const data = await fetchUser(id)
|
|
323
|
+
setState(d => {
|
|
324
|
+
d.user = data
|
|
325
|
+
})
|
|
326
|
+
}
|
|
327
|
+
})
|
|
328
|
+
```
|
|
249
329
|
|
|
250
|
-
|
|
330
|
+
Now UI only emits intent.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## 🎯 Philosophy
|
|
251
335
|
|
|
252
|
-
|
|
336
|
+
Rendering is reactive.
|
|
253
337
|
|
|
254
|
-
|
|
338
|
+
Business logic should be deterministic.
|
|
255
339
|
|
|
256
|
-
|
|
257
|
-
> Ultra-fast fine-grained UI
|
|
340
|
+
intentx-solid ensures they never mix.
|
|
258
341
|
|
|
259
342
|
---
|
|
260
343
|
|
package/build/index.cjs
CHANGED
|
@@ -1 +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]};
|
|
1
|
+
"use strict";var e=require("intentx-runtime"),t=require("solid-js/store"),r=require("solid-js");let n=null;const o=new Map;function c(){return n||(n=e.createIntentBus()),n}function s(t){return t?(o.has(t)||o.set(t,e.createIntentBus()),o.get(t)):c()}const i="undefined"!=typeof window;function u(n,o){const c="string"==typeof o?.scope?e.createScope(o.scope):o?.scope,u=o?.bus??(o?.sharedBus?s("string"==typeof o?.scope?o.scope:void 0):void 0),a=u?n.create(c,u):n.create(c),[p,f]=t.createStore(a.getSnapshot());let d=()=>{};return i&&(d=a.subscribe(()=>{f(t.reconcile(a.getSnapshot()))}),r.onCleanup(()=>{d(),a.destroy?.()})),{runtime:a,store:p,state:p,actions:a.actions,emit:a.emit.bind(a)}}const a=r.createContext({});Object.defineProperty(exports,"createIntentBus",{enumerable:!0,get:function(){return e.createIntentBus}}),Object.defineProperty(exports,"createLogic",{enumerable:!0,get:function(){return e.createLogic}}),Object.defineProperty(exports,"effect",{enumerable:!0,get:function(){return e.effect}}),exports.getGlobalBus=c,exports.getScopedBus=s,exports.setLogicContext=function(e,t,r){const n=u(t,r);return{Provider:function(t){return a.Provider({value:{[e]:n},get children(){return t.children}})},store:n}},exports.useLogic=u,exports.useLogicContext=function(e){const t=r.useContext(a);if(!t||!t[e])throw Error(`Logic "${e}" not found in context`);return t[e]};
|
package/build/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createIntentBus, LogicActions,
|
|
1
|
+
import { createIntentBus, LogicActions, InferComputed, Scope, ComputedDef, LogicFactory } from 'intentx-runtime';
|
|
2
2
|
export { EffectMode, ExtractLogicTypes, IntentContext, LogicActions, LogicFactory, LogicRuntime, createIntentBus, createLogic, effect } from 'intentx-runtime';
|
|
3
3
|
import * as solid_js from 'solid-js';
|
|
4
4
|
|
|
@@ -6,13 +6,7 @@ type IntentBus = ReturnType<typeof createIntentBus>;
|
|
|
6
6
|
declare function getGlobalBus(): IntentBus;
|
|
7
7
|
declare function getScopedBus(scope?: string): IntentBus;
|
|
8
8
|
|
|
9
|
-
type
|
|
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> = {
|
|
9
|
+
type LogicApi<S, C, A extends LogicActions> = {
|
|
16
10
|
runtime: any;
|
|
17
11
|
store: Readonly<S & InferComputed<C>>;
|
|
18
12
|
state: Readonly<S & InferComputed<C>>;
|
|
@@ -20,19 +14,20 @@ type LogicInstance<S, C, A extends LogicActions> = {
|
|
|
20
14
|
emit: (...args: any[]) => Promise<void>;
|
|
21
15
|
};
|
|
22
16
|
|
|
23
|
-
|
|
17
|
+
type LogicOptions = {
|
|
24
18
|
scope?: Scope | string;
|
|
25
19
|
sharedBus?: boolean;
|
|
26
|
-
bus?:
|
|
27
|
-
}
|
|
20
|
+
bus?: IntentBus;
|
|
21
|
+
};
|
|
22
|
+
declare function useLogic<S extends object, C extends ComputedDef<S>, A extends LogicActions>(logic: LogicFactory<S, C, A>, options?: LogicOptions): LogicApi<S, C, A>;
|
|
28
23
|
|
|
29
|
-
declare function setLogicContext<S extends object, C extends ComputedDef<S>, A extends LogicActions>(key: string, logic: LogicFactory<S, C, A>, options?:
|
|
24
|
+
declare function setLogicContext<S extends object, C extends ComputedDef<S>, A extends LogicActions>(key: string, logic: LogicFactory<S, C, A>, options?: LogicOptions): {
|
|
30
25
|
Provider: (props: {
|
|
31
26
|
children: any;
|
|
32
27
|
}) => solid_js.JSX.Element;
|
|
33
|
-
store:
|
|
28
|
+
store: LogicApi<S, C, A>;
|
|
34
29
|
};
|
|
35
30
|
declare function useLogicContext<T>(key: string): T;
|
|
36
31
|
|
|
37
32
|
export { getGlobalBus, getScopedBus, setLogicContext, useLogic, useLogicContext };
|
|
38
|
-
export type {
|
|
33
|
+
export type { IntentBus, LogicApi, LogicOptions };
|
package/build/index.js
CHANGED
|
@@ -1 +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};
|
|
1
|
+
import{createIntentBus as t,createScope as e}from"intentx-runtime";export{createIntentBus,createLogic,effect}from"intentx-runtime";import{createStore as n,reconcile as o}from"solid-js/store";import{onCleanup as r,createContext as i,useContext as s}from"solid-js";let c=null;const u=new Map;function f(){return c||(c=t()),c}function p(e){return e?(u.has(e)||u.set(e,t()),u.get(e)):f()}const d="undefined"!=typeof window;function a(t,i){const s="string"==typeof i?.scope?e(i.scope):i?.scope,c=i?.bus??(i?.sharedBus?p("string"==typeof i?.scope?i.scope:void 0):void 0),u=c?t.create(s,c):t.create(s),[f,a]=n(u.getSnapshot());let m=()=>{};return d&&(m=u.subscribe(()=>{a(o(u.getSnapshot()))}),r(()=>{m(),u.destroy?.()})),{runtime:u,store:f,state:f,actions:u.actions,emit:u.emit.bind(u)}}const m=i({});function l(t,e,n){const o=a(e,n);return{Provider:function(e){return m.Provider({value:{[t]:o},get children(){return e.children}})},store:o}}function g(t){const e=s(m);if(!e||!e[t])throw Error(`Logic "${t}" not found in context`);return e[t]}export{f as getGlobalBus,p as getScopedBus,l as setLogicContext,a as useLogic,g as useLogicContext};
|
package/build/logic/context.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { LogicFactory, LogicActions } from "intentx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
|
|
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]): {
|
|
1
|
+
import type { LogicFactory, LogicActions, ComputedDef } from "intentx-runtime";
|
|
2
|
+
import type { LogicOptions } from "./useLogic";
|
|
3
|
+
export declare function setLogicContext<S extends object, C extends ComputedDef<S>, A extends LogicActions>(key: string, logic: LogicFactory<S, C, A>, options?: LogicOptions): {
|
|
5
4
|
Provider: (props: {
|
|
6
5
|
children: any;
|
|
7
6
|
}) => import("solid-js").JSX.Element;
|
|
8
|
-
store: import("./types").
|
|
7
|
+
store: import("./types").LogicApi<S, C, A>;
|
|
9
8
|
};
|
|
10
9
|
export declare function useLogicContext<T>(key: string): T;
|
package/build/logic/types.d.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import type { LogicActions } from "intentx-runtime";
|
|
2
|
-
export type
|
|
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> = {
|
|
1
|
+
import type { InferComputed, LogicActions } from "intentx-runtime";
|
|
2
|
+
export type LogicApi<S, C, A extends LogicActions> = {
|
|
9
3
|
runtime: any;
|
|
10
4
|
store: Readonly<S & InferComputed<C>>;
|
|
11
5
|
state: Readonly<S & InferComputed<C>>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { Scope, LogicFactory, LogicActions } from "intentx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
4
|
-
export
|
|
1
|
+
import type { Scope, LogicFactory, LogicActions, ComputedDef } from "intentx-runtime";
|
|
2
|
+
import type { IntentBus } from "./bus";
|
|
3
|
+
import type { LogicApi } from "./types";
|
|
4
|
+
export type LogicOptions = {
|
|
5
5
|
scope?: Scope | string;
|
|
6
6
|
sharedBus?: boolean;
|
|
7
|
-
bus?:
|
|
8
|
-
}
|
|
7
|
+
bus?: IntentBus;
|
|
8
|
+
};
|
|
9
|
+
export declare function useLogic<S extends object, C extends ComputedDef<S>, A extends LogicActions>(logic: LogicFactory<S, C, A>, options?: LogicOptions): LogicApi<S, C, A>;
|
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "intentx-solid",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Intent-driven logic adapter for SolidJS. Connects intentx-runtime with Solid's fine-grained reactivity.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Delpi.Kye",
|
|
5
7
|
"type": "module",
|
|
8
|
+
|
|
6
9
|
"main": "build/index.cjs",
|
|
7
10
|
"module": "build/index.js",
|
|
8
11
|
"types": "build/index.d.ts",
|
|
12
|
+
|
|
9
13
|
"exports": {
|
|
10
14
|
".": {
|
|
11
15
|
"import": "./build/index.js",
|
|
@@ -13,24 +17,29 @@
|
|
|
13
17
|
"types": "./build/index.d.ts"
|
|
14
18
|
}
|
|
15
19
|
},
|
|
20
|
+
|
|
16
21
|
"files": [
|
|
17
22
|
"build"
|
|
18
23
|
],
|
|
24
|
+
|
|
19
25
|
"sideEffects": false,
|
|
20
|
-
|
|
21
|
-
"author": "Delpi.Kye",
|
|
26
|
+
|
|
22
27
|
"repository": {
|
|
23
28
|
"type": "git",
|
|
24
29
|
"url": "https://github.com/delpikye-v/intentx-solid.git"
|
|
25
30
|
},
|
|
31
|
+
|
|
26
32
|
"homepage": "https://github.com/delpikye-v/intentx-solid#readme",
|
|
33
|
+
|
|
27
34
|
"bugs": {
|
|
28
35
|
"url": "https://github.com/delpikye-v/intentx-solid/issues"
|
|
29
36
|
},
|
|
37
|
+
|
|
30
38
|
"funding": {
|
|
31
39
|
"type": "github",
|
|
32
40
|
"url": "https://github.com/sponsors/delpikye-v"
|
|
33
41
|
},
|
|
42
|
+
|
|
34
43
|
"keywords": [
|
|
35
44
|
"solid",
|
|
36
45
|
"solidjs",
|
|
@@ -43,15 +52,25 @@
|
|
|
43
52
|
"microfrontend",
|
|
44
53
|
"architecture"
|
|
45
54
|
],
|
|
55
|
+
|
|
46
56
|
"engines": {
|
|
47
57
|
"node": ">=18"
|
|
48
58
|
},
|
|
59
|
+
|
|
60
|
+
"scripts": {
|
|
61
|
+
"clean": "rimraf build",
|
|
62
|
+
"build": "rollup -c",
|
|
63
|
+
"cb": "npm run clean && npm run build"
|
|
64
|
+
},
|
|
65
|
+
|
|
49
66
|
"peerDependencies": {
|
|
50
67
|
"solid-js": "^1.8.0"
|
|
51
68
|
},
|
|
69
|
+
|
|
52
70
|
"dependencies": {
|
|
53
|
-
"intentx-runtime": "
|
|
71
|
+
"intentx-runtime": "^0.2.4"
|
|
54
72
|
},
|
|
73
|
+
|
|
55
74
|
"devDependencies": {
|
|
56
75
|
"@rollup/plugin-commonjs": "^25.0.0",
|
|
57
76
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
@@ -65,10 +84,5 @@
|
|
|
65
84
|
"tslib": "^2.6.2",
|
|
66
85
|
"typescript": "^5.3.3",
|
|
67
86
|
"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
87
|
}
|
|
74
88
|
}
|