···2020| | ✓ | [Refactor](#evaluator--binder-hardening) |
2121| v0.5.1 | ✓ | [Error Handling & Diagnostics](#error-handling--diagnostics) (partial) |
2222| v0.6.0 | | [Error Handling & Diagnostics](#error-handling--diagnostics) |
2323-| v0.7.0 | | [Bundle Size Optimization](#bundle-size-optimization) |
2424-| v0.8.0 | | [CSP Compatibility](#csp-compatibility) |
2525-| v0.9.0 | | [DOM Morphing & Streaming](#dom-morphing--streaming) |
2626-| v0.10.0 | | [Scope Inheritance & State Management](#scope-inheritance--state-management) |
2727-| v0.11.0 | | [Background Requests & Reactive Polling](#background-requests--reactive-polling) |
2828-| v0.12.0 | | [Attribute Prefix Support](#attribute-prefix-support) |
2929-| v0.13.0 | | [Persistence & Offline](#persistence--offline) (advanced features) |
3030-| v0.14.0 | | [Inspector & Developer Tools](#inspector--developer-tools) |
2323+| v0.6.0 | | [Bundle Size Optimization](#bundle-size-optimization) |
2424+| v0.6.0 | | [IIFE Build Support](#iife-build-support) |
2525+| v0.7.0 | | [Testing & Benchmarking](#testing--benchmarking) |
2626+| v0.7.0 | | [CSP Compatibility](#csp-compatibility) |
2727+| v0.8.0 | | [DOM Morphing & Streaming](#dom-morphing--streaming) |
2828+| v0.9.0 | | [Scope Inheritance & State Management](#scope-inheritance--state-management) |
2929+| v0.10.0 | | [Background Requests & Reactive Polling](#background-requests--reactive-polling) |
3030+| v0.11.0 | | [Attribute Prefix Support](#attribute-prefix-support) |
3131+| v0.12.0 | | [Persistence & Offline](#persistence--offline) (advanced features) |
3232+| v0.13.0 | | [Inspector & Developer Tools](#inspector--developer-tools) |
3133| v1.0.0 | | [Stable Release](#stable-release) |
32343335## Completed
···120122 - ✓ v0.5.1: Centralized error boundary system for directives and effects
121123 - ✓ v0.5.1: Sandbox error wrapping with contextual hints (directive name, expression, element)
122124 - ✓ v0.5.1: `$volt.report(error, context)` API for plugin and app-level reporting
123123- - v0.6.0: Enhanced console error messages with directive context
124124- - v0.6.0: Differentiated error levels: warn, error, fatal
125125- - v0.6.0: Documentation: "Understanding VoltX Errors" guide
125125+ - ✓ v0.6.0: Enhanced console error messages with directive context
126126+ - ✓ v0.6.0: Differentiated error levels: warn, error, fatal
127127+ - ✓ v0.6.0: Documentation: "Understanding VoltX Errors" guide
126128 - v0.6.0: Add error handling examples to demo
127127- - v0.14.0: Visual in-DOM error overlays for development mode
128128- - v0.14.0: Runtime health monitor tracking failures
129129- - v0.14.0: Configurable global error policy
129129+ - v0.13.0: Visual in-DOM error overlays for development mode
130130+ - v0.13.0: Runtime health monitor tracking failures
131131+ - v0.13.0: Configurable global error policy
130132131133### Persistence & Offline
132134···135137**Deliverables:**
136138 - ✓ Persistent signals (localStorage, sessionStorage, indexedDb)
137139 - ✓ Storage plugin (`data-volt-persist`)
138138- - v0.13.0: Storage modifiers on signals (`.local`, `.session`, `.ifmissing`)
139139- - v0.13.0: Sync strategy API (merge, overwrite, patch) for conflict resolution
140140- - v0.13.0: Cache invalidation strategies
141141- - v0.13.0: Offline queue for deferred stream events and HTTP requests
142142- - v0.13.0: Service Worker integration for offline-first apps
143143- - v0.13.0: Background sync for deferred requests
144144- - v0.13.0: Cross-tab synchronization via `BroadcastChannel`
140140+ - v0.12.0: Storage modifiers on signals (`.local`, `.session`, `.ifmissing`)
141141+ - v0.12.0: Sync strategy API (merge, overwrite, patch) for conflict resolution
142142+ - v0.12.0: Cache invalidation strategies
143143+ - v0.12.0: Offline queue for deferred stream events and HTTP requests
144144+ - v0.12.0: Service Worker integration for offline-first apps
145145+ - v0.12.0: Background sync for deferred requests
146146+ - v0.12.0: Cross-tab synchronization via `BroadcastChannel`
145147146148### Bundle Size Optimization
147149148150**Goal:** Reduce bundle size to <15KB gzipped while maintaining full feature set.
149151**Outcome:** Lightweight runtime footprint with comprehensive declarative capabilities.
150152**Deliverables:**
151151- - v0.7.0: Audit and tree-shake unused code paths
152152- - v0.7.0: Optimize evaluator and binder implementations
153153- - v0.7.0: Minimize plugin footprint, ensure lazy loading
154154- - v0.7.0: Refactor expression compiler for smaller output
155155- - v0.7.0: Compress constant strings and reduce runtime helpers
156156- - v0.7.0: Optimize signal subscription management
157157- - v0.7.0: Production mode stripping (remove dev-only error messages)
158158- - v0.7.0: Aggressive minification pipeline tuning
159159- - v0.7.0: Target: <15KB gzipped sustained
153153+ - v0.6.0: Audit and tree-shake unused code paths
154154+ - v0.6.0: Optimize evaluator and binder implementations
155155+ - v0.6.0: Minimize plugin footprint, ensure lazy loading
156156+ - v0.6.0: Refactor expression compiler for smaller output
157157+ - v0.6.0: Compress constant strings and reduce runtime helpers
158158+ - v0.6.0: Optimize signal subscription management
159159+ - v0.6.0: Production mode stripping (remove dev-only error messages)
160160+ - v0.6.0: Aggressive minification pipeline tuning
161161+ - v0.6.0: Target: <15KB gzipped sustained
162162+163163+### IIFE Build Support
164164+165165+**Goal:** Provide an IIFE build target for VoltX.js to support direct `<script>` tag usage without module systems.
166166+**Outcome:** VoltX.js can be used via CDN without build tools or module bundlers.
167167+**Deliverables:**
168168+ - v0.6.0: IIFE build output (voltx.iife.js) alongside ESM build
169169+ - v0.6.0: Global `Volt` namespace for browser environments
170170+ - v0.6.0: CDN-friendly distribution (unpkg, jsdelivr)
171171+ - v0.6.0: Update build pipeline to generate IIFE bundle
172172+ - v0.6.0: Document usage: `<script src="voltx.iife.min.js"></script>`
173173+ - v0.6.0: Ensure plugins work with IIFE build
174174+ - v0.6.0: Add IIFE examples to documentation
175175+176176+### Testing & Benchmarking
177177+178178+**Goal:** Establish comprehensive testing infrastructure and performance benchmarking.
179179+**Outcome:** VoltX.js has rigorous end-to-end testing and quantifiable performance metrics against competing frameworks.
180180+**Deliverables:**
181181+ - v0.7.0: Playwright-based integration test suite for real browser testing
182182+ - v0.7.0: End-to-end tests for all core directives and plugins
183183+ - v0.7.0: Cross-browser compatibility tests (Chrome, Firefox, Safari)
184184+ - v0.7.0: Memory usage and leak detection benchmarks
185185+ - v0.7.0: Bundle size tracking and regression detection
186186+ - v0.7.0: Reactivity performance benchmarks (signal updates, computed chains, effect execution)
187187+ - v0.7.0: DOM update performance benchmarks
188188+ - v0.7.0: CI integration for automated benchmark runs and regression alerts
160189161190### CSP Compatibility
162191163192**Goal:** Make VoltX.js Content Security Policy compliant without 'unsafe-eval'.
164193**Outcome:** VoltX.js can run in strict CSP environments (no Function constructor).
165194**Deliverables:**
166166- - v0.8.0: Research and design CSP-safe evaluator architecture
167167- - v0.8.0: Evaluate trade-offs: AST interpreter vs limited expression subset
168168- - v0.8.0: Implement CSP-safe expression evaluator (AST-based or restricted syntax)
169169- - v0.8.0: Maintain expression feature parity where possible
170170- - v0.8.0: Fallback mode detection for environments requiring CSP
171171- - v0.8.0: Full test coverage for CSP mode
172172- - v0.8.0: Documentation on CSP limitations and alternatives
173173- - v0.8.0: Bundle split: standard build vs CSP build
195195+ - v0.7.0: Research and design CSP-safe evaluator architecture
196196+ - v0.7.0: Evaluate trade-offs: AST interpreter vs limited expression subset
197197+ - v0.7.0: Implement CSP-safe expression evaluator (AST-based or restricted syntax)
198198+ - v0.7.0: Maintain expression feature parity where possible
199199+ - v0.7.0: Fallback mode detection for environments requiring CSP
200200+ - v0.7.0: Full test coverage for CSP mode
201201+ - v0.7.0: Documentation on CSP limitations and alternatives
202202+ - v0.7.0: Bundle split: standard build vs CSP build
174203175204### DOM Morphing & Streaming
176205177206**Goal:** Add intelligent DOM morphing and Server-Sent Events for real-time updates.
178207**Outcome:** Built-in morphing and SSE streaming for seamless server-driven UI updates.
179208**Deliverables:**
180180- - v0.9.0: Integrate Idiomorph or implement lightweight morphing algorithm
181181- - v0.9.0: `data-volt-morph` attribute for morphing-based swaps
182182- - v0.9.0: Preserve focus, scroll, and input state during morphs
183183- - v0.9.0: Server-Sent Events (SSE) integration
184184- - v0.9.0: `data-volt-stream` attribute for SSE endpoints
185185- - v0.9.0: Automatic reconnection with exponential backoff
186186- - v0.9.0: Signal patching from backend SSE events
187187- - v0.9.0: JSON Patch support for partial updates
188188- - v0.9.0: `data-volt-ignore-morph` for selective exclusion
189189- - v0.9.0: WebSocket as alternative to SSE
190190- - v0.9.0: Unified streaming API across SSE/WebSocket
209209+ - v0.8.0: Integrate Idiomorph or implement lightweight morphing algorithm
210210+ - v0.8.0: `data-volt-morph` attribute for morphing-based swaps
211211+ - v0.8.0: Preserve focus, scroll, and input state during morphs
212212+ - v0.8.0: Server-Sent Events (SSE) integration
213213+ - v0.8.0: `data-volt-stream` attribute for SSE endpoints
214214+ - v0.8.0: Automatic reconnection with exponential backoff
215215+ - v0.8.0: Signal patching from backend SSE events
216216+ - v0.8.0: JSON Patch support for partial updates
217217+ - v0.8.0: `data-volt-ignore-morph` for selective exclusion
218218+ - v0.8.0: WebSocket as alternative to SSE
219219+ - v0.8.0: Unified streaming API across SSE/WebSocket
191220192221### Scope Inheritance & State Management
193222194223**Goal:** Improve data scoping with optional inheritance for ergonomic nested components.
195224**Outcome:** Flexible scoping patterns for complex component hierarchies.
196225**Deliverables:**
197197- - v0.10.0: Optional scope inheritance via `data-volt-scope="inherit"`
198198- - v0.10.0: Child scopes inherit parent signals with override capability
199199- - v0.10.0: $parent accessor for explicit parent scope access
200200- - v0.10.0: Scoped context providers for dependency injection
201201- - v0.10.0: Enhanced $store with namespacing and modules
202202- - v0.10.0: Cross-scope signal sharing patterns
226226+ - v0.9.0: Optional scope inheritance via `data-volt-scope="inherit"`
227227+ - v0.9.0: Child scopes inherit parent signals with override capability
228228+ - v0.9.0: $parent accessor for explicit parent scope access
229229+ - v0.9.0: Scoped context providers for dependency injection
230230+ - v0.9.0: Enhanced $store with namespacing and modules
231231+ - v0.9.0: Cross-scope signal sharing patterns
203232204233### Background Requests & Reactive Polling
205234206235**Goal:** Enable declarative background data fetching and periodic updates.
207236**Outcome:** VoltX.js elements can fetch or refresh data automatically based on time, visibility, or reactive conditions.
208237**Deliverables:**
209209- - v0.11.0: `data-volt-visible` for fetching when element enters viewport (IntersectionObserver)
210210- - v0.11.0: `data-volt-poll` attribute for periodic background requests
211211- - v0.11.0: Configurable intervals, delays, and signal-based triggers
212212- - v0.11.0: Automatic cancellation when elements unmount
213213- - v0.11.0: Conditional polling tied to reactive signals
214214- - v0.11.0: Background task scheduler with priority management
238238+ - v0.10.0: `data-volt-visible` for fetching when element enters viewport (IntersectionObserver)
239239+ - v0.10.0: `data-volt-poll` attribute for periodic background requests
240240+ - v0.10.0: Configurable intervals, delays, and signal-based triggers
241241+ - v0.10.0: Automatic cancellation when elements unmount
242242+ - v0.10.0: Conditional polling tied to reactive signals
243243+ - v0.10.0: Background task scheduler with priority management
215244216245### Attribute Prefix Support
217246218247**Goal:** Support multiple attribute prefix options for developer preference.
219248**Outcome:** VoltX.js supports `voltx-`, `vx-`, and `data-volt-` prefixes.
220249**Deliverables:**
221221- - v0.12.0: Add support for `voltx-*` and `vx-*` attribute prefixes
222222- - v0.12.0: Recommend `vx-*` as primary in documentation
223223- - v0.12.0: Maintain backward compatibility with `data-volt-*`
224224- - v0.12.0: Update demo to use recommended prefix
250250+ - v0.11.0: Add support for `voltx-*` and `vx-*` attribute prefixes
251251+ - v0.11.0: Recommend `vx-*` as primary in documentation
252252+ - v0.11.0: Maintain backward compatibility with `data-volt-*`
253253+ - v0.11.0: Update demo to use recommended prefix
225254226255### Inspector & Developer Tools
227256228257**Goal:** Improve developer experience and runtime introspection.
229258**Outcome:** First-class developer ergonomics; VoltX.js is enjoyable to debug and extend.
230259**Deliverables:**
231231- - v0.14.0: Visual in-DOM error overlays for development mode
232232- - v0.14.0: Runtime health monitor tracking failures
233233- - v0.14.0: Configurable global error policy (silent, overlay, throw)
234234- - v0.14.0: Developer overlay for inspecting signals, subscriptions, and effects
235235- - v0.14.0: Time-travel debugging for signal history
236236- - v0.14.0: Signal dependency graph visualization
237237- - v0.14.0: Performance profiling tools
238238- - v0.14.0: Browser console integration (`window.$volt.inspect()`)
239239- - v0.14.0: Dev logging toggle (`Volt.debug = true`)
240240- - v0.14.0: Request/response debugging (HTTP actions, SSE streams)
241241- - v0.14.0: Browser DevTools extension with full integration
260260+ - v0.13.0: Visual in-DOM error overlays for development mode
261261+ - v0.13.0: Runtime health monitor tracking failures
262262+ - v0.13.0: Configurable global error policy (silent, overlay, throw)
263263+ - v0.13.0: Developer overlay for inspecting signals, subscriptions, and effects
264264+ - v0.13.0: Time-travel debugging for signal history
265265+ - v0.13.0: Signal dependency graph visualization
266266+ - v0.13.0: Performance profiling tools
267267+ - v0.13.0: Browser console integration (`window.$volt.inspect()`)
268268+ - v0.13.0: Dev logging toggle (`Volt.debug = true`)
269269+ - v0.13.0: Request/response debugging (HTTP actions, SSE streams)
270270+ - v0.13.0: Browser DevTools extension with full integration
242271243272### Stable Release
244273···254283 - Community contribution guide & governance doc
255284256285## Parking Lot
257257-258258-### IIFE Build Support
259259-260260-Provide an IIFE (Immediately Invoked Function Expression) build target for VoltX.js to support direct `<script>` tag usage without module systems.
261261-262262-**Deliverables:**
263263-264264-- IIFE build output (voltx.iife.js) alongside ESM build
265265-- Global `Volt` namespace for browser environments
266266-- CDN-friendly distribution (unpkg, jsdelivr)
267267-- Update build pipeline to generate IIFE bundle
268268-- Document usage: `<script src="voltx.iife.min.js"></script>`
269269-- Ensure plugins work with IIFE build
270270-- Add IIFE examples to documentation
271286272287### Evaluator & Binder Hardening
273288
+1-45
docs/cli.md
···99The CLI is available as `create-voltx` on npm:
10101111```bash
1212-# Use with pnpm (recommended)
1212+# Use with pnpm
1313pnpm create voltx my-app
14141515# Use with npm
···242242- Event handlers
243243- Counter example
244244245245-Best for: Learning VoltX.js basics, simple interactive pages.
246246-247245### With Router
248246249247A multi-page application featuring:
···252250- Multiple routes (home, about, contact, 404)
253251- Navigation with `data-volt-navigate`
254252- Route matching with `data-volt-url`
255255-256256-Best for: Multi-page applications, documentation sites, dashboards.
257253258254### With Plugins
259255···274270- VoltX.js CSS utilities
275271- Semantic HTML
276272- No JavaScript required
277277-278278-Best for: Static sites, progressively enhanced pages, CSS-only projects.
279273280274## Configuration
281275···287281import { defineConfig } from 'vite';
288282289283export default defineConfig({
290290- // Custom Vite configuration
291284 server: {
292285 port: 3000,
293286 },
···298291```
299292300293See the [Vite documentation](https://vitejs.dev/config/) for all available options.
301301-302302-## Troubleshooting
303303-304304-### Dev Server Won't Start
305305-306306-Ensure you're in a VoltX.js project directory with an `index.html` file:
307307-308308-```bash
309309-ls index.html
310310-```
311311-312312-If `index.html` is missing, you may not be in a VoltX.js project.
313313-314314-### Download Fails
315315-316316-Check your internet connection and try again. The CLI downloads assets from:
317317-318318-```text
319319-https://cdn.jsdelivr.net/npm/voltx.js@{version}/dist/
320320-```
321321-322322-If jsDelivr is blocked, manually download from the [npm package](https://www.npmjs.com/package/voltx.js).
323323-324324-### Build Fails
325325-326326-Ensure all dependencies are installed:
327327-328328-```bash
329329-pnpm install
330330-```
331331-332332-Check for syntax errors in your HTML, CSS, or JavaScript files.
333333-334334-## Next Steps
335335-336336-- Read the [Installation Guide](./installation) for framework setup
337337-- Explore [Usage Patterns](./usage/state) for state management
+201
docs/usage/error-handling.md
···11+# Error Handling
22+33+⚠️ Named error classes and enhanced error handling are unreleased as of writing. This documentation describes features planned for v0.6.0.
44+55+VoltX categorizes all errors by source and severity, wrapping them in named error classes with rich debugging context. This system enables precise error identification, flexible handling strategies, and seamless integration with logging services.
66+77+## Error Types
88+99+Each error source maps to a specific error class:
1010+1111+| Identifier | Source | Cause |
1212+| ---------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------- |
1313+| `EvaluatorError` | `evaluator` | Expression evaluation fails in directives (`data-volt-text`, `data-volt-if`, etc.) or computed values |
1414+| `BindingError` | `binding` | Directive setup or execution fails (`data-volt-model` with missing signal, invalid `data-volt-for` syntax, missing parent elements) |
1515+| `EffectError` | `effect` | Effect callbacks, computed signals, or async effects fail during execution or cleanup |
1616+| `HttpError` | `http` | HTTP directives encounter network errors, invalid swap strategies, missing target elements, or parsing failures |
1717+| `PluginError` | `plugin` | Custom plugin handlers fail during initialization or execution |
1818+| `LifecycleError` | `lifecycle` | Lifecycle hooks (`beforeMount`, `afterMount`, `onMount`, etc.) fail during execution |
1919+| `ChargeError` | `charge` | `charge()` encounters invalid `data-volt-state` JSON, malformed configuration, or initialization errors |
2020+| `UserError` | `user` | User code explicitly reports errors via `report()` |
2121+2222+All error classes extend `VoltError` and set their `name` property accordingly (e.g., `error.name === "HttpError"`).
2323+2424+## Severity Levels
2525+2626+Errors have three severity levels that control console output and execution flow:
2727+2828+**warn** — Non-critical issues logged via `console.warn`. Execution continues. Use for deprecations, missing optional features, or recoverable configuration issues.
2929+3030+**error** (default) — Recoverable errors logged via `console.error`. Execution continues but the specific operation fails. Most runtime errors use this level.
3131+3232+**fatal** — Unrecoverable errors logged via `console.error` and then thrown, halting execution. Reserve for critical initialization failures or corrupted state.
3333+3434+## Error Context
3535+3636+Every VoltX error includes contextual metadata for debugging:
3737+3838+```ts
3939+interface VoltError {
4040+ name: string; // Error class name
4141+ source: ErrorSource; // Error category
4242+ level: ErrorLevel; // Severity level
4343+ directive?: string; // Failed directive (e.g., "data-volt-text")
4444+ expression?: string; // Failed expression
4545+ element?: HTMLElement; // DOM element where error occurred
4646+ cause: Error; // Original wrapped error
4747+ timestamp: number; // Unix timestamp (ms)
4848+ context: ErrorContext; // Full context including custom properties
4949+5050+ // HTTP errors only
5151+ httpMethod?: string;
5252+ httpUrl?: string;
5353+ httpStatus?: number;
5454+5555+ // Plugin errors only
5656+ pluginName?: string;
5757+5858+ // Lifecycle errors only
5959+ hookName?: string;
6060+}
6161+```
6262+6363+## Handling Errors
6464+6565+### Registration
6666+6767+Register global error handlers with `onError()`. Handlers execute in registration order and receive all errors:
6868+6969+```ts
7070+import { onError } from "voltx.js";
7171+7272+const cleanup = onError((error) => {
7373+ analytics.track("error", error.toJSON());
7474+7575+ if (error instanceof HttpError) {
7676+ showToast(`Request failed: ${error.cause.message}`);
7777+ }
7878+});
7979+8080+// Cleanup when done
8181+cleanup();
8282+```
8383+8484+### Propagation Control
8585+8686+Call `error.stopPropagation()` to prevent subsequent handlers from running:
8787+8888+```ts
8989+onError((error) => {
9090+ if (error.source === "http") {
9191+ handleHttpError(error);
9292+ error.stopPropagation();
9393+ }
9494+});
9595+9696+// This handler won't run for HTTP errors
9797+onError((error) => logToConsole(error));
9898+```
9999+100100+### Cleanup
101101+102102+Remove handlers individually via their cleanup function or clear all handlers with `clearErrorHandlers()`.
103103+104104+## Console Fallback
105105+106106+When no handlers are registered, errors log to console based on severity (`console.warn` for warn, `console.error` for error/fatal) with formatted context:
107107+108108+```text
109109+[ERROR] [evaluator] Cannot read property 'foo' of undefined | Directive: data-volt-text | Expression: user.foo | Element: <div#app>
110110+Caused by: TypeError: Cannot read property 'foo' of undefined
111111+Element: <div id="app">...</div>
112112+```
113113+114114+Fatal errors throw after logging.
115115+116116+## Reporting Errors
117117+118118+Report errors from user code using `report(error, context)`:
119119+120120+```ts
121121+import { report } from "voltx.js";
122122+123123+try {
124124+ processForm(formElement);
125125+} catch (error) {
126126+ report(error as Error, {
127127+ source: "user",
128128+ level: "warn",
129129+ element: formElement as HTMLElement,
130130+ formId: formElement.id,
131131+ });
132132+}
133133+```
134134+135135+The `context` object accepts any custom properties beyond the standard fields.
136136+137137+## Serialization
138138+139139+All VoltX errors implement `toJSON()` for serialization to logging services or error tracking systems.
140140+141141+### Schema
142142+143143+```ts
144144+interface SerializedVoltError {
145145+ /** Error class name (e.g., "EvaluatorError", "HttpError") */
146146+ name: string;
147147+ /** Full formatted error message with context */
148148+ message: string;
149149+ /** Error source category */
150150+ source:
151151+ | "evaluator"
152152+ | "binding"
153153+ | "effect"
154154+ | "http"
155155+ | "plugin"
156156+ | "lifecycle"
157157+ | "charge"
158158+ | "user";
159159+160160+ /** Severity level */
161161+ level: "warn" | "error" | "fatal";
162162+ /** Directive name (e.g., "data-volt-text") */
163163+ directive?: string;
164164+ /** Expression that failed */
165165+ expression?: string;
166166+ /** Unix timestamp in milliseconds */
167167+ timestamp: number;
168168+ /** Full error context including custom properties */
169169+ context: {
170170+ source: string;
171171+ level?: string;
172172+ element?: HTMLElement;
173173+ directive?: string;
174174+ expression?: string;
175175+ pluginName?: string;
176176+ httpMethod?: string;
177177+ httpUrl?: string;
178178+ httpStatus?: number;
179179+ hookName?: string;
180180+ [key: string]: unknown;
181181+ };
182182+ /** Original error that was wrapped */
183183+ cause: { name: string; message: string; stack?: string; };
184184+ /** VoltX error stack trace */
185185+ stack?: string;
186186+}
187187+```
188188+189189+### Usage
190190+191191+```ts
192192+import { onError } from "voltx.js";
193193+194194+onError((error) => {
195195+ fetch("/api/errors", {
196196+ method: "POST",
197197+ headers: { "Content-Type": "application/json" },
198198+ body: JSON.stringify(error.toJSON()),
199199+ });
200200+});
201201+```
+9-1
lib/src/core/charge.ts
···8888 if (typeof stateData !== "object" || isNil(stateData) || Array.isArray(stateData)) {
8989 report(new Error(`data-volt-state must be a JSON object, got ${typeof stateData}`), {
9090 source: "charge",
9191+ level: "fatal",
9192 element: el as HTMLElement,
9293 directive: "data-volt-state",
9394 expression: stateAttr,
···100101 } catch (error) {
101102 report(error as Error, {
102103 source: "charge",
104104+ level: "fatal",
103105 element: el as HTMLElement,
104106 directive: "data-volt-state",
105107 expression: stateAttr,
···143145 if (typeof data !== "object" || isNil(data) || Array.isArray(data)) {
144146 report(new Error(`data-volt-store script must contain a JSON object, got: ${typeof data}`), {
145147 source: "charge",
148148+ level: "fatal",
146149 element: script as HTMLElement,
147150 directive: "data-volt-store",
148151 });
···151154152155 registerStore(data);
153156 } catch (error) {
154154- report(error as Error, { source: "charge", element: script as HTMLElement, directive: "data-volt-store" });
157157+ report(error as Error, {
158158+ source: "charge",
159159+ level: "fatal",
160160+ element: script as HTMLElement,
161161+ directive: "data-volt-store",
162162+ });
155163 }
156164 }
157165}
+183-32
lib/src/core/error.ts
···66 *
77 * @module core/error
88 */
99-import type { ErrorContext, ErrorHandler, ErrorSource } from "$types/volt";
99+import type { ErrorContext, ErrorHandler, ErrorLevel, ErrorSource } from "$types/volt";
10101111/**
1212- * Enhanced error class with VoltX context
1212+ * Base error class with VoltX context
1313 *
1414- * Wraps original errors with rich debugging information including
1515- * source, element, directive, and expression details.
1414+ * Wraps original errors with rich debugging information including ource, element, directive, and expression details.
1615 */
1716export class VoltError extends Error {
1817 /** Error source category */
1918 public readonly source: ErrorSource;
1919+ /** Error severity level */
2020+ public readonly level: ErrorLevel;
2021 /** DOM element where error occurred */
2122 public readonly element?: HTMLElement;
2223 /** Directive name */
···3839 this.name = "VoltError";
3940 this.cause = cause;
4041 this.source = context.source;
4242+ this.level = context.level ?? "error";
4143 this.element = context.element;
4244 this.directive = context.directive;
4345 this.expression = context.expression;
···4749 // V8-specific feature
4850 // See: https://github.com/microsoft/TypeScript/issues/3926
4951 if ((Error as any).captureStackTrace) {
5050- (Error as any).captureStackTrace(this, VoltError);
5252+ (Error as any).captureStackTrace(this, this.constructor);
5153 }
5254 }
5355···67696870 private static buildMessage(cause: Error, context: ErrorContext): string {
6971 const parts: string[] = [];
7272+ const level = context.level ?? "error";
70737171- parts.push(`[${context.source}] ${cause.message}`);
7474+ parts.push(`[${level.toUpperCase()}] [${context.source}] ${cause.message}`);
72757376 if (context.directive) {
7477 parts.push(`Directive: ${context.directive}`);
···112115 name: this.name,
113116 message: this.message,
114117 source: this.source,
118118+ level: this.level,
115119 directive: this.directive,
116120 expression: this.expression,
117121 timestamp: this.timestamp,
···123127}
124128125129/**
130130+ * Error during expression evaluation
131131+ *
132132+ * Thrown when evaluating expressions in directives like data-volt-text, data-volt-if, or any other binding that uses the expression evaluator.
133133+ */
134134+export class EvaluatorError extends VoltError {
135135+ constructor(cause: Error, context: ErrorContext) {
136136+ super(cause, { ...context, source: "evaluator" });
137137+ this.name = "EvaluatorError";
138138+ }
139139+}
140140+141141+/**
142142+ * Error during directive binding
143143+ *
144144+ * Thrown when setting up or executing DOM bindings like data-volt-text, data-volt-class, data-volt-model, etc.
145145+ */
146146+export class BindingError extends VoltError {
147147+ constructor(cause: Error, context: ErrorContext) {
148148+ super(cause, { ...context, source: "binding" });
149149+ this.name = "BindingError";
150150+ }
151151+}
152152+153153+/**
154154+ * Error during effect execution
155155+ *
156156+ * Thrown when effects, computed signals, or async effects fail during execution or cleanup.
157157+ */
158158+export class EffectError extends VoltError {
159159+ constructor(cause: Error, context: ErrorContext) {
160160+ super(cause, { ...context, source: "effect" });
161161+ this.name = "EffectError";
162162+ }
163163+}
164164+165165+/**
166166+ * Error during HTTP operations
167167+ *
168168+ * Thrown when HTTP directives (data-volt-get, data-volt-post, etc.) encounter network errors, parsing failures, or swap strategy issues.
169169+ */
170170+export class HttpError extends VoltError {
171171+ constructor(cause: Error, context: ErrorContext) {
172172+ super(cause, { ...context, source: "http" });
173173+ this.name = "HttpError";
174174+ }
175175+}
176176+177177+/**
178178+ * Error in plugin execution
179179+ *
180180+ * Thrown when custom plugins registered via registerPlugin fail during initialization or execution.
181181+ */
182182+export class PluginError extends VoltError {
183183+ constructor(cause: Error, context: ErrorContext) {
184184+ super(cause, { ...context, source: "plugin" });
185185+ this.name = "PluginError";
186186+ }
187187+}
188188+189189+/**
190190+ * Error in lifecycle hooks
191191+ *
192192+ * Thrown when lifecycle hooks (beforeMount, afterMount, onMount, etc.) fail during execution.
193193+ */
194194+export class LifecycleError extends VoltError {
195195+ constructor(cause: Error, context: ErrorContext) {
196196+ super(cause, { ...context, source: "lifecycle" });
197197+ this.name = "LifecycleError";
198198+ }
199199+}
200200+201201+/**
202202+ * Error during charge/initialization
203203+ *
204204+ * Thrown when charge() encounters errors during auto-discovery and mounting of [data-volt] elements, or when parsing data-volt-state.
205205+ */
206206+export class ChargeError extends VoltError {
207207+ constructor(cause: Error, context: ErrorContext) {
208208+ super(cause, { ...context, source: "charge" });
209209+ this.name = "ChargeError";
210210+ }
211211+}
212212+213213+/**
214214+ * User-triggered error
215215+ *
216216+ * Errors explicitly reported by user code via the report() function
217217+ * with source: "user".
218218+ */
219219+export class UserError extends VoltError {
220220+ constructor(cause: Error, context: ErrorContext) {
221221+ super(cause, { ...context, source: "user" });
222222+ this.name = "UserError";
223223+ }
224224+}
225225+226226+/**
126227 * Global error handler registry
127228 */
128229let errorHandlers: ErrorHandler[] = [];
···131232 * Register an error handler
132233 *
133234 * Multiple handlers can be registered and will be called in registration order.
134134- * Handlers can call `error.stopPropagation()` to prevent subsequent handlers
135135- * from being called.
235235+ * Handlers can call `error.stopPropagation()` to prevent subsequent handlers from being called.
136236 *
137237 * @param handler - Error handler function
138238 * @returns Cleanup function to unregister the handler
···183283 * If no error handlers are registered, errors are logged to console as fallback.
184284 * Once handlers are registered, console logging is disabled.
185285 *
286286+ * Error levels determine console output and behavior:
287287+ * - warn: Non-critical issues logged with console.warn
288288+ * - error: Recoverable errors logged with console.error (default)
289289+ * - fatal: Unrecoverable errors logged with console.error and thrown to halt execution
290290+ *
186291 * @param error - Error to report (can be Error, unknown, or string)
187292 * @param context - Error context with source and additional details
188293 *
189294 * @example
190295 * ```ts
191191- * // Internal usage (by VoltX)
192192- * try {
193193- * evaluate(expression, scope);
194194- * } catch (err) {
195195- * report(err, {
196196- * source: ErrorSource.Evaluator,
197197- * element: ctx.element,
198198- * directive: 'data-volt-text',
199199- * expression: expression
200200- * });
201201- * }
296296+ * // Warning for non-critical issues
297297+ * report(err, {
298298+ * source: "binding",
299299+ * level: "warn",
300300+ * directive: "data-volt-deprecated"
301301+ * });
202302 *
203203- * // External usage (by plugins/apps)
204204- * try {
205205- * myCustomLogic();
206206- * } catch (err) {
207207- * report(err, {
208208- * source: ErrorSource.User,
209209- * customContext: 'My feature failed'
210210- * });
211211- * }
303303+ * // Error for recoverable issues (default)
304304+ * report(err, {
305305+ * source: "evaluator",
306306+ * level: "error",
307307+ * directive: "data-volt-text",
308308+ * expression: expression
309309+ * });
310310+ *
311311+ * // Fatal error that halts execution
312312+ * report(err, {
313313+ * source: "charge",
314314+ * level: "fatal",
315315+ * directive: "data-volt-state"
316316+ * });
212317 * ```
213318 */
214319export function report(error: unknown, context: ErrorContext): void {
215320 const errorObj = error instanceof Error ? error : new Error(String(error));
216216- const voltError = new VoltError(errorObj, context);
321321+322322+ const voltError = createErrorBySource(errorObj, context);
217323218324 if (errorHandlers.length === 0) {
219219- console.error(voltError.message);
220220- console.error("Caused by:", voltError.cause);
325325+ const logFn = voltError.level === "warn" ? console.warn : console.error;
326326+327327+ logFn(voltError.message);
328328+ logFn("Caused by:", voltError.cause);
221329 if (voltError.element) {
222222- console.error("Element:", voltError.element);
330330+ logFn("Element:", voltError.element);
331331+ }
332332+333333+ if (voltError.level === "fatal") {
334334+ throw voltError;
223335 }
224336 return;
225337 }
···232344 }
233345 } catch (handlerError) {
234346 console.error("Error in error handler:", handlerError);
347347+ }
348348+ }
349349+350350+ if (voltError.level === "fatal") {
351351+ throw voltError;
352352+ }
353353+}
354354+355355+/**
356356+ * Create the appropriate error type based on the source
357357+ */
358358+function createErrorBySource(cause: Error, context: ErrorContext): VoltError {
359359+ switch (context.source) {
360360+ case "evaluator": {
361361+ return new EvaluatorError(cause, context);
362362+ }
363363+ case "binding": {
364364+ return new BindingError(cause, context);
365365+ }
366366+ case "effect": {
367367+ return new EffectError(cause, context);
368368+ }
369369+ case "http": {
370370+ return new HttpError(cause, context);
371371+ }
372372+ case "plugin": {
373373+ return new PluginError(cause, context);
374374+ }
375375+ case "lifecycle": {
376376+ return new LifecycleError(cause, context);
377377+ }
378378+ case "charge": {
379379+ return new ChargeError(cause, context);
380380+ }
381381+ case "user": {
382382+ return new UserError(cause, context);
383383+ }
384384+ default: {
385385+ return new VoltError(cause, context);
235386 }
236387 }
237388}
+2
lib/src/core/http.ts
···231231 default: {
232232 report(new Error(`Unknown swap strategy: ${strategy as string}`), {
233233 source: "http",
234234+ level: "warn",
234235 element: target as HTMLElement,
235236 });
236237 }
···510511 if (!target) {
511512 report(new Error(`Target element not found: ${targetConf}`), {
512513 source: "http",
514514+ level: "warn",
513515 element: defaultEl as HTMLElement,
514516 directive: "data-volt-target",
515517 });
+15-2
lib/src/index.ts
···77export { asyncEffect } from "$core/async-effect";
88export { mount } from "$core/binder";
99export { charge } from "$core/charge";
1010-export { clearErrorHandlers, onError, report } from "$core/error";
1111-export type { VoltError } from "$core/error";
1010+export {
1111+ BindingError,
1212+ ChargeError,
1313+ clearErrorHandlers,
1414+ EffectError,
1515+ EvaluatorError,
1616+ HttpError,
1717+ LifecycleError,
1818+ onError,
1919+ PluginError,
2020+ report,
2121+ UserError,
2222+ VoltError,
2323+} from "$core/error";
1224export { parseHttpConfig, request, serializeForm, serializeFormToJSON, swap } from "$core/http";
1325export {
1426 clearAllGlobalHooks,
···8698 ComputedSignal,
8799 ErrorContext,
88100 ErrorHandler,
101101+ ErrorLevel,
89102 ErrorSource,
90103 GlobalHookName,
91104 GlobalStore,
+11
lib/src/types/volt.d.ts
···559559export type ErrorSource = "evaluator" | "binding" | "effect" | "http" | "plugin" | "lifecycle" | "charge" | "user";
560560561561/**
562562+ * Error severity level
563563+ *
564564+ * - `warn`: Non-critical issues that don't prevent operation (e.g., deprecated usage, missing optional features)
565565+ * - `error`: Recoverable errors that prevent specific operations (e.g., failed evaluations, missing elements)
566566+ * - `fatal`: Unrecoverable errors that should halt execution (e.g., critical initialization failures)
567567+ */
568568+export type ErrorLevel = "warn" | "error" | "fatal";
569569+570570+/**
562571 * Context information for error reporting
563572 */
564573export type ErrorContext = {
565574 /** Error source category */
566575 source: ErrorSource;
576576+ /** Error severity level (defaults to "error") */
577577+ level?: ErrorLevel;
567578 /** DOM element where error occurred */
568579 element?: HTMLElement;
569580 /** Directive name (e.g., "data-volt-text", "data-volt-on-click") */