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

@novasamatech/product-sdk

v0.6.8

Published

Polkadot product SDK: integrate and run your product inside Polkadot browser.

Downloads

2,622

Readme

@novasamatech/product-sdk

An easy way to embed Polkadot host functionality into your dapp.

Overview

Product SDK provides a set of tools to integrate your application with any Polkadot host application. Core features:

  • Generic injectWeb3 provider similar to polkadot-js extension
  • Chat module integration
  • Statement store integration
  • Accounts provider for product accounts and signing
  • Redirect PAPI requests to host application
  • Receive additional information from host application - supported chains, theme, etc.
  • Local storage for persisting data in the host application
  • Preimage manager for looking up and submitting preimages

Installation

npm install @novasamatech/product-sdk --save -E

Usage

Injecting account provider into injectedWeb3 interface

Product SDK can provide account information and signers with the same interface as any other Polkadot-compatible wallet.

import { injectSpektrExtension, SpektrExtensionName } from '@novasamatech/product-sdk';
import { connectInjectedExtension, type InjectedPolkadotAccount } from '@polkadot-api/pjs-signer';

async function getSpektrExtension() {
  const ready = await injectSpektrExtension();

  if (ready) {
    return connectInjectedExtension(SpektrExtensionName)
  }

  return null;
}

async function getAccounts(): Promise<InjectedPolkadotAccount[]> {
  const extension = await getSpektrExtension();

  if (extension) {
    return extension.getAccounts()
  }

  // fallback to other providers
  return [];
}

Redirecting PAPI requests to host application

You can wrap your PAPI provider with Spektr provider to support redirecting requests to the host application.

import { createClient, type PolkadotClient } from 'polkadot-api';
import { getWsProvider } from 'polkadot-api/ws-provider';
import { createPapiProvider, WellKnownChain } from '@novasamatech/product-sdk';

function createPapiClient(): PolkadotClient {
  const polkadotEndpoint = 'wss://...';

-  const provider = getWsProvider(polkadotEndpoint);
+  const provider = createPapiProvider({
+    chainId: WellKnownChain.polkadotRelay,
+    fallback: getWsProvider(polkadotEndpoint),
+  });

  return createClient(provider);
}

Subscribing host connection status

import { metaProvider } from '@novasamatech/product-sdk';

const unsubscribe = metaProvider.subscribeConnectionStatus((status) => {
  console.log('connection status changed', status);
});

Chat Integration

import { createProductChatManager } from '@novasamatech/product-sdk';

// Create manager instance
const chat = createProductChatManager();

// Register your product as a chat contact
const roomRegistrationStatus = await chat.registerRoom({
  roomId: 'my-product-room',
  name: 'My Product',
  icon: 'https://example.com/icon.png'
});

// Register your product as a chat bot
const botRegistrationStatus = await chat.registerBot({
  botId: 'my-product-bot',
  name: 'My Product',
  icon: 'https://example.com/icon.png'
});

// Send a message
const { messageId } = await chat.sendMessage('my-product-room', {
  tag: 'Text',
  value: 'Hello dear user!'
});

// Subscribing to chat actions (incoming messages, etc.)
const subscriber = chat.subscribeAction((action) => {
  console.log('Room:', action.roomId);
  console.log('Sender:', action.peer);

  const payload = action.payload;

  if (payload.tag === 'MessagePosted') {
    console.log('Received message:', action.value);
  }
  if (payload.tag === 'ActionTriggered') {
    console.log('User triggered action:', action.value)
  }
});

// Subscribing to chat room list updates
const chatListSubscriber = chat.subscribeChatList((rooms) => {
  console.log('Chat rooms updated:', rooms);
});

// Sending a custom message
await chat.sendMessage('my-product-room', {
  tag: 'Custom',
  value: { messageType: 'my-custom-type', payload: new Uint8Array([/* ... */]) }
});

// Handling custom message rendering requests from host
const unsubscribeRenderer = chat.onCustomMessageRenderingRequest((messageType, payload, render) => {
  // Build a CustomRendererNode tree and pass it to render()
  render({
    tag: 'Text',
    value: {
      modifiers: undefined,
      props: { style: undefined, color: undefined },
      children: [{ tag: 'String', value: 'Custom message content' }],
    },
  });

  return () => {
    // cleanup when subscription ends
  };
});

Note: Messages sent before registration will be queued and sent automatically after successful registration.

Statement Store

The Statement Store provides a decentralized way to store statements (messages). It can be used for various purposes like p2p communication, storing temp data, etc.

import { createStatementStore } from '@novasamatech/product-sdk';
import type { Topic, Statement, SignedStatement } from '@novasamatech/product-sdk';

// Create statement store instance
const statementStore = createStatementStore();

// Define topics (32-byte identifiers) to categorize statements
const topic: Topic = new Uint8Array(32);

// Subscribe to statement updates for specific topics
const subscription = statementStore.subscribe([topic], (statements) => {
  console.log('Received statement updates:', statements);
});

// Create a proof for a new statement
const accountId = ['product.dot', 0]; // [DotNS identifier, derivation index]
const statement: Statement = {
  proof: undefined,
  decryptionKey: undefined,
  priority: undefined,
  channel: undefined,
  topics: [topic],
  data: new Uint8Array([/* your data */]),
};

const proof = await statementStore.createProof(accountId, statement);

// Submit a signed statement
const signedStatement: SignedStatement = {
  ...statement,
  proof,
};

await statementStore.submit(signedStatement);

// Unsubscribe when done
subscription.unsubscribe();

Accounts Provider

The Accounts Provider allows you to access product accounts and create signers for signing transactions.

import { createAccountsProvider } from '@novasamatech/product-sdk';
import type { ProductAccount } from '@novasamatech/product-sdk';

// Create accounts provider instance
const accountsProvider = createAccountsProvider();

// Get a product account by DotNS identifier and derivation index
const accountResult = await accountsProvider.getProductAccount('product.dot', 0);

if (accountResult.isOk()) {
  const account: ProductAccount = accountResult.value;
  console.log('Public key:', account.publicKey);
}

// Get account alias
const aliasResult = await accountsProvider.getProductAccountAlias('product.dot', 0);

if (aliasResult.isOk()) {
  console.log('Alias:', aliasResult.value);
}

// Get non-product accounts (external wallets)
const nonProductAccountsResult = await accountsProvider.getNonProductAccounts();

if (nonProductAccountsResult.isOk()) {
  console.log('Non-product accounts:', nonProductAccountsResult.value);
}

// Subscribe to account connection status changes
const unsubscribe = accountsProvider.subscribeAccountConnectionStatus((status) => {
  // status: 'connected' | 'disconnected'
  console.log('Account connection status:', status);
});

// Create a signer for a product account (for use with PAPI)
const account: ProductAccount = {
  dotNsIdentifier: 'product.dot',
  derivationIndex: 0,
  publicKey: new Uint8Array([/* ... */])
};
const signer = accountsProvider.getProductAccountSigner(account);

// Create a signer for a non-product account
const nonProductSigner = accountsProvider.getNonProductAccountSigner(account);

// PAPI transaction signing example

const productAccountSignedTx = await tx.signAndSubmit(signer);
const nonProductAccountSignedTx = await tx.signAndSubmit(nonProductSigner);

Local Storage

The Local Storage module provides a way to persist data in the host application's storage.

import { hostLocalStorage, createLocalStorage } from '@novasamatech/product-sdk';

// Use the default instance
const storage = hostLocalStorage;

// Or create a custom instance with a different transport
// const storage = createLocalStorage(customTransport);

// Write and read raw bytes
await storage.writeBytes('key', new Uint8Array([1, 2, 3]));
const bytes = await storage.readBytes('key');

// Write and read strings
await storage.writeString('greeting', 'Hello, World!');
const greeting = await storage.readString('greeting');

// Write and read JSON
await storage.writeJSON('config', { theme: 'dark', fontSize: 14 });
const config = await storage.readJSON('config');

// Clear a key
await storage.clear('key');

Preimage Manager

The Preimage Manager allows you to lookup and submit preimages to the host application.

import { preimageManager, createPreimageManager } from '@novasamatech/product-sdk';

// Use the default instance
const manager = preimageManager;

// Or create a custom instance with a different transport
// const manager = createPreimageManager(customTransport);

// Lookup a preimage by its hash key
const subscription = manager.lookup('0x1234...', (preimage) => {
  if (preimage) {
    console.log('Preimage found:', preimage);
  } else {
    console.log('Preimage not found');
  }
});

// Unsubscribe when done
subscription.unsubscribe();

// Submit a preimage
const preimageKey = await manager.submit(new Uint8Array([1, 2, 3, 4]));