The full-stack web framework that speaks jQuery.
Batteries-included TypeScript framework for the modern web — signals, SSR, Web Components,
routing, and more — with a jQuery-inspired API and zero mandatory build step.
- Full-stack by default: signals, SSR, routing, server middleware, Web Components, and 15+ modules ship together — use only what you need, or bring everything.
- Zero mandatory build step: start in plain HTML with the CDN entry points, or use your preferred bundler without changing the API surface.
- Reactive data across the stack: fetch composables, HTTP clients, polling, pagination, WebSocket / SSE, REST helpers, and request coordination plug directly into signals.
- From UI to backend: declarative views, forms, accessibility helpers, plugins, devtools, testing utilities, SSR, and server routing cover the full app lifecycle.
- TypeScript-first and tree-shakeable: explicit entry points keep large apps typed while letting smaller apps import focused modules.
- Security-focused: DOM writes are sanitized by default, with Trusted Types and CSP helpers built in.
# npm npm install @bquery/bquery # bun bun add @bquery/bquery # pnpm pnpm add @bquery/bquery
<script type="module"> import { $, signal } from 'https://unpkg.com/@bquery/bquery@1/dist/full.es.mjs'; const count = signal(0); $('#counter').text(`Count: ${count.value}`); </script>
<script src="https://unpkg.com/@bquery/bquery@1/dist/full.iife.js"></script> <script> const { $, $$, signal } = bQuery; const count = signal(0); $$('.items').addClass('loaded'); </script>
const { $, signal } = require('@bquery/bquery');
Only the root and /full entries have a require condition; the sub-path
entries are ESM-only. See
Module format.
// Full bundle (all modules) import { $, signal, component, registerDefaultComponents, defineBqueryConfig, } from '@bquery/bquery'; // Core only import { $, $$ } from '@bquery/bquery/core'; // Core utilities (named exports, tree-shakeable) import { debounce, merge, uid, once, utils } from '@bquery/bquery/core'; // Reactive only import { signal, computed, effect, linkedSignal, persistedSignal, useAsyncData, useFetch, createUseFetch, createHttp, http, usePolling, usePaginatedFetch, useInfiniteFetch, useWebSocket, useWebSocketChannel, useEventSource, useResource, useResourceList, useSubmit, createRestClient, createRequestQueue, deduplicateRequest, } from '@bquery/bquery/reactive'; import type { WebSocketSendData } from '@bquery/bquery/reactive'; // Concurrency only import { batchTasks, callWorkerMethod, createReactiveRpcPool, createReactiveRpcWorker, createReactiveTaskPool, createReactiveTaskWorker, createRpcPool, createRpcWorker, createTaskPool, createTaskWorker, every, filter, find, getConcurrencySupport, map, parallel, pipeline, reduce, runTask, some, } from '@bquery/bquery/concurrency'; // Components only import { bool, component, defineComponent, html, registerDefaultComponents, } from '@bquery/bquery/component'; // Motion only import { transition, spring, animate, timeline } from '@bquery/bquery/motion'; // Security only import { sanitize, sanitizeHtml, trusted } from '@bquery/bquery/security'; // Platform only import { storage, cache, useCookie, definePageMeta, useAnnouncer } from '@bquery/bquery/platform'; // Router, Store, View import { createRouter, navigate } from '@bquery/bquery/router'; import { clearPlugins, createStore, defineStore, unregisterPlugin } from '@bquery/bquery/store'; import { mount, createTemplate } from '@bquery/bquery/view'; // Forms, i18n, accessibility, drag & drop, media import { createForm, required, email } from '@bquery/bquery/forms'; import { createI18n } from '@bquery/bquery/i18n'; import { trapFocus, rovingTabIndex } from '@bquery/bquery/a11y'; import { draggable, droppable, sortable } from '@bquery/bquery/dnd'; import { mediaQuery, useViewport, useIntersectionObserver, useResizeObserver, useMutationObserver, clipboard, } from '@bquery/bquery/media'; // Plugins, devtools, testing, SSR, server import { use } from '@bquery/bquery/plugin'; import { enableDevtools, inspectSignals } from '@bquery/bquery/devtools'; import { renderComponent, fireEvent, waitFor } from '@bquery/bquery/testing'; import { createSSRContext, hydrateMount, renderToResponse, renderToStream, renderToString, renderToStringAsync, serializeStoreState, } from '@bquery/bquery/ssr'; import { createServer } from '@bquery/bquery/server'; // Storybook helpers import { storyHtml, when } from '@bquery/bquery/storybook';
Module status below is mirrored from the canonical Stability Matrix (the single source of truth, enforced by
bun run check:stability). As of 1.15.0 every module is Stable — the release graduated the final thirteen (view,forms,i18n,a11y,dnd,media,plugin,devtools,testing,storybook,concurrency,ssr,server).
| Module | Status | Description |
|---|---|---|
| Core | Stable | Selectors, DOM manipulation, events, traversal, and typed utilities |
| Reactive | Stable | signal, computed, effect, watchDebounce, watchThrottle, async data, HTTP clients, polling, pagination, WebSocket / SSE, and REST helpers |
| Concurrency | Stable | Zero-build worker tasks, explicit RPC helpers, optional reactive state wrappers, bounded worker pools, high-level collection helpers, an optional fluent pipeline layer, CSP-safe module workers, and client UI-scheduling primitives |
| Component | Stable | Typed Web Components with scoped reactivity and configurable Shadow DOM |
| Storybook | Stable | Secure-by-default story template helpers with a pinned unsafeHtml contract |
| Motion | Stable | View transitions, FLIP, morphing, parallax, typewriter, springs, and timelines |
| Security | Stable | HTML sanitization, Trusted Types, CSP helpers, and trusted fragment composition |
| Platform | Stable | Storage, cache, cookies, page metadata, announcers, and shared runtime config |
| Router | Stable | SPA routing, constrained params, redirects, guards, useRoute(), <bq-link>, and an opt-in file-route convention with typed load / action |
| Store | Stable | Signal-based state management, persistence, migrations, action hooks, and plugin lifecycle helpers |
| View | Stable | Declarative DOM bindings with bq-* directives, declarative enter/leave/move transitions, and an optional expression precompiler |
| Forms | Stable | Reactive form state, validation, field arrays, progressive-enhancement form actions, and optimistic updates |
| i18n | Stable | Reactive locales, interpolation, ICU MessageFormat plurals, lazy loading, Intl formatting, and optional message-extraction tooling |
| A11y | Stable | Focus traps, live-region announcements, roving tabindex, skip links, and audits with documented WCAG scope |
| DnD | Stable | Draggable elements, droppable zones, and keyboard-accessible sortable lists |
| Media | Stable | Reactive, SSR-safe browser/device signals for viewport, network, battery, geolocation, clipboard, and DOM observers |
| Plugin | Stable | Global plugin registration (hook bus, DI, namespaced directives) with symmetric install/uninstall, plus definePlugin |
| Devtools | Stable | Runtime inspection helpers plus a stable bridge protocol and a separately released browser extension (component tree, signals/stores, timeline) |
| Testing | Stable | Testing-Library-parity, shadow-DOM-aware queries, userEvent/fireEvent, mocks, runner-agnostic (Vitest/Jest/bun:test) |
| SSR | Stable | Runtime-agnostic server-side rendering (Node ≥ 24, Deno, Bun), streaming, async loaders, hydration islands, head/asset/CSP-nonce management, runtime adapters |
| Server | Stable | Express-inspired backend routing, middleware, safe responses, SSR-aware requests, sessions, CSRF, guards, auth, and WebSocket sessions |
Storybook authoring helpers are also available as a dedicated entry point via @bquery/bquery/storybook. Worker-task, RPC, worker-pool, high-level task-list / collection helpers, and the optional fluent pipeline layer ship as a dedicated entry point via @bquery/bquery/concurrency. Server-side middleware, HTTP routing, and runtime-agnostic WebSocket session helpers ship as a dedicated entry point via @bquery/bquery/server.
Reusable workers and pools can also opt into readonly signal mirrors such as state$, busy$, pending$, and size$ through the createReactive*() concurrency wrappers.
bQuery.js covers the full development lifecycle — from interactive DOM scripting to server-side rendering. The examples below show each layer independently; in practice they compose seamlessly.
import { $, $$ } from '@bquery/bquery/core'; $('#save').on('click', (event) => { console.log('Saved', event.type); }); $('#list').delegate('click', '.item', (event, target) => { console.log('Item clicked', target.textContent); }); $('#box').addClass('active').css({ opacity: '0.8' }).attr('data-state', 'ready'); const color = $('#box').css('color'); if ($('#el').is('.active')) { console.log('Element is active'); } $$('.container').find('.item').addClass('found');
import { signal, computed, effect, batch, watch, watchDebounce, watchThrottle, readonly, linkedSignal, } from '@bquery/bquery/reactive'; const count = signal(0); const doubled = computed(() => count.value * 2); effect(() => { console.log('Count changed', count.value); }); watch(count, (newVal, oldVal) => { console.log(`Changed from ${oldVal} to ${newVal}`); }); watchDebounce( count, (newVal) => { console.log('Debounced count', newVal); }, 150 ); const readOnlyCount = readonly(count); batch(() => { count.value++; count.value++; }); count.dispose(); const first = signal('Ada'); const last = signal('Lovelace'); const fullName = linkedSignal( () => `${first.value} ${last.value}`, (next) => { const [nextFirst, nextLast] = next.split(' '); first.value = nextFirst ?? ''; last.value = nextLast ?? ''; } ); fullName.value = 'Grace Hopper';
import { runTask } from '@bquery/bquery/concurrency'; const total = await runTask( ({ values }: { values: number[] }) => values.reduce((sum, value) => sum + value, 0), { values: [1, 2, 3, 4] }, { timeout: 1_000 } ); console.log(total); // 10
import { createRpcWorker } from '@bquery/bquery/concurrency'; const rpc = createRpcWorker({ formatUser: ({ first, last }: { first: string; last: string }) => `${last}, ${first}`, sum: ({ values }: { values: number[] }) => values.reduce((total, value) => total + value, 0), }); console.log(await rpc.call('formatUser', { first: 'Ada', last: 'Lovelace' })); console.log(await rpc.call('sum', { values: [1, 2, 3] })); rpc.terminate();
import { createTaskPool } from '@bquery/bquery/concurrency'; const pool = createTaskPool(({ value }: { value: number }) => value * 2, { concurrency: 4, maxQueue: 16, name: 'double-pool', }); const results = await Promise.all([ pool.run({ value: 1 }), pool.run({ value: 2 }), pool.run({ value: 3 }), ]); console.log(results); // [2, 4, 6] pool.terminate();
import { createReactiveTaskPool } from '@bquery/bquery/concurrency'; import { effect } from '@bquery/bquery/reactive'; const pool = createReactiveTaskPool( async ({ delay, value }: { delay: number; value: number }) => { await new Promise((resolve) => setTimeout(resolve, delay)); return value * 2; }, { concurrency: 2, maxQueue: 8 } ); effect(() => { console.log(pool.state$.value, pool.pending$.value, pool.size$.value); }); await Promise.all([ pool.run({ delay: 20, value: 1 }), pool.run({ delay: 20, value: 2 }), pool.run({ delay: 0, value: 3 }), ]); pool.terminate();
import { batchTasks, every, filter, find, map, parallel, pipeline, reduce, some, } from '@bquery/bquery/concurrency'; const tasks = await parallel([ { handler: (value: number) => value * 2, input: 5 }, { handler: ({ first, last }: { first: string; last: string }) => `${last}, ${first}`, input: { first: 'Ada', last: 'Lovelace' }, }, ]); const batched = await batchTasks( [ { handler: (value: number) => value * 2, input: 1 }, { handler: (value: number) => value * 2, input: 2 }, { handler: (value: number) => value * 2, input: 3 }, ], 2 ); const mapped = await map([1, 2, 3, 4], (value, index) => value + index, { batchSize: 2, concurrency: 2, }); const filtered = await filter([5, 2, 9, 4], (value) => value % 2 === 1); const hasEven = await some([1, 3, 4], (value) => value % 2 === 0); const allEven = await every([2, 4, 6], (value) => value % 2 === 0); const firstLarge = await find([3, 8, 11, 14], (value) => value > 10); const reduced = await reduce([1, 2, 3, 4], (accumulator, value) => accumulator + value, 0); const piped = await pipeline([1, 2, 3, 4], { batchSize: 2, concurrency: 2 }) .map((value) => value * 2) .filter((value) => value > 4) .toArray(); console.log(tasks, batched, mapped, filtered, hasEven, allEven, firstLarge, reduced, piped);
import { signal, useFetch, createUseFetch } from '@bquery/bquery/reactive'; const userId = signal(1); const user = useFetch<{ id: number; name: string }>(() => `/users/${userId.value}`, { baseUrl: 'https://api.example.com', watch: [userId], query: { include: 'profile' }, }); const useApiFetch = createUseFetch({ baseUrl: 'https://api.example.com', headers: { 'x-client': 'bquery-readme' }, }); const settings = useApiFetch<{ theme: string }>('/settings'); console.log(user.pending.value, user.data.value, settings.error.value);
import { mount } from '@bquery/bquery/view'; import { signal } from '@bquery/bquery/reactive'; const formError = signal(''); const fieldState = signal({ invalid: false, describedBy: '' }); mount('#profile-form', { formError, fieldState, }); formError.value = 'Email is required'; fieldState.value = { invalid: true, describedBy: 'email-error' };
<input id="email" bq-aria="{ invalid: fieldState.value.invalid, 'aria-describedby': fieldState.value.describedBy }" /> <p id="email-error" bq-error="formError"></p>
import { createHttp, createRequestQueue, deduplicateRequest, useEventSource, useWebSocket, } from '@bquery/bquery/reactive'; const api = createHttp({ baseUrl: 'https://api.example.com', retry: { count: 2, onRetry: (error, attempt) => console.warn(`Retry #${attempt}`, error.message), }, }); const queue = createRequestQueue({ concurrency: 4 }); const ws = useWebSocket<{ type: string; payload: unknown }>('wss://api.example.com/live'); const sse = useEventSource<{ token: string }>('/api/stream'); const users = await deduplicateRequest('/users', () => queue.add(() => api.get('/users'))); console.log(users.data, ws.status.value, sse.eventName.value);
import { bool, component, defineComponent, html, registerDefaultComponents, safeHtml, } from '@bquery/bquery/component'; import { sanitizeHtml, trusted } from '@bquery/bquery/security'; const badge = trusted(sanitizeHtml('<span class="badge">Active</span>')); component('user-card', { props: { username: { type: String, required: true }, age: { type: Number, validator: (v) => v >= 0 && v <= 150 }, }, state: { count: 0 }, beforeMount() { console.log('About to mount'); }, connected() { console.log('Mounted'); }, beforeUpdate(newProps, oldProps) { return newProps.username !== oldProps.username; }, updated(change) { console.log('Updated because of', change?.name ?? 'state/signal change'); }, onError(error) { console.error('Component error:', error); }, render({ props, state }) { return safeHtml` <button class="user-card" ${bool('disabled', state.count > 3)}> ${badge} <span>Hello ${props.username}</span> </button> `; }, }); const UserCard = defineComponent('user-card-manual', { props: { username: { type: String, required: true } }, render: ({ props }) => html`<div>Hello ${props.username}</div>`, }); customElements.define('user-card-manual', UserCard); const tags = registerDefaultComponents({ prefix: 'ui' }); console.log(tags.button); // ui-button
import { storyHtml, when } from '@bquery/bquery/storybook'; export const Primary = { args: { disabled: false, label: 'Save' }, render: ({ disabled, label }) => storyHtml` <ui-card> <ui-button ?disabled=${disabled}>${label}</ui-button> ${when(!disabled, '<small>Ready to submit</small>')} </ui-card> `, };
import { animate, keyframePresets, spring, transition } from '@bquery/bquery/motion'; await transition({ update: () => { $('#content').text('Updated'); }, classes: ['page-transition'], types: ['navigation'], skipOnReducedMotion: true, }); await animate(card, { keyframes: keyframePresets.pop(), options: { duration: 240, easing: 'ease-out' }, }); const x = spring(0, { stiffness: 120, damping: 14 }); x.onChange((value) => { element.style.transform = `translateX(${value}px)`; }); await x.to(100);
import { sanitize, escapeHtml, sanitizeHtml, trusted } from '@bquery/bquery/security'; import { safeHtml } from '@bquery/bquery/component'; const safeMarkup = sanitize(userInput); const safe = sanitize('<form id="cookie">...</form>'); const urlSafe = sanitize('<a href="java\u200Bscript:alert(1)">click</a>'); const secureLink = sanitize('<a href="https://external.com" target="_blank">Link</a>'); const safeSrcset = sanitize('<img srcset="safe.jpg 1x, javascript:alert(1) 2x">'); const safeForm = sanitize('<form action="javascript:alert(1)">...</form>'); const escaped = escapeHtml('<script>alert(1)</script>'); const icon = trusted(sanitizeHtml('<span class="icon">♥</span>')); const button = safeHtml`<button>${icon}<span>Save</span></button>`;
import { defineBqueryConfig, useCookie, definePageMeta, useAnnouncer, storage, notifications, } from '@bquery/bquery/platform'; defineBqueryConfig({ fetch: { baseUrl: 'https://api.example.com' }, transitions: { skipOnReducedMotion: true, classes: ['page-transition'] }, components: { prefix: 'ui' }, }); const theme = useCookie<'light' | 'dark'>('theme', { defaultValue: 'light' }); const cleanupMeta = definePageMeta({ title: 'Dashboard' }); const announcer = useAnnouncer(); theme.value = 'dark'; announcer.announce('Preferences saved'); cleanupMeta(); const local = storage.local(); await local.set('theme', theme.value); const permission = await notifications.requestPermission(); if (permission === 'granted') { notifications.send('Build complete', { body: 'Your docs are ready.', }); }
import { mediaQuery, useViewport, useIntersectionObserver, useResizeObserver, useMutationObserver, } from '@bquery/bquery/media'; import { effect } from '@bquery/bquery/reactive'; const prefersDark = mediaQuery('(prefers-color-scheme: dark)'); const viewport = useViewport(); const intersection = useIntersectionObserver(document.querySelector('#hero')); const resize = useResizeObserver(document.querySelector('#panel')); const mutations = useMutationObserver(document.querySelector('#feed'), { childList: true, subtree: true, }); effect(() => { console.log(prefersDark.value, viewport.value.width, intersection.value.isIntersecting); }); console.log(resize.value.width, mutations.value.mutations.length);
import { effect } from '@bquery/bquery/reactive'; import { createRouter, navigate, currentRoute } from '@bquery/bquery/router'; const router = createRouter({ routes: [ { path: '/', name: 'home', component: HomePage }, { path: '/user/:id', name: 'user', component: UserPage }, { path: '*', component: NotFound }, ], }); router.beforeEach(async (to) => { if (to.path === '/admin' && !isAuthenticated()) { await navigate('/login'); return false; } }); effect(() => { console.log('Current path:', currentRoute.value.path); });
import { createForm, email, required } from '@bquery/bquery/forms'; const form = createForm({ fields: { name: { initialValue: '', validators: [required()] }, email: { initialValue: '', validators: [required(), email()] }, }, onSubmit: async (values) => { await fetch('/api/signup', { method: 'POST', body: JSON.stringify(values), }); }, }); await form.handleSubmit(); console.log(form.isValid.value, form.fields.email.error.value);
import { createI18n } from '@bquery/bquery/i18n'; const i18n = createI18n({ locale: 'en', fallbackLocale: 'en', messages: { en: { greeting: 'Hello, {name}!' }, de: { greeting: 'Hallo, {name}!' }, }, }); console.log(i18n.t('greeting', { name: 'Ada' })); i18n.$locale.value = 'de';
import { trapFocus, announceToScreenReader } from '@bquery/bquery/a11y'; import { mediaQuery, useViewport } from '@bquery/bquery/media'; import { draggable } from '@bquery/bquery/dnd'; const modalTrap = trapFocus(document.querySelector('#dialog')!); announceToScreenReader('Dialog opened'); const isDark = mediaQuery('(prefers-color-scheme: dark)'); const viewport = useViewport(); const drag = draggable(document.querySelector('#card')!, { bounds: 'parent' }); console.log(isDark.value, viewport.value.width); drag.destroy(); modalTrap.release();
import { use } from '@bquery/bquery/plugin'; import { enableDevtools, getTimeline } from '@bquery/bquery/devtools'; import { renderComponent, fireEvent } from '@bquery/bquery/testing'; import { createSSRContext, renderToResponse, renderToString } from '@bquery/bquery/ssr'; import { createServer } from '@bquery/bquery/server'; use({ name: 'focus-plugin', install(ctx) { ctx.directive('focus', (el) => (el as HTMLElement).focus()); }, }); enableDevtools(true, { logToConsole: true }); console.log(getTimeline()); const mounted = renderComponent('ui-button', { props: { variant: 'primary' } }); fireEvent(mounted.el, 'click'); const { html } = renderToString('<p bq-text="label"></p>', { label: 'Hello SSR' }); console.log(html); const app = createServer(); app.get('/hello/:name', (ctx) => ctx.json({ name: ctx.params.name, q: ctx.query.q })); // Runtime-agnostic async render with head injection (works on Node, Deno, Bun): const ctx = createSSRContext({ request: new Request('http://localhost/') }); ctx.head.add({ title: 'Home' }); ctx.assets.module('/app.js'); const response = await renderToResponse( '<html><head></head><body><p bq-text="label"></p></body></html>', { label: 'Hello' }, { context: ctx, etag: true } ); mounted.unmount();
import { clearPlugins, createStore, createPersistedStore, defineStore, mapGetters, registerPlugin, unregisterPlugin, watchStore, } from '@bquery/bquery/store'; const counterStore = createStore({ id: 'counter', state: () => ({ count: 0, name: 'Counter' }), getters: { doubled: (state) => state.count * 2, }, actions: { increment() { this.count++; }, }, }); const settingsStore = createPersistedStore({ id: 'settings', state: () => ({ theme: 'dark', language: 'en' }), }); const useCounter = defineStore('counter', { state: () => ({ count: 0 }), getters: { doubled: (state) => state.count * 2, }, actions: { increment() { this.count++; }, }, }); const counter = useCounter(); const getters = mapGetters(counter, ['doubled']); watchStore( counter, (state) => state.count, (value) => { console.log('Count changed:', value, getters.doubled); } ); const logger = ({ store, options }) => { store.$subscribe((state) => console.log(`[${options.id}]`, state)); }; registerPlugin(logger); unregisterPlugin(logger); // true when the plugin registration was present clearPlugins(); // useful in test teardown
import { mount, createTemplate } from '@bquery/bquery/view'; import { signal } from '@bquery/bquery/reactive'; const count = signal(0); const items = signal(['Apple', 'Banana', 'Cherry']); mount('#app', { count, items, increment: () => count.value++, });
| Browser | Version | Support |
|---|---|---|
| Chrome | 90+ | ✅ Full |
| Firefox | 90+ | ✅ Full |
| Safari | 15+ | ✅ Full |
| Edge | 90+ | ✅ Full |
No IE support by design.
Server-side runtimes: Node.js ≥ 24, Bun ≥ 1.4.0, and Deno 2 are supported for SSR and server modules.
- Getting Started: docs/guide/getting-started.md
- Tutorial: docs/guide/tutorial.md
- Core API: docs/guide/api-core.md
- Agents: docs/guide/agents.md
- Components: docs/guide/components.md
- Storybook: docs/guide/storybook.md
- Reactivity: docs/guide/reactive.md
- Motion: docs/guide/motion.md
- Security: docs/guide/security.md
- Platform: docs/guide/platform.md
- Router: docs/guide/router.md
- File-based Routing: docs/guide/file-routing.md
- Store: docs/guide/store.md
- View: docs/guide/view.md
- Forms: docs/guide/forms.md
- i18n: docs/guide/i18n.md
- Accessibility: docs/guide/a11y.md
- Drag & Drop: docs/guide/dnd.md
- Media: docs/guide/media.md
- Concurrency: docs/guide/concurrency.md
- Plugin System: docs/guide/plugin.md
- Devtools: docs/guide/devtools.md
- Testing Utilities: docs/guide/testing.md
- SSR / Hydration: docs/guide/ssr.md
- Server: docs/guide/server.md
- Best Practices: docs/guide/best-practices.md
- Migration: docs/guide/migration.md
- Examples: docs/guide/examples.md
- FAQ: docs/guide/faq.md
- Glossary: docs/glossary.md
The cross-runtime SSR examples in examples/ import directly from src/, so you can run them from a repo checkout without building dist/ first.
# Install dependencies bun install # Start VitePress docs bun run dev # Run Storybook bun run storybook # Run tests bun test # Build library bun run build # Verify AI guidance / release metadata sync bun run check:ai-guidance # Build docs bun run build:docs # Generate API documentation bun run docs:api # Run the cross-runtime SSR examples directly from source bun examples/ssr-bun/serve.ts deno run -A examples/ssr-deno/serve.ts node --experimental-strip-types examples/ssr-node/serve.ts
bQuery.js
├── src/
│ ├── core/ # Selectors, DOM ops, events, utils
│ ├── reactive/ # Signals, computed, effects, async data
│ ├── concurrency/ # Zero-build worker tasks, RPC, pools, collection helpers
│ ├── component/ # Web Components helper + default library
│ ├── storybook/ # Story template helpers
│ ├── motion/ # View transitions, FLIP, springs
│ ├── security/ # Sanitizer, CSP, Trusted Types
│ ├── platform/ # Storage, cache, cookies, meta, config
│ ├── router/ # SPA routing, navigation guards
│ ├── store/ # State management, persistence
│ ├── view/ # Declarative DOM bindings
│ ├── forms/ # Reactive forms + validators
│ ├── i18n/ # Internationalization + formatting
│ ├── a11y/ # Accessibility utilities
│ ├── dnd/ # Drag & drop helpers
│ ├── media/ # Browser and device reactive signals
│ ├── plugin/ # Global plugin system
│ ├── devtools/ # Runtime inspection helpers
│ ├── testing/ # Test utilities
│ ├── ssr/ # Runtime-agnostic server-side rendering + hydration
│ └── server/ # Backend helpers and WebSocket sessions
├── docs/ # VitePress documentation
├── .storybook/ # Storybook config
├── stories/ # Component stories
├── tests/ # bun:test suites
└── dist/ # Built files (ESM, UMD, IIFE)
See CONTRIBUTING.md for guidelines.
This project provides dedicated context files for AI coding agents:
- AGENT.md — Architecture, module API reference, coding conventions, common tasks
- llms.txt — Compact LLM-optimized project summary
- .github/copilot-instructions.md — GitHub Copilot context
bun run check:ai-guidance— Lightweight sync check for version / engine / AI guidance driftbun run check:full-bundle— Static guard for/fullruntime and type export drift
MIT – See LICENSE.md for details.