New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@async/framework

Package Overview
Dependencies
Maintainers
3
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@async/framework

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

Source
npmnpm
Version
0.18.1
Version published
Weekly downloads
79
-65.5%
Maintainers
3
Weekly downloads
 
Created
Source

@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.

LayerNameEra anchorAddsRequires
L0EnhancejQuery/Backbone; htmxServer-led HTML, native forms/actions, and behavior references on server-owned viewsScript tag
L1Interpretangular.js: runtime, no buildRuntime-interpreted app model: registries, components, lifecycleScript tag or ESM
L2BundleBuilt SPAsBuild as delivery, client routing, app serverBuild optional
L3SSRReact-without-JSX + SSR serverServer-rendered components with activation, no hydrationServer; build optional
L4TransformReact+JSXJSX/TSX transforms lowering to protocol recordsBuild
L5StreamStreaming SSR; SuspenseProgressive documents, boundary reveal orderingStreaming server
L6ReorderRSC; islands; Qwik-style server$Out-of-order settling, co-located server functions, chunks, and plans automated by the OptimizerOptimizer
L7OptimizeReact Compiler; TSRXWhole-program compilationSpec 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:.

AttributeBehavior
async:containerMarks a scannable app root
async:boundary="product"Marks a replaceable boundary
async:snapshotHolds 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.

ExampleShows
examples/counterSignal text binding and delegated handlers
examples/productAsync signal loading, ready, and error boundaries
examples/componentsScoped fragment components and lifecycle hooks
examples/streamingBoundary swaps with rescanned handlers
examples/server-callCommand events calling server functions
examples/hateoas-actionsHono-rendered HATEOAS links and forms enhanced into partial swaps
examples/routerCSR first render and local route boundary swaps
examples/partialsServer-rendered partial fragments
examples/cacheBrowser/server cache declarations
examples/ssrServer render output and browser activation snapshot
examples/vite-honoHono-backed Vite dev server plus client asset build
examples/vite-jsx-streamingJSX optimizer bootstrap with stream runtime slice selection
examples/sizeScenario-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.

AreahtmxAsync
Primary modelHTML attributes issue HTTP requests and swap server responses.Server-generated HTML can stay primary; Async attributes add behavior, state, actions, and boundaries.
StateServer-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 interactionDOM 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.
RoutingUsually server navigation or htmx-boosted navigation.MPA and SSR keep navigation server-led; CSR, SPA, and signals modes opt into client-owned routing.
ComponentsServer-rendered HTML fragments.Scoped fragment functions today; the compiler layers add JSX/TSRX authoring.
Build storyNo 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

PageQuestion it answers
Getting StartedWhat is the smallest running app?
Install & LoadHow do npm, CDN, UMD, and import-map loading work?
Why AsyncWhat does Async keep and avoid?
Core ConceptsWhich runtime pieces make up an app?
LayersHow do L0-L7 fit together?
Runtime OverviewWhat happens when a root starts?
App Hub & RegistriesHow are declarations registered, inspected, and materialized?
HTML ProtocolWhich attributes connect HTML to runtime behavior?
Signals & Async SignalsHow does state update and async work refresh?
ComponentsHow do scoped fragments, children, lifecycle, and intersection work?
Router & PartialsHow do routes, partials, modes, and boundaries work?
Server Calls & CacheHow do server functions, envelopes, and cache split work?
SSR & ActivationHow does server-rendered HTML start in the browser?
Streaming & BoundariesHow do swaps, refresh plans, morphing, and patch ordering work?
Build ProfileWhat does the compiler-layer profile promise?
Vite & HonoHow does the Vite plugin wire a Hono dev server and client build?
EntrypointsWhich package subpaths expose which surfaces?
ExamplesWhich 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

Keywords

async

FAQs

Package last updated on 09 Jul 2026

Related posts