Releases: bQuery/bQuery
Release list
Release 1.16.1
[1.16.1] - 2026-08-26
A toolchain-and-build maintenance patch. Nothing under src/ changed, so every 1.16.0 API behaves identically and upgrading is a drop-in. The supported Bun floor moves to 1.4.0, the dev-dependency set is refreshed, and both Vite configs now build warning-free.
Changed (1.16.1)
- Toolchain: The supported Bun floor moves from
1.3.13to1.4.0(engines.bun), mirrored inmise.toml, the AI guidance files (AGENT.md,llms.txt,.github/copilot-instructions.md,.cursorrules,.clinerules), the runtime support matrix, and the bug-report template. CI workflows installbun-version: 'latest'instead of pinning a patch release, and the SSR cross-runtime matrix legbun-1.3becomesbun-1.4. Node.js stays at>=24.0.0. - Build:
vite.config.tsandvite.umd.config.tsresolve the repository root fromimport.meta.dirnameinstead of__dirname, making both configs compatible with Vite'sconfigLoader: 'native'(planned to become the default in a future major) and silencing the loader warning it emitted on every build. - Dev dependencies: Bumped
@storybook/addon-docs,@storybook/web-components-vite, andstorybookfrom10.5.7to10.5.10,@typescript-eslint/eslint-pluginand@typescript-eslint/parserfrom8.67.0to8.68.0,bun-typesfrom1.3.14to1.4.0,eslintfrom10.8.1to10.9.1,globalsfrom17.9.0to17.11.0,happy-domfrom20.11.2to20.11.6, andvitefrom8.2.1to8.2.2.
Fixed (1.16.1)
- Build: The UMD/IIFE build no longer logs
Module "node:http" has been externalized for browser compatibility.createServer().listen()dynamically importsnode:httpon its Node branch, which is unreachable in a browser bundle, but Vite's resolver substituted its own stub and warned on every build (rollupOptions.externaldoes not apply —node:*is handled earlier by Vite's client-environment resolver). A build-only plugin invite.umd.config.tsnow mapsnode:*to a stub module that throws a message naming the missing built-in, so the dynamic import rejects with actionable text instead of failing later as a cryptic "not a function". Bundle contents are otherwise unchanged.
Full Changelog: v1.16.0...v1.16.1
Release 1.16.0
[1.16.0] - 2026-08-11
A quality-and-performance pass over the three hot paths of the framework — the reactive core, the DOM core, and the view layer — driven by a full audit of each. Signal writes, computed propagation, list reconciliation, and directive updates all got measurably cheaper, and the audit surfaced (and this release fixes) several real correctness bugs. The release also folds in the previously staged follow-up to the 1.15.1 security review (a residual evaluator-hardening gap, the deepClone prototype-pollution guard, and a compiler numeric-literal fix). No breaking changes; one small additive API (watchThrottle's trailing option).
Added (1.16.0)
@bquery/bquery/reactive—watchThrottleaccepts a newtrailingoption (WatchThrottleOptions). Whentrue, the last value of a burst is delivered once the interval elapses, so consumers never end up on a stale intermediate value. Defaults tofalse, preserving the leading-edge-only behavior of earlier releases.
Changed (1.16.0)
@bquery/bquery/reactive— batching now spans the whole propagation:batch()keeps the batch open while flushing, so signal writes performed by observers keep coalescing into the same flush instead of dispatching synchronously one by one. Flushes drain re-queued observers in follow-up passes (bounded at 100 passes, mirroring the existing cyclic-effect guard) — diamond dependencies inside a batch now trigger their effect once instead of once per branch.@bquery/bquery/reactive—Computedre-validates before waking subscribers: when a dependency changes but the recomputed value isObject.is-equal to the last observed one, downstream effects are not notified at all. In the micro-benchmark, acomputed(() => count.value > 5)under 20k writes went from 20k effect runs to 2.@bquery/bquery/reactive— hot-path allocation cuts: signal writes with zero or one subscriber no longer allocate a snapshot array (~6× faster with no subscribers), repeat reads of the same source inside one observer skip the dependency bookkeeping (~1.6× faster), computed chains propagate ~1.7× faster, andeffect()no longer allocates an inspectionSymbolwhen effect inspection is disabled.@bquery/bquery/core— collection/element cheapening:replaceWith(string)sanitizes and parses the HTML once and clones per element (matchinginsertAll);css(object)hoistsObject.entriesout of the per-element loop;children()/siblings()iterate liveHTMLCollections withoutArray.fromcopies andsiblings()visits each unique parent once;index()countspreviousElementSiblinginstead of materializing the sibling list;empty()usesreplaceChildren()(no HTML parser, no Trusted Types sink);unwrap()collapses to a singlereplaceWith(...childNodes)mutation; form serialization resolves each control's kind with onetagName.toLowerCase()instead of three;data()'s camel→kebab regex is compiled once at module level. The per-instance delegation maps are gone entirely (see theundelegatefix below).@bquery/bquery/view— per-update work moved to bind time:bq-class/bq-style/bq-ariaparse their static object expression once (memoized) instead of on every reactive tick, and pre-normalize property names;bq-ifresolves its transition config only on an actual visibility flip instead of on every effect run;bq-text/bq-bind/bq-modelskip the DOM write when the value is unchanged;bq-htmlskips sanitize+parse when the HTML string is unchanged.processElementreuses one set of per-prefix attribute-name strings instead of rebuilding them per element,parseDirectiveresults are memoized (bounded like the expression caches),bq-for's key extraction reuses one context object per reconcile instead of spreading the context per item, and expression evaluation caches its sandbox proxies per context object instead of allocating one per evaluation.- Tooling / Dev dependencies: Bumped
@storybook/addon-docsand@storybook/web-components-vitefrom10.4.6to10.5.7,@typescript-eslint/eslint-pluginand@typescript-eslint/parserfrom8.63.0to8.67.0,eslintfrom10.6.0to10.8.1,globalsfrom17.7.0to17.9.0,happy-domfrom20.10.6to20.11.2,prettierfrom3.9.4to3.9.6,storybookfrom10.4.6to10.5.7, andvitefrom8.1.3to8.2.1.
Fixed (1.16.0)
@bquery/bquery/core—undelegate()called on a fresh wrapper (e.g.$$('.container').undelegate(...)after delegating via an earlier$$()call — the documented usage) was a silent no-op because the handler registry lived on the wrapper instance, permanently leaking the delegated listener. The registry is now module-level and keyed by element,delegate()attaches a single listener per (element, event, selector, handler) and counts its registrations so one owner'sundelegate()cannot detach a delegation another owner still holds, and the delegated dispatcher no longer throws whenevent.targetis not anElement(e.g. aTextnode).@bquery/bquery/core—wrap(element)over a multi-element collection cloned the wrapper after the first element had been moved into it, so later wrappers contained copies of previously wrapped elements. The pristine wrapper is snapshotted before the loop.@bquery/bquery/view— directives declared beforebq-foron the same element (<li bq-text="item.name" bq-for="item in items">) were bound against the discarded template element and the outer context, leaking a live effect that errored on every update.bq-foris now dispatched first regardless of attribute order.@bquery/bquery/view—bq-once/bq-memo/bq-initevaluated their expression while the enclosingbq-forreconciler was the active observer, silently subscribing the whole list to signals the "non-reactive" directives read. Their evaluation is now untracked, matching their documented contract.@bquery/bquery/view—bq-modelre-wroteinput.valueon the effect tick triggered by the input's owninputevent, resetting the caret position while typing. The write is now skipped when the input already holds the value.@bquery/bquery/view— children ofbq-html/bq-html-safecontent were processed for directives at mount and their effects kept running (and writing) after the first re-render replaced the markup. Child processing is skipped for author-opaque HTML content.@bquery/bquery/motion—onReducedMotionChangenow re-binds to the currentwindow.matchMediawhen subscribing (a replacedmatchMedia— e.g. in tests or embedded contexts — previously left the subscription attached to the stale source) and flushes preference changes that happened without achangeevent, so existing listeners and the new subscriber's baseline stay accurate. This also fixes two order-dependent test failures in the motion suite.@bquery/bquery/reactive— nestedbatch()calls could execute observers twice per flush (the flush loop iterated a stale snapshot); acomputedwhose compute function threw was left marked clean and served its stale cached value on subsequent reads (it now stays dirty and retries);watchThrottlecancels a pending trailing delivery on scope disposal, mirroringwatchDebounce.@bquery/bquery/store—deepClone(used by$patchDeep) now special-cases only the genuinely dangerous__proto__key, defining it as a real own data property so it can no longer trigger the prototype-reassigning setter. Own data properties merely namedconstructororprototypeare copied normally again instead of being silently dropped, which had discarded legitimate cloned data.@bquery/bquery/view/compiler—NUMERIC_LITERAL_REnow rejects legacy leading-zero decimal literals (007,01.5), which areSyntaxErrors in the strict-mode ES module the compiler emits, instead of compiling them into invalid output.
Security (1.16.0)
@bquery/bquery/view— closes a residual escape from thewith-scoped evaluator hardening shipped in 1.15.1 (#168): shadowing dangerous identifiers on thewithscope didn't stop a member access chain off any reachable context value from reachingFunction, e.g.items.constructor.constructor('return 2')(). A new shared guard,hasDangerousMemberAccess(), rejects dotted (.constructor), optional-chaining (?.constructor), and string-literal bracket (['constructor']) access toconstructor,prototype, or__proto__— applied to both the runtime evaluator (evaluate/evaluateRaw, which now refuse and log instead of executing) and the ahead-of-time compiler (which bails to the runtime evaluator, itself also guarded). Computed bracket access assembled at runtime (foo['con' + 'structor']) remains out of scope, documented as a residual limit of thewith-scope evaluator's threat model (#202).
Full Changelog: v1.15.1...v1.16.0
Release 1.15.1
[1.15.1] - 2026-07-06
A security-and-correctness patch closing the findings of a full-codebase audit. No breaking changes and no module status transitions — every entry is a fix on the 1.15.0 surface. Three small, backwards-compatible additions are noted inline with the fixes that introduced them (the trustedHtmlForSink helper, the effectScope(detached) parameter, and a dispose() method on deferred()'s handle).
Security (1.15.1)
@bquery/bquery/security— the anti-mutation-XSS fallback insanitizeHtmlreturned raw, un-escapedtextContentwhen the serialize→re-parse stability check failed. Because every HTML sink ($el.html(),.append()/.before()/.after(), the default-sanitizedbq-html) assigns that result toinnerHTML, an entity-encoded payload combined with a foster-parenting construct could smuggle live markup through the defense meant to stop it. The fallback is now HTML-escaped (#162).@bquery/bquery/ssr—bq-texton raw-text elements (textarea,title) is now escaped in the default DOM-free renderer. Raw-text children are serialized verbatim, so an untrusted value such as</textarea><img onerror=…>could break out of the element (stored XSS) — the escaping now mirrors the existingbq-modelhandling (#163).@bquery/bquery/view+@bquery/bquery/ssr—bq-bindnow guards runtime-bound attribute values via a sharedsrc/security/bind-guard.ts: inlineon*handlers are never written, URL attributes (href,src,xlink:href,formaction,action,poster,background,cite,data) andsrcsetreject dangerous protocols, andsrcdocis treated as an HTML sink (sanitized). Applied consistently to the client directive and both SSR backends (#164).@bquery/bquery/view— thewith-scoped runtime evaluator no longer resolves inherited members or globals, closing aconstructor.constructor('…')()(and bareFunction('…')()) code-execution path. The proxy now shadows a denylist (constructor,__proto__,prototype,Function,eval,globalThis,window,self, …) for bothevaluateandevaluateRaw; own context properties, arithmetic, and method calls on values are unaffected (#168).@bquery/bquery/ssr— the DOM-backed evaluator now routes through the CSP-safe Pratt parser shared with the pure renderer, removing thenew Function()fallback ('unsafe-eval') and a prototype-lookup gap (constructor.constructorreachability). Evaluator behaviour is now unified across both SSR backends (#167).@bquery/bquery/server— the session-id cookie and the CSRF secret cookie now default toSecure, keeping these bearer credentials off plaintext HTTP. Opt out explicitly withcookie: { secure: false }for local HTTP dev (#169).@bquery/bquery/security— Trusted Types are now wired into the framework's HTML sinks. The newtrustedHtmlForSink()helper (also re-exported from/full) returns aTrustedHTMLobject when a policy is active — so writes satisfy an enforcedrequire-trusted-types-for 'script'CSP instead of throwing — and the sanitized string otherwise.setHtml,Collection.html()/insert paths,bq-html, andbq-html-saferoute through it (#171).@bquery/bquery/ssr—bq-styledeclarations are validated in the pure renderer before concatenation: property names must be valid CSS identifiers and values containing;,{,}, or<are dropped, preventing injection of extra declarations/rules (UI-redress, exfiltration) from untrusted style objects (#176).@bquery/bquery/security— DOM-clobbering defenses strengthened: the reserved-id/namedenylist is expanded with the many missing high-value targets (attributes,nodeName,getElementById,defaultView,implementation, DOM-traversal properties, …) and duplicateids within a sanitized fragment are now stripped, mitigating the classic HTMLCollection-clobbering vector. Documented as defense-in-depth (#179).@bquery/bquery/i18n— placeholder and message-key resolution now use own-property checks, so a placeholder or key colliding with anObject.prototypemember (toString,constructor, …) is left intact rather than substituted with the inherited value (#174).@bquery/bquery/store—deepClone(used by$patchDeep) now skips prototype-pollution keys, so an own enumerable__proto__(e.g. fromJSON.parse) no longer triggers the setter and reassigns the clone's prototype (#175).@bquery/bquery/server— file-route loader (JSON) endpoints now default their middleware to the action middleware chain. Protecting mutations withmiddlewares: [auth]no longer accidentally exposes every route'sload()output as unauthenticated JSON; opt out with an explicitdataMiddlewares: [](#181).
Fixed (1.15.1)
@bquery/bquery/store—$subscribenotifications iterate a snapshot of the subscriber list, so a callback that unsubscribes during notification no longer causes the next subscriber to be silently skipped (mirrors the existing$onActionguard) (#165).@bquery/bquery/reactive— an effect that writes a signal it also reads no longer recurses synchronously into a stack overflow. Self-triggered re-runs are drained in a bounded loop and acyclic effect update detectedwarning is logged instead of crashing the page; effects that legitimately settle still converge silently (#166).@bquery/bquery/view/compiler— the compiler bails to the runtime evaluator on an unterminated string literal or an invalid numeric literal instead of emitting a syntactically broken module (one bad expression previously took down every precompiled expression in the emitted file) (#170).@bquery/bquery/reactive— overlappinguseFetch/useAsyncDataexecutions (e.g. awatchrefresh racing a manualrefresh()) now abort the superseded in-flight request instead of leaving it running un-cancellable (#172).@bquery/bquery/reactive+@bquery/bquery/concurrency— composables that created long-lived reactive primitives now have disposal paths.deferred()returns a handle with adispose();persistedSignal()runs its persistence effect in a detached scope tied to the signal's owndispose()(so an ambientscope.stop()no longer silently stops persistence). Adds an optionaleffectScope(detached?)parameter (#173).@bquery/bquery/ssr—titleTemplateinserts the page title literally, so specialString.prototype.replacepatterns ($&,$1,$`,$') in a title no longer mangle the rendered<title>(#177).@bquery/bquery/core—debounce({ leading: true, trailing: true })no longer double-invokes on a single call; the trailing edge fires only when the function was called more than once during the wait window (lodash semantics) (#178).@bquery/bquery/view—bq-ondecides bare-reference vs. call by evaluating the expression rather than string-scanning for(. Handlers resolved through an expression containing an inner paren (e.g.items.find(fn).handler) are now invoked instead of silently doing nothing (#180).
Full Changelog: v1.15.0...v1.15.1
Version 1.15.0
[1.15.0] - 2026-06-30
This release graduates the final thirteen modules to Stable — view, forms, i18n, a11y, dnd, media, plugin, devtools, testing, storybook, concurrency, ssr, and server. With them, every bQuery module is now Stable and bound by the no-breaking-changes-between-minor-releases contract (see STABILITY.md). All graduations are additive — there are no breaking changes this cycle.
Added (1.15.0)
@bquery/bquery/view— declarative enter/leave/move transitions (#137). New companion attributesbq-transition,bq-in,bq-out,bq-transition-duration,bq-transition-easingdrive enter/leave animations onbq-if/bq-show, andbq-animate="flip"drives FLIP move animations whenbq-foritems reorder. The layer delegates to the existingmotionengine (Web Animations + FLIP), skips the initial paint, defers removal until the leave finishes, is race-safe on rapid toggles, and honoursprefers-reduced-motion.@bquery/bquery/view/compiler— optional, build-tool-agnostic compiler (#138).compileViews(),compileToModule(),compileExpression(),emitModule(), and the dependency-free CLI (runCompileCli/compileFiles,bquery-view-compile) pre-parsebq-*expressions into optimized,with-free update functions. New runtime hooksregisterCompiledExpressions()/clearCompiledExpressions()(exported from@bquery/bquery/view) let the runtime use the precompiled functions, skipping thenew Function()evaluator (and its'unsafe-eval'requirement). The runtime evaluator stays the default; un-compilable expressions transparently fall back to it, so both paths are behaviourally identical.@bquery/bquery/forms— progressive-enhancement form actions + optimistic updates (#140). NewformAction(target, options)binds a form to a server action that POSTs natively without JS and progressively enhances to afetch-based submit with reactivepending/error/resultstate when JS is present (enhance(form)sets the nativeaction/methodand an optional hidden CSRF field, then interceptssubmit).useFormStatus(action)exposes read-only status signals (mirroring React 19), andoptimistic(base, reducer)is an optimistic-update primitive whose reactivevaluefolds pending drafts over the base and reverts automatically (add/run/clear). Composes with the validation pipeline and theservermodule'scsrf(). A non-OK response throwsFormActionError(carryingstatus/response).@bquery/bquery/forms—createFieldArray()gains an optionalgetKeyfor keyed list reconciliation (#139), pluskeys()/keyAt(index). When supplied, the stable-key contract (present, unique keys) is validated on every structural mutation and a descriptive error names the offending key. WithoutgetKeythe array stays positional (unchanged behaviour).@bquery/bquery/i18n— ICU MessageFormat support (#141). Messages using typed arguments ({count, plural, …},{n, selectordinal, …},{gender, select, …}) are routed through a locale-aware formatter backed byIntl.PluralRules, withoffset:, exact=Nselectors, nested arguments, the#token, and apostrophe escaping. New authoring helpersdefineMessages()(identity + extraction anchor) andformatMessage()(standalone single-message formatter). Plain{name}interpolation and the legacysingular | pluralpipe form are unchanged.@bquery/bquery/i18n/extract— optional, dependency-free message-extraction tooling (#141).extractFromSource(),mergeCatalog(),extractFiles(),expandGlobs(),flatten()/unflatten(), and the CLI (runExtractCli,bquery-i18n extract) scan source fordefineMessagescatalogs andt()/tc()calls, then emit/merge nested JSON catalogs without overwriting existing translations (--pruneopt-in). A separate entry point — importing it is never required at runtime, preserving the zero-build path.@bquery/bquery/a11y— the runtime audit now stamps eachAuditFindingwith its WCAG 2.1 criterion (wcag), and the full rule catalog is exported asauditRules(#142) — each rule documents its WCAG mapping, default severity, and a known limitation (what it cannot detect).@bquery/bquery/plugin— newdefinePlugin()authoring helper (#145): an identity helper that infers a plugin's install-options type and gives third-party authors a single, stable entry point.@bquery/bquery/devtools— new stable, versioned bridge protocol for the DevTools browser extension (#146):connectDevtoolsBridge()(overwindow.postMessage), the transport-agnosticcreateBridgeServer(),serializeComponentTree(), andBRIDGE_PROTOCOL_VERSION/BRIDGE_SOURCE/BRIDGE_CAPABILITIES. A reference Manifest V3 extension (component tree, signal/store inspection, live timeline) ships inextension/.@bquery/bquery/router+@bquery/bquery/server— opt-in, bundler-agnostic file-route convention with typedload/action(#149). NewcreateFileRoutes(manifest, options?)turns a manifest (a bundler glob such asimport.meta.glob, or a hand-written map) into the sameRouteDefinitionscreateRouter()already consumes, withparseFilePath/filePathToRoutePattern(routes/users/[id]/+page.ts→/users/:id,[...rest]→*,(group)dropped) and specificity sorting (sortEntriesBySpecificity). Route modules export a typedLoad(data into the view) andAction(mutation target). Loaders run on the server before render (the SSR router bridge now recognisesmeta.loadalongsidemeta.loader) and on client navigation viacreateRouteData(router)/useRouteData(). Theservermodule exposesmountFileRoutes(app, entries, options?)/createFileRouteServerRoutes()so a<form>(orformAction()) posts to a route'saction, composing withcsrf(). Programmatic routing stays fully supported and unchanged; no bundler is shipped. See the new File-based Routing guide.- Docs / Stability — single-source Stability Matrix plus a per-module stability changelog (#150). A new canonical
STABILITY.md(backed byscripts/stability-matrix.mjs) records each module's maturity and its status-transition history; the README "Modules at a glance" table and the docsintroduction.mdmatrix are now validated against it bybun run check:stability(scripts/check-stability-matrix.mjs), so the three surfaces can no longer silently drift.
Changed (1.15.0)
@bquery/bquery/view—viewgraduated to Stable in 1.15.0 (#136). The directive set and expression grammar are frozen for one minor cycle, and a per-directive SSR support matrix is published in the View guide.@bquery/bquery/forms—formsgraduated to Stable in 1.15.0 (#139). The 1.13 batteries-included surface is frozen for one minor cycle; the'manual'validationStrategydefault is documented as a deliberate contract (handleSubmit()always runs the full validation pass; the strategy gates only automatic per-change/per-blur validation); the SSR serialization boundary is now a guaranteed contract (serializeFormState()deterministically drops functions,File/Blob/FileList,bigint, andsymbol); and thecreateFieldArray()stable-key requirement is validated with clear errors. See the Forms guide.@bquery/bquery/i18n—i18ngraduated to Stable in 1.15.0 (#141). The formatting/locale surface is frozen for one minor cycle, ICU MessageFormat coverage is documented and tested, and lazy-loading of catalogs is documented. See the i18n guide.@bquery/bquery/a11y—a11ygraduated to Stable in 1.15.0 (#142). The surface (focus management, live regions,inert/scrollLock, preference signals) is frozen for one minor cycle, and the audit's WCAG coverage is documented with its known limitations. See the A11y guide.@bquery/bquery/dnd—dndgraduated to Stable in 1.15.0 (#143). The surface is frozen for one minor cycle; the keyboard model (pick up / move / drop / cancel,aria-grabbed) is hardened and tested acrossgrid/delay/viewport; and an accessibility statement is published. Drag announcements route through the shareda11ylive-region announcer. See the DnD guide.@bquery/bquery/media—mediagraduated to Stable in 1.15.0 (#144). The 1.14 composable surface is frozen for one minor cycle; each composable's SSR-safe default and cleanup is documented; and reactivity, idempotentdestroy(), listener detachment, andAbortSignalteardown are verified. Bake-and-verify — no new features. See the Media guide.@bquery/bquery/plugin—plugingraduated to Stable in 1.15.0 (#145). T...
Version 1.14.2
Version Release 1.14.1
[1.14.1] - 2026-05-28
Fixed (1.14.1)
- Motion:
prefersReducedMotion()andreducedMotionSignal()now refresh their cached reduced-motion media query whenwindow.matchMediachanges, preventing stale preference reads in tests and other environments that swap the media-query implementation at runtime.
What's Changed
Full Changelog: v1.14.0...v1.14.1
Version 1.14.0
[1.14.0] - 2026-05-26
Added (1.14.0)
- Media / Preference signals: Added
usePreferredColorScheme(),usePreferredContrast(),usePreferredReducedTransparency(),usePreferredLanguage(), andusePreferredLanguages()reactive composables to@bquery/bquery/mediathat wrapprefers-color-scheme,prefers-contrast,prefers-reduced-transparency, andnavigator.language(s)with deterministic SSR defaults. - Media / Page state: Added
useOnlineStatus()(slim boolean variant ofuseNetworkStatus()),usePageVisibility(),useDocumentFocus(),useWindowFocus(), anduseIdle(timeoutMs, opts?)to track top-level user-activity state. - Media / Element observers: Added
useElementSize(target, opts?),useElementBounding(target, opts?),useElementVisibility(target, opts?),useHover(target),useFocus(target),useFocusWithin(target), anduseActiveElement()— ergonomic wrappers overResizeObserver/IntersectionObserverand DOM focus events. Targets accept plainElement | null | undefinedvalues. - Media / Pointer & scroll: Added
usePointer()({ x, y, pressure, type, isInside }) anduseScroll(target?)({ x, y, directionX, directionY, isScrolling, arrived }). - Media / Platform integrations: Added
usePermission(name)('granted' | 'denied' | 'prompt' | 'unsupported'),useWakeLock()(isActive,request(),release()),useShare()/useShareSupported(),useBroadcastChannel<T>(name)({ data, post, close }),useEventListener(target, event, opts?),useMediaDevices(), anduseStorage<T>(key, defaultValue, opts?)with cross-tabstorageevent sync. - Media / Clipboard: Added
clipboard.isSupported,clipboard.isImageSupported,clipboard.readImage(),clipboard.writeImage(), and the standaloneclipboardText()reactive accessor. - Media / Composables: Every new composable accepts an optional
{ signal: AbortSignal }for auto-teardown matching themotion1.13 convention, and an internal sharedcreateMediaSignalhelper standardises SSR safety + idempotent teardown. - Plugin / Hooks: Added a synchronous filter pipeline (
addFilter,applyFilters,removeFilter,listFilters) and a fire-and-forget action bus (addAction,doAction,removeAction,listActions) exposed both on the install context (ctx.addFilter,ctx.addAction) and as standalone exports for app-level consumers. - Plugin / DI: Added container-level dependency injection —
createInjectionKey<T>(),provide(key, value),inject(key),hasProvided(key),resetDi()— and a matchingctx.provide/ctx.inject. Plugins can registerctx.onCleanup(fn)callbacks that fire when the plugin is uninstalled. - Plugin / Lifecycle: Added
unuse(name)anduninstall(name)to detach every directive, filter, action, and DI binding owned by a plugin and run its registered cleanups.install()may now returnvoid | Promise<void>; concurrent installs of the same name are serialised. - Plugin / Metadata:
BQueryPluginnow accepts optionalversion,description, anddependencies: string[].use()enforces dependencies viadependencyMode: 'error' | 'warn'. NewgetPluginInfo(name)andgetInstalledPlugins({ withMetadata: true })overloads expose plugin metadata. - Plugin / Directives: Directives may now register lifecycle objects
{ mounted, unmounted }and use plugin-namespaced names liketooltip:arrow. - Devtools / Timeline: Timeline gained a ring buffer (
maxTimelineEntries, default 1000) andTimelineEntrynow carries optionalpayload,source, andduration. New event types:signal:create,signal:dispose,effect:dispose,component:mount,component:unmount,component:render,route:guard,error:caught,measure,mark. - Devtools / Querying: Added
filterTimeline({ types, since, until, search })andsubscribeTimeline(listener)for live consumers. - Devtools / Inspection: Added privacy-aware
inspectSignals({ includeValues: false }), structuraldiffSignals(prev, next)/diffStores(prev, next),traceSignal(label)/untraceSignal(label), andinspectEffects(). - Devtools / Snapshots: Added
exportDevtoolsSnapshot()andimportDevtoolsSnapshot(json)for offline inspection and bug reports. - Devtools / Bridge: Added
installBrowserBridge()that mirrors timeline events towindow.__BQUERY_DEVTOOLS__.eventsfor future browser-extension panels (no-op outside a DOM). - Devtools / Performance: Added
time(label, fn),measureRender(tagName, fn), andgetPerformanceSummary()aggregating event counts and average durations per type. - Testing / Cleanup: Added
cleanup()to unmount any tracked render results from the current test, plusautoCleanup(beforeEach, afterEach)to wire it intobun:test. - Testing / Events: Attached shortcut methods to the existing
fireEvent—fireEvent.click,fireEvent.dblClick,fireEvent.input(el, value),fireEvent.change(el, value),fireEvent.submit,fireEvent.focus,fireEvent.blur,fireEvent.keyDown,fireEvent.keyUp— and added auserEventnamespace (click,dblClick,hover,unhover,type(el, text, { delay? }),clear,selectOptions,tab,paste) that flushes effects + microtasks before returning. - Testing / Queries: Added a shadow-DOM-aware query layer —
screen.getByRole/getByText/getByLabelText/getByPlaceholderText/getByTestIdwithquery*andfind*variants — and awithin(root)factory that produces the same scoped query API. - Testing / Reactive helpers: Added
mockComputed(fn)(withrecomputeCount),mockEffect(fn)({ runs, dispose }),tick()/nextTick(),flushPromises(), andrunScheduled(). - Testing / Mocks: Added
mockStore<T>(initialState),mockI18n({ locale, messages }),mockForm<T>(initialValues),mockFetch(routes), andmockWebSocket()for isolated module testing. - Testing / Snapshots & a11y: Added
prettyDOM(el, { maxLength, includeShadow }),getReactiveSummary(el), andexpectAccessible(el)returning a structuredAccessibilityResultfor image-alt / button-name / label-input rules. @bquery/bquery/router— additive 1.14.0 expansion:NavigationResulttype withpushResult()andreplaceResult()
methods that return structured results withstatus,requestedPath,
to,from, anderrorfields instead of bare promises (existing
push/replacecontinue to returnPromise<void>).beforeResolve(guard)global hook fired afterbeforeEachand
route-levelbeforeEnterguards but before navigation commits.resolveRoute(input)method for synchronous route lookup without
navigating.- Dynamic route management via
addRoute(parentName?, route),
removeRoute(name), andhasRoute(name). isReady()returning a promise that settles after the initial route
synchronization during router construction,
pluslastNavigationsignal exposing the most recent result.useNavigation()composable returning reactive navigation state
(isNavigating,error, etc.).
@bquery/bquery/view— additive 1.14.0 expansion:- Public
parseDirective(name)helper andParsedDirectivetype for
parsingbq-on:event.modifier-param.modifiersyntax. - New directives
bq-once,bq-init,bq-pre,bq-cloak,
bq-html-safe, andbq-memo. - Full
bq-onmodifier system:.stop,.prevent,.self,.capture,
.passive,.once, mouse-button filters (.left/.middle/.right),
system-modifier filters (.ctrl/.alt/.shift/.meta), and
KeyboardEvent.key filters including aliases (.enter,.esc, arrow
keys, etc.).
- Public
@bquery/bquery/a11y— additive 1.14.0 expansion:createLiveRegion(options)for imperative, per-instance ARIA live
regions independent of the singletonannounceToScreenReader.- Reactive
keyboardUserSignal()andfocusVisible()signals. - New media-preference signals
prefersReducedTransparency(),
prefersReducedData(), andforcedColors(). - DOM helpers
inert(target),scrollLock(), andautoFocus(target, opts).
@bquery/bquery/i18n— additive 1.14.0 expansion:negotiateLocale(requested, available, opts)for pure locale
negotiation against a list of available tags.detectLocale(opts)reading from cookies,localStorage,
<html lang>, andnavigator.languages.isRTL(locale)usingIntl.Localetext-info when available with a
well-known-language fallback.- New Intl helpers
formatRelativeTime,formatList,
formatDisplayName, andsegment(graceful fallbacks when the
underlying Intl API is unavailable).
@bquery/bquery/dnd— additive 1.14.0 expansion:- Programmatic API on existing handles —
DraggableHandle.moveTo/reset/getPosition/setBounds/setAxis,SortableHandle.move/setOrder/getItems,DroppableHandle.setAccept/isOver/getActiveDragged. - New draggable options
grid(snap-to-grid),delay(long-press threshold),touchStartThreshold(minimum pointer movement before drag activates),keyboard(opt-in keyboard accessibility withSpace/Enterpickup, arrow-key movement,Escapecancel, and ARIA announcements via@bquery/bquery/a11y), andkeyboardStep(keyboard movement step). boundsnow accepts anHTMLElementreference directly and supports a'viewport'shorthand.- Reactive composables
useDraggable(),useDroppable(),useSortable(), plus thedraggablePosition()andsortableOrder()adapters for raw handles. Composables auto-dispose when the surrounding reactive scope stops.
- Programmatic API on existing handles —
@bquery/bquery/storybook: New ergonomic helpersclassMap(),styleMap(),ifDefined(),repeat(),storyText(), and the opt-in sanitizer escape hatchunsafeHtml(), all callable insidestoryHtmltempl...
Version 1.13.0
[1.13.0] - 2026-05-21
Added (1.13.0)
- Forms / Validators: Added a batteries-included set of tree-shakeable validators to
@bquery/bquery/forms—integer,numeric,between,length,oneOf,notOneOf,arrayOf,requiredIf,requiredUnless,dateAfter,dateBefore,validDate,fileSize,fileType— plus combinatorscompose,all,not, andwithMessage. (validDateis exported under that name to avoid collision with the existingisDatetype guard in@bquery/bquery/core.) - Forms / Field state: Lifted
isValidating,isFocused, anddirtySincesignals onto everyFormField. Added per-field helpersfocus(),blur(),setValue(value, { touch, validate, silent }),setError(message),clearError(), adisabledsignal that excludes the field from validation, and per-fieldvalidateOn/debounceMsparity withuseFormField.FieldConfignow acceptsparseandformatfor programmatic inbound/outbound value normalization. - Forms / Form state: Added
submitCount,lastSubmittedAt,submitError, aggregatedisValidatingandisPristine, and helperstouchAll(),untouchAll(),resetField(name),resetErrors(),getDirtyValues(), andsubscribe(listener).FormConfignow acceptsonSubmitError,onSubmitSuccess,validationStrategy, andmode: 'all' | 'first'. - Forms / Field arrays: Added
createFieldArray({ initial, factory, validators })withadd,remove,move,insert,clear,items, andlengthfor dynamic repeating field groups. - Forms / Schema: Added a fluent
schema({ name: field<string>().required().minLength(2), … })helper that composes existing validator factories into aFieldConfigmap. - Forms / DOM bindings: Added
bindField(field, element, options?)andbindForm(form, formElement, options?)to bridgeFormandFormFieldinstances to standard inputs, selects, textareas, checkboxes, radios, file inputs, and[contenteditable]elements; both return cleanup functions.bindFormauto-discovers[name]inputs, marksaria-invalid, and supports a configurable error slot mapper. - Forms / Composables: Added scope-aware
useForm,useField, anduseFieldArraywrappers that auto-dispose with the owning component. - Forms / SSR: Added
serializeFormState(id, form.snapshot()),readSerializedFormState(id), andhydrateForm(form, id)helpers (built onsrc/ssr/escape.ts) so server-rendered form state can resume on the client. - Component / Refs: Added
useRef<T>()that auto-clears on disconnect. - Component / Slots: Added
useSlot(host, name?)(reactiveSignal<Element[]>),hasSlot(host, name?), andslotText(host, name?). - Component / Events: Added sanitizer-safe delegated event helpers
on(event, handler),onClick,onInput,onChange,onSubmit, andbindDelegatedEvents(host). Handlers are stored in a module-level map keyed by opaque IDs; templates only carrydata-bq-on-<event>="<id>"attributes. - Component / DI: Added
provide(host, key, value),inject(host, key, fallback?),injectionKey<T>(description), and theformContextKeyfor letting inputs auto-bind to an enclosing<bq-form>without globals. - Component / Lifecycle: Added
beforeUnmountanderrorBoundary(error, info)hooks onComponentDefinition, plus a scope-trackedwhenIdle(fn)helper. - Component / Async: Added
useAsync(fn)returning{ data, error, loading, refresh }signals withAbortController-aware cancellation. - Component / Props: Added imperative
setProp(name, value)andgetProp(name)methods on every component instance for non-string objects (arrays, callbacks) that bypass attribute serialization. - Component / Styles: Added a
csstagged template literal that produces aComponentStylespayload. When Constructable Stylesheets are available the styles are shared viadocument.adoptedStyleSheets; otherwise the existing<style>element pathway is used. Interpolated values are CSS-escaped. - Component / Lists: Added
keyedList(items, keyFn, renderItem)andreconcileKeyed(container)for keyed list rendering inside shadow DOM. - Motion / Easing: Full Penner easing family —
easeIn/easeOut/easeInOutvariants ofQuart,Quint,Sine,Expo,Circ,Back,Elastic, andBounceare now exported and mirrored ineasingPresets. Added thecubicBezier(x1, y1, x2, y2)factory (Newton-Raphson refinement matching CSScubic-bezier()),steps(count, position?)factory mirroring CSSsteps(), and themix(a, b, weight)/chain(...easings)composers. - Motion / Tweens: New
animateValue<T>()andtween<T>()interpolate numbers, number arrays, orRecord<string, number>betweenfromandtousingrequestAnimationFrame.tween()returns full imperative controls (pause/resume/reverse/seek/stop/progress) with afinishedpromise, supports anAbortSignal, and respectsprefers-reduced-motion. - Motion /
animate()controls:animate()now accepts asignal: AbortSignalto cancel mid-flight and aplaybackRateoverride. NewanimateTo(element, styles, opts)ergonomic wrapper turns a CSS property record (or[from, to]tuples) into keyframes. - Motion / Springs:
spring()instances now expose.velocity(v?)and.set(v)for gesture-driven workflows. NewspringVector(dims, config)drives coordinated multi-dimensional motion.springPresetsexpands withwobbly,slow, andmolassespresets. - Motion / Timeline: Timelines now support labels (
addLabel(name, at?)+ label-relativeatstrings like'label+=200'),reverse(),playbackRate(n),repeat(count|'infinite'),yoyo(boolean),onUpdate(time)subscriptions, and aprogress()getter in[0, 1]. - Motion / New primitives:
scrollProgress(element, opts)exposes a 0..1 scroll-linked stream;inView(element, opts)resolves a thenable on enter (with an optional reactiveonChangecallback);magnetic(element, opts),tilt(element, opts),shake(element, opts),pulse(element, opts), andcountUp(element, from, to, opts)cover the micro-interaction toolkit. All effects honorprefers-reduced-motionby default. - Motion / Stagger:
stagger()gainsgrid: [cols, rows]+from: { x, y }2D origins, anaxis: 'x' | 'y'distance restriction, and a deterministicrandomoption (with optionalrandomSeed). - Motion / Reduced motion:
onReducedMotionChange(callback)subscribes to changes (system preference orsetReducedMotion()override) and returns an unsubscribe;reducedMotionSignal()exposes the same value as a reactiveReadonlySignal<boolean>forview/components. - Utils / Array (
@bquery/bquery/core): AddedgroupBy,keyBy,partition,zip,range,first,last,take,drop,sample,shuffle(Fisher–Yates),uniqueBy,sortBy(single or multi-selector),intersection,difference,flattenDeep,move, andchunkBy. - Utils / Function: Added
memoize(fn, keyFn?)(.clear()/.delete(key)),compose(...fns)/pipe(...fns),curry(fn),partial(fn, ...preset), andretry(fn, opts?)with exponential backoff, jitter,shouldRetry,onRetry, andAbortSignalsupport.debounce()gained an optional{ leading?, trailing?, maxWait? }option bag plus a.flush()method;throttle()gained{ leading?, trailing? }plus.flush(). Existing(fn, ms)signatures remain fully backward-compatible. - Utils / Object: Added prototype-pollution-safe deep accessors
get(obj, path, default?),set(obj, path, value), andhas(obj, path)with dot/bracket path syntax;mapValues,mapKeys,invert,deepEqual(withisEqualalias),freeze(deep),defaults(target, ...sources), and typed wrappersentriesTyped/keysTyped. - Utils / String: Added
toSnakeCase,toPascalCase,toTitleCase,pad,padStart,padEnd,wordCount, safetemplate(str, vars)(${name}interpolation with noeval), DOM-freestripHtml, crypto-backedrandomString(length, charset?), and universal-terminatorlines(str). - Utils / Number: Added
round(value, precision?),roundTo(value, step),lerp,inverseLerp,mapRange, locale-awareformatBytes(bytes, opts?)(decimal & binary units),randomFloat,sum,average,median,degToRad, andradToDeg. - Utils / Misc: Added RFC 4122 v4
uuid()(usescrypto.randomUUID()/getRandomValues()when available, with aMath.random()fallback), Go-style sync/asynctryCatch(fn),times(n, fn),pollUntil(predicate, opts?),nextFrame(), andnextTick(). - Utils / Type guards: Added
isError,isMap,isSet,isRegExp,isSymbol,isBigInt,isAsyncFunction,isIterable,isAsyncIterable,isNullish, andisDefined. - The
utilsnamespace andBQueryUtilsinterface include every new entry alongside the existing helpers.
Changed (1.13.0)
- Full bundle:
src/full.tsre-exports every new public forms, component, and motion runtime/type surface alongside the new core utility helpers;bun run check:full-bundlecontinues to enforce drift detection. - AI guidance: AGENT.md, llms.txt, copilot-instructions, Cursor / Cline rules, README, and CHANGELOG were refreshed for the 1.13.0 baseline.
bun run check:ai-guidancepasses.
What's Changed
- Switch documentation domain metadata to bquery.js.org by @Copilot in #98
- Version 1.13.0 by @JosunLP in #97
Full Changelog: v1.12.0...v1.13.0
Version Release 1.12.0
[1.12.0] - 2026-05-16
Added (1.12.0)
- Reactive / WebSocket: Promoted
WebSocketSendDatato a public type-only export from@bquery/bquery/reactive. The alias was previously@internaleven though it already surfaced throughUseWebSocketReturn.sendRaw,WebSocketSerializer.serialize, andWebSocketHeartbeatConfig.message. Consumers can nowimport type { WebSocketSendData } from '@bquery/bquery/reactive'to reuse the union, matching the existingServerWebSocketDataexport from@bquery/bquery/server. - Store / Plugins: Added
unregisterPlugin(plugin)andclearPlugins()to@bquery/bquery/store.unregisterPlugin()removes the first matching registration by identity and returns whether one was found;clearPlugins()empties the registry in one call. Already-created stores keep extensions that were applied before unregister; subsequentdefineStore()/createStore()calls no longer receive the removed plugins. The previously global, append-only plugin registry now has a proper teardown path for test isolation and runtime plugin reloads.
Changed (1.12.0)
- Docs / Server: Expanded the server guide with a public-surface reference, commonly used server types, null-prototype
params/querydetails, route-scoped middleware examples, custom error handling, and WebSocket middleware short-circuit behavior. Added server module export tests for the barrel, root entry point, and full bundle.
Fixed (1.12.0)
- Full bundle / Tooling:
src/full.tsnow re-exports all public type-only module exports from the platform, a11y, and media barrels, andbun run check:full-bundlenow validates runtime and type exports statically so/fulldeclaration drift is caught before release.
What's Changed
Full Changelog: v1.11.1...v1.12.0
Version 1.11.1
[1.11.1] - 2026-05-12
Changed (1.11.1)
- Tooling / Dev dependencies: Bumped
@typescript-eslint/eslint-pluginand@typescript-eslint/parserfrom8.59.1to8.59.3,eslintfrom10.2.1to10.3.0,globalsfrom17.5.0to17.6.0, andvitefrom8.0.10to8.0.12. Theviteupdate brings in the stable[email protected]release (previously1.0.0-rc.17) and[email protected].
What's Changed
- docs: repo-wide messaging update — README header redesign, centred layout, updated branding by @Copilot in #90
- Redesign README layout and update framework messaging by @JosunLP in #91
Full Changelog: v1.11.0...v1.11.1