Skip to content

@napplet/vite-plugin

Vite plugin for napplet local development — injects aggregate-hash meta tags and generates NIP-5A manifests for testing.

@napplet/vite-plugin is a development tool. In dev mode it injects the discovery meta tags the shim looks for; at build time (with a test private key) it walks dist/, computes per-file SHA-256 hashes and the NIP-5A aggregate hash, signs a NIP-5D kind 35129 named-napplet manifest event (NIP-5A tag schema: path tags + one aggregate x tag), and emits the requires / config tags. It runs at build/dev time only — it is not a runtime dependency.

TIP

For production deployment of napplets to nsites, use community deploy tools like nsyte, which handle NIP-5A event creation and relay publishing. The build-time manifest here is for verifying the hash workflow locally.

Install

bash
npm install -D @napplet/vite-plugin

Quick start

ts
// vite.config.ts
import { defineConfig } from 'vite';
import { nip5aManifest } from '@napplet/vite-plugin';

export default defineConfig({
  plugins: [nip5aManifest({ nappletType: 'my-napp' })],
});

Options

nip5aManifest(options) returns a Vite Plugin. The options:

OptionTypePurpose
nappletType (required)stringThe napp type / d tag; injected as <meta name="napplet-napp-type"> and used as the manifest d tag.
requiresstring[]Bare NAP domain names this napplet needs, such as outbox or storage. Injects a napplet-requires meta tag and ["requires", …] manifest tags.
titlestringHuman-readable title. Sets/overrides the built HTML <title> (plain HTML, not a napplet-* meta; untouched when omitted). The napplet CLI reads it back out of the built index.html and emits the NIP-5A ["title", …] manifest tag.
descriptionstringHuman-readable description. Sets/overrides the built HTML <meta name="description"> (plain HTML, not a napplet-* meta; untouched when omitted). The napplet CLI reads it back out and emits the NIP-5A ["description", …] manifest tag.
configSchemaNappletConfigSchema | stringA JSON Schema (draft-07+) for the napplet's NAP-CONFIG surface. Inline object or path; falls through to config.schema.json then napplet.config.* discovery.
artifactMode'external-assets' | 'single-file'Default 'external-assets'. 'single-file' inlines local JS/CSS into index.html before hashing — for gateway-portable NIP-5A artifacts.

What gets injected

In dev mode, two meta tags so the shim can find them:

html
<meta name="napplet-aggregate-hash" content="">
<meta name="napplet-napp-type" content="my-napp">

At build time (with VITE_DEV_PRIVKEY_HEX set), the plugin walks dist/, computes hashes, signs the kind 35129 event, writes .nip5a-manifest.json, and stamps the real aggregate hash into the meta tag:

json
{
  "kind": 35129,
  "tags": [
    ["d", "my-music-app"],
    ["path", "/index.html", "<sha256>"],
    ["x", "<aggregateHash>", "aggregate"],
    ["requires", "outbox"],
    ["requires", "storage"]
  ]
}

Build-time guards & diagnostics

  • Config schema validation — the resolved schema is checked against the NAP-CONFIG Core Subset; pattern, $ref, a non-object root, or a x-napplet-secret with a default abort the build.
  • Inline scripts are supported — NIP-5D loads a napplet as a single self-contained /index.html via iframe.srcdoc (opaque origin), so its JS is inline by design. The plugin does not reject inline <script> elements. With artifactMode: 'single-file' it folds local script/style assets into the HTML and leaves any pre-existing inline scripts intact.

Environment

  • VITE_DEV_PRIVKEY_HEX — hex-encoded 32-byte test private key. If set, the plugin signs the manifest at build time; if unset, manifest generation is gracefully skipped. Never use a real key — generate a dedicated test key.

See also

Released under the MIT License.