@napplet/core
v0.2.1
Published
Shared protocol types, constants, and message definitions for the napplet protocol
Maintainers
Readme
@napplet/core
JSON envelope types and NUB dispatch infrastructure for the napplet ecosystem.
Getting Started
Package Overview
This package is the single source of truth for all protocol-level definitions in the napplet ecosystem. All other @napplet/* packages import their envelope types, dispatch infrastructure, and protocol constants from here.
Zero dependencies. No DOM or browser APIs. Works in any JavaScript runtime.
Installation
npm install @napplet/coreQuick Start
import {
type NappletMessage, type NubDomain, type ShellSupports,
type NubHandler, type NubDispatch,
NUB_DOMAINS, SHELL_BRIDGE_URI, PROTOCOL_VERSION,
createDispatch, registerNub, dispatch, getRegisteredDomains,
ALL_CAPABILITIES, TOPICS,
} from '@napplet/core';API Reference
Envelope Types
The JSON envelope wire format is the primary API introduced in NIP-5D v4. All messages between napplet and shell use a type field as a discriminant in domain.action format.
NappletMessage
Base interface for all messages exchanged between napplet and shell.
interface NappletMessage {
/** Message type discriminant in "domain.action" format */
type: string;
}Concrete message types extend this interface with domain-specific payload fields:
// Example concrete message type:
interface RelaySubscribe extends NappletMessage {
type: 'relay.subscribe';
id: string;
subId: string;
filters: NostrFilter[];
}The type field domain prefix (relay, identity, storage, ifc, theme, keys, media, notify, config) routes messages to the correct NUB handler via dispatch().
NubDomain
String literal union of the nine NUB capability domains.
type NubDomain = 'relay' | 'identity' | 'storage' | 'ifc' | 'theme' | 'keys' | 'media' | 'notify' | 'config';| Domain | Scope |
|-----------|------------------------------------------|
| relay | Relay proxy (subscribe, publish, query) |
| identity | Read-only user identity queries |
| storage | Scoped key-value storage proxy |
| ifc | Inter-frame communication (dispatch + channel) |
| theme | Theme tokens and appearance settings |
| keys | Keyboard forwarding and action keybindings|
| media | Media session control and playback |
| notify | Shell-rendered notifications |
| config | Per-napplet declarative configuration (JSON Schema-driven) |
NUB_DOMAINS
Runtime constant array of all NUB domain strings. Useful for iteration and validation.
const NUB_DOMAINS: readonly NubDomain[] = ['relay', 'identity', 'storage', 'ifc', 'theme', 'keys', 'media', 'notify', 'config'];
for (const domain of NUB_DOMAINS) {
console.log(`Checking support for: ${domain}`);
}ShellSupports
Interface for the shell capability query API.
interface ShellSupports {
supports(capability: NubDomain | string): boolean;
}Napplets call window.napplet.shell.supports(domain) to check whether the shell declared support for a NUB domain before using that domain's API.
NappletGlobalShell
Type for the window.napplet.shell namespace. Extends ShellSupports.
interface NappletGlobalShell extends ShellSupports {}NUB Dispatch Infrastructure
The dispatch system allows NUB modules to self-register at import time. Inbound messages are routed to the correct NUB handler based on the domain prefix extracted from message.type (the part before the first .).
createDispatch()
Factory that returns an isolated { registerNub, dispatch, getRegisteredDomains } backed by its own Map<string, NubHandler>. Use for testing or multi-instance scenarios.
function createDispatch(): NubDispatch;import { createDispatch } from '@napplet/core';
const { registerNub, dispatch } = createDispatch();
registerNub('relay', handleRelayMessage);
dispatch({ type: 'relay.subscribe' }); // trueregisterNub(domain, handler)
Register a handler for a NUB domain on the module-level singleton registry. NUB modules call this at import time.
const registerNub: (domain: string, handler: NubHandler) => void;import { registerNub } from '@napplet/core';
registerNub('relay', (msg) => {
// handles all relay.* messages
console.log('relay message:', msg.type);
});Throws if the domain is already registered.
dispatch(message)
Dispatch a message to the handler matching its domain prefix. Returns true if a handler was found and called.
const dispatch: (message: NappletMessage) => boolean;import { dispatch } from '@napplet/core';
dispatch({ type: 'relay.subscribe' }); // true (if relay handler registered)
dispatch({ type: 'unknown.action' }); // false
dispatch({ type: 'malformed' }); // false (no dot)The domain is extracted by splitting message.type on the first .. A type with no . or an empty domain prefix returns false without throwing.
getRegisteredDomains()
Return all currently registered domain strings from the singleton registry.
const getRegisteredDomains: () => string[];import { getRegisteredDomains } from '@napplet/core';
getRegisteredDomains(); // ['relay', 'identity', 'storage']NubHandler
Callback type for NUB message handlers.
type NubHandler = (message: NappletMessage) => void;NubDispatch
Interface returned by createDispatch().
interface NubDispatch {
registerNub: (domain: string, handler: NubHandler) => void;
dispatch: (message: NappletMessage) => boolean;
getRegisteredDomains: () => string[];
}Protocol Types
Types shared by all napplet packages for Nostr event structures and the capability system.
NostrEvent
Standard Nostr event structure (used by relay NUB and identity NUB).
interface NostrEvent {
id: string;
pubkey: string;
created_at: number;
kind: number;
tags: string[][];
content: string;
sig: string;
}NostrFilter
Subscription filter (used by relay NUB for relay.subscribe and relay.query).
interface NostrFilter {
ids?: string[];
authors?: string[];
kinds?: number[];
since?: number;
until?: number;
limit?: number;
[key: `#${string}`]: string[] | undefined; // tag filters, e.g. '#t', '#e'
}Capability
String union type listing all 10 protocol capability strings.
type Capability =
| 'relay:read' | 'relay:write'
| 'cache:read' | 'cache:write'
| 'hotkey:forward'
| 'sign:event' | 'sign:nip04' | 'sign:nip44'
| 'state:read' | 'state:write';Shell implementations use bitfield constants (CAP_*) for fast runtime checks. Capability strings are the human-readable protocol-level representation.
ALL_CAPABILITIES
readonly Capability[] containing all 10 capability strings.
for (const cap of ALL_CAPABILITIES) {
console.log(cap); // 'relay:read', 'relay:write', ...
}Subscription
Handle returned by relay.subscribe() and ipc.on().
interface Subscription {
close(): void;
}EventTemplate
Unsigned event template passed to relay.publish().
interface EventTemplate {
kind: number;
content: string;
tags: string[][];
created_at: number;
}Protocol Constants
| Constant | Value | Description |
|----------|-------|-------------|
| PROTOCOL_VERSION | '4.0.0' | Current napplet-shell protocol version (JSON envelope era, NIP-5D v4) |
| SHELL_BRIDGE_URI | 'napplet://shell' | URI identifying the shell bridge in relay tags |
| REPLAY_WINDOW_SECONDS | 30 | Maximum event age (seconds) for replay protection |
Topic Constants
The TOPICS object contains string constants for IFC topic-based routing. These are legacy constants from the pre-envelope era — with JSON envelope messages, topic strings are passed directly in ifc.emit and ifc.subscribe payloads.
import { TOPICS } from '@napplet/core';
TOPICS.STATE_GET // 'shell:state-get'
TOPICS.SHELL_CONFIG_GET // 'shell:config-get'
TOPICS.WM_FOCUSED_WINDOW_CHANGED // 'wm:focused-window-changed'
// ... see source for full listNote: With JSON envelope wire format (v0.16.0+), state operations use
storage.*messages directly rather than IFC topic routing. These constants are retained for backward compatibility with shell runtime implementations.
Types
import type {
NappletMessage, NubDomain, NamespacedCapability, ShellSupports, NappletGlobalShell,
NubHandler, NubDispatch,
NostrEvent, NostrFilter, Capability,
Subscription, EventTemplate, NappletGlobal,
} from '@napplet/core';| Type | Description |
|------|-------------|
| NappletMessage | Base interface for all JSON envelope messages |
| NubDomain | Union of the nine NUB domain strings |
| NamespacedCapability | Union of NubDomain \| nub:* \| perm:* for supports() |
| ShellSupports | Interface with supports() capability query method |
| NappletGlobalShell | Type for window.napplet.shell (extends ShellSupports) |
| NubHandler | Callback type for NUB domain handlers |
| NubDispatch | Interface returned by createDispatch() |
| NostrEvent | Nostr event structure |
| NostrFilter | Subscription filter for relay NUB |
| Capability | Human-readable capability string union |
| Subscription | Handle with close() returned by subscribe/on |
| EventTemplate | Unsigned event template for publishing |
Integration Note
@napplet/core is consumed by all packages in the napplet ecosystem for envelope types and NUB dispatch.
- In this repo:
@napplet/shim,@napplet/sdk, and@napplet/vite-pluginimportNappletMessage,NubDomain,ShellSupports, and all shared protocol types from@napplet/core. - NUB packages (
@napplet/nub-relay,@napplet/nub-identity,@napplet/nub-storage,@napplet/nub-ifc,@napplet/nub-keys,@napplet/nub-media,@napplet/nub-notify,@napplet/nub-config): extendNappletMessagefor their domain-specific message types and callregisterNubat import time.
Protocol Reference
- NIP-5D -- Napplet-shell protocol specification
License
MIT
