Rising Tide Developers
UI PackageReact

RisingTideProvider

Setting up the SDK context provider that backs the data hooks in the @rising-tide/ui/react entry point.

RisingTideProvider (also re-exported as RisingTideQueryProvider) holds a RisingTideSDK instance in React context so the data hooks in @rising-tide/ui/react can resolve it. It does not bundle a QueryClientProvider - you bring your own from @tanstack/react-query.

RisingTideProviders (plural, from @rising-tide/ui/providers) does not mount this context. The estate's apps keep their SDK client in a module (@/lib/sdk/client) and call it from useQuery directly; mount RisingTideProvider when you want the pre-shaped substrate hooks instead.

Provider stack

RootLayout
your top-level layout
QueryClientProvider
your QueryClient
RisingTideProvider
config = { baseUrl, apiKey }
ProtocolUserProvider
from @rising-tide/ui/auth, with its sdk and config
your app tree
hooks resolve from here

Setup

ProtocolUserProvider takes the same SDK client as a prop plus a config whose storagePrefix, linkInviteCodes and onSignupComplete are required. It also has to sit inside Privy's provider to sign anyone in, which is the part RisingTideProviders handles for you - this page shows the hand-assembled version.

// app/providers.tsx
"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { RisingTideProvider } from "@rising-tide/ui/react";
import { ProtocolUserProvider } from "@rising-tide/ui/auth";
import { rtClient } from "@/lib/sdk/client";

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 30_000,
      gcTime: 5 * 60_000,
      retry: 2,
      refetchOnWindowFocus: false,
    },
  },
});

const sdkConfig = {
  baseUrl: process.env.NEXT_PUBLIC_RT_API_URL!,
  apiKey: process.env.NEXT_PUBLIC_API_KEY,
};

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <RisingTideProvider config={sdkConfig}>
        <ProtocolUserProvider
          sdk={rtClient}
          config={{
            storagePrefix: "myapp",
            linkInviteCodes: true,
            onSignupComplete: () => {},
          }}
        >
          {children}
        </ProtocolUserProvider>
      </RisingTideProvider>
    </QueryClientProvider>
  );
}

Then in your root layout:

// app/layout.tsx
import { Providers } from "./providers";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Props

PropTypeRequiredDescription
configRisingTideConfigYesSame shape as the RisingTideSDK constructor input - baseUrl, apiKey?, timeout?, headers?. The provider memoizes the SDK by baseUrl and apiKey, so changing those swaps the client.

Reading the SDK directly

The client the provider holds is not exposed by a hook. If you need raw SDK access inside a component, import the app's own client module - the same instance you handed to the providers:

import { useQuery } from "@tanstack/react-query";
import { rtClient } from "@/lib/sdk/client";

function ProductTypes() {
  const { data } = useQuery({
    queryKey: ["productTypes"],
    queryFn: () => rtClient.productTypes.list(),
  });
  // ...
}

useRisingTide(config) from the same entry point builds a memoized client from a RisingTideConfig - a second instance, not the one in context - and is kept for older call sites. Prefer the module import.