TypeScript SDK
Fabric includes a TypeScript SDK with a fetch-based client and React hooks.
Installation
Section titled “Installation”The SDK is located at sdk/typescript/ in the Fabric repository. Import directly:
import { FabricClient } from './sdk/typescript';Client Setup
Section titled “Client Setup”import { FabricClient } from './sdk/typescript';
// With API keyconst fabric = new FabricClient({ baseUrl: 'http://localhost:3001', token: 'fab_your_api_key_here',});
// With dev-mode principal (development only)const devFabric = new FabricClient({ baseUrl: 'http://localhost:3001', principalId: '550e8400-e29b-41d4-a716-446655440000',});Configuration Options
Section titled “Configuration Options”| Option | Type | Description |
|---|---|---|
baseUrl | string | Fabric server URL (required) |
token | string? | API key or JWT bearer token |
principalId | string? | Dev-mode principal ID (X-Principal-Id header) |
Identity
Section titled “Identity”// Get current principalconst me = await fabric.getMe();// => { principal_id: "uuid", authenticated: true }
// Get my organizationsconst orgs = await fabric.getMyOrganizations();// => [{ id: "uuid", slug: "acme", name: "Acme Corp", archived: false }]
// Get my teamsconst teams = await fabric.getMyTeams();
// Get effective permissionsconst permissions = await fabric.getMyPermissions();// => [{ organization_id: "uuid", team_id: null, role: "admin" }]Tenancy
Section titled “Tenancy”// Create an organizationconst org = await fabric.createOrganization({ slug: 'acme', name: 'Acme Corp',});
// Get organization detailsconst org = await fabric.getOrganization(orgId);
// List all organizationsconst orgs = await fabric.listOrganizations();
// Create a teamconst team = await fabric.createTeam({ organization_id: orgId, slug: 'engineering', name: 'Engineering',});
// Create an invitationconst invite = await fabric.createInvitation({ organization_id: orgId, email: 'user@example.com', role: 'member',});
// Accept an invitationconst accepted = await fabric.acceptInvitation(inviteId);Authorization
Section titled “Authorization”// Check a single permissionconst result = await fabric.checkPermission({ resource_type: 'organization', resource_id: orgId, action: 'team.create',});// => { allowed: true, resource_type: "organization", ... }
// Batch permission checkconst results = await fabric.checkPermissionsBatch([ { resource_type: 'organization', resource_id: orgId, action: 'read' }, { resource_type: 'team', resource_id: teamId, action: 'invite' },]);Workflows
Section titled “Workflows”// Create a workflow definitionconst def = await fabric.createWorkflowDefinition({ organization_id: orgId, name: 'transcribe-and-summarize', nodes: [ { key: 'transcribe', kind: 'audio.transcribe' }, { key: 'summarize', kind: 'text.generate', depends_on: ['transcribe'] }, ],});
// Create a workflow runconst run = await fabric.createWorkflowRun({ workflow_definition_id: defId, context: { audio: { url: 'https://example.com/audio.wav' } },});
// Start executionawait fabric.startWorkflowRun(runId);
// Get run statusconst status = await fabric.getWorkflowRun(runId);
// Cancelawait fabric.cancelWorkflowRun(runId);Event Subscriptions
Section titled “Event Subscriptions”Subscribe to All Events
Section titled “Subscribe to All Events”const source = fabric.subscribeToEvents( (event) => { console.log(`${event.kind}:`, event.payload); }, (error) => { console.error('Connection error:', error); });
// Close when donesource.close();Subscribe to a Specific Run
Section titled “Subscribe to a Specific Run”const source = fabric.subscribeToRunEvents( runId, (event) => { if (event.kind === 'workflow.run.completed') { console.log('Run finished!'); source.close(); } });React Hooks
Section titled “React Hooks”The SDK provides React hooks for common operations. Requires React 18+.
import { FabricClient } from './sdk/typescript';
const client = new FabricClient({ baseUrl: 'http://localhost:3001' });import { useMe } from './sdk/typescript';
function Profile() { const { data, loading, error, refetch } = useMe(client);
if (loading) return <p>Loading...</p>; if (error) return <p>Error: {error.message}</p>;
return <p>Principal: {data?.principal_id}</p>;}useMyOrganizations
Section titled “useMyOrganizations”import { useMyOrganizations } from './sdk/typescript';
function OrgList() { const { data: orgs, loading } = useMyOrganizations(client);
if (loading) return <p>Loading...</p>;
return ( <ul> {orgs?.map(org => <li key={org.id}>{org.name}</li>)} </ul> );}useMyTeams
Section titled “useMyTeams”import { useMyTeams } from './sdk/typescript';
function TeamList() { const { data: teams } = useMyTeams(client); // ...}usePermissions
Section titled “usePermissions”import { usePermissions } from './sdk/typescript';
function PermissionGuard({ children, action }) { const { data: permissions } = usePermissions(client); // Use permissions to conditionally render}useEventStream
Section titled “useEventStream”import { useEventStream } from './sdk/typescript';
function EventLog() { const [events, setEvents] = useState([]);
useEventStream(client, (event) => { setEvents(prev => [...prev, event]); });
return ( <ul> {events.map(e => <li key={e.id}>{e.kind}</li>)} </ul> );}useRunEvents
Section titled “useRunEvents”import { useRunEvents } from './sdk/typescript';
function RunMonitor({ runId }) { useRunEvents(client, runId, (event) => { if (event.kind === 'workflow.run.completed') { console.log('Done!'); } });}Error Handling
Section titled “Error Handling”The client throws FabricError when the API returns an error envelope:
import { FabricError } from './sdk/typescript';
try { await fabric.checkPermission({ ... });} catch (err) { if (err instanceof FabricError) { console.error(`${err.code}: ${err.message} (HTTP ${err.status})`); }}All request/response types are exported:
import type { Envelope, Organization, Team, MeResponse, PermissionSummary, AuthzCheckRequest, AuthzCheckResponse, CreateOrgRequest, CreateTeamRequest, CreateInvitationRequest, InvitationResponse, WorkflowDefinitionRequest, WorkflowRunRequest, DomainEvent, FabricClientConfig,} from './sdk/typescript';