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

@stake-sdk/ui

v1.1.8

Published

Stake UI widgets for React Native with Material Design 3 theming

Readme

@stake-sdk/ui

Stake UI SDK for React Native. It ships three widgets — AccountWidget, CreditBuilderWidget, and NeighborhoodCashWidget — plus shared runtime helpers. Theming uses Material Design 3 via react-native-paper.

Widgets decode a host-minted JWT (token) and never take a residentId prop. The payload must include credit_builder_id; that value is used on /resident/{id}/... API calls.

Installation

npm install @stake-sdk/ui react-native-paper @tanstack/react-query axios react-native-confetti-cannon react-native-maps react-native-safe-area-context react-native-svg
# or
yarn add @stake-sdk/ui react-native-paper @tanstack/react-query axios react-native-confetti-cannon react-native-maps react-native-safe-area-context react-native-svg

Peer dependencies (must be present in your app):

| Package | Version | | ------- | ------- | | react | ≥18 | | react-native | ≥0.70 | | react-native-paper | ≥5 | | @tanstack/react-query | ≥5 | | axios | ≥1.19 | | react-native-confetti-cannon | ≥1.5 | | react-native-maps | ≥1.20 | | react-native-safe-area-context | ≥4 | | react-native-svg | ≥13 | | fidel-react-native | ≥3.2.1 (optional — card linking only) |

Expo apps typically already include @expo/vector-icons. react-native-maps requires a native rebuild after install. fidel-react-native is optional and must be used in a dev/production build (not Expo Go).

Setup

Call Stake.open once (for example in a root layout useEffect) before any widget that hits Stake APIs. The SDK does not store credentials: you pass an async getAuthToken provider and your app owns fetching, caching, and refreshing the token. The SDK calls getAuthToken() per request and getAuthToken({ forceRefresh: true }) once after a 401, then retries the request.

import { Stake } from "@stake-sdk/ui";
import type { StakeAuthTokenProvider } from "@stake-sdk/ui";

const getAuthToken: StakeAuthTokenProvider = async ({ forceRefresh } = {}) => {
  return await fetchTokenFromYourBackend({ forceRefresh });
};

await Stake.open({
  environment: "development", // "development" | "sandbox" | "production"
  getAuthToken,
  googlePlacesApiKey: process.env.EXPO_PUBLIC_GOOGLE_PLACES_API_KEY,
  // Optional: take over Plaid Hosted Link (Custom Tabs / Safari / expo-web-browser).
  // Return true so the SDK does not also call Linking.openURL.
  // onOpenHostedLink: (url) => { void WebBrowser.openBrowserAsync(url); return true; },
  onSuccess: (message) => console.log(message),
  onError: (message) => console.error(message),
});

Mint the OAuth token on your own backend and hand it to getAuthToken. Do not ship the client secret in a public EXPO_PUBLIC_* variable. The JWT must include credit_builder_id (the resident identifier). Pass that same JWT as token on each widget.

Stake.open primes the token once so mint failures surface through onError. Every Stake API request also sends API-Version: 2026-08-01; mint tokens against the same version.

StakeConfig

| Name | Type | Required | Description | | ---- | ---- | -------- | ----------- | | environment | "production" \| "sandbox" \| "development" | Yes | Selects the Stake API base URL. | | getAuthToken | StakeAuthTokenProvider | Yes | Returns a bearer token. Called with { forceRefresh: true } after a 401. | | googlePlacesApiKey | string | No | Google key used for address autocomplete and as the fallback Maps key for Neighborhood Cash. | | coreApiKey | string | No | Optional Core dealsAPIKey header for legacy Core routes. Neighborhood Cash does not need this. | | onOpenHostedLink | (url: string) => boolean \| void \| Promise<boolean \| void> | No | Open the Plaid Hosted Link URL yourself. Return true (or a Promise) to take over; otherwise the SDK uses React Native Linking.openURL. Same contract as the Web SDK. | | onSuccess | (message: string) => void | No | Called after a successful Stake.open. | | onError | (message: string) => void | No | Called if Stake.open fails (the promise also rejects). |

Linking a bank (Plaid Hosted Link)

Cash out, Venmo, and Connected Accounts need a linked checking account. The SDK asks Stake for a Hosted Link session and opens the returned URL. Nothing from Plaid is bundled into the SDK.

By default the URL is opened with React Native Linking.openURL (system Safari / Chrome). Completion is detected by polling linked accounts for about two minutes. When the resident returns to the app, the SDK also polls immediately.

For an in-app browser (Chrome Custom Tabs, SFSafariViewController, expo-web-browser), supply onOpenHostedLink(url) on Stake.open and return true. Do not await the browser dismiss inside the handler if you want polling to run while it is open — fire-and-forget and return true. Do not open Hosted Link in a WebView; banks block those.

Google Maps / Places

Address autocomplete (Request paper check and Stake Checking onboarding) calls the Places Autocomplete and Place Details HTTP APIs. Enable Places API in Google Cloud, set EXPO_PUBLIC_GOOGLE_PLACES_API_KEY in the host app, and pass the same value to Stake.open as googlePlacesApiKey. You can override it per widget with AccountWidget's googlePlacesApiKey.

Neighborhood Cash map previews and Near You pan/zoom need the Maps SDK for Android / iOS (and typically Maps Static API). Configure the key in native Expo config (android.config.googleMaps / ios.config.googleMapsApiKey) and rebuild. Pass googleMapsApiKey on NeighborhoodCashWidget to override the Stake.open key.

Neighborhood Cash native setup

Hosts that ship NeighborhoodCashWidget must:

  1. Install peer react-native-maps, wire Google Maps API keys in Expo config, and rebuild the native app.
  2. Install optional peer fidel-react-native ≥ 3.2.1 in a dev/production build (not Expo Go) for card linking.

The widget talks to resident-scoped Stake APIs (/resident/{credit_builder_id}/neighborhood_cash/...) with the same OAuth bearer token. The token must include Neighborhood Cash scopes such as nc_get_link_data, nc_get_cards, nc_delete_card, nc_get_offers, nc_get_rewards, and consumer_deals_get.

Usage

Every widget requires an MD3Theme and a JWT token. When token is missing or cannot be decoded into a credit_builder_id, the widget renders nothing and calls onError with an error message (and null once a valid token resolves).

Account widget

Balance, activity, unclaimed cash-back claiming, paper check, cash out, Venmo transfer, connected accounts (Plaid Hosted Link), and Stake Checking onboarding.

import { AccountWidget } from "@stake-sdk/ui";
import { useTheme } from "react-native-paper";

function MyScreen() {
  const theme = useTheme();
  return (
    <AccountWidget
      theme={theme}
      token={token}
      onError={(message) => {
        if (message) console.error(message);
      }}
      googlePlacesApiKey={process.env.EXPO_PUBLIC_GOOGLE_PLACES_API_KEY}
      onContactSupport={() => {
        /* host opens chat, mailto, or a support URL */
      }}
    />
  );
}

Or with withTheme:

import { AccountWidget } from "@stake-sdk/ui";
import { withTheme } from "react-native-paper";
import type { MD3Theme } from "react-native-paper";

function MyScreen({ theme }: { theme: MD3Theme }) {
  return <AccountWidget theme={theme} token={token} />;
}

export default withTheme(MyScreen);

googlePlacesApiKey is optional. When omitted, the value passed to Stake.open is used. onContactSupport is called from read-only Stake Checking steps; the SDK never opens a URL, chat widget, or dialer itself.

Credit builder widget

Eligibility, opt-in / opt-out, and the credit builder tracker.

import { CreditBuilderWidget } from "@stake-sdk/ui";
import { useTheme } from "react-native-paper";

function MyScreen() {
  const theme = useTheme();
  return (
    <CreditBuilderWidget
      theme={theme}
      token={token}
      onError={(message) => {
        if (message) console.error(message);
      }}
    />
  );
}

Neighborhood Cash widget

Neighborhood Network hub, offers, Near You map, cash-back history, and Fidel card linking.

import { NeighborhoodCashWidget } from "@stake-sdk/ui";
import { useTheme } from "react-native-paper";

function MyScreen() {
  const theme = useTheme();
  return (
    <NeighborhoodCashWidget
      theme={theme}
      token={token}
      onError={(message) => {
        if (message) console.error(message);
      }}
      onUnavailable={() => {
        /* hide your Neighborhood Cash entry point */
      }}
      onDismiss={() => {
        /* user backed out of Hub — navigate away */
      }}
      onContactSupport={() => {
        /* cash-back detail “Contact Support” */
      }}
      googleMapsApiKey={process.env.EXPO_PUBLIC_GOOGLE_PLACES_API_KEY}
    />
  );
}

Set useMockData to skip Core/Fidel APIs and render local preview data (token is then optional). initialRoute can start on a named screen ("apply", "hub", "allOffers", "nearYou", "cashBack", "linkedCards"); live mode hides the widget when the offer is not enabled and remaps "apply" to the hub.

Theming helpers

Pass any MD3Theme from react-native-paper. Stake defaults and a font-family helper are exported:

import {
  StakeLightTheme,
  StakeDarkTheme,
  withFontFamily,
} from "@stake-sdk/ui";

const theme = withFontFamily(StakeLightTheme, "YourBrandSans");

Load the typeface in the host (for example expo-font / useFonts) before rendering widgets. The SDK never fetches fonts — unlike the Web SDK there is no theme.fontUrl.

A single family name is enough when one file covers every weight. For a face with separate files per weight (Raleway, most Google Fonts), pass a map so Android and StyleSheet fontWeight resolve the right cut:

import {
  useFonts,
  Raleway_400Regular,
  Raleway_500Medium,
  Raleway_600SemiBold,
  Raleway_700Bold,
} from "@expo-google-fonts/raleway";

const [loaded] = useFonts({
  Raleway_400Regular,
  Raleway_500Medium,
  Raleway_600SemiBold,
  Raleway_700Bold,
});

const theme = withFontFamily(StakeLightTheme, {
  regular: "Raleway_400Regular",
  medium: "Raleway_500Medium",
  semibold: "Raleway_600SemiBold",
  bold: "Raleway_700Bold",
});

Button labels

withButtonLabels maps to the Web SDK's buttonTextTransform and buttonLetterSpacing tokens. They default to as-authored copy and normal tracking. The two are independent — uppercase does not add tracking on its own. Set both for all-caps labels; emToLetterSpacing converts the Web SDK's em value at the 14px button size:

import {
  StakeLightTheme,
  withButtonLabels,
  emToLetterSpacing,
} from "@stake-sdk/ui";

const theme = withButtonLabels(StakeLightTheme, {
  buttonTextTransform: "uppercase",
  buttonLetterSpacing: emToLetterSpacing(0.04),
});

buttonTextTransform accepts "none", "uppercase", "capitalize", or "lowercase". buttonLetterSpacing is a number (React Native pixels), not a CSS em string. Tokens apply to action buttons only — not titles, body copy, or links.

Brand vs CTA fill

Paper colors.primary tints links, selected tabs, snackbars, and loaders. Contained action buttons use that same role unless you stamp accentFill / accentText — the Web SDK's split when button fill is not the brand accent (Progress: teal chrome, lime buttons).

import {
  StakeLightTheme,
  withBrandTokens,
} from "@stake-sdk/ui";

const theme = withBrandTokens(StakeLightTheme, {
  accentFill: "#8BCB02",
  accentText: "#01444B",
  heading: "#01444B",
});

Omit the tokens and contained buttons keep colors.primary. ctaFill / ctaLabel / headingColor read these keys with MD3 fallbacks.

Exports

| Export | Description | | ------ | ----------- | | Stake | Stake.open(config) — initialize SDK / auth for the session | | StakeConfig | Type for Stake.open configuration | | StakeAuthTokenProvider | Type for the async getAuthToken provider | | StakeOpenHostedLinkHandler | Type for Stake.open({ onOpenHostedLink }) | | AccountWidget | Account UI: balance, activity, cash-out flows, connected accounts, Stake Checking | | CreditBuilderWidget | Credit builder UI: eligibility, opt-in/out, and tracker | | NeighborhoodCashWidget | Neighborhood Cash UI: apply/hub, offers, map, cash-back, card linking | | NeighborhoodCashWidgetProps | Props type for NeighborhoodCashWidget | | NeighborhoodScreenName | Named screens accepted by initialRoute | | CashBackEntry, LinkedCard, NeighborhoodOffer, NeighborhoodRoute, OfferChannel | Neighborhood Cash data types | | StakeLightTheme / StakeDarkTheme | Paper-compatible theme objects | | withFontFamily | Apply a host-loaded typeface (string or per-weight map) to every MD3 type role | | FontWeightFamilies | Type for the per-weight map passed to withFontFamily | | withButtonLabels | Apply buttonTextTransform / buttonLetterSpacing to action-button labels | | withBrandTokens | Optional accentFill / accentText / heading when CTA fill ≠ primary | | ctaFill / ctaLabel / headingColor | Read brand tokens with MD3 fallbacks | | BrandTokenOptions | Type for withBrandTokens | | emToLetterSpacing | Convert Web SDK em tracking to RN letterSpacing at 14px | | buttonLabelStyle | Style object to spread onto a custom action-button label | | ButtonTextTransform / ButtonLabelOptions | Types for withButtonLabels |

Props

AccountWidget

| Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | | theme | MD3Theme | Yes | Material Design 3 theme from react-native-paper | | token | string | Yes | Host-minted JWT with credit_builder_id | | googlePlacesApiKey | string | No | Overrides the Stake.open key for address autocomplete | | onError | (message: string \| null) => void | No | Token validity: error message when invalid, null when resolved. Invalid tokens render nothing. | | onContactSupport | () => void | No | Stake Checking “Contact Support”. The host decides how support is surfaced. |

CreditBuilderWidget

| Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | | theme | MD3Theme | Yes | Material Design 3 theme from react-native-paper | | token | string | Yes | Host-minted JWT with credit_builder_id | | onError | (message: string \| null) => void | No | Token validity: error message when invalid, null when resolved. Invalid tokens render nothing. |

NeighborhoodCashWidget

| Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | | theme | MD3Theme | Yes | Material Design 3 theme from react-native-paper | | token | string | No | JWT with credit_builder_id. Required unless useMockData is true. | | onError | (message: string \| null) => void | No | Token validity (skipped in mock mode). Invalid tokens render nothing. | | onUnavailable | () => void | No | Resident is not in the Neighborhood Network program (neighborhood_network missing or is_enabled is not true). Widget renders nothing. | | onDismiss | () => void | No | User backed out of the root screen (Hub). | | onContactSupport | () => void | No | Cash-back detail “Contact Support”. | | googleMapsApiKey | string | No | Maps key for hub / Near You. Falls back to Stake.open({ googlePlacesApiKey }). | | useMockData | boolean | No | Skip Core/Fidel APIs and render local mock data (UI preview only). Default false. | | initialRoute | NeighborhoodScreenName | No | Override starting screen. Live mode still hides the widget when the offer is not enabled. |

Publishing (for maintainers)

Package name: @stake-sdk/ui. Source lives under packages/stake-sdk/.

From the monorepo root:

| Script | Description | | ------ | ----------- | | npm run build:packages | Build the UI package (output in packages/stake-sdk/dist/). | | npm run version:sdk:patch | Bump patch version. Creates a git commit and tag in the workspace package. | | npm run version:sdk:minor | Bump minor version. | | npm run version:sdk:major | Bump major version. | | npm run publish:sdk | Build and publish the current version to npm. | | npm run release:sdk:patch | Build, bump patch, then publish. | | npm run release:sdk:minor | Build, bump minor, then publish. | | npm run release:sdk:major | Build, bump major, then publish. |

From packages/stake-sdk:

npm run build
npm run publish:package   # npm publish --access public

One-step release from root (example — patch):

npm run release:sdk:patch

Ensure you are logged in (npm login) with publish access to the @stake-sdk scope, and use --access public for the first scoped publish. To change the npm name or scope, edit name in packages/stake-sdk/package.json.