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

@polkadot-apps/terminal

v0.3.0

Published

QR code login and signing for CLI/terminal apps via Polkadot mobile wallet pairing

Readme

@polkadot-apps/terminal

QR code login, attestation, and transaction signing for CLI/terminal apps via the Polkadot mobile wallet.

Wraps the @novasamatech/host-papp SDK with Node.js-compatible adapters (file-based storage, WebSocket transport) so the full SSO protocol works outside the browser.

Installation

pnpm add @polkadot-apps/terminal

Setup

Register the WASM loader — the host-papp SDK depends on verifiablejs which uses inline WASM (browser-only). The register hook redirects it to the Node.js WASM build. Pass it via --import:

node --import @polkadot-apps/terminal/register app.js
tsx --import @polkadot-apps/terminal/register app.ts

Or in your package.json scripts:

{
    "scripts": {
        "start": "tsx --import @polkadot-apps/terminal/register index.ts"
    }
}

Quick Start

import { createTerminalAdapter, renderQrCode, waitForSessions } from "@polkadot-apps/terminal";

// 1. Create the adapter
const adapter = createTerminalAdapter({
    appId: "my-terminal-app",
    metadataUrl: "https://example.com/metadata.json",
});

// 2. Subscribe to pairing status to show the QR code
adapter.sso.pairingStatus.subscribe(async (status) => {
    if (status.step === "pairing") {
        console.log(await renderQrCode(status.payload));
        console.log("Scan with the Polkadot mobile app...");
    }
});

// 3. Authenticate (QR pairing + on-chain attestation)
const result = await adapter.sso.authenticate();

result.match(
    (session) => console.log("Logged in!", session?.id),
    (error) => console.error("Failed:", error.message),
);

// 4. Wait for sessions to load (they load asynchronously from disk)
const sessions = await waitForSessions(adapter, 2000);

// 5. Sign messages via the paired wallet
if (sessions.length > 0) {
    const session = sessions[0];
    const sig = await session.signRaw({
        address: "0x" + Buffer.from(session.remoteAccount.accountId).toString("hex"),
        data: { tag: "Bytes", value: new TextEncoder().encode("Hello") },
    });

    sig.match(
        (data) => console.log("Signature:", data.signature),
        (error) => console.error("Failed:", error.message),
    );
}

API

createTerminalAdapter(options): PappAdapter

Creates a terminal adapter backed by the host-papp SDK.

Options:

  • appId -- unique app identifier (used as storage namespace)
  • metadataUrl -- URL to metadata JSON shown during pairing
  • endpoints? -- statement store WebSocket endpoints (defaults to Paseo)
  • hostMetadata? -- optional host environment info

Returns a PappAdapter with:

  • sso -- auth component (.authenticate(), .abortAuthentication(), status subscriptions)
  • sessions -- session manager (signing, disconnect)

renderQrCode(data, options?): Promise<string>

Render a string as a QR code using Unicode half-block characters for terminal display.

createNodeStorageAdapter(appId, storageDir?): StorageAdapter

File-based storage adapter for Node.js. Data persists in storageDir (defaults to ~/.polkadot-apps/).

Testing

The @polkadot-apps/terminal/testing subpath exports createTestSession, a helper that synthesizes a valid persisted session on disk. E2E tests can inject a known-good session without going through QR pairing + attestation:

import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { createTerminalAdapter, waitForSessions } from "@polkadot-apps/terminal";
import { createTestSession } from "@polkadot-apps/terminal/testing";

const storageDir = mkdtempSync(join(tmpdir(), "e2e-"));
const { sessionId } = await createTestSession({
    appId: "my-terminal-app",
    storageDir,
});

const adapter = createTerminalAdapter({
    appId: "my-terminal-app",
    metadataUrl: "https://example.com/metadata.json",
    storageDir,
});
const sessions = await waitForSessions(adapter);
// sessions[0].id === sessionId

Limits and usage notes.

  • Signing does not round-trip. session.signRaw goes out over the statement store and expects a real phone to respond. Use this helper for flows that test session discovery, persistence, and logout — not happy-path signing.
  • Expiry tests still work. The synthesized local account was never registered on the People chain, so any statement-store write from this session fails with NoAllowanceError. That's the same error the CLI sees when a previously valid session's on-chain attestation has expired, so tests that assert "CLI handles an expired session" can be written against a synthesized session even though there's no expiresAt knob.
  • No expiresAt option. The on-disk codec has no expiry field; validity lives on chain. See above.
  • Corrupted-session cases don't need a helper — fs.writeFile("<storageDir>/<appId>_SsoSessions.json", "not-hex") from the test is enough.

Signing

After login and attestation, the paired wallet can sign messages via the statement store.

signRaw works end-to-end: the wallet receives the request, shows a prompt, and returns the signature.

signPayload (for signing transaction payloads) is not yet functional — the request is submitted but the wallet does not respond. This is a known limitation of the current wallet/protocol version.

Notes

WebSocket transport

The adapter uses @polkadot-api/ws-provider/node, which internally bundles the ws package — no globalThis.WebSocket polyfill is required.

The bundled WebSocket is constructed without followRedirects: true, so endpoints behind an HTTP redirect will fail to connect. The default Paseo stable-stage endpoints do not redirect. If you must point at an endpoint that does, supply the resolved URL directly via the endpoints option rather than the redirecting one.

How It Works

  1. QR Pairing -- generates Sr25519 + P256 keypairs, encodes a polkadotapp://pair?handshake=0x... deep link, subscribes to the statement store
  2. Attestation -- registers the local account on the People chain so it can publish statements
  3. Signing -- sends encrypted signing requests to the wallet via the statement store, receives signed responses

Sessions are persisted to ~/.polkadot-apps/ and survive across restarts. The SDK loads them asynchronously on startup — subscribe to adapter.sessions.sessions and wait for the first emission.

Dependencies

  • @novasamatech/host-papp -- Polkadot host-product SDK (auth, attestation, signing)
  • @novasamatech/statement-store -- statement store client and session management
  • @novasamatech/storage-adapter -- storage interface
  • @polkadot-api/ws-provider -- WebSocket JSON-RPC provider
  • neverthrow -- Result type for error handling
  • qrcode -- QR code generation