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

@hazbase/react

v0.1.0

Published

React toolkit for wallet connection, passkey-native account bootstrap, and sponsored smart-wallet UX built on ethers v6.

Readme

@hazbase/react

npm version License

Overview

@hazbase/react is a React toolkit for two frontend patterns:

  • standard injected wallet apps with WalletProvider
  • passkey-native hazBase smart-wallet apps with PasskeyAccountProvider

The passkey flow is intentionally flow-oriented. Instead of wiring every backend step yourself, you create one client and then use helpers like ensurePasskey(), ensureAccount(), ensureSession(), ensureLiveSession(), sponsorAndSend(), and sponsorAndSendExecute().

Requirements

  • Node.js >= 18
  • React >= 18
  • Ethers v6
  • A hazBase-compatible backend for the passkey flow
  • WebAuthn support in the browser when you use passkeys

Installation

pnpm add @hazbase/react @hazbase/auth @hazbase/kit ethers react
# or
npm i @hazbase/react @hazbase/auth @hazbase/kit ethers react

Usage patterns

@hazbase/react supports two main frontend patterns:

  • WalletProvider: MetaMask / injected wallet apps
  • PasskeyAccountProvider: email OTP + passkey + account bootstrap + sponsored action apps

Use WalletProvider when your app should behave like a normal wallet-connected dApp. Use PasskeyAccountProvider when your app should guide users through a hazBase-managed smart-wallet flow.

Quick start: WalletProvider (MetaMask / injected wallet)

import {
  WalletProvider,
  useAddress,
  useNetwork,
  useSigner,
} from '@hazbase/react';

function WalletPanel() {
  const { signer, connectMetaMask, disconnect } = useSigner();
  const { address, isConnected } = useAddress();
  const network = useNetwork();

  return (
    <div>
      <button onClick={() => connectMetaMask()}>Connect MetaMask</button>
      <button onClick={() => disconnect()}>Disconnect</button>
      <pre>
        {JSON.stringify(
          {
            isConnected,
            address,
            chainId: network.chainId,
            hasSigner: Boolean(signer),
          },
          null,
          2,
        )}
      </pre>
    </div>
  );
}

export function App() {
  return (
    <WalletProvider autoConnect>
      <WalletPanel />
    </WalletProvider>
  );
}

Quick start: PasskeyAccountProvider

import {
  PasskeyAccountProvider,
  createHazbasePasskeyClient,
  usePasskeyAccount,
} from '@hazbase/react';

const client = createHazbasePasskeyClient();

function PasskeyPanel() {
  const {
    sendOtp,
    verifyOtp,
    ensurePasskey,
    ensureSession,
    ensureAccount,
    sponsorAndSendExecute,
  } = usePasskeyAccount();

  async function runFlow() {
    await sendOtp({ email: '[email protected]' });
    await verifyOtp({ email: '[email protected]', code: '123456' });
    await ensurePasskey({ deviceLabel: 'Chrome on MacBook' });
    const account = await ensureAccount({ chainId: 11155111, accountSalt: 'user-owned-account' });
    await ensureSession({ actionProfileKey: 'first_party_l2' });

    const sent = await sponsorAndSendExecute({
      mode: 'session',
      nonce: '0',
      target: '0x1111111111111111111111111111111111111111',
      data: '0x12345678',
      value: '0',
      callGasLimit: '150000',
      verificationGasLimit: '120000',
      preVerificationGas: '50000',
      maxFeePerGas: '1000000000',
      maxPriorityFeePerGas: '100000000',
    });

    console.log(account.smartAccountAddress, sent.userOpHash, sent.transactionHash);
  }

  return <button onClick={runFlow}>Run passkey account flow</button>;
}

export function App() {
  return (
    <PasskeyAccountProvider
      client={client}
      defaultChainId={11155111}
      defaultAccountSalt="user-owned-account"
      defaultActionProfileKey="first_party_l2"
    >
      <PasskeyPanel />
    </PasskeyAccountProvider>
  );
}

Quick start: usePasskeyOnboarding

import {
  PasskeyAccountProvider,
  createHazbasePasskeyClient,
  usePasskeyOnboarding,
} from '@hazbase/react';

const client = createHazbasePasskeyClient();

function OnboardingPanel() {
  const { sendOtp, completeOnboarding, isAccountReady, smartAccountAddress } = usePasskeyOnboarding();

  async function onboard() {
    await sendOtp({ email: '[email protected]' });
    await completeOnboarding({
      email: '[email protected]',
      code: '123456',
      deviceLabel: 'Chrome on MacBook',
      chainId: 11155111,
      accountSalt: 'user-owned-account',
    });
  }

  return (
    <div>
      <button onClick={onboard}>Bootstrap account</button>
      {isAccountReady ? <pre>{smartAccountAddress}</pre> : null}
    </div>
  );
}

export function App() {
  return (
    <PasskeyAccountProvider client={client} defaultChainId={11155111}>
      <OnboardingPanel />
    </PasskeyAccountProvider>
  );
}

Common operations

Standard wallet hooks

  • useSigner()
  • useAddress()
  • useNetwork()

Passkey flow hooks

The main passkey hook is usePasskeyAccount().

High-level helpers:

  • sendOtp()
  • verifyOtp()
  • ensurePasskey()
  • ensureHighTrust()
  • ensureAccount()
  • ensureSession()
  • grantSession()
  • ensureLiveSession()
  • sponsorUserOp()
  • executeSessionDirect()
  • executeSessionDirectExecute()
  • executeSessionDirectExecuteBatch()
  • sponsorAndSend()
  • sponsorAndSendExecute()
  • sponsorAndSendExecuteBatch()
  • authorizeOwnerUserOp()
  • refreshAccount()
  • endSession()
  • signOut()

Onboarding-focused helper:

  • usePasskeyOnboarding()

Account security helper:

  • useAccountSecurity()

Execute helpers:

  • encodeSmartAccountExecute()
  • encodeSmartAccountExecuteBatch()
  • createExecuteUserOp()
  • createExecuteBatchUserOp()

Advanced escape hatch:

  • raw: access to the low-level client for custom integrations

Main exports

  • WalletProvider
  • PasskeyAccountProvider
  • createHazbasePasskeyClient
  • useSigner
  • useAddress
  • useNetwork
  • usePasskeyAccount
  • usePasskeyOnboarding
  • useAccountSecurity
  • encodeSmartAccountExecute
  • encodeSmartAccountExecuteBatch
  • createExecuteUserOp
  • createExecuteBatchUserOp

Notes

  • PasskeyAccountProvider assumes a first-party or allowlisted partner backend.
  • @hazbase/react stays backend-contract based: apps integrate against a backend URL, and the React surface does not depend on any specific infrastructure provider.
  • The same React integration should work with any hazBase-compatible backend as long as the backend API contract is preserved.
  • sendOtp() and verifyOtp() manage the application session, not wallet ownership by themselves.
  • ensureAccount() will reuse an existing bound smart account when possible and bootstrap only when needed.
  • New embedded sessions always require a fresh purpose=session passkey step-up. Existing active sessions are reused until revoked or expired.
  • Backends that expose the V2 bundler path return additive fields such as accountVariant, relayMode, and submittedUserOpHash; existing callers can ignore them safely.
  • Session mode is sponsor-required. The backend returns the final accountSignature for the sponsored payload, and the React layer forwards it to the bundler.
  • Embedded sessions use a snapshot of the action profile taken at issuance time. Later profile broadening does not widen already-issued sessions.
  • Profile deactivation still acts as a kill switch for active sessions.
  • raw is useful when you want to override one step without giving up the higher-level flow state.
  • useAccountSecurity() wraps device/session inventory plus reauth-gated revoke flows for first-party security settings screens.

Troubleshooting (FAQ)

MetaMask is not found

Make sure the browser has an injected wallet and that your app is running in a context where window.ethereum is available.

ensureSession() says that actionProfileKey is required

Pass an actionProfileKey directly, or set defaultActionProfileKey on PasskeyAccountProvider.

How do I build a device/session security screen?

Use useAccountSecurity() to list active devices and embedded sessions, then call revokeDevice() or revokeSession() when the user confirms a revoke. The hook triggers a fresh passkey reauth before destructive operations.

Why does passkey setup still need OTP?

The intended model is:

  • OTP starts the app session
  • passkey binds the device and handles step-up authentication
  • account bootstrap and sponsorship happen only after those steps succeed

Why does a new embedded session always ask for passkey step-up?

Session issuance is treated as a privileged action. A fresh purpose=session high-trust token is required whenever the provider needs to mint a new embedded session.

When should I use sponsorAndSendExecute() instead of sponsorAndSend()?

Use sponsorAndSendExecute() when you want the React layer to build SmartAccount.execute(...) callData for you. Use sponsorAndSend() when you already have a full userOp draft.

Low-level account security methods

PasskeyAccountProvider does not add first-class settings UI in this phase, but the underlying client exposed as raw includes backend-first account security methods:

  • raw.listPasskeyDevices()
  • raw.revokePasskeyDevice()
  • raw.listEmbeddedSessions()
  • raw.revokeEmbeddedSession()

Listing uses app-session auth. Revoke calls require a fresh purpose=reauth passkey step-up token. Device revoke cascades to active embedded sessions on that device.


License

Apache-2.0