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

@verajs/inserts

v0.2.1

Published

Enables inserts system for injecting functionality in VeraJS.

Readme

@verajs/inserts

The VeraJS extension registry (357 B gzip). Every capability that attaches to VeraJS — renderers, autoloaders, styling, error boundaries, batching — attaches through here. It is the module system's backbone rather than a feature.

You rarely install this directly: @verajs/core and @verajs/router re-export what you need.

import { wire } from '@verajs/core';

Everything VeraJS does beyond state and templates is registered here, on the same five points and the same public function you have. @verajs/renderer is a 'render' insert. @verajs/styles is an 'init' insert. An error boundary is an 'error' insert, and write batching is a 'set-handler' insert — both are a few dozen lines, and both are worked examples in examples/cdn-js/src/inserts/.

Take wire from the package that owns the extension point, never from @verajs/inserts directly. A production .min.js inlines this package into every bundle, so registering through a separately imported copy writes to a map that package never reads — it works in development and silently does nothing in production.

Registering

wire({ on: 'error', fn: (error, element) => report(error, element), priority: 40 });

wire({ on: name, fn: callback, priority: priority }) — priority is required. Lower runs first. Registering at a priority that is already taken replaces that entry, which is how a renderer is swapped. Chains are stored dense and priority-sorted rather than indexed by priority: indexing left holes (a renderer at 50 produced a 51-element array with 50 of them) and every chain is walked on the hot path, which cost roughly 238 ns per store read.

Two more exports, for a module that reads chains on its own hot path:

import { inserts, revision } from '@verajs/inserts';

let cached = inserts.get('proxy-handler');   // the registry: Map of name -> ordered chain
let seen = revision;                          // bumped by every registration
const chain = () => (seen === revision ? cached : ((seen = revision), (cached = inserts.get('proxy-handler'))));

revision is a live binding, not a getter — reading it is a variable access, which is the point: the chains that matter are read on every store read and write, a Map.get there measured at 13% of a tracked read, and a registration is a once-per-app event, so the cost sits on the registration side. (Remember the rule below before importing inserts directly: registering goes through core's wire, always.)

The extension points

| Name | Runs when | Signature | | --- | --- | --- | | 'render' | a component renders | (template, element, ...args) | | 'init' | init() sets an element up — after its shadow root exists, before its first render | (element) | | 'proxy-handler' | a store property is read | (obj, prop, value, addCallback, runCallbacks) | | 'set-handler' | a store property is written, before the default propagation. Return false to suppress it — that is how batching, transactions and undo/redo hold changes back | (obj, prop, value, prevValue, runCallbacks) | | 'error' | a hook callback threw. Core never lets one failing effect stop the others, so this decides what happens to it. With nothing registered it falls back to console.error | (error, element) | | 'collection' | a method is read off a Map or Set inside a store. Type-keyed, so a plain-object read never reaches it — that is what lets reactive collections live outside core. With nothing registered, a Map in a store is inert and core raises a __DEV__ error naming the package | (obj, prop, propValue, addCallback, runCallbacks) | | 'slot' | a <slot> in a template being rendered into LIGHT DOM — @verajs/renderer/slots takes it over and distributes the host's own children. Returning null or undefined declines, which is what a shadow root gets (the platform slots there) and what the SSR shim gets (the server distributes in its own pass). One registrant owns it: the renderer takes the highest-priority answer rather than chaining | (slot, root, name) | | 'loader' | a DIRECTIVE NAME nobody has wired — @verajs/directives asks before rejecting an unknown data-vd-*, and @verajs/autoloader's directiveLoader answers by convention ({base}/{name}.js). First claimer wins: return the import() promise (or any truthy) to claim, false/undefined to decline; the claimed module registers itself through wireDirectives, and the asker re-checks its registry when the promise settles | (name, element) | | 'settle' | a SERVER render's component tree is final — lifecycle run, frames drained, markup about to be serialized. The only moment a server can offer for reading rendered content, since 'init' fires before the first render and a server has no observer to catch what follows. @verajs/directives evaluates declarative directives here, so reflections are correct before any JavaScript reaches the browser | (element) | | 'value' | a child-position value the renderer does not already handle — <div>${value}</div>. For types you do not own: a Promise, an Observable, a Temporal.PlainDate. Return true to claim the value and stop the chain. Strings, numbers, null and undefined never reach it — those take a fast path — so this cannot be used to intercept text | (part, value) |

Priority 50 is the convention for a default implementation: register below it to run first, or at it to replace.

Every callback in a chain runs, in priority order. An insert that wants to change what core does — rather than merely watch — says so through its return value, and only 'set-handler' has one: returning false suppresses the default propagation, which is what lets a module hold writes back and flush them itself.

For a whole new kind of hook rather than a new implementation of an existing one, createHook in @verajs/core is the primitive useEffect and its siblings are built from.

An insert that throws

Nothing catches it, and that is deliberate — but it is not the same as a hook. A useEffect that throws is isolated and reported through the 'error' insert, because core runs an element's hooks in one loop and an escaping error would skip every hook after the failing one. An insert is not in that position:

  • 'set-handler' and 'proxy-handler' run inside the store's own set and get traps, so a throw comes out of state.count = 1 in the caller's own stack, at the line that wrote it. That is the most useful place it could surface, and swallowing it would leave the write in an undefined state — a suppressed handler has already decided whether the value propagates. These are also the hottest paths in the framework, and a try/catch on every property read is not free.
  • 'collection' and 'value' are the same case as those two, for the same reason: the first runs inside a Map or Set method and the second inside a child-position commit, so a throw comes out of tags.add('x') or of renderInto at the line that called it.
  • 'init' and 'render' run inside init() and the render, so a throw surfaces there. And the chain stops there: an insert is not isolated from the ones beside it, so every insert after the failing one is skipped. 'init' is where per-element setup hooks in, so one throwing module keeps the rest from initialising at all — which is why the practical rule below matters most here.
  • 'error' is the one that must not throw. It is already handling a failure, and a throw from it replaces the error being reported with its own.

The practical rule: an insert is framework-level code and is expected not to throw. If yours can, catch inside it and decide what to do — the callback knows what a failure means and core does not.

Two copies is a mistake, not an arrangement

Each standalone .min.js inlines its own copy of this package, so loading vera.min.js and a module that imported this package directly would yield two separate registries — one written to, the other read from, in production only.

There is no repair function for that any more. connectInserts, which replayed one registry's chains into another, was removed once every module took the registry it writes to instead of carrying its own:

import { wire } from '@verajs/core';
import { renderer } from '@verajs/renderer';
import { router } from '@verajs/router';
import { collections } from '@verajs/store/collections';

wire([renderer, router, collections]);

router is a connector — wire hands it this registry, and the router keeps no registry of its own. That removes the hazard by construction rather than reconciling it afterwards, and it is why @verajs/router has no dependencies at all. tests/cdn-cross-bundle.test.mjs guards the shape.

Take wire from @verajs/core, never from this package. @verajs/eslint-config has a rule for exactly that mistake.

For AI assistants — and anyone who wants the whole API on one page

The repository root's llms.txt is the complete, hand-maintained API reference for every package, written to be pasted into a model's context window: full export tables, the buildless CDN and JSX recipes, semantics that differ from other frameworks, and the mistakes that come up most. Its recipes are executed by the test suite, so they stay honest.

License

MIT