Skip to content

v0.7.5

Choose a tag to compare

@github-actions github-actions released this 27 May 14:40
· 129 commits to main since this release
ecdfde5

v0.7.5 — @hover-dev/next accepts plugins via register() second arg

A small but user-visible API addition. Before v0.7.5 there was no way to wire @hover-dev/security (or any future Hover plugin) into a Next.js project — the docs claimed Vite / Astro / Nuxt / Next / Webpack all mirror hover({}, securityMode()), but Next had no slot for it. The other four still do; Next now takes plugins via a different shape because of how it compiles instrumentation.ts.

What changed

// instrumentation.ts
import { register as registerHover } from '@hover-dev/next/instrumentation';

export async function register() {
  await registerHover({}, [
    '@hover-dev/security',
    // Object form for plugins that take options:
    // { module: '@hover-dev/security', options: { cdpPort: 9444 } },
  ]);
}

The second argument is a PluginSpec[] — either a bare module-specifier string or a { module, options } pair.

Why a string, not import securityMode from '@hover-dev/security'

Next compiles instrumentation.ts for both the Node and Edge runtimes. A top-level import of a plugin package would be statically traced into the Edge bundle, and plugin packages like @hover-dev/security carry Node-only deps (mockttp, playwright-core) that error out under Edge compilation.

The specifier is resolved at runtime inside @hover-dev/next/internal/register-node via the same new Function('s','return import(s)') opaque dynamic import the v0.7.4 release used to load the Node-runtime entry itself. Turbopack's static tracer can't follow a string-constructed function, so plugin code stays strictly Node-runtime-only.

Why we don't take plugins through withHover()

Two reasons:

  1. HoverOptions is env-var-serialised across the withHover()register() boundary (since v0.7.3). Plugin manifests carry hook closures / functions that don't survive JSON.
  2. Plugin imports at the config layer would still be statically traced into Edge by the same mechanism described above.

So Next's wiring lives entirely in instrumentation.ts, which is already Node-runtime-gated.

Resolver: walks node_modules from process.cwd()

Plugin packages ship ESM-only — their exports map has no require condition, and most don't expose ./package.json as a subpath. createRequire(...).resolve('@hover-dev/security') (CJS) errors with "No exports main defined"; createRequire(...).resolve('@hover-dev/security/package.json') errors with "Package subpath not defined".

The new resolver walks up from process.cwd() looking for node_modules/<plugin>/package.json (Node's own algorithm), then reads exports['.'].import / module / main itself and loads the resulting absolute path via a file:// dynamic import. Sidesteps every conditional-exports edge case at once.

Verified end-to-end in:

Example Layout Verified
examples/next-app Flat repo, Next 16.2.6, Turbopack default Service log reads plugins=[@hover-dev/security]; CDP probe of the widget shadow root shows mode bar with label "Security testing"; WS set-mode { modeId: "security" } broadcasts { current: "security" }
examples/turbo-monorepo/apps/web turbo + pnpm-workspace, Next 15.5 Same — resolver walks up from apps/web/ to find the workspace-linked plugin

Docs

  • README.md — Security section and Optional Security mode block both now show the correct Next wiring. The "Astro / Nuxt / Next / Webpack mirror the same pattern" line (incorrect for Next) is gone.
  • CLAUDE.md@hover-dev/next description now spells out the PluginSpec[] design + Edge-tracer reasoning, so future contributors don't try to add a vararg slot to withHover().
  • packages/next-integration/README.md (new) — brings @hover-dev/next in line with the other four integration READMEs, with a dedicated "Plugins" section.

Packages on npm

All nine publishable packages updated to 0.7.5:

@hover-dev/core · @hover-dev/widget-bootstrap · @hover-dev/astro · @hover-dev/nuxt · @hover-dev/next · @hover-dev/cli · @hover-dev/security · vite-plugin-hover · webpack-plugin-hover

The only package whose behaviour actually changed is @hover-dev/next; the others are republished at the same version so monorepos that pin all @hover-dev/* to one tag don't fall out of sync.

Full Changelog: v0.7.4...v0.7.5