TypeScript SDK
The @arsaka/puguh-sdk NPM package provides a fully typed TypeScript client for integrating ARSAKA PUGUH infrastructure services into your frontend and Node.js applications. The SDK ships with 6 modules covering authentication, organizations, IAM, audit/control, applications, and webhooks.
Installation
npm install @arsaka/puguh-sdk
# or
bun add @arsaka/puguh-sdk Quick Start
import { AuthClient, OrganizationClient, IAMClient } from '@arsaka/puguh-sdk';
const auth = new AuthClient({ baseUrl: 'https://api-puguh.arsaka.io' });
// Login
const { access_token } = await auth.login({
email: 'user@example.com',
password: 'password',
});
// Use authenticated clients
const orgs = new OrganizationClient({
baseUrl: 'https://api-puguh.arsaka.io',
accessToken: access_token,
});
const orgList = await orgs.list();
// orgList = { items: OrganizationWithMembership[], total: number }
console.log(orgList.items[0].organization.name); Modules
The SDK is organized into 6 client modules, each mapping to a PUGUH core service. Import only the clients you need — every module is tree-shakeable.
1. AuthClient
Handles user authentication, token lifecycle, magic links, and multi-factor authentication.
import { AuthClient } from '@arsaka/puguh-sdk';
const auth = new AuthClient({ baseUrl: 'https://api-puguh.arsaka.io' });
// Register a new user
await auth.register({ email: 'new@example.com', password: 'securePass123' });
// Login and receive tokens
const { access_token, refresh_token } = await auth.login({
email: 'new@example.com',
password: 'securePass123',
});
// Refresh an expired access token
const { access_token: newToken } = await auth.refreshToken({ refresh_token });
// Magic link authentication
await auth.requestMagicLink({ email: 'user@example.com' });
const session = await auth.verifyMagicLink({ token: 'magic-link-token' });
// Multi-factor authentication
const { secret, qr_code_url } = await auth.setupMFA({ type: 'totp' });
await auth.confirmMFA({ code: '123456' }); Methods: login, register, refreshToken, requestMagicLink, verifyMagicLink, setupMFA, confirmMFA
2. OrganizationClient
Manage organizations, membership, and invitations. PUGUH uses a GitHub-style organization model where each user has a personal workspace plus team organizations.
import { OrganizationClient } from '@arsaka/puguh-sdk';
const orgs = new OrganizationClient({
baseUrl: 'https://api-puguh.arsaka.io',
accessToken: access_token,
});
// List organizations the user belongs to
// Returns { items: OrganizationWithMembership[], total: number }
const orgList = await orgs.list();
console.log(orgList.items, orgList.total);
// Create a new team organization
const org = await orgs.create({ name: 'Acme Corp', slug: 'acme-corp' });
// Get organization details
const details = await orgs.get(org.organization.organizationId);
// Update organization settings
await orgs.update(org.organization.organizationId, { name: 'Acme Corporation' });
// Member management
const members = await orgs.listMembers(org.organization.organizationId);
await orgs.inviteMember(org.organization.organizationId, {
email: 'colleague@example.com', role: 'member',
});
await orgs.removeMember(org.organization.organizationId, memberId);
// Delete organization
await orgs.delete(org.organization.organizationId); Methods: list, get, create, update, delete, listMembers, inviteMember, removeMember
3. IAMClient
Identity and Access Management — manage users, roles, and role assignments across your organization.
import { IAMClient } from '@arsaka/puguh-sdk';
const iam = new IAMClient({
baseUrl: 'https://api-puguh.arsaka.io',
accessToken: access_token,
organizationId: 'org-uuid',
});
// List users in the organization
// Returns { items: IamUser[], total, page, pageSize, hasNext, hasPrev }
const users = await iam.listUsers();
console.log(users.items, users.total);
// Get a specific user
const user = await iam.getUser(userId);
// Get user stats
const stats = await iam.getUserStats();
console.log(stats.total, stats.active);
// Role management
const roles = await iam.listRoles();
const customRole = await iam.createRole({
name: 'billing_admin',
description: 'Can manage billing',
permissions: ['billing.invoices.read', 'billing.invoices.create'],
});
await iam.assignRole(userId, customRole.roleId);
// Permission matrix (roles x permissions)
const matrix = await iam.getPermissionMatrix();
console.log(matrix.roles, matrix.permissions); // permissions is string[] Methods: listUsers, getUserStats, getUser, getUserRoles, listRoles, getRole, getRolePermissions, createRole, updateRole, deleteRole, assignRole, revokeRole, listServiceAccounts, listPermissions, getPermissionMatrix
4. ControlClient
Access the audit trail, event logs, dead-letter queue, and platform metrics. All paths are under /control.
import { ControlClient } from '@arsaka/puguh-sdk';
const control = new ControlClient({
baseUrl: 'https://api-puguh.arsaka.io',
accessToken: access_token,
organizationId: 'org-uuid',
});
// Audit logs — who did what, when
// Returns { items: AuditRecord[], total, page, limit, pages }
const audit = await control.listAudit({
resourceType: 'user',
limit: 50,
});
// Single audit record
const record = await control.getAudit(auditId);
// Event stream
// Returns { items: SystemEvent[], total, page, limit, pages }
const events = await control.listEvents({ limit: 50 });
// Dead-letter queue — failed event deliveries
// DLQ items have totalAttempts (not retryCount)
const dlq = await control.listDLQ();
// Metrics trends (7d, 30d, or 90d)
const trends = await control.getMetricsTrends('30d'); Methods: listAudit, getAudit, listEvents, getEvent, listDLQ, getDLQ, retryDLQ, getMetricsTrends
5. ApplicationClient
Manage applications within an organization. Each organization can contain multiple applications with their own member lists.
import { ApplicationClient } from '@arsaka/puguh-sdk';
const apps = new ApplicationClient({
baseUrl: 'https://api-puguh.arsaka.io',
accessToken: access_token,
organizationId: 'org-uuid',
});
// List all applications
// Returns { applications: Application[], total, limit, offset }
const appList = await apps.list();
// Create a new application
const app = await apps.create({ name: 'MANTRA Dashboard', slug: 'mantra' });
// Get application details
const appDetails = await apps.get(app.id);
// Update application
await apps.update(app.id, { name: 'MANTRA Production' });
// Manage application members
const appMembers = await apps.listMembers(app.id);
// Delete application
await apps.delete(app.id); Methods: list, get, create, update, delete, listMembers
6. WebhookClient
Configure webhook endpoints and manage event deliveries. Use webhooks to receive real-time notifications when events occur in your organization.
import { WebhookClient } from '@arsaka/puguh-sdk';
const webhooks = new WebhookClient({
baseUrl: 'https://api-puguh.arsaka.io',
accessToken: access_token,
organizationId: 'org-uuid',
});
// List registered webhooks
// Returns { items: Webhook[], total, page, limit, pages }
const list = await webhooks.list();
// Create a new webhook (secret only returned on create)
const webhook = await webhooks.create({
url: 'https://example.com/webhooks/puguh',
eventTypes: ['user.registered', 'organization.created'],
description: 'My webhook endpoint',
});
console.log(webhook.secret); // Save this — not returned again
// Get a webhook (no secret in response)
const wh = await webhooks.get(webhook.id);
// Update webhook
await webhooks.update(webhook.id, {
description: 'Updated description',
isActive: false,
});
// List recent deliveries for a webhook
const deliveries = await webhooks.listDeliveries(webhook.id);
// Test webhook (sends ping)
const testResult = await webhooks.test(webhook.id);
console.log(testResult.deliveryId, testResult.status);
// Delete webhook
await webhooks.delete(webhook.id); Methods: create, list, get, update, delete, listDeliveries, test
TypeScript Types
The SDK exports full type definitions for all API entities. Use them to type your application code:
import type {
OrganizationListResponse,
OrganizationWithMembership,
IamUser,
AuditRecord,
LoginResponse,
PuguhError,
} from '@arsaka/puguh-sdk';
// Type your handlers
function handleOrg(item: OrganizationWithMembership): void {
console.log(item.organization.name, item.role);
}
// Organization list is paginated
function showOrgs(response: OrganizationListResponse): void {
console.log(response.items); // OrganizationWithMembership[]
console.log(response.total); // number
} Error Handling
All client methods throw PuguhError on non-2xx responses. The error includes the HTTP status code, a human-readable message, and optional details.
import { PuguhError } from '@arsaka/puguh-sdk';
try {
const orgs = await client.list();
} catch (error) {
if (error instanceof PuguhError) {
console.error(error.statusCode); // HTTP status code (e.g. 401, 403, 404)
console.error(error.message); // Human-readable error message
console.error(error.errorCode); // Error code string (e.g. 'UNAUTHORIZED')
console.error(error.details); // Optional additional error details
}
} Configuration Options
All client constructors accept the same configuration object:
| Option | Type | Required | Description |
|---|---|---|---|
baseUrl | string | Yes | PUGUH API URL (e.g. https://api-puguh.arsaka.io) |
accessToken | string | No* | JWT access token from AuthClient.login(). Required for all clients except AuthClient. |
apiKey | string | No | API key for server-to-server authentication (alternative to accessToken) |
organizationId | string | No | Default organization UUID for scoped operations |
applicationId | string | No | Default application UUID for scoped operations |
timeout | number | No | Request timeout in milliseconds (default: 30000) |
Note
AuthClient does not require accessToken since it is used to obtain tokens in the first place. All other clients require either accessToken or apiKey for authentication.
Environment Variables
A recommended .env setup for server-side usage:
PUGUH_BASE_URL=https://api-puguh.arsaka.io
PUGUH_API_KEY=pk_live_your_api_key
PUGUH_ORGANIZATION_ID=your-org-uuid
PUGUH_APPLICATION_ID=your-app-uuid import { OrganizationClient } from '@arsaka/puguh-sdk';
const client = new OrganizationClient({
baseUrl: process.env.PUGUH_BASE_URL!,
apiKey: process.env.PUGUH_API_KEY!,
organizationId: process.env.PUGUH_ORGANIZATION_ID!,
}); Best Practices
1. Never Hardcode Credentials
// Bad
const auth = new AuthClient({ baseUrl: 'https://api-puguh.arsaka.io' });
const { access_token } = await auth.login({
email: 'admin@arsaka.dev',
password: 'hardcoded-password', // Never do this
});
// Good — use environment variables
const { access_token } = await auth.login({
email: process.env.PUGUH_EMAIL!,
password: process.env.PUGUH_PASSWORD!,
}); 2. Reuse Client Instances
Create client instances once and reuse them. Each instance maintains its configuration and authentication state.
// Create once at application startup
const orgs = new OrganizationClient({
baseUrl: process.env.PUGUH_BASE_URL!,
accessToken: access_token,
});
// Reuse across your application
export { orgs }; 3. Handle Token Refresh
Access tokens expire. Use refreshToken to obtain a new access token without requiring the user to log in again.
import { AuthClient, PuguhError } from '@arsaka/puguh-sdk';
async function withTokenRefresh<T>(
fn: () => Promise<T>,
auth: AuthClient,
refreshToken: string,
): Promise<T> {
try {
return await fn();
} catch (error) {
if (error instanceof PuguhError && error.statusCode === 401) {
const { access_token } = await auth.refreshToken({
refresh_token: refreshToken,
});
// Update client token and retry
client.accessToken = access_token;
return await fn();
}
throw error;
}
} 4. Use Proper Error Handling
import { PuguhError } from '@arsaka/puguh-sdk';
try {
const org = await orgs.get(orgId);
} catch (error) {
if (error instanceof PuguhError) {
switch (error.statusCode) {
case 401:
// Token expired — refresh and retry
break;
case 403:
// Insufficient permissions
break;
case 404:
// Organization not found
break;
case 429:
// Rate limited — back off and retry
break;
default:
// Unexpected error
throw error;
}
}
}