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

@luknyb/cipd

v0.1.0

Published

Cosmos Injected Provider Discovery - A standardized way to discover Cosmos wallet extensions, inspired by EIP-6963

Readme

CIPD - Cosmos Injected Provider Discovery

A standardized way to discover Cosmos wallet extensions in the browser, inspired by EIP-6963 for Ethereum.

Why?

The Cosmos ecosystem lacks a standardized way to discover wallet extensions. Currently, dApps need to:

  • Check for specific global variables (window.keplr, window.leap, etc.)
  • Hardcode wallet detection logic for each wallet
  • Deal with race conditions when wallets inject at different times
  • Maintain a growing list of wallet-specific detection code

CIPD solves this by providing an event-based discovery protocol that:

  • Works with any wallet that implements the protocol
  • Handles race conditions automatically
  • Provides a consistent API for wallet discovery
  • Includes a polyfill for existing wallets that don't yet support CIPD natively

What?

CIPD defines two custom events:

  • cosmos:requestProvider - Dispatched by dApps to request wallet announcements
  • cosmos:announceProvider - Dispatched by wallets to announce their presence

Each wallet announcement includes:

interface CosmosProviderDetail {
  info: {
    uuid: string           // Unique identifier for this provider instance
    name: string           // Human-readable wallet name (e.g., "Keplr")
    icon: string           // Data URL of the wallet icon
    rdns: string           // Reverse domain name ID (e.g., "app.keplr")
  }
  provider: CosmosProvider // The wallet's Cosmos provider interface
}

Installation

npm install @luknyb/cipd
# or
pnpm add @luknyb/cipd
# or
yarn add @luknyb/cipd

Usage

Basic Usage

import { createStore } from '@luknyb/cipd'

// Create a store to manage discovered wallets
const store = createStore()

// Subscribe to wallet changes
store.subscribe((providers) => {
  console.log('Available wallets:', providers.map(p => p.info.name))
})

// Get all currently discovered wallets
const wallets = store.getProviders()

// Find a specific wallet by RDNS
const keplr = store.findProvider('app.keplr')
if (keplr) {
  await keplr.provider.enable('cosmoshub-4')
  const key = await keplr.provider.getKey('cosmoshub-4')
  console.log('Address:', key.bech32Address)
}

With Svelte

<script lang="ts">
import { onMount } from 'svelte'
import { createStore, type CosmosProviderDetail } from '@luknyb/cipd'

let wallets = $state<CosmosProviderDetail[]>([])

onMount(() => {
  const store = createStore()
  return store.subscribe((providers) => {
    wallets = [...providers]
  }, { emitImmediately: true })
})
</script>

{#each wallets as wallet}
  <button onclick={() => connect(wallet)}>
    <img src={wallet.info.icon} alt={wallet.info.name} />
    {wallet.info.name}
  </button>
{/each}

With React

import { useEffect, useState } from 'react'
import { createStore, type CosmosProviderDetail } from '@luknyb/cipd'

function WalletList() {
  const [wallets, setWallets] = useState<CosmosProviderDetail[]>([])

  useEffect(() => {
    const store = createStore()
    return store.subscribe((providers) => {
      setWallets([...providers])
    }, { emitImmediately: true })
  }, [])

  return (
    <div>
      {wallets.map((wallet) => (
        <button key={wallet.info.uuid} onClick={() => connect(wallet)}>
          <img src={wallet.info.icon} alt={wallet.info.name} />
          {wallet.info.name}
        </button>
      ))}
    </div>
  )
}

With Vue

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { createStore, type CosmosProviderDetail } from '@luknyb/cipd'

const wallets = ref<CosmosProviderDetail[]>([])
let unsubscribe: (() => void) | undefined

onMounted(() => {
  const store = createStore()
  unsubscribe = store.subscribe((providers) => {
    wallets.value = [...providers]
  }, { emitImmediately: true })
})

onUnmounted(() => unsubscribe?.())
</script>

<template>
  <button v-for="wallet in wallets" :key="wallet.info.uuid" @click="connect(wallet)">
    <img :src="wallet.info.icon" :alt="wallet.info.name" />
    {{ wallet.info.name }}
  </button>
</template>

API Reference

createStore(options?)

Creates a store for managing discovered wallet providers.

interface CreateStoreOptions {
  polyfill?: boolean  // Whether to detect existing wallets (default: true)
}

const store = createStore({ polyfill: true })

Store Methods

| Method | Description | |--------|-------------| | subscribe(listener, options?) | Subscribe to provider changes. Returns unsubscribe function. | | getProviders() | Get all currently discovered providers. | | findProvider(rdns) | Find a provider by its RDNS identifier. | | reset() | Clear and re-request providers. | | clear() | Clear all providers from the store. | | destroy() | Destroy the store and remove all listeners. |

requestProviders()

Manually request all wallets to announce themselves.

import { requestProviders } from '@luknyb/cipd'

requestProviders()

announceProvider(detail)

Manually announce a wallet provider (useful for wallet developers).

import { announceProvider } from '@luknyb/cipd'

announceProvider({
  info: {
    uuid: crypto.randomUUID(),
    name: 'My Wallet',
    icon: 'data:image/svg+xml;base64,...',
    rdns: 'com.mywallet',
  },
  provider: myCosmosProvider,
})

Supported Wallets

The polyfill automatically detects these wallets:

| Wallet | RDNS | |--------|------| | Keplr | app.keplr | | Leap | io.leapwallet | | Cosmostation | io.cosmostation | | XDEFI | io.xdefi | | Falcon | io.falconwallet | | Coin98 | io.coin98 |

For Wallet Developers

To natively support CIPD in your wallet extension:

// Listen for discovery requests
window.addEventListener('cosmos:requestProvider', () => {
  announceWallet()
})

// Announce on load
announceWallet()

function announceWallet() {
  window.dispatchEvent(
    new CustomEvent('cosmos:announceProvider', {
      detail: {
        info: {
          uuid: crypto.randomUUID(),
          name: 'My Wallet',
          icon: 'data:image/svg+xml;base64,...',
          rdns: 'com.mywallet',
        },
        provider: window.myWallet,
      },
    })
  )
}

TypeScript

Full TypeScript support with exported types:

import type {
  CosmosProvider,
  CosmosProviderDetail,
  CosmosProviderInfo,
  Key,
  OfflineSigner,
  ChainInfo,
  Store,
} from '@luknyb/cipd'

License

MIT