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

@localnerve/trusted-types-rules

v1.0.0

Published

Compute Content-Security-Policy trusted-types rules and audit injection sinks from JavaScript sources, including web components.

Readme

@localnerve/trusted-types-rules

Compute Content-Security-Policy trusted-types rules and audit injection sinks from JavaScript sources, including web components.

A build-time companion to the CSP meta tag: it scans your application code (or build output) for Trusted Types injection sinks and derives the trusted-types <policyName> directive you need — so newly added web components or innerHTML usage are picked up automatically on each build instead of being missed in a hand-maintained policy.

Why

require-trusted-types-for 'script' makes the browser reject plain strings at DOM injection sinks (innerHTML, document.write, eval, <script src>, ...). To keep your app working you must:

  1. register a policy with hooks that cover every sink your code uses, and
  2. allowlist that policy's name in the CSP trusted-types directive.

Doing this by hand drifts as the codebase grows — especially when web components each register their own named policy. This library computes the full multi-name allowlist from the sources themselves.

Install

npm install @localnerve/trusted-types-rules

Usage

import { extractTrustedTypesSources } from '@localnerve/trusted-types-rules';

const report = extractTrustedTypesSources(
  [
    { path: 'dist/app.js', source: fs.readFileSync('dist/app.js', 'utf8') },
    { path: 'dist/sw.reg.js', source: fs.readFileSync('dist/sw.reg.js', 'utf8') }
  ],
  // optional: policy name(s) you always want in the directive. Detected
  // createPolicy() names (e.g. web component policies) are added automatically.
  { policyNames: ['default'] }
);

// report.cspDirective -> "trusted-types default editable-object"

Then substitute the directive into your CSP meta tag at build time:

html = html.replace(/trusted-types [^;']+/g, report.cspDirective);

Options

| Option | Default | Description | | --- | --- | --- | | policyNames | ['default'] | Policy name (string) or names (array of strings) to always include in the directive. Names detected from createPolicy() registrations are added automatically (deduplicated), so web components that register their own policies are allowlisted without being listed here. |

Report shape

{
  cspDirective: 'trusted-types default editable-object', // ready to drop into a CSP
  policyNames: ['default', 'editable-object'],           // every name in the directive
  detectedPolicyNames: ['editable-object'],              // names found via createPolicy()
  sinks: [                                               // every injection sink found
    { file: 'dist/app.js', line: 12, column: 5, sink: 'innerHTML', hook: 'createHTML' }
  ],
  webComponents: [                                       // customElements.define() tags found
    { tag: 'editable-object', file: 'dist/app.js', line: 40 }
  ],
  policyHooks: { createHTML: true, createScriptURL: true, createScript: false },
  requiredHooks: { createHTML: true, createScriptURL: true, createScript: false },
  warnings: [                            // uncovered sinks, mismatches, URL heuristics
    'Worker detected in dist/sw.reg.js: verify the policy createScriptURL hook covers these URLs.'
  ]
}

What is detected

  • Markup sinks (createHTML): innerHTML, outerHTML, insertAdjacentHTML, document.write/writeln, srcdoc attribute.
  • Code execution sinks (createScript or the CSP trusted-types-eval keyword): eval(), new Function().
  • Script URL patterns (createScriptURL): createElement('script'), new Worker() — reported as warnings because they need review.
  • Web components: every customElements.define('<tag>', ...) tag, so new components added to the site are automatically part of the audit.
  • Existing policies: trustedTypes.createPolicy('name', { ... }) registrations and which hooks (createHTML, createScriptURL, createScript) they define.

Policy name resolution (AST)

Policy names are resolved with real AST analysis (acorn), not a text regex, so they survive arbitrary minification/terser output. This matters because terser hoists createPolicy('my-name', ...) into shapes like:

const r = "my-name"; /* ... */ f(r); // f eventually calls trustedTypes.createPolicy

The resolver handles all of these, scope-aware (each identifier resolves against the innermost binding at its own position, so minified single-letter name reuse across scopes cannot false-match):

  • string literals: trustedTypes.createPolicy('my-name', ...)
  • hoisted string constants: const r = "my-name"; f(r)
  • parameters passed through nested function call chains (bounded depth, cycle-safe)

Sources that fail to parse fall back to literal-name detection only.

Limitations

  • Sink detection is a text heuristic (regex), not AST-based. It errs toward reporting more than fewer — the right bias for a security audit: a false positive becomes a warning to review, while a false negative would be a hole. The patterns are written to survive terser-style minification.
  • Script URL sinks (createElement('script'), new Worker()) are reported as warnings rather than hard requirements, because whether they need coverage depends on the URLs in play.

License

MIT — license.md