Workspaces & memberships
@hyperyai/sdk workspace APIs — WorkspaceSwitcher, useMemberships, useActiveWorkspace and setActiveWorkspace for users who belong to several teams and workspaces.
A Hypery user can belong to several teams, each with one or more workspaces. The active team + workspace is stored on the user's OAuth session on the server, so it persists across reloads and devices. These APIs list the memberships and switch the active workspace.
The hooks and WorkspaceSwitcher resolve the gateway URL as: explicit
gatewayUrl argument/prop > the provider's gatewayUrl >
NEXT_PUBLIC_GATEWAY_URL > a relative /api/... path. setActiveWorkspace is a
plain function and can't read the provider — see below.
@hyperyai/sdk 1.1.5 ignored the provider's gatewayUrl here and fell back to
NEXT_PUBLIC_GATEWAY_URL or a relative path. If you set that env var only as a
workaround, it's no longer needed.
WorkspaceSwitcher
A dropdown listing every workspace grouped by team (the personal team is labelled
"Personal"). Selecting one calls setActiveWorkspace, reloads
memberships and closes. Renders a loading button first and nothing if the user has
no memberships.
'use client';
import { WorkspaceSwitcher } from '@hyperyai/sdk';
import { useRouter } from 'next/navigation';
export function TopBar() {
const router = useRouter();
return <WorkspaceSwitcher onSwitched={() => router.refresh()} />;
}Switch failures are logged to the console; the dropdown stays open.
useMemberships
useMemberships(opts?: { gatewayUrl?: string }) fetches
GET /api/auth/list_memberships with the user's token. Returns data: null when
signed out. Concurrent identical requests (same URL and token) share one fetch.
import { useMemberships } from '@hyperyai/sdk';
function TeamList() {
const { data, isLoading, error, reload } = useMemberships();
if (isLoading) return <p>Loading…</p>;
if (error) return <button onClick={reload}>Retry ({error})</button>;
return (
<ul>
{data?.memberships.map((m) => (
<li key={m.team.id}>
{m.team.isPersonal ? 'Personal' : m.team.name} ({m.team.role})
<ul>{m.workspaces.map((w) => <li key={w.id}>{w.name}{w.isActive && ' ✓'}</li>)}</ul>
</li>
))}
</ul>
);
}MembershipEntry is { team: MembershipTeam, workspaces: MembershipWorkspace[] }:
useActiveWorkspace
Resolves the active team + workspace. Uses activeWorkspaceId, falling back to the
personal team's default workspace.
import { useActiveWorkspace } from '@hyperyai/sdk';
const { active, isLoading } = useActiveWorkspace();
if (active?.role === 'viewer') return <ReadOnlyNotice />;useActiveWorkspace(opts?: { gatewayUrl?: string }) calls useMemberships(opts)
internally; components mounting together share the in-flight request.
setActiveWorkspace
A plain async function (not a hook) that sends PATCH /api/oauth/session with
{ activeOrganizationId: teamId, activeWorkspaceId: workspaceId }.
import { setActiveWorkspace, useAuth } from '@hyperyai/sdk';
const { getAccessToken, gatewayUrl } = useAuth();
await setActiveWorkspace({ teamId, workspaceId, getAccessToken, gatewayUrl });Returns Promise<void>. Throws No access token; user is not signed in without a
token, or Failed to switch workspace: <detail> on a non-2xx response. Components
using useMemberships don't refresh on their own — call reload() afterwards.