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

meteor-canton-sdk

v0.1.1

Published

SDK for dApps to connect to Meteor Canton Wallet

Readme

Meteor Canton SDK (meteor-canton-sdk)

A comprehensive, developer-friendly SDK for decentralized applications (dApps) to securely interact with the Meteor Canton Wallet.

This SDK utilizes a JSON-RPC over postMessage architecture, providing a seamless popup-based user experience for wallet connection and transaction approval. It enables dApps to authenticate users, query accounts and token holdings, and submit both standard transfers and raw Daml commands directly to the Canton network via the Meteor Wallet.


Table of Contents


Installation

npm install meteor-canton-sdk
# or
bun add meteor-canton-sdk
# or
yarn add meteor-canton-sdk

Quick Start

import { meteor } from 'meteor-canton-sdk';

// 1. Initialize the SDK (Call once on app startup)
meteor.init({
  network: 'testnet', // 'testnet' | 'mainnet'
  appName: 'My Awesome DApp',
});

// 2. Connect the wallet (Triggers a popup for user approval)
const { partyId, publicKey, token } = await meteor.connect();
console.log(`Connected Party: ${partyId}`);

// 3. Fetch user's token holdings
const tokens = await meteor.listTokens();

// 4. Initiate a token transfer (Triggers popup for signature/approval)
if (tokens.length > 0) {
  const token = tokens[0].interfaceViewValue;
  const result = await meteor.transfer({
    receiverPartyId: 'recipient::party-id',
    amount: '10.5',
    instrumentId: token.instrumentId.id,
    instrumentAdmin: token.instrumentId.admin,
    memo: 'Payment for services',
  });
  console.log('Transfer Result:', result);
}

// 5. Disconnect when finished
await meteor.disconnect();

Architecture & Lifecycle

The SDK communicates with the Meteor Canton Wallet through two channels: a popup window (for interactive operations) and direct HTTP calls (for read-only queries).

┌──────────────────────────┐
│  Your DApp               │
│  meteor-canton-sdk       │
└───┬──────────────────┬───┘
    │                  │
    │ postMessage      │ HTTP (REST)
    │ (JSON-RPC)       │ with JWT
    ▼                  ▼
┌──────────┐   ┌─────────────────┐
│  Wallet  │   │  Wallet Backend │
│  Popup   │──▶│  /api/wallet/*  │
│          │   └────────┬────────┘
│ • connect│ HTTP (REST)│ gRPC/HTTP
│ • approve│            ▼
│ • sign   │   ┌─────────────────┐
└──────────┘   │  Canton Network │
               └─────────────────┘

Popup channel — used for interactive operations that require user approval:

  • connect(), disconnect(), status()
  • listAccounts()
  • transfer(), prepareExecuteAndWait()

Direct HTTP channel — used for read-only queries (no popup needed):

  • listTokens()GET /wallet/tokens
  • pendingTokens()GET /wallet/pending-tokens

Lifecycle

  1. Connection: connect() opens a popup to the wallet's /dapp-connect page. The SDK polls with SPLICE_WALLET_EXT_READY until the popup replies SPLICE_WALLET_EXT_ACK to establish a secure JSON-RPC bridge. On success, the SDK receives a JWT token, party ID, and account list.
  2. Read-only queries: listTokens() and pendingTokens() call the wallet backend directly via HTTP using the JWT obtained during connection. No popup interaction is needed.
  3. Transactions: State-mutating actions (e.g., transfer, prepareExecuteAndWait) send a request to the popup for the user to review and approve. After approval, results are returned via postMessage.
  4. Auto-recovery: If the popup is closed between calls, the SDK will automatically reopen it when a new popup-based operation is initiated.
  5. Disconnect: disconnect() sends a disconnect RPC, closes the popup, and clears all state (JWT, partyId, accounts).

API Reference

The SDK exports a singleton instance named meteor.

Core State Properties

After a successful connection, the meteor instance exposes the following synchronous properties:

| Property | Type | Description | | -------- | ---- | ----------- | | meteor.partyId | string | The primary connected Canton party ID. | | meteor.token | string | The active JWT auth token used for backend API queries. | | meteor.isConnected | boolean | true if a wallet connection is currently active. |


Initialization & Connection

meteor.init(config: MeteorConfig): void

Must be called before any other methods to configure network endpoints. Sets the URL for the popup and backend REST calls.

Network Defaults:

  • devnet: Wallet http://localhost:8081/dapp-connect, API http://localhost:3000/api (Note: there is no public devnet wallet)
  • testnet: Wallet https://testnet.canton.meteorwallet.app/dapp-connect, API https://testnet.canton.meteorwallet.app/api
  • mainnet: Wallet https://app.canton.meteorwallet.app/dapp-connect, API https://app.canton.meteorwallet.app/api

meteor.connect(): Promise<ConnectResult>

Opens the wallet popup, requests user approval, and retrieves primary account details and an authentication token. Note: Must be triggered by a user gesture (e.g., button click) to bypass browser popup blockers.

Returns: A Promise that resolves to a ConnectResult object.

meteor.disconnect(): Promise<void>

Sends a disconnect signal to the wallet, closes the active popup, and wipes the local session state (including the JWT, cached partyId, and accounts).

meteor.status(): Promise<StatusResult>

Queries the underlying wallet connection and network synchronization status via JSON-RPC.

Returns: A Promise that resolves to a StatusResult.


Queries

(These methods require an active connection and utilize the fetched JWT to query the wallet backend directly).

meteor.listAccounts(): Promise<Account[]>

Returns all accounts (parties) associated with the connected wallet. The first account or the one marked primary is typically used as the default sender.

meteor.listTokens(): Promise<TokenHolding[]>

Fetches all confirmed token balances owned by the connected party.

meteor.pendingTokens(): Promise<TokenHolding[]>

Fetches in-flight (pending) token holdings that have not yet been fully finalized on the ledger.


Transactions & Commands

(These methods will automatically refocus or reopen the wallet popup for user review and signature).

meteor.transfer(params: TransferParams): Promise<TransferResult>

Initiates a standard token transfer to another party. Validates the parameters client-side before sending the RPC request.

Validation Rules:

  • receiverPartyId, amount, instrumentId, and instrumentAdmin are strictly required.
  • amount must be a positive numeric string.

meteor.prepareExecuteAndWait(params: ExecuteParams): Promise<ExecuteResult>

Submits raw Daml commands directly to the ledger. Opens the wallet popup for the user to review and sign the execution request. See Advanced: Raw Daml Commands.


TypeScript Interfaces

The SDK exports all its types. You can import them directly:

import type { MeteorConfig, TransferParams, Account, TokenHolding } from 'meteor-canton-sdk';

Core Configuration & Connection

export type MeteorNetwork = 'testnet' | 'mainnet' | 'devnet';

export interface MeteorConfig {
  network: MeteorNetwork;
  appName?: string;
  popupFeatures?: string; // Default: 'width=420,height=700'
}

export interface ConnectResult {
  partyId: string;
  publicKey: string;
  token: string;
}

Entities

export interface Account {
  primary: boolean;
  partyId: string;
  publicKey: string;
  status: string;
  hint: string;
  namespace: string;
  networkId: string;
  signingProviderId: string;
}

export interface TokenHolding {
  interfaceViewValue: {
    owner: string;
    amount: string;
    instrumentId: { id: string; admin: string };
    lock: unknown;
  };
  createdAt: string;
  utxoCount: number;
  contractIds: string[];
}

Transactions

export interface TransferParams {
  receiverPartyId: string;
  amount: string;
  instrumentId: string;
  instrumentAdmin: string;
  memo?: string;
  expiryDate?: string;
  senderPartyId?: string; // Defaults to meteor.partyId
}

export interface TransferResult {
  tx: {
    status: string;
    commandId: string;
    payload: { updateId: string; completionOffset: number };
  };
}

export interface ExecuteParams {
  commands: unknown;
  commandId?: string;
}

export interface ExecuteResult {
  tx: {
    status: string;
    commandId: string;
    payload: { updateId: string; completionOffset: number };
  };
}

export interface StatusResult {
  provider: { id: string; providerType: string };
  connection: {
    isConnected: boolean;
    isNetworkConnected: boolean;
  };
}

Error Handling & Edge Cases

Popup Blockers

Because meteor.connect() relies on window.open, browsers will block it if it's not triggered directly by a user interaction. Error: Error: Failed to open wallet popup — check your popup blocker Solution: Always call meteor.connect() inside an onClick or similar event handler.

Authentication State

If you attempt to call listTokens(), transfer(), or prepareExecuteAndWait() without connecting first, the SDK will throw: Error: Error: Not connected. Call connect() first. or Error: No auth token. Call connect() first.

Wallet Initialization Timeout

If the popup opens but the wallet application fails to load or handshake within 15 seconds, the SDK will reject the connection: Error: Error: Wallet failed to initialize

RPC Timeouts

Transactions and status requests that rely on user approval or wallet processing have a 120-second timeout. Error: Error: RPC "<method>" timed out


React Integration Guide

The ideal way to integrate meteor-canton-sdk into a React application is via @tanstack/react-query, which handles caching, loading states, and refetching elegantly.

1. Global Setup

Initialize the SDK once at the root of your application.

import { useEffect } from 'react';
import { meteor } from 'meteor-canton-sdk';

export function App() {
  useEffect(() => {
    meteor.init({ network: 'testnet', appName: 'My React DApp' });
  }, []);
  
  return <WalletConnector />;
}

2. Connect & List Tokens

import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { meteor } from 'meteor-canton-sdk';

function WalletConnector() {
  const [connected, setConnected] = useState(meteor.isConnected);

  const handleConnect = async () => {
    try {
      await meteor.connect();
      setConnected(true);
    } catch (error) {
      console.error("Connection failed", error);
    }
  };

  const { data: tokens, isLoading } = useQuery({
    queryKey: ['tokens', meteor.partyId],
    queryFn: () => meteor.listTokens(),
    enabled: connected, // Only fetch if connected
  });

  if (!connected) return <button onClick={handleConnect}>Connect Wallet</button>;

  return (
    <div>
      <p>Welcome, {meteor.partyId}</p>
      {isLoading ? <p>Loading tokens...</p> : (
        <ul>
          {tokens?.map(t => (
            <li key={`${t.interfaceViewValue.instrumentId.id}-${t.interfaceViewValue.instrumentId.admin}`}>
              {t.interfaceViewValue.instrumentId.id}: {t.interfaceViewValue.amount}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

Advanced: Raw Daml Commands

For complex smart contract interactions beyond standard transfers, use meteor.prepareExecuteAndWait(). This accepts a JSON array of standard Daml ExerciseCommand or CreateCommand structures.

const result = await meteor.prepareExecuteAndWait({
  commands: [
    {
      ExerciseCommand: {
        templateId: '#splice-api-token-transfer-instruction-v1:Splice.Api.Token.TransferInstructionV1:TransferFactory',
        contractId: 'your-target-contract-id',
        choice: 'TransferFactory_Transfer',
        choiceArgument: {
          // Arguments matching your Daml choice structure
        },
      },
    },
  ],
  // commandId: 'optional-custom-id' // Auto-generated if omitted
});

console.log('Transaction Status:', result.tx.status);