/** * Cloud API client functions (S-7.1, S-7.2) * * Org management and team management endpoints. */ const BASE = ''; class ApiError extends Error { constructor(public readonly status: number, message: string) { super(message); this.name = 'ApiError'; } } async function request(path: string, init?: RequestInit): Promise { const res = await fetch(`${BASE}${path}`, { ...init, headers: { 'Content-Type': 'application/json', ...init?.headers }, }); if (!res.ok) { const body = await res.text().catch(() => ''); throw new ApiError(res.status, body || `HTTP ${res.status}`); } return res.json() as Promise; } // ─── Types ────────────────────────────────────────────────────── export interface CloudOrg { id: string; name: string; slug: string; plan: string; created_at: string; } export interface CloudOrgMember { user_id: string; email: string; display_name: string | null; avatar_url: string | null; role: string; joined_at: string; } export interface CloudInvitation { id: string; org_id: string; email: string; role: string; invited_by: string; invited_by_name: string | null; expires_at: string; created_at: string; } // ─── Org Endpoints (S-7.1) ────────────────────────────────────── export async function getMyOrgs(): Promise { return request('/api/cloud/orgs'); } export async function createOrg(name: string): Promise { return request('/api/cloud/orgs', { method: 'POST', body: JSON.stringify({ name }), }); } export async function switchOrg(orgId: string): Promise<{ token: string }> { return request<{ token: string }>('/api/cloud/orgs/switch', { method: 'POST', body: JSON.stringify({ orgId }), }); } // ─── Team Endpoints (S-7.2) ───────────────────────────────────── export async function getOrgMembers(orgId: string): Promise { return request(`/api/cloud/orgs/${orgId}/members`); } export async function getOrgInvitations(orgId: string): Promise { return request(`/api/cloud/orgs/${orgId}/invitations`); } export async function inviteMember( orgId: string, email: string, role: string, ): Promise { return request(`/api/cloud/orgs/${orgId}/invitations`, { method: 'POST', body: JSON.stringify({ email, role }), }); } export async function cancelInvitation(orgId: string, invitationId: string): Promise<{ ok: boolean }> { return request<{ ok: boolean }>(`/api/cloud/orgs/${orgId}/invitations/${invitationId}`, { method: 'DELETE', }); } export async function changeMemberRole( orgId: string, userId: string, role: string, ): Promise<{ ok: boolean }> { return request<{ ok: boolean }>(`/api/cloud/orgs/${orgId}/members/${userId}/role`, { method: 'PUT', body: JSON.stringify({ role }), }); } export async function removeMember(orgId: string, userId: string): Promise<{ ok: boolean }> { return request<{ ok: boolean }>(`/api/cloud/orgs/${orgId}/members/${userId}`, { method: 'DELETE', }); } export async function transferOwnership(orgId: string, toUserId: string): Promise<{ ok: boolean }> { return request<{ ok: boolean }>(`/api/cloud/orgs/${orgId}/transfer`, { method: 'POST', body: JSON.stringify({ toUserId }), }); } // ─── API Key Types (S-7.3) ────────────────────────────────────── export type ApiKeyEnvironment = 'production' | 'staging' | 'development' | 'test'; export interface CloudApiKey { id: string; org_id: string; key_prefix: string; name: string; environment: ApiKeyEnvironment; scopes: string[]; rate_limit_override: number | null; created_by: string; last_used_at: string | null; revoked_at: string | null; created_at: string; } export interface CreateApiKeyResponse { fullKey: string; record: CloudApiKey; } export interface ApiKeyLimitInfo { current: number; limit: number; plan: string; } // ─── API Key Endpoints (S-7.3) ────────────────────────────────── export async function listApiKeys(orgId: string): Promise { return request(`/api/cloud/orgs/${orgId}/api-keys`); } export async function createApiKey( orgId: string, name: string, environment: ApiKeyEnvironment, ): Promise { return request(`/api/cloud/orgs/${orgId}/api-keys`, { method: 'POST', body: JSON.stringify({ name, environment }), }); } export async function revokeApiKey(orgId: string, keyId: string): Promise<{ ok: boolean }> { return request<{ ok: boolean }>(`/api/cloud/orgs/${orgId}/api-keys/${keyId}`, { method: 'DELETE', }); } export async function getApiKeyLimit(orgId: string): Promise { return request(`/api/cloud/orgs/${orgId}/api-keys/limit`); } // ─── Usage Types (S-7.4) ──────────────────────────────────────── export type UsageTimeRange = '7d' | '30d' | '90d'; export interface UsageSummary { events_count: number; api_calls: number; storage_bytes: number; quota_events: number; quota_storage_bytes: number; plan: string; period_start: string; period_end: string; } export interface UsageTimePoint { timestamp: string; events: number; api_calls: number; } export interface UsageBreakdown { summary: UsageSummary; timeseries: UsageTimePoint[]; } // ─── Usage Endpoints (S-7.4) ──────────────────────────────────── export async function getUsage(orgId: string, range: UsageTimeRange = '30d'): Promise { return request(`/api/cloud/orgs/${orgId}/usage?range=${range}`); } // ─── DLQ Types (S-3.6) ────────────────────────────────────────── export interface DlqEntry { streamId: string; event: { id: string; type: string; timestamp: string; session_id: string; org_id: string; data: Record; }; dlqReason: string; originalStreamId: string; dlqTimestamp: string; } export interface DlqHealth { dlqDepth: number; dlqHealthy: boolean; dlqWarning?: string; } export interface DlqReplayResult { replayed: number; failed: number; errors: string[]; } // ─── DLQ Endpoints (S-3.6) ────────────────────────────────────── export async function getDlqHealth(orgId: string): Promise { return request(`/api/cloud/orgs/${orgId}/dlq/health`); } export async function listDlqEntries(orgId: string, limit = 50): Promise { return request(`/api/cloud/orgs/${orgId}/dlq?limit=${limit}`); } export async function replayDlqEntry(orgId: string, streamId: string): Promise<{ success: boolean }> { return request<{ success: boolean }>(`/api/cloud/orgs/${orgId}/dlq/replay`, { method: 'POST', body: JSON.stringify({ streamId }), }); } export async function replayDlqBatch(orgId: string, streamIds: string[]): Promise { return request(`/api/cloud/orgs/${orgId}/dlq/replay/batch`, { method: 'POST', body: JSON.stringify({ streamIds }), }); } // ─── Audit Log Types (S-7.6) ──────────────────────────────────── export interface AuditEntry { id: string; org_id: string; actor_type: string; actor_id: string; action: string; resource_type: string; resource_id: string | null; details: Record | null; ip_address: string | null; result: string; created_at: string; } export interface AuditLogResponse { entries: AuditEntry[]; total: number; limit: number; offset: number; } export interface AuditLogFilters { action?: string; actor?: string; from?: string; to?: string; limit?: number; offset?: number; } // ─── Audit Log Endpoints (S-7.6) ──────────────────────────────── export async function queryAuditLog(orgId: string, filters: AuditLogFilters = {}): Promise { const params = new URLSearchParams(); if (filters.action) params.set('action', filters.action); if (filters.actor) params.set('actor', filters.actor); if (filters.from) params.set('from', filters.from); if (filters.to) params.set('to', filters.to); if (filters.limit) params.set('limit', String(filters.limit)); if (filters.offset) params.set('offset', String(filters.offset)); const qs = params.toString(); return request(`/api/cloud/orgs/${orgId}/audit-log${qs ? `?${qs}` : ''}`); } export async function exportAuditLog(orgId: string, from?: string, to?: string): Promise { const params = new URLSearchParams(); if (from) params.set('from', from); if (to) params.set('to', to); const qs = params.toString(); return request(`/api/cloud/orgs/${orgId}/audit-log/export${qs ? `?${qs}` : ''}`); } // ─── Onboarding Types (S-7.7) ─────────────────────────────────── export interface OnboardingStatus { has_org: boolean; has_api_key: boolean; has_first_event: boolean; org_id: string | null; api_key_prefix: string | null; } // ─── Onboarding Endpoints (S-7.7) ─────────────────────────────── export async function getOnboardingStatus(): Promise { return request('/api/cloud/onboarding/status'); } export async function verifyFirstEvent(orgId: string): Promise<{ received: boolean; event_count: number }> { return request<{ received: boolean; event_count: number }>(`/api/cloud/onboarding/verify`, { method: 'POST', body: JSON.stringify({ orgId }), }); } export { ApiError };