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

@bitakit/core

v0.1.2

Published

AI-friendly, type-safe building blocks for modular apps: plugins, services, actions, and events.

Readme

BitaKit Core

Build bigger apps from smaller, pluggable features — together with your team and AI.

BitaKit gives developers and AI coding assistants a shared structure for building applications. Organize a feature into a plugin, put reusable behavior in services, and expose operations through actions. Each piece has a clear home, a clear role, and typed connections to the rest of your app.

Keep Next.js, TanStack Start, or your own stack. BitaKit adds feature organization and shared lifecycle management alongside your framework. You keep control of your routes, UI, business rules, and data.

Contents

Install

npm install @bitakit/core

Core works in Node.js and the browser, without React or a router.

Starting a new application? Let the generator connect the packages for you:

npx @bitakit/create-app my-app

The generator requires Node.js 24 or newer. Choose Next.js or experimental TanStack Start, then select the optional features you want. React bindings and framework adapters are available as separate packages.

Why add BitaKit?

Your framework handles pages and rendering. As an app grows, you also need a clear way to organize features, share behavior, connect dependencies, and clean up resources. BitaKit gives those pieces a common structure.

  • Smaller pieces. Clearer ownership. Keep a feature's services and actions together in a plugin. Teams can work on focused parts of the app with explicit connections between them.
  • A shared language for humans and AI. Predictable files and typed contracts make it easier to describe a change, give an AI assistant focused context, and review its work. The same conventions guide both developers and coding assistants.
  • Pluggable features. Compose the capabilities your app needs. Add a plugin, configure its defaults, or replace supported contributions through the same APIs.
  • Less repeated wiring. With discovery configured, file paths supply names and generated types. Core handles startup, dependencies, registration, and cleanup.
  • Type-safe connections. Service methods, action inputs and results, and known event payloads carry their types to callers. Your editor helps you connect the pieces.
  • Your stack stays yours. Start with headless Core. Add React bindings, settings, an app shell, or provider integrations when they help your product.

Room to grow. As your app and team grow, keep changes focused on small features with explicit dependencies. This is about scaling your codebase and collaboration; performance and infrastructure remain choices for your application.

How the pieces fit

Imagine a To-do plugin that lets someone add a task:

Application — chooses which plugins to use
    │
    ▼
BitaKit Core — starts plugins and checks their dependencies
    │
    └── To-do plugin — groups one feature's contributions
          ├── Service: holds tasks and provides add/list operations
          └── Action: calls the service to add a task

Button or server code
    │ executes "todos.create"
    ▼
Action ──calls──▶ To-do service ──returns──▶ Task

Application UI displays the result; Core does not render it.

| Concept | What it does | In this example | | ---------------- | ------------------------------------------------------------------- | ------------------------------------------------- | | Plugin | Bundles the parts of a feature. | The To-do feature. | | Service | Owns reusable behavior and, when needed, state or resources. | Stores tasks and exposes create() and list(). | | Action | Provides a named operation that application code or UI can execute. | todos.create adds a task through the service. | | Core runtime | Coordinates dependencies, registrations, startup, and cleanup. | Creates the service and registers the action. |

Core manages the lifecycle of plugin-created services. A service that acquires resources can supply disposal logic. Core does not automatically save data to a database or subscribe your UI to service changes.

Try a To-do plugin

Follow the To-do tutorial to run three actions: create a task, list tasks, and delete a task. Each action lives in its own file:

examples/
├── todos.mjs                  # Starts the runtime and executes the actions
└── todos/
    ├── plugin.mjs             # Groups the service and actions
    ├── services/
    │   └── tasks.mjs          # In-memory task operations
    └── actions/
        ├── create.mjs         # todos.create
        ├── list.mjs           # todos.list
        └── delete.mjs         # todos.delete

The plugin uses explicit imports, so no framework or discovery setup is required. The script creates three tasks, lists them, deletes the second, and lists the two remaining tasks. Stopping the runtime releases its registrations. Data stays in memory and is lost on restart.

With a configured framework adapter, contribution files can instead live under src/plugins/todos/services and src/plugins/todos/actions. Its build integration generates registration and types. Installing Core alone does not scan folders. See file contributions for the exact conventions.

Type safety that follows your feature

Define a service once, then use its method types wherever you call it. Discovery connects supported files to typed service access, action IDs, and configuration. Shared service keys let separate packages agree on the same contract.

Use exposeAs when you want a custom public service name; otherwise discovery uses the file path. Known event names and payloads are connected through EventMap.

Unknown action IDs remain allowed unless strict mode is enabled. TypeScript checks code; validate external data and authorize requests at your application boundaries. See the type-safety guide for examples.

React to events

Available since Core 0.1.1, each runtime owns one event service. Services emit notifications after updating their data; actions declare events and onEvent.

With file discovery configured, IDs can be omitted:

// src/services/todos.ts
import { defineService } from '@bitakit/core';

export default defineService({
  create({ events }) {
    let items: { id: number; title: string }[] = [];
    let nextId = 1;
    return {
      list: () => [...items],
      add(title: string) {
        const todo = { id: nextId++, title };
        items.push(todo);
        events.emit('todos.changed', { kind: 'added', id: todo.id });
      },
      remove(id: number) {
        items = items.filter((todo) => todo.id !== id);
        events.emit('todos.changed', { kind: 'removed', id });
      },
    };
  },
});
// src/actions/todos/delete.ts
import { defineAction } from '@bitakit/core';

export default defineAction<number>({
  requires: ['todos'],
  events: ['todos.changed'],
  setup({ services, action }) {
    action.enabled = services.todos.list().length > 0;
  },
  onEvent(event, { services, action }) {
    action.enabled = services.todos.list().length > 0;
  },
  execute: ({ services, input }) => services.todos.remove(input),
});

Here discovery supplies todos and todos.delete from the paths (with no explicit app namespace). Plugin contributions also receive their plugin namespace. Provide an explicit id when you need a custom identity. Direct imports without discovery, including the Node tutorial above, still need explicit IDs.

events: ['todos.loaded', 'todos.changed'] calls onEvent for each matching event. Handlers receive { type, data } and can be synchronous or asynchronous. Core owns subscriptions created in action setup and service create, including cleanup after failed setup. No manual unsubscribe is needed. For dynamic subscriptions, setup still offers events.watch. React components use useWatchEvent from @bitakit/ui.

See events and action setup for payload typing, errors, async cancellation, and the distinction from observable-service watch.

What belongs outside Core?

  • React rendering: the UI bindings and your visual components.
  • Routes and navigation: your application's router and its BitaKit adapter.
  • Settings: the separate App Preferences package.
  • Email, authentication, and persistence: optional integrations or your own services.

Plugins are trusted application code. Core is not a sandbox or a remote plugin marketplace.

Go deeper

License

MIT. Third-party dependencies retain their own licenses.

See client authentication for the shared provider contract, externally configured login/logout paths, UI bindings and an adapter template.