Drop-in authentication and error handling library for Hypery apps. Simple, secure, and built for React.
This package provides everything you need for OAuth authentication, user management, and structured error handling (spending limits, insufficient credits, etc.) in your Hypery applications.
Inspired by Clerk, but purpose-built for Hypery's OAuth system.
See docs/COMPONENTS.md for a visual reference of every component with live screenshots and usage.
- 🔐 Secure OAuth 2.0 + PKCE - Industry-standard authentication
- ⚛️ React-first - Hooks and components that feel natural
- 🎨 Customizable - Bring your own UI or use our defaults
- 📦 Tiny - Minimal dependencies, maximum performance
- 🔄 Auto-refresh - Seamless token management
- 💾 Flexible storage - localStorage, sessionStorage, or memory
npm install @hyperyai/sdkThe package ships compiled JavaScript with type declarations (plus the TypeScript
source under src/ for reference), so it works out of the box — no
transpilePackages or build configuration needed.
To develop @hyperyai/sdk alongside a consuming app, use
yalc (npm link duplicates React and breaks hooks):
# in hypery-sdk
npm i -g yalc
yalc publish # builds via prepack and stores the real pack output
# in your app
yalc add @hyperyai/sdk && npm install
# iterate: rebuild + push updates into consumers
yalc push # in hypery-sdk, after changes
# before committing your app
yalc remove --all && npm installimport { HyperyProvider } from '@hyperyai/sdk';
function App() {
return (
<HyperyProvider
config={{
clientId: 'your-client-id',
redirectUri: 'http://localhost:3000/callback',
gatewayUrl: 'https://hypery.ai',
// Optional: defaults to ['read', 'write', 'ai:chat', 'ai:completions', 'ai:models', 'billing:read']
scopes: ['read', 'write', 'ai:chat', 'ai:completions', 'ai:models', 'billing:read'],
}}
>
<YourApp />
</HyperyProvider>
);
}import { SignedIn, SignedOut, SignIn, UserButton } from '@hyperyai/sdk';
function YourApp() {
return (
<>
<SignedIn>
<header>
<h1>Welcome!</h1>
<UserButton showUserInfo />
</header>
<Dashboard />
</SignedIn>
<SignedOut>
<div className="login-page">
<h1>Sign in to continue</h1>
<SignIn buttonText="Sign in with Hypery" />
</div>
</SignedOut>
</>
);
}import { useUser, useHyperyAuth } from '@hyperyai/sdk';
function Dashboard() {
const { user, isLoading } = useUser();
const { logout } = useHyperyAuth();
if (isLoading) return <div>Loading...</div>;
return (
<div>
<h1>Welcome, {user?.name}!</h1>
<p>Email: {user?.email}</p>
<button onClick={logout}>Sign out</button>
</div>
);
}The main provider component. Wrap your app with this.
<HyperyProvider
config={{
clientId: string; // Your OAuth client ID
redirectUri: string; // Callback URL after auth
gatewayUrl: string; // Hypery API URL
scopes?: string[]; // OAuth scopes (default: ['read', 'write'])
storage?: 'localStorage' | 'sessionStorage' | 'memory'; // Storage type
}}
>
{children}
</HyperyProvider><SignIn /> - Sign-in button
<SignIn
buttonText="Sign in with Hypery"
variant="primary" // 'primary' | 'secondary' | 'outline'
className="custom-button-class"
/><SignUp /> - Sign-up button
<SignUp
buttonText="Get Started"
variant="primary"
onSignUpStart={() => console.log('Starting signup')}
/><SignInForm /> - Embedded login form with social OAuth
Full-featured login form with GitHub, Google, and email/password authentication.
<SignInForm
showCard
showTitle
showSocial // Show GitHub and Google buttons
showEmailPassword // Show email/password form
title="Welcome back"
description="Sign in to your account"
onSuccess={() => console.log('Logged in!')}
onError={(error) => console.error(error)}
/>// Social auth only (no email/password)
<SignInForm
showCard
showSocial={true}
showEmailPassword={false}
/><UserButton /> - User avatar with dropdown menu
<UserButton
showUserInfo
size="md" // 'sm' | 'md' | 'lg'
renderDropdown={(user, logout) => (
<div>
<p>{user.name}</p>
<button onClick={logout}>Sign out</button>
</div>
)}
/><UserProfile /> - User profile card
<UserProfile
showExtended
showLoading
/><SignedIn> - Only renders when user is authenticated
<SignedIn>
<Dashboard />
</SignedIn><SignedOut> - Only renders when user is NOT authenticated
<SignedOut>
<SignIn />
</SignedOut><Protect> - Protects content and redirects if needed
<Protect fallback={<SignIn />}>
<ProtectedContent />
</Protect><RedirectToSignIn /> - Immediately redirects to sign in
<RedirectToSignIn />Full auth context with methods. Matches Clerk's API pattern.
const {
user, // Current user
isAuthenticated, // Auth status
isLoading, // Loading state
error, // Error message
login, // Initiate login
logout, // Sign out
refreshAuth, // Manually refresh
getAccessToken, // Get valid access token
} = useAuth();Access current user data only.
const { user, isLoading } = useUser();
// user object contains:
// - id: string
// - name: string
// - email: string
// - image?: stringSame as useAuth(), but with explicit naming.
const auth = useHyperyAuth();<HyperyProvider
config={{
// ...other config
storage: 'sessionStorage', // or 'memory' for SSR
}}
>import { useHyperyAuth } from '@hyperyai/sdk';
function MyComponent() {
const { getAccessToken } = useHyperyAuth();
const makeAuthenticatedRequest = async () => {
const token = await getAccessToken();
const response = await fetch('/api/data', {
headers: {
Authorization: `Bearer ${token}`,
},
});
return response.json();
};
}Build your own UI using the hooks:
import { useHyperyAuth } from '@hyperyai/sdk';
function CustomLoginButton() {
const { login, isLoading } = useHyperyAuth();
return (
<button
onClick={login}
disabled={isLoading}
className="my-custom-button"
>
{isLoading ? 'Loading...' : 'Sign in'}
</button>
);
}Create a .env.local file:
NEXT_PUBLIC_OAUTH_CLIENT_ID=your_client_id
NEXT_PUBLIC_REDIRECT_URI=http://localhost:3000/callback
NEXT_PUBLIC_AUTH_URL=https://hypery.aiWhen a gateway request is blocked mid-flow, the SDK lets you pop a payment modal (out of credits / spending limit / card issue) or trigger re-auth (expired/invalid token). This is opt-in — the SDK does not install a global fetch interceptor, so you wire it into your own API calls.
Errors arrive as a JSON envelope. Classify on error.code (status is a
fallback only — spending-limit is 429, insufficient-credits/payment is 402,
auth is 401):
useError().setError(body) accepts the raw { error: { code } } envelope or
an already-unwrapped object, and falls back to the HTTP status (402/401) when
the body has no recognized code. It exposes isBillingRestriction (any of the
payment/credit/limit cases) and isAuth (a 401) so you can drive
RestrictionModal and AuthModal respectively. The guards
isBillingRestriction(body) and isAuthError(body) are also exported for use
outside the hook.
See the /apps/chat and /apps/imagine directories for complete working examples.
MIT

{ "error": { "code": "INSUFFICIENT_CREDITS", "type": "insufficient_credits_error" } } { "error": { "code": "SPENDING_LIMIT_EXCEEDED", "type": "spending_limit_error" } } { "error": { "code": "PAYMENT_METHOD_REQUIRED", "type": "payment_method_required_error" } } { "error": { "code": "PAYMENT_DECLINED", "type": "payment_declined_error" } } { "error": { "code": "UNAUTHENTICATED", "type": "authentication_error" } }