Stack API Reference
The Stack API is the client-side interface to your Hyperstack spec. It provides type-safe access to views, transactions, and helpers.
Overview
Section titled “Overview”import { defineStack, useHyperstack, createListView, createStateView } from 'hyperstack-react';
// 1. Define your stackconst MyStack = defineStack({ name: 'my-app', views: { /* view definitions */ }, transactions: { /* optional */ }, helpers: { /* optional */ },});
// 2. Use in componentsfunction Component() { const stack = useHyperstack(MyStack); const { data } = stack.views.tokens.list.use();}defineStack
Section titled “defineStack”Creates a typed stack definition.
function defineStack<TViews, TTxs, THelpers>(definition: { name: string; views: TViews; transactions?: TTxs; helpers?: THelpers;}): StackDefinitionParameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique identifier for the stack |
views | object | Yes | View definitions grouped by entity |
transactions | object | No | Transaction builders with refresh logic |
helpers | object | No | Utility functions |
Example
Section titled “Example”const TokenStack = defineStack({ name: 'token-tracker',
views: { tokens: { list: createListView<Token>('Token/list'), state: createStateView<Token>('Token/state'), }, trades: { recent: createListView<Trade>('Trade/list', { transform: (raw) => ({ ...raw, timestamp: new Date(raw.timestamp) }) }), }, },
transactions: { swap: { build: (params: { mint: string; amount: number }) => ({ instruction: 'swap', accounts: { mint: params.mint }, data: { amount: params.amount }, }), refresh: [{ view: 'tokens/state', key: (p) => p.mint }], }, },
helpers: { formatPrice: (lamports: number) => (lamports / 1e9).toFixed(6) + ' SOL', calculateMarketCap: (token: Token) => token.supply * token.price, },});useHyperstack
Section titled “useHyperstack”Main hook that provides access to a stack’s features.
function useHyperstack<TStack>(stack: TStack): StackClient<TStack>Return Value
Section titled “Return Value”interface StackClient<TStack> { views: ViewInterface; // Real-time data subscriptions tx: TransactionMethods; // Transaction submission helpers: TStack['helpers']; // Utility functions store: HyperstackStore; // Direct store access runtime: HyperstackRuntime; // Runtime instance}Example
Section titled “Example”function TokenDashboard() { const stack = useHyperstack(TokenStack);
// Access views const { data: tokens } = stack.views.tokens.list.use();
// Access helpers const formatted = stack.helpers.formatPrice(1000000000);
// Access transactions const { submit } = stack.tx.useMutation();
return <div>{/* ... */}</div>;}View Factory Functions
Section titled “View Factory Functions”createListView
Section titled “createListView”Creates a view that returns entities as an array.
function createListView<T>( viewPath: string, options?: ViewOptions<T>): ListViewDefinition<T>Usage:
// Basicconst tokenList = createListView<Token>('Token/list');
// With transformconst tokenList = createListView<Token>('Token/list', { transform: (raw) => ({ ...raw, priceFormatted: formatPrice(raw.price), })});In component:
const { data, isLoading, error, refresh } = stack.views.tokens.list.use({ limit: 50, where: { volume: { gte: 1000 } },});// data: Token[] | undefinedcreateStateView
Section titled “createStateView”Creates a view that returns a single entity by key.
function createStateView<T>( viewPath: string, options?: ViewOptions<T>): StateViewDefinition<T>Usage:
const tokenState = createStateView<Token>('Token/state');In component:
const { data, isLoading, error } = stack.views.tokens.state.use({ key: mintAddress});// data: Token | undefinedView Options
Section titled “View Options”interface ViewOptions<T> { transform?: (data: any) => T;}| Option | Description |
|---|---|
transform | Transform raw data before returning |
Transform Examples
Section titled “Transform Examples”// Convert bigint strings to BigIntcreateListView<Token>('Token/list', { transform: (raw) => ({ ...raw, supply: BigInt(raw.supply), })});
// Flatten nested datacreateStateView<Token>('Token/state', { transform: (raw) => ({ mint: raw.id.mint, name: raw.info.name, volume: raw.trading.total_volume, })});View Hook Return Values
Section titled “View Hook Return Values”ListViewHookResult
Section titled “ListViewHookResult”interface ListViewHookResult<T> { data: T[] | undefined; // Array of entities isLoading: boolean; // True while loading error?: Error; // Error if failed refresh: () => void; // Force refresh}StateViewHookResult
Section titled “StateViewHookResult”interface StateViewHookResult<T> { data: T | undefined; // Single entity isLoading: boolean; error?: Error; refresh: () => void;}List Query Parameters
Section titled “List Query Parameters”interface ListParams { key?: string; // Filter by partition key where?: WhereClause; // Field filters limit?: number; // Max results filters?: Record<string, string>; // Additional filters}
interface WhereClause { [field: string]: { eq?: any; // Equals gt?: any; // Greater than gte?: any; // Greater than or equal lt?: any; // Less than lte?: any; // Less than or equal };}Query Examples
Section titled “Query Examples”// Limit resultsstack.views.tokens.list.use({ limit: 10 })
// Filter by fieldstack.views.tokens.list.use({ where: { volume: { gte: 10000 } }})
// Multiple conditionsstack.views.tokens.list.use({ where: { volume: { gte: 10000 }, created_at: { gt: Date.now() - 86400000 } }, limit: 20})View Path Format
Section titled “View Path Format”View paths follow the pattern: {EntityName}/{mode}
| Mode | Returns | Example |
|---|---|---|
list | T[] | Token/list |
state | T | Token/state |
kv | Record<string, T> | Token/kv |
The entity name must match your spec’s #[entity(name = "EntityName")].
Transaction Definitions
Section titled “Transaction Definitions”interface TransactionDefinition<TParams> { build: (params: TParams) => TransactionInstruction; refresh?: RefreshSpec[];}
interface RefreshSpec { view: string; key?: string | ((params: any) => string);}Example
Section titled “Example”const MyStack = defineStack({ name: 'my-app', views: { /* ... */ }, transactions: { createToken: { build: (params: { name: string; symbol: string }) => ({ instruction: 'createToken', data: { name: params.name, symbol: params.symbol }, }), // Refresh token list after transaction refresh: [{ view: 'tokens/list' }], },
updateToken: { build: (params: { mint: string; newName: string }) => ({ instruction: 'updateToken', accounts: { mint: params.mint }, data: { name: params.newName }, }), // Refresh specific token state refresh: [{ view: 'tokens/state', key: (p) => p.mint }], }, },});useMutation Hook
Section titled “useMutation Hook”Submit transactions with status tracking.
interface UseMutationReturn { submit: (instruction: any) => Promise<string>; status: 'idle' | 'pending' | 'success' | 'error'; error?: string; signature?: string; reset: () => void;}Example
Section titled “Example”function CreateTokenButton() { const stack = useHyperstack(MyStack); const { submit, status, error, signature } = stack.tx.useMutation();
const handleCreate = async () => { const instruction = stack.transactions.createToken.build({ name: 'My Token', symbol: 'MTK', });
try { const sig = await submit(instruction); console.log('Transaction:', sig); } catch (e) { console.error('Failed:', e); } };
return ( <div> <button onClick={handleCreate} disabled={status === 'pending'}> {status === 'pending' ? 'Creating...' : 'Create Token'} </button> {status === 'error' && <p>Error: {error}</p>} {status === 'success' && <p>Success: {signature}</p>} </div> );}Helpers
Section titled “Helpers”Helpers are utility functions bundled with your stack.
const TokenStack = defineStack({ name: 'tokens', views: { /* ... */ }, helpers: { formatPrice: (lamports: number) => `${(lamports / 1e9).toFixed(6)} SOL`, formatSupply: (supply: bigint) => supply.toLocaleString(), calculatePrice: (token: Token) => Number(token.sol_reserves) / Number(token.token_reserves), },});Usage:
function TokenCard({ token }: { token: Token }) { const stack = useHyperstack(TokenStack);
return ( <div> <p>Price: {stack.helpers.formatPrice(token.price)}</p> <p>Supply: {stack.helpers.formatSupply(token.supply)}</p> </div> );}Connection State
Section titled “Connection State”Monitor WebSocket connection status.
import { useConnectionState } from 'hyperstack-react';
function ConnectionIndicator() { const state = useConnectionState(); // 'disconnected' | 'connecting' | 'connected' | 'error' | 'reconnecting'
const colors = { disconnected: 'gray', connecting: 'yellow', connected: 'green', error: 'red', reconnecting: 'orange', };
return <span style={{ color: colors[state] }}>{state}</span>;}TypeScript Integration
Section titled “TypeScript Integration”The Stack API is fully typed. TypeScript infers types from your stack definition:
// Types are inferred from createListView<Token>const { data } = stack.views.tokens.list.use();// data: Token[] | undefined
// Helper types are preservedconst formatted = stack.helpers.formatPrice(1000);// formatted: string (inferred from helper return type)
// Transaction params are typedstack.transactions.createToken.build({ name: 'Test', // TypeScript knows this is required // symbol: missing - TypeScript error!});Common Patterns
Section titled “Common Patterns”Conditional Subscription
Section titled “Conditional Subscription”function TokenDetail({ mint }: { mint: string | null }) { const stack = useHyperstack(TokenStack);
// Only subscribe when mint is available const { data } = stack.views.tokens.state.use( mint ? { key: mint } : undefined );
if (!mint) return <p>Select a token</p>; if (!data) return <p>Loading...</p>; return <p>{data.name}</p>;}Combining Multiple Views
Section titled “Combining Multiple Views”function Dashboard() { const stack = useHyperstack(MyStack);
const { data: tokens } = stack.views.tokens.list.use(); const { data: stats } = stack.views.stats.state.use({ key: 'global' });
const isLoading = !tokens || !stats;
if (isLoading) return <Loading />; return <DashboardView tokens={tokens} stats={stats} />;}Refresh on Demand
Section titled “Refresh on Demand”function RefreshableList() { const stack = useHyperstack(TokenStack); const { data, refresh, isLoading } = stack.views.tokens.list.use();
return ( <div> <button onClick={refresh} disabled={isLoading}> {isLoading ? 'Refreshing...' : 'Refresh'} </button> {data?.map(token => <TokenRow key={token.mint} token={token} />)} </div> );}