npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@faultsense/agent

v0.5.5

Published

A Framework & Language Agnostic Application Feature Monitor for the Frontend

Readme

E2E Test Assertions That Run Against Real Users

Faultsense is a lightweight (8.7 KB gzipped) browser agent that validates feature correctness in production. Your AI coding assistant instruments the assertions — the same reasoning it uses to write Playwright or Cypress tests — and real user sessions validate them.

<button
  fs-assert="checkout/submit-order"
  fs-trigger="click"
  fs-assert-added-success=".order-confirmation"
  fs-assert-added-error=".error-message[text-matches=try again]">
  Place Order
</button>

When a user clicks Place Order: if the order confirmation appears, the success condition passes. If an error message appears instead, the error condition passes. If neither happens, Faultsense reports a failure — which assertion, which release, what went wrong.

Quick Start

Installation via CDN

<script
  defer
  id="fs-agent"
  src="https://cdn.faultsense.com/v0/faultsense-agent.min.js"
  data-release-label="0.0.0"
  data-collector-url="console"
  data-debug="true"
></script>

Pin to an exact version for production by swapping v0 for the specific semver (e.g. v0.5.0).

Or initialize manually:

<script defer src="https://cdn.faultsense.com/v0/faultsense-console.min.js"></script>
<script defer src="https://cdn.faultsense.com/v0/faultsense-agent.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
  Faultsense.init({
    releaseLabel: '0.0.0',
    collectorURL: Faultsense.collectors.console,
    debug: true
  });
});
</script>

Installation via npm

npm install @faultsense/agent @faultsense/console-collector
import { init } from '@faultsense/agent';
import { consoleCollector } from '@faultsense/console-collector';

init({
  releaseLabel: '0.0.0',
  collectorURL: consoleCollector,
  debug: true,
});

Tell Your AI to Instrument

Ask your AI coding assistant to add Faultsense assertions to a component. It already knows how — same reasoning as writing E2E tests.

"Add faultsense assertions to the checkout form component"

The AI reads your component, understands what should happen when users interact with it, and generates the fs-* attributes.

Claude Code Plugin

Install the Faultsense skill for Claude Code:

claude plugin add Faultsense/faultsense-agent

Then ask Claude to instrument any component — the skill provides the full API reference and instrumentation patterns.

How It Works

Every assertion needs three things:

  1. A keyfs-assert="checkout/submit-order" identifies this assertion
  2. A triggerfs-trigger="click" defines when the assertion activates
  3. An expected outcomefs-assert-added=".success" defines what should happen

Assertion Types

Value is a CSS selector, optionally with inline modifiers in brackets.

| Attribute | Resolves when | |---|---| | fs-assert-added="<selector>" | Element appears in the DOM | | fs-assert-removed="<selector>" | Element is removed from the DOM | | fs-assert-updated="<selector>" | Element or subtree is mutated | | fs-assert-visible="<selector>" | Element exists and is visible | | fs-assert-hidden="<selector>" | Element exists but is hidden | | fs-assert-loaded="<selector>" | Media element finishes loading | | fs-assert-stable="<selector>" | Element is NOT mutated during timeout window | | fs-assert-emitted="<event>" | CustomEvent fires on document | | fs-assert-after="<key>" | Parent assertion(s) have already passed |

Conditional Assertions

Handle multiple outcomes from a single action using condition keys:

<button fs-assert="auth/login" fs-trigger="click"
  fs-assert-added-success=".dashboard"
  fs-assert-added-error=".error-msg">Login</button>

First condition to match wins, others are dismissed. No server-side integration needed — the UI is the signal.

For cross-type conditionals (e.g., removed-success + added-error), use fs-assert-mutex="each" to group them.

Inline Modifiers

Chained in the value using CSS-like bracket syntax:

fs-assert-updated='#count[text-matches=\d+]'
fs-assert-updated='#logo[src=/img/new.png][alt=New Logo]'
fs-assert-updated='.panel[classlist=active:true,hidden:false]'
  • [text-matches=pattern] — Text content regex match (partial)
  • [value-matches=pattern] — Form control .value regex match (partial)
  • [checked=true|false] — Checkbox/radio checked state
  • [disabled=true|false] — Disabled state
  • [count=N] / [count-min=N] / [count-max=N] — Element count
  • [classlist=class:true,class:false] — Class presence check
  • [attr=value] — Attribute check (full match)

Triggers

| Trigger | When it fires | |---|---| | click | Element is clicked | | dblclick | Element is double-clicked | | change | Input value changes | | blur | Element loses focus | | submit | Form is submitted | | mount | Element is added to the DOM | | unmount | Element is removed from the DOM | | load / error | Resource loads or fails | | invariant | Continuous monitoring | | hover / focus / input | Interaction events | | keydown / keydown:<key> | Key press events | | online / offline | Connectivity changes | | event:<name> | Custom event on document |

Assertion Keys

Use / to group related assertions hierarchically:

fs-assert="checkout/add-to-cart"
fs-assert="checkout/submit-order"
fs-assert="profile/media/upload-photo"

Keys must be stable across releases. Human-readable labels are configured on the collector side.

Element-Level Attributes

| Attribute | Purpose | |---|---| | fs-assert-timeout="<ms>" | SLA timeout — fail if not resolved in time | | fs-assert-mpa="true" | Persist across page navigation (MPA) | | fs-assert-mutex="<mode>" | Cross-type conditional grouping | | fs-assert-oob="<keys>" | Trigger on parent assertion pass (OOB) | | fs-assert-oob-fail="<keys>" | Trigger on parent assertion fail |

Configuration

| Option | Type | Required | Default | Description | |---|---|---|---|---| | releaseLabel | string | Yes | — | App version or commit hash | | collectorURL | string or function | Yes | — | Backend endpoint or custom collector function | | apiKey | string | If URL | — | API key for the collection endpoint | | timeout | number | No | 1000 | Default assertion timeout (ms) | | debug | boolean | No | false | Enable console logging | | userContext | Record<string, any> | No | — | Arbitrary context attached to all payloads | | userCohorts | Record<string, string> | No | — | Low-cardinality cohort dimensions for per-cohort assertion health |

Event Payload

Each resolved assertion sends this to the collector:

interface EventPayload {
  api_key: string;
  assertion_key: string;
  assertion_trigger: string;
  assertion_type: "added" | "removed" | "updated" | "visible" | "hidden" | "loaded" | "stable" | "emitted" | "after";
  assertion_type_value: string;
  assertion_type_modifiers: Record<string, string>;
  attempts: number[];
  condition_key: string;
  element_snapshot: string;
  release_label: string;
  status: "passed" | "failed";
  timestamp: string;
  user_context?: Record<string, any>;
  user_cohorts?: Record<string, string>;
  agent_version: string;
  error_context?: {
    message: string;
    stack?: string;
    source?: string;
    lineno?: number;
    colno?: number;
  };
}

Framework Usage

The fs-* attributes work in any framework that renders to the DOM.

React JSX

<button onClick={handleAdd}
  fs-assert="cart/add-item" fs-trigger="click"
  fs-assert-updated="#cart-count">
  Add to Cart
</button>

Vue SFC

<template>
  <button @click="handleAdd"
    fs-assert="cart/add-item" fs-trigger="click"
    fs-assert-updated="#cart-count">
    Add to Cart
  </button>
</template>

Svelte

<button on:click={handleAdd}
  fs-assert="cart/add-item" fs-trigger="click"
  fs-assert-updated="#cart-count">
  Add to Cart
</button>

Works With

Faultsense is framework-agnostic — it observes the DOM, not framework internals — so anything that ships HTML works. The table below is verified end-to-end against real framework dev servers via Playwright on every release.

| Framework | Runtime | Coverage | |---|---|---| | React 19 + Vite | conformance/react/ | 10/10 scenarios | | Vue 3 + Vite | conformance/vue3/ | 10/10 scenarios | | Svelte 5 (runes) + Vite | conformance/svelte/ | 10/10 scenarios | | Solid 1.9 + Vite | conformance/solid/ | 10/10 scenarios | | Alpine.js 3 | conformance/alpine/ | 10/10 scenarios | | Astro 6 (SSR + React island) | conformance/astro/ | 11/11 scenarios (PAT-09 empirical) | | Hotwire (Rails 8 + Turbo 8) | conformance/hotwire/ (Docker) | 8/8 scenarios (PAT-04 empirical) | | HTMX 2 + Express | conformance/htmx/ | 7/7 scenarios | | Livewire 3 (Laravel 11) | conformance/livewire/ (Docker) | 8/8 scenarios (PAT-04 empirical) | | Phoenix LiveView 1.0 | conformance/liveview/ (Docker) | 8/8 scenarios (PAT-04 empirical) |

The Layer 1 mutation-pattern suite at tests/conformance/ locks in every DOM mutation shape the agent handles, so frameworks that produce those shapes are supported by transitivity — the per-framework Layer 2 drivers under conformance/ are empirical confirmation, not the source of truth.

Running the full Layer 2 suite locally needs Docker for the Hotwire, Livewire, and LiveView harnesses (each boots its own Rails / Laravel / Phoenix runtime in a container). The other seven harnesses run directly in Node. See conformance/README.md for setup details and how to skip the Docker harnesses.

Performance

Designed to stay off the critical path.

Benchmarked across 50-1000 assertions in a React 19 stress harness with background DOM churn and CPU throttling. All results use paired statistical comparisons.

  • 0ms INP across all configurations, including 1000 assertions under 4x CPU throttle
  • Zero new long tasks — the main thread stays clean
  • Sub-linear heap scaling — 140KB at 1000 assertions (less than a medium JPEG)

Run the stress benchmark yourself:

npm run benchmark:stress

See tools/benchmark/README.md for full methodology.

Package Info

  • Size: 8.7 KB gzipped
  • Dependencies: None
  • Browser Support: Modern browsers (ES2020+)
  • Framework: Any framework that renders HTML
  • License: FSL-1.1-ALv2

Worked Examples

The examples/ directory contains reference ports you can run locally. The same assertion keys are used in each so you can diff them side-by-side and see how the instrumentation pattern works across rendering paradigms.

  • todolist-tanstack — React + TanStack Router + TanStack Start (virtual DOM, JSX interpolation for dynamic assertion values).
  • todolist-htmx — HTMX 2 + Express + EJS (server-rendered fragments, hx-boost SPA nav, server-side interpolation for dynamic assertion values).

Links