Skip to content

TypeScript SDK

Fabric includes a TypeScript SDK with a fetch-based client and React hooks.

The SDK is located at sdk/typescript/ in the Fabric repository. Import directly:

import { FabricClient } from './sdk/typescript';
import { FabricClient } from './sdk/typescript';
// With API key
const 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',
});
OptionTypeDescription
baseUrlstringFabric server URL (required)
tokenstring?API key or JWT bearer token
principalIdstring?Dev-mode principal ID (X-Principal-Id header)
// Get current principal
const me = await fabric.getMe();
// => { principal_id: "uuid", authenticated: true }
// Get my organizations
const orgs = await fabric.getMyOrganizations();
// => [{ id: "uuid", slug: "acme", name: "Acme Corp", archived: false }]
// Get my teams
const teams = await fabric.getMyTeams();
// Get effective permissions
const permissions = await fabric.getMyPermissions();
// => [{ organization_id: "uuid", team_id: null, role: "admin" }]
// Create an organization
const org = await fabric.createOrganization({
slug: 'acme',
name: 'Acme Corp',
});
// Get organization details
const org = await fabric.getOrganization(orgId);
// List all organizations
const orgs = await fabric.listOrganizations();
// Create a team
const team = await fabric.createTeam({
organization_id: orgId,
slug: 'engineering',
name: 'Engineering',
});
// Create an invitation
const invite = await fabric.createInvitation({
organization_id: orgId,
email: 'user@example.com',
role: 'member',
});
// Accept an invitation
const accepted = await fabric.acceptInvitation(inviteId);
// Check a single permission
const result = await fabric.checkPermission({
resource_type: 'organization',
resource_id: orgId,
action: 'team.create',
});
// => { allowed: true, resource_type: "organization", ... }
// Batch permission check
const results = await fabric.checkPermissionsBatch([
{ resource_type: 'organization', resource_id: orgId, action: 'read' },
{ resource_type: 'team', resource_id: teamId, action: 'invite' },
]);
// Create a workflow definition
const 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 run
const run = await fabric.createWorkflowRun({
workflow_definition_id: defId,
context: { audio: { url: 'https://example.com/audio.wav' } },
});
// Start execution
await fabric.startWorkflowRun(runId);
// Get run status
const status = await fabric.getWorkflowRun(runId);
// Cancel
await fabric.cancelWorkflowRun(runId);
const source = fabric.subscribeToEvents(
(event) => {
console.log(`${event.kind}:`, event.payload);
},
(error) => {
console.error('Connection error:', error);
}
);
// Close when done
source.close();
const source = fabric.subscribeToRunEvents(
runId,
(event) => {
if (event.kind === 'workflow.run.completed') {
console.log('Run finished!');
source.close();
}
}
);

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>;
}
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>
);
}
import { useMyTeams } from './sdk/typescript';
function TeamList() {
const { data: teams } = useMyTeams(client);
// ...
}
import { usePermissions } from './sdk/typescript';
function PermissionGuard({ children, action }) {
const { data: permissions } = usePermissions(client);
// Use permissions to conditionally render
}
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>
);
}
import { useRunEvents } from './sdk/typescript';
function RunMonitor({ runId }) {
useRunEvents(client, runId, (event) => {
if (event.kind === 'workflow.run.completed') {
console.log('Done!');
}
});
}

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';