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.

latest
Source
npmnpm
Version
0.19.2
Version published
Weekly downloads
199
37.24%
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/app-patternsFramework-native app composition, derived signals, and app-level errors
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?
App Authoring ContractWhich framework-native patterns should applications and examples follow?
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?
Errors & DiagnosticsWhich stable codes, hints, callbacks, and events report failures?
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 01 Aug 2026

Related posts