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

@kasanovaio/dapp-sdk

v1.0.2

Published

TypeScript SDK for integrating Kasanova as a dApp wallet — KasWare-compatible L1 + EIP-1193 L2

Readme

Kasanova dApp SDK

TypeScript types, detection helpers, and examples for integrating Kasanova as a wallet provider in your Kaspa dApp.

Kasanova's dApp browser injects a KasWare-compatible window.kasware provider (L1) and an EIP-1193 compatible window.ethereum provider (L2, in development). If your dApp already works with KasWare, it works with Kasanova — zero code changes needed.

This SDK gives you:

  • Full TypeScript types for both provider APIs
  • Detection and connection helpers
  • Working examples (vanilla JS + React)

Quick Start

Install

npm install @kasanovaio/dapp-sdk

Detect & Connect (TypeScript)

import { waitForKasware } from '@kasanovaio/dapp-sdk';

async function connect() {
  try {
    const kasware = await waitForKasware();
    const accounts = await kasware.requestAccounts(); // Shows approval UI
    console.log('Connected:', accounts[0]);

    const balance = await kasware.getBalance();
    console.log('Balance:', balance.confirmed / 1e8, 'KAS');
  } catch (err) {
    console.error('Wallet connection failed:', err);
  }
}

Detect & Connect (Plain JavaScript)

No build step needed — just check window.kasware:

<script>
  function onReady() {
    window.kasware.requestAccounts().then(accounts => {
      console.log('Connected:', accounts[0]);
    });
  }

  if (window.kasware) {
    onReady();
  } else {
    // Kasanova fires both events — listen for either
    window.addEventListener('kasware#initialized', onReady, { once: true });
    window.addEventListener('kasanova:ready', onReady, { once: true });
  }
</script>

Detect Kasanova Specifically (Work in Progress)

Note: The window.kasanova namespace is under active development and not yet available in production builds.

// window.kasanova is only set inside Kasanova (not KasWare)
if (window.kasanova) {
  console.log('Running inside Kasanova v' + window.kasanova.version);
  const kasware = window.kasanova.kasware; // same as window.kasware
}

How It Works

When a user opens your dApp inside Kasanova's built-in browser, the app injects JavaScript providers into the page before your code runs:

┌───────────────────────────────────────────────┐
│              Kasanova Mobile App               │
│  ┌─────────────────────────────────────────┐  │
│  │         In-App WebView (your dApp)      │  │
│  │                                         │  │
│  │   window.kasware  ← L1 KasWare API     │  │
│  │   window.ethereum ← L2 EIP-1193 (dev)  │  │
│  │                                         │  │
│  │   Your dApp code calls these providers  │  │
│  │   ↓                                     │  │
│  │   Kasanova shows approval UI            │  │
│  │   ↓                                     │  │
│  │   User swipes to confirm                │  │
│  │   ↓                                     │  │
│  │   Transaction signed & broadcast        │  │
│  └─────────────────────────────────────────┘  │
└───────────────────────────────────────────────┘

Sensitive operations (connect, send, sign) show a native approval sheet that the user must confirm. Read-only operations (getBalance, getNetwork) resolve immediately.

API Reference — L1 (window.kasware)

The KasWare-compatible provider for Kaspa L1 operations.

Account Methods

requestAccounts()

Request wallet connection. Shows an approval UI to the user.

const accounts: string[] = await window.kasware.requestAccounts();
// accounts[0] = "kaspa:qr..."
  • First call for an origin shows the connection approval sheet
  • Subsequent calls return the cached address (until the user revokes)
  • Throws if the user rejects

getAccounts()

Get connected accounts without triggering approval.

const accounts: string[] = await window.kasware.getAccounts();
// Returns [] if not connected

getPublicKey()

Get the connected account's X-only public key (hex).

const pubkey: string = await window.kasware.getPublicKey();
// "a1b2c3..." (64-character hex string)

getBalance()

Get the connected account's balance.

const balance = await window.kasware.getBalance();
// { total: 1234500000, confirmed: 1234500000, unconfirmed: 0 }

const kas = balance.confirmed / 100_000_000; // Convert sompi to KAS

Note: 1 KAS = 100,000,000 sompi

Network Methods

getNetwork()

Get the current Kaspa network.

const network: string = await window.kasware.getNetwork();
// "kaspa_mainnet" | "kaspa_testnet"

| Network String | Environment | |-----------------|-------------| | kaspa_mainnet | Mainnet | | kaspa_testnet | Testnet 10 |

switchNetwork(network) (not yet implemented)

Will throw an error. Network is determined by the user's Kasanova settings.

await window.kasware.switchNetwork('kaspa_testnet');

Transaction Methods

sendKaspa(toAddress, sompi, options?)

Send KAS. Shows approval UI with amount, recipient, and fee breakdown.

const txid: string = await window.kasware.sendKaspa(
  'kaspa:qr...recipient',
  500_000_000, // 5 KAS in sompi
  { feeRate: undefined } // optional fee override
);
console.log('Transaction:', txid);
  • Amount is in sompi (multiply KAS by 100,000,000)
  • Fee is calculated automatically
  • User sees the full breakdown before confirming
  • Returns the transaction ID on success

signPsbt(psbtHex, options?) (not yet implemented)

Sign a PSKT (Partially Signed Kaspa Transaction). Shows approval UI.

Will throw an error in the current version.

const signedPsbt: string = await window.kasware.signPsbt(psbtHex, {
  autoFinalized: true,
  toSignInputs: [{ index: 0 }],
});

signPsbts(psbtHexs, options?) (not yet implemented)

Sign multiple PSKTs in batch.

Will throw an error in the current version.

const signed: string[] = await window.kasware.signPsbts(
  [psbt1Hex, psbt2Hex],
  [{ autoFinalized: true }, { autoFinalized: true }],
);

pushTx(rawTx) (not yet implemented)

Broadcast a raw transaction.

Will throw an error in the current version.

const txid: string = await window.kasware.pushTx(rawTransactionHex);

pushPsbt(psbtHex) (not yet implemented)

Finalize and broadcast a signed PSKT.

Will throw an error in the current version.

const txid: string = await window.kasware.pushPsbt(signedPsbtHex);

Message Signing

signMessage(message, type?)

Sign a text message. Shows approval UI with the message content.

// Schnorr signature (default)
const sig: string = await window.kasware.signMessage('Hello dApp!');

// ECDSA signature
const sigEcdsa: string = await window.kasware.signMessage('Hello dApp!', 'ecdsa');
  • Default signature type is 'schnorr' (Kaspa native)
  • 'ecdsa' is available for compatibility

Utility

getVersion()

Get the wallet version.

const version: string = await window.kasware.getVersion();
// "1.2.3"

Events

Subscribe to wallet state changes:

// Account changed (user switched wallet)
window.kasware.on('accountsChanged', (accounts: string[]) => {
  console.log('Active account:', accounts[0]);
});

// Network changed
window.kasware.on('networkChanged', (network: string) => {
  console.log('Network:', network);
});

// Wallet disconnected
window.kasware.on('disconnect', () => {
  console.log('Wallet disconnected');
});

// Wallet locked (session expired)
window.kasware.on('lock', () => {
  console.log('Wallet locked — user needs to re-authenticate');
});

// Wallet unlocked (biometric passed)
window.kasware.on('unlock', () => {
  console.log('Wallet unlocked');
});

| Event | Data | Description | |--------------------|------------|---------------------------------| | connect | {} | Provider ready | | disconnect | — | Connection lost | | accountsChanged | string[] | Active account changed | | networkChanged | string | Network switched | | lock | — | Wallet locked (session expired) | | unlock | — | Wallet unlocked |

Unsubscribe:

const handler = (accounts) => { /* ... */ };
window.kasware.on('accountsChanged', handler);
window.kasware.removeListener('accountsChanged', handler);

API Reference — L2 (window.ethereum) (In Development)

Note: L2 support is in active development and not yet available in production builds.

For Kasplex L2 / EVM-compatible dApps, Kasanova will inject an EIP-1193 provider.

Detection

// Check if it's Kasanova specifically (not just any MetaMask-compatible wallet)
if (window.ethereum?.isKasanova) {
  console.log('Running inside Kasanova L2 browser');
}

Kasanova also announces itself via EIP-6963:

window.addEventListener('eip6963:announceProvider', (event) => {
  if (event.detail.info.rdns === 'app.kasanova') {
    const provider = event.detail.provider;
    // Use provider...
  }
});

// Request announcement
window.dispatchEvent(new Event('eip6963:requestProvider'));

Standard EIP-1193 Usage

// Connect
const accounts = await window.ethereum.request({
  method: 'eth_requestAccounts',
});

// Get chain ID
const chainId = await window.ethereum.request({
  method: 'eth_chainId',
});

// Send transaction
const txHash = await window.ethereum.request({
  method: 'eth_sendTransaction',
  params: [{
    to: '0x...',
    value: '0x...',
    data: '0x...',
  }],
});

Properties

| Property | Type | Description | |-------------------|-----------|---------------------------------| | isMetaMask | boolean | Always true (compatibility) | | isKasanova | boolean | Always true (Kasanova-specific) | | chainId | string | Current chain ID (hex) | | selectedAddress | string | Connected address | | isConnected | boolean | Connection status |

Provider Detection Pattern

Here's the recommended pattern for supporting multiple wallets:

async function connectWallet() {
  // Option 1: Running inside Kasanova (WIP — not yet in production)
  if (window.kasanova) {
    const accounts = await window.kasanova.kasware.requestAccounts();
    return { provider: 'kasanova', address: accounts[0] };
  }

  // Option 2: KasWare-compatible provider (works with both Kasanova and KasWare)
  if (window.kasware) {
    const accounts = await window.kasware.requestAccounts();
    return { provider: 'kasware', address: accounts[0] };
  }

  // Option 3: No wallet found
  throw new Error('No Kaspa wallet detected. Please install Kasanova or KasWare.');
}

For L2 dApps, distinguish Kasanova from other Ethereum wallets:

function getProvider() {
  if (window.ethereum?.isKasanova) {
    return { name: 'Kasanova', provider: window.ethereum };
  }
  if (window.ethereum?.isMetaMask) {
    return { name: 'MetaMask', provider: window.ethereum };
  }
  return null;
}

Examples

Vanilla JavaScript

See examples/vanilla/index.html — a self-contained HTML page with connect, send, and sign flows. Open it inside Kasanova's dApp browser.

React

See examples/react/KasanovaWallet.tsx — a useKasanova() hook and example component. Drop it into any React app.

Opening Your dApp from a Deeplink

Your dApp can include a button or link that opens it directly inside Kasanova's dApp browser. This is how The Lucky Chamber's "Open in Kasanova" button works.

Deeplink Format

The raw scheme for opening a dApp in Kasanova:

kasanova://open-dapp?url=https://yourdapp.com

Short form:

ksnv://open-dapp?url=https://yourdapp.com

Using Airbridge (Recommended)

In production, use Kasanova's Airbridge link (go.kasanova.app) instead of the raw scheme. This gives you:

  • Install fallback — redirects to App Store / Play Store if Kasanova isn't installed
  • Deferred deep linking — the dApp opens automatically after install
  • Attribution tracking — know where your users come from
<!-- Recommended: Airbridge link with deferred deep link -->
<a href="https://go.kasanova.app?deeplink_url=kasanova%3A%2F%2Fopen-dapp%3Furl%3Dhttps%3A%2F%2Fyourdapp.com">
  Open in Kasanova
</a>

With JavaScript:

function openInKasanova() {
  const dappUrl = 'https://yourdapp.com';
  const deeplink = `kasanova://open-dapp?url=${encodeURIComponent(dappUrl)}`;
  const airbridgeUrl = `https://go.kasanova.app?deeplink_url=${encodeURIComponent(deeplink)}`;

  window.location.href = airbridgeUrl;
}

Contact the Kasanova team to get a dedicated Airbridge tracking URL for your dApp (with sub_id for attribution).

Raw Scheme (Development Only)

For local testing, you can use the raw scheme directly:

// Only for development — no install fallback
window.location.href = 'kasanova://open-dapp?url=http://localhost:4200';

How It Works

  1. User taps the Airbridge link on their phone
  2. If Kasanova is installed, it opens directly
  3. If not installed, user is sent to App Store / Play Store (then deep link fires after install)
  4. If the wallet is locked, biometric authentication is triggered
  5. Kasanova validates the URL against its backend-configured dApp allowlist
  6. The dApp browser opens at your URL with window.kasware injected

Requirements

  • Your dApp URL must be registered in Kasanova's backend dApp list for the deeplink to work (security measure — unregistered URLs are silently rejected)
  • URL must use HTTPS (except localhost for local development)
  • URL matching is by origin (scheme + host + port), case-insensitive

Getting Listed in Kasanova

Kasanova's dApp browser has a discovery screen with curated dApps. To get your dApp listed:

  1. Make sure your dApp works with window.kasware (this guide)
  2. Your site must be served over HTTPS
  3. Contact the Kasanova team to submit your dApp for listing:

Listed dApps appear in the discovery grid with:

  • Icon, name, and description
  • Category badge (games, marketplace, defi, social, etc.)
  • Layer indicator (L1 or L2)

Users can also browse to any URL directly — listing is not required for compatibility.

Sompi Conversion Reference

| KAS | Sompi | |-----------|-----------------| | 0.001 KAS | 100,000 | | 0.01 KAS | 1,000,000 | | 0.1 KAS | 10,000,000 | | 1 KAS | 100,000,000 | | 10 KAS | 1,000,000,000 | | 100 KAS | 10,000,000,000 |

// KAS to sompi
const sompi = Math.round(kasAmount * 100_000_000);

// Sompi to KAS
const kas = sompi / 100_000_000;

Security Notes

  • Private keys never leave the device. All signing happens inside Kasanova's secure enclave.
  • Every sensitive operation requires user confirmation. Your dApp cannot silently send transactions or sign messages.
  • Origin-based permissions. Users grant access per-origin and can revoke at any time from Settings.
  • HTTPS required. Kasanova rejects HTTP URLs (except localhost during development).

KasWare Compatibility

Kasanova implements the same window.kasware API as the KasWare browser extension. This means:

  • Any dApp built for KasWare works in Kasanova without code changes
  • Any dApp built for Kasanova works in KasWare without code changes
  • The API surface, method signatures, and return types are identical

The only difference is the transport: KasWare uses browser extension messaging, while Kasanova uses an in-app WebView bridge. This is transparent to your dApp code.

License

MIT