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

@algorandfoundation/wallet-provider

v1.0.0

Published

Abstract interface for compatibility between wallets

Readme

💳 Wallet Provider

A modular, extensible wallet provider abstraction for wallet providers. Inspired by the architecture of OctoKit and TxnLab's use-wallet, this package provides a base for building wallet integrations that can be dynamically extended with additional functionality.

🏗️ Provider

The Provider is the base class that represents a wallet's identity and core configuration. It manages:

  • Configuration: Shared options for the provider and its extensions.
  • Composition: Orchestrating the application of extensions.

🧩 Extensions

Extensions are modular functions that augment the Provider with specific capabilities.

  • Responsibility: Extensions handle domain-specific logic such as account management, transaction signing, or specific API integrations (e.g., Liquid, OIDC).
  • Flexibility: They can be independent packages, provided by third parties, or baseline defaults (like KeyStore + BIP39).
  • Prefer Composition: Use withExtensions to create specialized Provider classes with a fixed set of extensions.

🚀 Usage

The following walk-through assembles a provider from several extensions at your application's composition root and wires it to your stores. It sticks to the steps; the reasoning behind each one is in the TUTORIAL, and how data then flows between the stores is in ARCHITECTURE.

1. Pick your extensions

An extension is a plain, synchronous function (provider, options) => api exported as With<DomainPlural>. Install the packages for the domains you need, for example:

  • @algorandfoundation/keystore [published canary]
  • @algorandfoundation/accounts [not published, future meta package]
  • @algorandfoundation/accounts-keystore-extension [published canary, reference example, not for production]
  • @algorandfoundation/provider-migrations [published canary]

(see For extension authors). The examples below use WithKeyStore, WithAccounts, and WithAccountsKeystore.

[!NOTE] WithAccountsKeystore appears in this walkthrough because it is the smallest published bridge and shows the pattern end to end. It is a reference implementation only: it has no chain address scheme and keys each account by the raw (base64) public key. For a real Algorand wallet substitute the chain-specific bridge, WithAlgorandAccounts (@algorandfoundation/algorand-accounts-extension [not published]), which owns Algorand and Falcon-1024 address derivation.

2. Create one store per domain

You own the stores. Create one TanStack Store atom per domain and keep them at your composition root:

import { Store } from "@tanstack/store";
import type { KeyStoreState } from "@algorandfoundation/keystore";
import type { AccountStoreState } from "@algorandfoundation/accounts";

const keysStore = new Store<KeyStoreState>({ keys: [], status: "idle" });
const accountsStore = new Store<AccountStoreState>({
  wallets: {},
  activeWallet: null,
});

Because you create the stores, you can also persist them, hydrate them on a server, inspect them in devtools, or swap them wholesale in tests. The provider operates on them; it does not own them (why).

3. Compose and instantiate

Provider.withExtensions([...]) composes a class on the fly. Its constructor is (config: ProviderOptions, options?: ExtensionOptions): each extension's configuration, including its store, goes in under that domain's namespace, options.<plural>:

import { Provider, type ProviderOptions } from "@algorandfoundation/wallet-provider";
import { WithKeyStore } from "@algorandfoundation/keystore";
import { WithAccounts } from "@algorandfoundation/accounts";
import { WithAccountsKeystore } from "@algorandfoundation/accounts-keystore-extension";

const MyWallet = Provider.withExtensions([WithKeyStore, WithAccounts, WithAccountsKeystore]);

const config: ProviderOptions = {
  id: "my-wallet",
  name: "My Wallet",
  icon: "https://example.com/icon.png",
};

const wallet = new MyWallet(config, {
  keystore: { store: keysStore },
  accounts: { store: accountsStore },
});

When you want a named, importable class, extend the composed one:

export class MyWalletProvider extends Provider.withExtensions([
  WithKeyStore,
  WithAccounts,
  WithAccountsKeystore,
]) {}

Either way, TypeScript infers the combined surface: everything each extension contributes shows up fully typed on the instance, and options is the single ExtensionOptions registry, so an unregistered namespace or a misspelled field is a compile error. (The plain class MyWallet extends Provider { … } form deliberately keeps options loose so a concrete wallet can own its option shape; see DISCOVERY.)

4. Mind the ordering

Extensions apply in order, and each one receives the provider as it exists so far. An extension that depends on another's API (a bridge that reads from the keystore, say) must come after it (bridges are named With<Domain><Dependency>):

// Correct: the bridge can see everything WithKeyStore and WithAccounts contributed.
// (Swap WithAccountsKeystore for WithAlgorandAccounts in a real Algorand wallet.)
Provider.withExtensions([WithKeyStore, WithAccounts, WithAccountsKeystore]);

// Wrong: the bridge applies first and finds no keys API on the provider.
Provider.withExtensions([WithAccountsKeystore, WithKeyStore, WithAccounts]);

Extensions that only collaborate through shared stores have no ordering constraint.

5. Use the composed provider

Invoke commands on the provider's API namespace (provider.<singular>.store); read state through the reactive getters (provider.<plural>) or subscribe to the stores you created:

// Commands go through the provider.
await wallet.account.store.addAccount({ ... });

// Reads can go through convenience getters...
console.log(wallet.accounts);

// ...or reactively through the store you created.
accountsStore.subscribe(() => {
  console.log("accounts changed:", accountsStore.state.wallets);
});

In React, bind a store slice with a selector so components re-render only when their slice changes: components read from stores and use the provider only to invoke commands (example).

📚 Where the docs live

This repository is the single home for the concepts and how-tos of the provider / extension model:

  • README.md: this composition-root walk-through.
  • TUTORIAL.md: the building blocks, the provider ↔ state contract, and the app-developer and extension-author perspectives.
  • ARCHITECTURE.md: how data flows through a provider: standalone vs composed, the flow rules, bridges, and the whole wallet as one document.
  • DISCOVERY.md: the options registry, namespace resolution, and the rules that keep extensions composable.
  • Architectural Decision Records: why the design is the way it is.
  • API Reference: the generated markdown API reference, browsable on GitHub (pnpm docs).

The wallet-provider-extensions repository documents only its per-package flows (keystore, migrations, logs, …).

Consult the CONTRIBUTING guide for information on development, testing, and pull requests.

🤝 Acknowledgments

We would like to acknowledge the following individuals and entities for their contributions and inspiration to this project and the broader Algorand ecosystem:

  • Architectural Vision: Algorand Foundation and Bruno Martins (@bmartins) for his role as an Architect.
  • use-wallet: TxnLab and Doug Richar (@drichar), along with Gabriel Kuettel (@gabrielkuettel) (currently at Algorand Foundation), for their role in building the use-wallet hook.
  • Ecosystem Support: The Engineering Teams at Algorand Foundation ranging from AlgoKit, Engineering, and Devrel for their role in providing ecosystem libraries and support.
  • Wallets:
    • Pera and Will Beaumount (@mjbeau) for their role in the ecosystem as a wallet and the large refactor to React Native.
    • Akita for their role in ARC58 adoption. With special thanks to Algorand Foundation engineering to Kyle(@kylebee) and Joe Polny(@joe-p) for their contributions to the ARC58 plugin standards.
    • Lute and Andrew Funk (@acfunk) for their contributions to web wallets, readily adopting the latest features.
    • Kibis-is and Kieran Roneill (@kieranroneill) for their work as an extension-based wallet and contributions to ARC standards such as ARC27.
    • Defly and Kevin Wellenzohn (@k13n) for pioneering wallet features and deep engagement with the Algorand ecosystem and ARC standards.