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

@async/framework

v0.19.2

Published

No-build Loader app runtime with browser and server entrypoints, signals, command events, route partials, cache split, SSR activation, and streaming boundaries.

Readme

@async/framework

Async is a layered framework plan that starts as a no-build browser bootloader: signals, async signals, delegated command events, scoped fragment components, server calls, route partials, and out-of-order boundary swaps without a virtual DOM.

pnpm add @async/framework
<main async:container>
  <button type="button" on:click="decrement">-</button>
  <strong signal:text="count"></strong>
  <button type="button" on:click="increment">+</button>
</main>
<script type="module" src="./main.js"></script>
import {
  Async,
  createSignal
} from "@async/framework";

Async.use({
  signal: {
    count: createSignal(0)
  },
  handler: {
    increment() {
      this.signals.update("count", (count) => count + 1);
    },
    decrement() {
      this.signals.update("count", (count) => count - 1);
    }
  }
});

Async.start({ root: document });

Why Async

Async keeps the browser path small and explicit:

  • Native HTML remains the document contract.
  • Signals are the state boundary.
  • Async.use(...) registers app declarations before or after startup.
  • Handlers run through delegated DOM events.
  • Async signals use native AbortSignal cancellation.
  • Browser and server cache declarations are structurally split.
  • Boundaries can be swapped out of order and rescanned.

It avoids a virtual DOM, hidden hydration pass, implicit startup fetch, component rerender loop, and browser snapshots that leak server-only cache contents.

Guide: docs/start/why-async.md · Contract: specs/framework/00-system-overview.md

The Abstraction Layers

Async uses L0-L7 abstraction layers. Layers describe the authoring surface; capabilities are protocol properties that land at the lowest layer the protocol allows.

| Layer | Name | Era anchor | Adds | Requires | | --- | --- | --- | --- | --- | | L0 | Enhance | jQuery/Backbone; htmx | Server-led HTML, native forms/actions, and behavior references on server-owned views | Script tag | | L1 | Interpret | angular.js: runtime, no build | Runtime-interpreted app model: registries, components, lifecycle | Script tag or ESM | | L2 | Bundle | Built SPAs | Build as delivery, client routing, app server | Build optional | | L3 | SSR | React-without-JSX + SSR server | Server-rendered components with activation, no hydration | Server; build optional | | L4 | Transform | React+JSX | JSX/TSX transforms lowering to protocol records | Build | | L5 | Stream | Streaming SSR; Suspense | Progressive documents, boundary reveal ordering | Streaming server | | L6 | Reorder | RSC; islands; Qwik-style server$ | Out-of-order settling, co-located server functions, chunks, and plans automated by the Optimizer | Optimizer | | L7 | Optimize | React Compiler; TSRX | Whole-program compilation | Spec only today |

Layers compose within one document: an L2-bundled SPA can host an L0-enhanced form next to an L5-streamed boundary. This package ships the no-compiler layers (L0-L3, L5) plus the first compiler-layer surfaces (./jsx, ./vite, ./runtime/*).

Guide: docs/start/layers.md · Contract: specs/framework/15-abstraction-layers.md

How It Works

The framework is a protocol stack: HTML attributes connect to registered state and behavior, server work returns explicit envelopes, route partials and stream patches replace named boundaries, and SSR activation resumes already-rendered HTML without hydration.

HTML Protocol

Loader scans regular HTML attributes. The shorthand prefixes are the author-facing syntax: async:, signal:, on:, class:, and intersect:.

| Attribute | Behavior | | --- | --- | | async:container | Marks a scannable app root | | async:boundary="product" | Marks a replaceable boundary | | async:snapshot | Holds serialized startup state | | async:component="Card" | Mounts a registered component | | on:click="selectProduct" | Delegated command event | | on:submit="preventDefault; save" | Sequential command chain | | on:click="server.cart.add(productId)" | Server command with signal args | | on:intersect="trackSection" | Continuous intersection lifecycle event | | signal:text="product.title" | Text binding | | signal:value="productId" | Form value binding with writeback | | signal:attr:disabled="product.$loading" | Attribute binding | | class:selected="selected" | Class toggle from a signal path |

Guide: docs/runtime/html-protocol.md · Contract: specs/framework/04-dom-protocol.md

Signals & Async Signals

Signals are the state boundary for DOM bindings, handlers, server effects, router state, and async resources. Signal writes are synchronous; bindings, lifecycle callbacks, effects, and async refreshes are scheduled in deterministic phases.

const signals = createSignalRegistry({
  productId: createSignal("sku-1")
});

const product = signals.asyncSignal("product", async function () {
  return this.server.products.get(this.signals.get("productId"));
});

Guide: docs/runtime/signals.md · Contract: specs/framework/03-reactivity-system.md

App Hub & Registries

Async is the app hub singleton. It stores declarations, materializes fresh runtime registries on startup, exposes inspection APIs, and queues loader work that runs before a root attaches.

Async.use({
  signal: { count: createSignal(0) },
  handler: {
    increment() {
      this.signals.update("count", (count) => count + 1);
    }
  }
});

Async.start({ root: document });

Guide: docs/runtime/app-hub.md · Contract: specs/framework/02-runtime-kernel.md

Components

Components are scoped fragment functions. They return strings or html templates; Loader inserts and scans the result, and scoped signals, handlers, effects, and lifecycle cleanup follow the fragment.

const Toggle = component(function Toggle() {
  const selected = this.signal(false);

  return html`
    <button on:click="${this.handler(() => selected.update((value) => !value))}"
      class:selected="${selected}">
      Toggle
    </button>
  `;
});

Guide: docs/runtime/components.md · Contract: specs/framework/05-component-system.md

Server Calls & Cache

Server registries run locally on the server. Browser proxies use an explicit transport supplied by the app; responses can return values, signal patches, browser cache patches, boundary HTML, redirects, or errors.

const server = createServerProxy({
  endpoint: "/__async/server",
  transport,
  signals,
  loader,
  router
});

await server.cart.add("sku-1", 2);

Guide: docs/runtime/server-calls.md · Contract: specs/framework/06-server-and-data-system.md

Router & Partials

The router lives behind @async/framework/router. It handles URL matching, route params, hash-based static-host routes, same-origin link and GET form interception, route partial swaps, and route-only router.* state.

Async.use({
  route: {
    "/products/:id": defineRoute("product.page")
  },
  partial: {
    "product.page"({ id }) {
      return html`<h1>Product ${id}</h1>`;
    }
  }
});

Guide: docs/runtime/router-partials.md · Contract: specs/framework/07-routing-and-partials.md

SSR & Activation

SSR uses related app definitions: a server runtime renders HTML plus snapshots, and the browser runtime activates the existing document. Activation scans and attaches; it does not hydrate, diff, patch, rerender, or fetch route fragments.

const response = await createApp(serverApp, {
  target: "server",
  request
}).render("/products/123");

Guide: docs/runtime/ssr-activation.md · Contract: specs/framework/08-resume-and-streaming.md

Streaming & Boundaries

Boundary swaps replace named regions and rescan inserted content by default. createBoundaryReceiver(...) adds per-boundary sequence tracking, signal/cache effects, and stale patch suppression for independently arriving patches.

await receiver.apply({
  boundary: "product",
  seq: 1,
  signals: { product: { title: "Keyboard" } },
  html: `<h1 signal:text="product.title"></h1>`
});

Guide: docs/runtime/streaming.md · Contract: specs/framework/08-resume-and-streaming.md

Install & Load

Install from npm:

pnpm add @async/framework

Load directly from a CDN for no-build prototypes:

<script type="module">
  import { Async, createSignal } from "https://unpkg.com/@async/framework@latest/browser.js";
</script>

Use @async/framework/vite when a Vite app needs the Hono development server lane, a browser client build lane, or JSX optimizer reports.

Guide: docs/start/install.md · Build guide: docs/build/vite-hono.md

Examples

See examples/README.md for start commands and a short description of every example.

| Example | Shows | | --- | --- | | examples/counter | Signal text binding and delegated handlers | | examples/product | Async signal loading, ready, and error boundaries | | examples/components | Scoped fragment components and lifecycle hooks | | examples/app-patterns | Framework-native app composition, derived signals, and app-level errors | | examples/streaming | Boundary swaps with rescanned handlers | | examples/server-call | Command events calling server functions | | examples/hateoas-actions | Hono-rendered HATEOAS links and forms enhanced into partial swaps | | examples/router | CSR first render and local route boundary swaps | | examples/partials | Server-rendered partial fragments | | examples/cache | Browser/server cache declarations | | examples/ssr | Server render output and browser activation snapshot | | examples/vite-hono | Hono-backed Vite dev server plus client asset build | | examples/vite-jsx-streaming | JSX optimizer bootstrap with stream runtime slice selection | | examples/size | Scenario-size fixtures for bundle and runtime slices |

Async And htmx

Async and htmx are both HTML-first and avoid a virtual DOM, but they optimize for different boundaries. In layer model terms, htmx-style hypermedia is the L0 Enhance layer, and in Async it stays available at every layer above.

| Area | htmx | Async | | --- | --- | --- | | Primary model | HTML attributes issue HTTP requests and swap server responses. | Server-generated HTML can stay primary; Async attributes add behavior, state, actions, and boundaries. | | State | Server-owned hypermedia state; browser state is intentionally minimal. | Server-led HTML can stay server-owned; browser signals are available when a view needs local state. | | Server interaction | DOM attributes describe HTTP verbs, targets, and swaps. | Native method/action flows can submit to any backend; partial responses can return HTML or envelopes for boundary swaps. | | Routing | Usually server navigation or htmx-boosted navigation. | MPA and SSR keep navigation server-led; CSR, SPA, and signals modes opt into client-owned routing. | | Components | Server-rendered HTML fragments. | Scoped fragment functions today; the compiler layers add JSX/TSRX authoring. | | Build story | No build by default. | Layers L0-L3 and L5 are no-build/CDN; the compiler layers (L4, L6, L7) add build or compiler steps. |

Async supports server-led views: any backend can render HTML strings for full documents or fragments, native forms can post through ordinary method and action attributes, and browser navigation can stay native in MPA/SSR modes. Add Async attributes only where a fragment needs local signals, command handlers, server functions, boundary swaps, or streamed patches. Use htmx when its HTTP-attribute model is the desired contract. Use Async when server-led HTML should share a protocol with local signals, registered browser/server handlers, route partials, streaming boundaries, and the compiler layers. See examples/hateoas-actions for a Hono-rendered HATEOAS flow using links, forms, verbs, and partial swaps.

Guide: docs/start/why-async.md · Contract: specs/framework/15-abstraction-layers.md

Status

The core runtime is intentionally small. Build-required JSX (L4) has optimizer artifacts for event, signal, stream, and children-fragment lowering, while full compiler emission, lazy chunk manifests, TSRX lowering, server resource compilation, and higher-level resumability metadata remain compiler-layer work (L6 and L7).

Contracts: specs/framework/12-composition-patterns.md · specs/framework/15-abstraction-layers.md · specs/framework/16-whole-program-compiler.md

Documentation Map

| Page | Question it answers | | --- | --- | | Getting Started | What is the smallest running app? | | App Authoring Contract | Which framework-native patterns should applications and examples follow? | | Install & Load | How do npm, CDN, UMD, and import-map loading work? | | Why Async | What does Async keep and avoid? | | Core Concepts | Which runtime pieces make up an app? | | Layers | How do L0-L7 fit together? | | Runtime Overview | What happens when a root starts? | | App Hub & Registries | How are declarations registered, inspected, and materialized? | | HTML Protocol | Which attributes connect HTML to runtime behavior? | | Signals & Async Signals | How does state update and async work refresh? | | Components | How do scoped fragments, children, lifecycle, and intersection work? | | Router & Partials | How do routes, partials, modes, and boundaries work? | | Server Calls & Cache | How do server functions, envelopes, and cache split work? | | SSR & Activation | How does server-rendered HTML start in the browser? | | Streaming & Boundaries | How do swaps, refresh plans, morphing, and patch ordering work? | | Build Profile | What does the compiler-layer profile promise? | | Vite & Hono | How does the Vite plugin wire a Hono dev server and client build? | | Entrypoints | Which package subpaths expose which surfaces? | | Errors & Diagnostics | Which stable codes, hints, callbacks, and events report failures? | | Examples | Which runnable example demonstrates each surface? |

Contributing & Release

Common checks:

pnpm run pipeline:pages
pnpm run registry:lint
git diff --check

Pipeline and release automation are generated from pipeline.ts; update that source and run the sync checks before changing generated workflow output.

Guide: CONTRIBUTING.md