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

@corbado/autocapture

v0.2.0

Published

Observer-style capture helpers for WebAuthn ceremonies, selected network exchanges, in-app navigation, and composed event paths.

Readme

@corbado/autocapture

Observe browser authentication signals without changing application code.

@corbado/autocapture provides small, focused observers for the browser APIs that authentication flows run through. Each observer reports a well-defined stream of events while leaving the application — and other code sharing the same APIs — as safely as browser monkey-patching permits. It is designed to be dropped into a page it does not own and fail closed when a surface cannot be instrumented safely. The remaining cases where observation cannot be perfectly transparent are called out in the safety invariants and data handling sections below.

The package observes three kinds of signal:

  • WebAuthn ceremonies — the lifecycle of navigator.credentials.get/create passkey ceremonies, from invocation to settlement, including silent cancellations.
  • Network requests and exchanges — request starts and their eventual outcomes over XMLHttpRequest and fetch, limited to URLs a caller-provided predicate selects. A page-local request ID correlates both callbacks.
  • In-app navigation — same-document (SPA) route changes.

It also exposes composedPath() for selector matching across visible shadow-DOM boundaries.

It has no runtime dependencies, ships TypeScript type definitions, and targets ES2019 so it parses on older engines.

Installation

npm install @corbado/autocapture

Usage

Every observer follows the platform observer pattern (MutationObserver, ResizeObserver): create it with a callback, receive events, and call disconnect() when finished.

import { captureWebAuthn, captureNetwork, captureNavigation, composedPath } from "@corbado/autocapture";

const webauthn = captureWebAuthn({
  onEvent: (event) => console.log(event.kind, event.mediation, event.phase, event.ceremonyId),
});

const network = captureNetwork({
  match: (url) => url.origin === location.origin && url.pathname.startsWith("/auth-api/"),
  bodyCapture: {
    request: (body) => {
      const value = typeof body === "string" ? JSON.parse(body) : body;
      return value && typeof value === "object" ? { type: "type" in value ? value.type : undefined } : undefined;
    },
    response: (body) => {
      const value = typeof body === "string" ? JSON.parse(body) : body;
      return value && typeof value === "object" ? { status: "status" in value ? value.status : undefined } : undefined;
    },
  },
  onRequest: (request) => console.log(request.requestId, request.method, request.path),
  onExchange: (exchange) => console.log(exchange.method, exchange.path, exchange.status, exchange.outcome),
});

const navigation = captureNavigation({
  onNavigate: (event) => console.log(event.source, event.path),
});

document.addEventListener("click", (event) => {
  const clickedButton = composedPath(event).find(
    (entry) => entry instanceof HTMLButtonElement,
  );
  if (clickedButton) console.log(clickedButton);
});

// when finished
webauthn.disconnect();
network.disconnect();
navigation.disconnect();

Each capture call returns a CaptureHandle with a mode ("standard" or "unavailable") and a disconnect() method. Environments that cannot be instrumented report "unavailable" rather than throwing; a misconfigured captureNetwork call (missing match or onExchange) throws a TypeError instead, since that is a programming error, not a degraded environment. Full event and option types ship with the package.

WebAuthn events use a protocol-native discriminated union. Authentication phases carry normalized mediation, uiMode, and credentialSet ("allowlisted" or "discoverable"); registration phases carry normalized mediation. The same profile is present on every phase of one ceremony. Autocapture deliberately does not infer product concepts such as conditional-UI spec types, known-identifier state, enrollment intent, or the user/system actor. Integrations map those facts in their own state context.

Safety invariants

The observers run inside application call paths, so their behaviour is defined by what they promise never to disturb:

  • Exact host delegation. Patched methods call the delegate once with the original receiver and argument vector, and preserve its return value and synchronous exception. Non-WebAuthn Credential Management calls are literal pass-throughs. Two Promise-observation choices are unavoidable: public-key ceremonies return a derived Promise (identity and microtask timing change), and fetch settlement is observed on the platform Promise itself, so an ignored failed fetch no longer surfaces as an unhandledrejection.
  • Observation is firewalled. Synchronous callback, projector, serializer, and logger faults are contained; rejected asynchronous event callbacks are consumed and logged. The firewall covers first-party faults on a real browser engine — hostile polyfills and patched built-ins are outside the threat model.
  • Coexistence over ownership. Existing delegates are preserved, slots are restored only while still owned by the capture, and later wrappers are never overwritten. A buried wrapper becomes an inert pass-through after disconnect. Locked WebAuthn methods are never bypassed through a container proxy; the entire WebAuthn attachment is rolled back and reported as unavailable.
  • Exactly-once reporting. Each patched surface holds a single capture wrapper, so one application action passes through observation once. A later integration that overwrites a wrapped method without forwarding through it displaces capture for that surface: the application call still succeeds, telemetry is lost. A package wrapper hidden below an unknown third-party wrapper cannot currently be detected by another copy.
  • Conditional removal. disconnect() stops delivery immediately, releases active listeners, and restores only slots still owned by the capture. If another integration sits above it, the inert pass-through is deliberately left in that chain.

These are implementation invariants, not a claim that monkey-patching is undetectable or has zero timing, memory, privacy, or Promise-semantics impact.

Data handling

Network observation is designed for minimal data exposure:

  • Only URLs a caller's match predicate explicitly selects are observed; all other traffic is ignored. The Corbado /observe/events/{projectID} sink is always excluded to prevent recursion.
  • Requests and exchanges carry metadata only by default. onRequest runs after the platform accepts the call; onExchange reports its eventual outcome, and their requestId values match. A request or response body is read only when the caller configures a projector for that direction.
  • Projected XHR request bodies are available at request time. For fetch(new Request(...)), reading the request clone is asynchronous, so the request body may be absent from onRequest and present only on onExchange; string bodies passed through RequestInit are available synchronously.
  • Autocapture performs no generic body parsing or redaction. The endpoint-specific projector is the privacy boundary: it receives the matched raw body and must return only the fields the consumer is allowed to observe. The exact projected value is attached to the exchange without generic serialization, cloning, or size limiting. Projector failures, promises, and undefined fail closed by omitting the body.
  • Readable bodies come from isolated clones read within a 500 ms window; the source body is never directly consumed, and streaming and binary payloads are never read. Body cloning still has inherent stream tee/backpressure costs, so enabling it is a security and performance decision.

Network metadata currently includes the resolved full URL and final response URL. Query strings can contain secrets or PII; callers should restrict match accordingly until a URL-redaction policy is chosen.

Navigation events likewise contain the raw search and hash. OAuth responses, password-reset links, and application routes can put secrets or PII there; no navigation redaction policy is currently applied.

WebAuthn responses use an explicit serializer rather than credential.toJSON(). The allowlist keeps the assertion and attestation fields the Observe backend parses for credential, authenticator, backup-state, AAGUID, transport, and discoverability insight. Client-extension output is limited to credProps.rk; PRF and unrelated extension results are omitted. The payload therefore still contains credential IDs, user handles, challenges, signatures, authenticator data, and attestation material.

The tested 1Password browser extension exposes locked get and create accessors. WebAuthn capture therefore reports mode: "unavailable"; passkey operations continue through 1Password unchanged but produce no autocaptured WebAuthn events. Password managers that wrap the writable methods before autocapture are delegated to; one that assigns its wrapper afterwards keeps working, and its ceremonies stay observed when the wrapper forwards through the method it replaced (the surveyed managers do). A later assignment that does not forward displaces WebAuthn telemetry.

Runtime support

The published bundle targets ES2019 and assumes ES2019-era runtime primitives such as Promise, WeakMap, WeakSet, Symbol, Reflect, and URL. Body capture additionally relies on the Streams API and TextDecoder; these are part of the assumed baseline, not feature-detected at runtime. The current real-browser suite covers current Chromium, Firefox, and WebKit, with password-manager simulation and virtual WebAuthn in Chromium. That is not yet evidence for old iOS, Android WebView, legacy Edge, or arbitrary polyfills; expanding the declared browser floor and test matrix is an open release decision.