npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

intentx-solid

v0.2.3

Published

Intent-driven logic adapter for SolidJS. Connects intentx-runtime with Solid's fine-grained reactivity.

Readme

🔷⚡ intentx-solid

NPM Downloads

LIVE EXAMPLE


intentx-solid enforces a strict architectural boundary between deterministic business logic and reactive UI in Solid.

It enforces a strict separation between:

  • Business Logic (deterministic runtime)
  • UI Rendering (fine-grained reactivity)

It is a bridge between deterministic logic and Solid’s reactive UI.


✨ Why intentx-solid?

Use it when your UI starts to feel like business logic.

✅ Complex async workflows
✅ Intent-based architecture
✅ Microfrontend communication
✅ Testable business logic
✅ Cross-framework runtime reuse

Avoid it when:

❌ This library introduces an architectural boundary.
❌ If you don’t need architectural boundaries, don’t use it.


🧠 Mental Model

UI / HTTP / Queue / Cron
        ↓
  intentx-runtime
        ↓
Fine-grained reactivity updates UI

Core principle:

Intent is the only mutation entry point. The runtime owns behavior. UI only triggers intent.


📦 Installation

npm install intentx-solid

🧩 Core Logic (Framework-Agnostic)

Even though this is the React package, the runtime is fully usable without React.

import { createLogic } from "intentx-solid"

export const counterLogic = createLogic({
  name: "counter",

  state: {
    count: 0
  },

  computed: {
    double: ({ state }) => state.count * 2
  },

  intents: (bus) => {
    bus.on("inc", ({ setState }) => {
      setState((s) => {
        s.count++;
      });
    });
  },

  actions: {
    inc({ emit }) {
      return () => emit("inc");
    },
  },
})

🚀 Usage

import { useLogic } from "intentx-solid"
import { counterLogic } from "./counter.logic"

export default function Counter() {
  const counter = useLogic(counterLogic)
  // const { actions, emit, store } = useLogic(counterLogic)

  return (
    <>
      <button onClick={counter.actions.inc}>
        {counter.state.count}
      </button>

      <button onClick={() => emit("inc")}>
        {counter.state.count}
      </button>

      <p>Double: {counter.store.double}</p>
    </>
  )
}

No wrapper components. No providers required (unless you want shared context).


📦 What useLogic Returns

const counter = useLogic(counterLogic)
  {
    store, //
    state, // alias state
    actions, // actions -> emit
    emit // directly
  }

🔥 Important

  • store is readonly

  • Mutations must go through actions

  • Solid reactivity remains fine-grained


📡 Multiple Logic Communication (Bus)

Each logic instance is isolated by default.

To enable communication between runtimes, you can share an Intent Bus.


1️⃣ Scoped Shared Bus (Recommended)

import { useLogic } from "intentx-solid"

// ✅ Same scope → shared bus
useLogic(logic, {
  scope: "dashboard",
  sharedBus: true
})

// ❌ Different scope → different bus
useLogic(logic, {
  scope: "settings",
  sharedBus: true
})

How it works

When sharedBus: true is enabled:

  • A singleton bus is created per scope

  • Same scope → same bus instance

  • Different scope → different bus

  • No global leakage

If no scope is provided:

useLogic(logic, {
  sharedBus: true
})

→ uses a default global scope bus.


2️⃣ Custom Bus (Advanced / Cross-Scope)

import { createIntentBus } from "intentx-react"

const bus = createIntentBus()

useLogic(logicA, { bus })
useLogic(logicB, { bus })

Behavior

  • Full cross-scope communication
  • Manual orchestration control
  • Suitable for:
    • Microfrontend
    • App-wide coordination
    • Complex workflow systems

🔍 Behavior Comparison

| Mode | Isolation | Scope-aware | Cross-scope | Recommended | | -------------------- | ----------- | ----------- | ------------ | --------------------- | | Default (no options) | ✅ Full | ❌ | ❌ | Small/local logic | | sharedBus: true | ❌ Per scope | ✅ | ❌ | Modular apps | | Custom bus | ❌ Manual | ❌ | ✅ | Advanced architecture |

🎯 Recommendation

✅ Use sharedBus for modular communication.
✅ Use custom bus for orchestration layer.
🚫 Avoid global single bus without scope in large apps.


🧩 Context API

Provide logic via Solid context:

import { setLogicContext, useLogicContext } from "intentx-solid"
import { counterLogic } from "./counter.logic"

Provider:

const { Provider } = setLogicContext(
  "counter",
  counterLogic
)

export default function App() {
  return (
    <Provider>
      <Child />
    </Provider>
  )
}

Consume:

const counter = useLogicContext("counter")

🌍 SSR

  • Runtime created during SSR
  • Deterministic snapshot
  • Hydration-safe
  • No client-only hacks
  • Server snapshot serializable
  • Client rehydrates from deterministic state

Works with:

  • SolidStart
  • Node SSR
  • Edge runtimes

🧪 Testability Upgrade

Without rendering anything:

const runtime = counterLogic.create()

runtime.actions.inc()
expect(runtime.state.count).toBe(1)

That is the real split.


🔍 Comparison

| Criteria | Solid primitives | intentx-solid | | ----------------------- | ---------------- | ------------- | | Local UI | Excellent | Overkill | | Async orchestration | Manual | Structured | | Cross-environment reuse | No | Yes | | Deterministic runtime | No | Yes |

  • UI consumes state.
  • Logic lives outside components.

🔥 What This Library Actually Does

It separates business logic from UI completely.

Without this split:

  • Components start holding async workflows
  • Event chains become implicit
  • State transitions become coupled to rendering
  • Testing requires rendering components

With intentx-solid:

  • Logic lives outside the component tree
  • UI becomes a pure consumer
  • Async workflows are deterministic
  • Runtime can be reused in Node, SSR, microfrontends

🧩 Architectural Boundary

Solid owns:

  • Signals
  • Reactivity
  • DOM updates
  • Rendering lifecycle

intentx owns:

  • State machine
  • Intent routing
  • Async orchestration
  • Computed graph
  • Cross-runtime communication

This is not about replacing createSignal.

It is about preventing this:

// ❌ Business logic leaking into UI
createEffect(async () => {
  if (userId()) {
    const data = await fetchUser(userId())
    setUser(data)
  }
})

And moving it here:

// ✅ Logic outside UI
intents: (bus) => {
  bus.on("loadUser", async ({ setState }) => {
    const data = await fetchUser(id)
    setState(d => {
      d.user = data
    })
  });
}

Now UI only emits intent.


🎯 Philosophy

Rendering is reactive.

Business logic should be deterministic.

intentx-solid ensures they never mix.


❌ What This Is Not

  • Not a signal replacement
  • Not a store wrapper
  • Not a UI state helper
  • Not a reducer abstraction

📜 License

MIT