
Security News
Socket for Origin Now Available
Socket for Origin scans dependency changes in pull requests and flags security risks based on your team’s policies. Now available in Cursor’s App Marketplace.
@async/framework
Advanced tools
No-build Loader app runtime with browser and server entrypoints, signals, command events, route partials, cache split, SSR activation, and streaming boundaries.
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 });
Async keeps the browser path small and explicit:
Async.use(...) registers app declarations before or after startup.AbortSignal cancellation.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
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
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.
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 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
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 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 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
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 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
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 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
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 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
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
| 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? |
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
FAQs
No-build Loader app runtime with browser and server entrypoints, signals, command events, route partials, cache split, SSR activation, and streaming boundaries.
The npm package @async/framework receives a total of 41 weekly downloads. As such, @async/framework popularity was classified as not popular.
We found that @async/framework demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.

Security News
Socket for Origin scans dependency changes in pull requests and flags security risks based on your team’s policies. Now available in Cursor’s App Marketplace.

Security News
Agent Baseline’s new reference architecture shows how to secure software factories with four boundaries enforced outside the AI agent.

Security News
arXiv now limits authors to two submissions a month as AI slop overwhelms moderators, delays good papers, and sparks debate over applying the limit to everyone.