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

@pyyush/useid

v0.1.0

Published

uSEID - Universal Semantic Element ID for stable cross-run element identity

Readme

uSEID

Your selectors break. uSEID doesn't.

Browser agents and E2E tests fail when the UI changes. A developer renames a CSS class, wraps a button in a new <div>, or ships an A/B variant — and suddenly your carefully crafted selectors target the wrong element. Or nothing at all.

uSEID solves this by identifying elements the way a human would: by what they are (a "Submit" button), where they sit (inside the checkout form), and where they appear (bottom-right of the main content). When the DOM reshuffles but the element is still there, uSEID finds it. When it's genuinely gone or ambiguous, uSEID tells you — it never silently acts on the wrong thing.

How It Works

                     Build                              Resolve
                     ─────                              ───────
Snapshots ──→ Canonicalize ──→ Extract ──→ Signature    Signature + New Snapshots
 (DOM + A11y)   (normalize)    (features)   (portable)      ↓
                                                        Candidates → Score → Safety Gate
                                                                              ↓
                                                                    Match (with confidence)
                                                                    or Abstain (with reason)

uSEID builds a portable signature from three signals:

| Signal | What it captures | Why it's stable | |--------|-----------------|-----------------| | Semantic | ARIA role + accessible name | Standardized by W3C, rarely changes | | Structural | Ancestor roles, sibling labels, form associations | Survives wrapper changes | | Spatial | Bounding box position | Catches layout-only changes |

Install

npm install @pyyush/useid

Zero config. One dependency (zod). Works with any Node.js 20+ project.

Quick Start

import { buildUSEID, resolveUSEID } from "@pyyush/useid";

// Capture snapshots from your browser automation tool
const domSnapshot = {
  snapshot: await cdpSession.send("DOMSnapshot.captureSnapshot", {
    computedStyles: ["display", "visibility", "opacity", "position"],
    includeDOMRects: true,
  }),
};
const a11ySnapshot = {
  tree: await page.accessibility.snapshot({ interestingOnly: false }),
};

// Build a signature for the "Add to Cart" button
const signature = buildUSEID({
  domSnapshot,
  accessibilitySnapshot: a11ySnapshot,
  elementIndex: 0,  // Index in the extracted element list
  pageUrl: "https://shop.example.com/product/42",
});

// Store the signature. Ship it. Come back next week.

// Resolve it against fresh snapshots — even after a redesign
const result = resolveUSEID({
  signature,
  domSnapshot: freshDomSnapshot,
  accessibilitySnapshot: freshA11ySnapshot,
  pageUrl: "https://shop.example.com/product/42",
});

if (result.resolved) {
  console.log(result.selectorHint);  // role=button[name="add to cart"]
  console.log(result.confidence);    // 0.94
} else {
  console.log(result.abstentionReason);  // "below_threshold"
  console.log(result.explanation);       // human-readable why
}

Safety: Wrong Element Is Worse Than No Element

Most selector strategies fail silently — they click something, just not the right thing. uSEID's safety gate ensures that doesn't happen:

| When this happens... | uSEID does this | Why | |---------------------|----------------|-----| | Page URL doesn't match signature | Abstains (binding_mismatch) | Prevents cross-page false matches | | No elements match the expected role | Abstains (no_candidates) | Element was removed | | Best match scores below 0.85 | Abstains (below_threshold) | Not confident enough | | Two candidates score too close | Abstains (ambiguous_match) | Can't tell which is right |

Every abstention comes with an explanation string and a ranked candidates list so you can debug or escalate to a human.

Configurable Scoring

The defaults work well for most cases. When they don't, everything is tunable:

resolveUSEID({
  signature,
  domSnapshot,
  accessibilitySnapshot: a11ySnapshot,
  pageUrl: "https://example.com/page",
  config: {
    threshold: 0.9,          // Stricter (default: 0.85)
    marginConstraint: 0.15,  // Wider gap required (default: 0.1)
    weights: {
      semantic: 0.7,         // Trust names more (default: 0.5)
      structural: 0.2,       // Trust DOM context less (default: 0.3)
      spatial: 0.1,          // Trust position less (default: 0.2)
    },
  },
});

Privacy Built In

Element signatures can contain accessible names from form labels. For logging or storage:

import { redactUSEID } from "@pyyush/useid";

const safe = redactUSEID(signature);
// accessible names → hashed, sibling tokens → stripped, form labels → removed
// Safe to log. NOT resolvable after redaction (by design).

Bring Your Own Automation

uSEID is framework-agnostic. It accepts two minimal interfaces:

interface DOMSnapshotResult {
  snapshot: unknown;  // CDP DOMSnapshot.captureSnapshot response
}

interface AccessibilitySnapshotResult {
  tree: unknown;  // Playwright, Puppeteer, or any a11y tree
}

No Playwright dependency. No CDP dependency. If your tool can produce a DOM tree and an accessibility tree, uSEID works with it.

What Works Today (v0.1.0)

| | Supported | Behavior | |-|-----------|----------| | Chromium | Yes | Full CDP snapshot support | | Main frame | Yes | Default | | Same-origin iframes | Yes | Via framePath binding | | Cross-origin iframes | No | Abstains with explanation | | Open shadow DOM | Yes | Flattened by CDP DOMSnapshot | | Closed shadow DOM | No | Abstains |

Full API

| Function | Purpose | |----------|---------| | buildUSEID(opts) | Build a portable signature from snapshots | | resolveUSEID(opts) | Resolve a signature against current snapshots | | compareUSEID(a, b) | Compare two signatures (0, 0.5, or 1) | | explainResolution(result) | Human-readable explanation | | redactUSEID(signature) | Strip PII for safe logging |

Lower-level functions are also exported for custom pipelines: extractElements, generateCandidates, scoreCandidates, applySafetyGate, checkBinding.

License

Apache-2.0