@voiceassist/api-client
Type-safe HTTP client for VoiceAssist backend services.
Installation
pnpm add @voiceassist/api-client
Features
- Type-safe API calls with TypeScript
- Automatic retry with exponential backoff
- JWT authentication with automatic token refresh
- Distributed tracing with correlation IDs
- Configurable timeout and error handling
Usage
import { VoiceAssistApiClient } from "@voiceassist/api-client"; const client = new VoiceAssistApiClient({ baseURL: "https://assist.asimo.io/api", timeout: 30000, getAccessToken: () => localStorage.getItem("accessToken"), onUnauthorized: () => { // Handle token expiry window.location.href = "/login"; }, enableRetry: true, retryConfig: { maxRetries: 3, baseDelay: 1000, }, });
API Methods
Authentication
// Login const tokens = await client.login({ email, password }); // Register const user = await client.register({ email, password, full_name }); // Logout await client.logout(); // Refresh token const newTokens = await client.refreshToken(refreshToken); // Get current user const user = await client.getCurrentUser();
Conversations
// List conversations const conversations = await client.getConversations(page, pageSize); // Create conversation const conversation = await client.createConversation("My Conversation"); // Get conversation const conversation = await client.getConversation(id); // Update conversation const updated = await client.updateConversation(id, { title: "New Title" }); // Delete conversation await client.deleteConversation(id);
Messages
// Get messages const messages = await client.getMessages(conversationId, page, pageSize); // Send message const message = await client.sendMessage(conversationId, "Hello"); // Send idempotent message (safe to retry) const message = await client.sendIdempotentMessage(conversationId, clientMessageId, "Hello");
Voice
// Transcribe audio const text = await client.transcribeAudio(audioBlob); // Text-to-speech const audioBlob = await client.synthesizeSpeech(text, voiceId); // Create realtime voice session const session = await client.createRealtimeSession({ conversation_id: conversationId, voice: "alloy", language: "en", });
Knowledge Base
// Search const results = await client.searchKnowledgeBase(query, limit); // List documents const docs = await client.getDocuments(page, pageSize); // Upload document const doc = await client.uploadDocument(file, category);
Admin
// System metrics const metrics = await client.getSystemMetrics(); // Audit logs const logs = await client.getAuditLogs(page, pageSize); // Feature flags const flags = await client.getFeatureFlags(); await client.toggleFeatureFlag(flagName); // Cache management const stats = await client.getCacheStats(); await client.clearCache();
Retry Configuration
The client includes built-in retry logic with exponential backoff:
import { withRetry, createRetryWrapper } from "@voiceassist/api-client"; // Manual retry const result = await withRetry( () => fetchData(), { maxRetries: 3, baseDelay: 1000 }, (attempt, error) => console.log(`Retry ${attempt}`, error), ); // Create reusable wrapper const fetchWithRetry = createRetryWrapper(fetchData, { maxRetries: 3 });
Development
# Build pnpm build # Watch mode pnpm dev # Type check pnpm type-check
Dependencies
axios- HTTP client@voiceassist/types- Shared type definitions
@voiceassist/config
Shared configuration files for VoiceAssist applications.
Installation
pnpm add @voiceassist/config
Contents
This package provides shared configuration for:
- ESLint - Code linting rules
- Tailwind CSS - Styling configuration with design tokens
- TypeScript - Compiler configurations
- i18n - Internationalization settings
Usage
ESLint
Extend the shared ESLint configuration in your .eslintrc.js:
module.exports = { extends: ["@voiceassist/config/eslint"], // Add project-specific overrides };
Tailwind CSS
Use the shared Tailwind configuration in your tailwind.config.js:
const sharedConfig = require("@voiceassist/config/tailwind"); /** @type {import('tailwindcss').Config} */ module.exports = { presets: [sharedConfig], content: ["./src/**/*.{js,ts,jsx,tsx}", "../../packages/ui/src/**/*.{js,ts,jsx,tsx}"], // Project-specific customizations };
The Tailwind config includes:
- Color system from
@voiceassist/design-tokens - Typography scale
- Spacing system
- Border radius tokens
- Shadow system
- Dark mode support via class strategy
TypeScript
Extend one of the base TypeScript configurations:
Base configuration (tsconfig.base.json):
{ "extends": "@voiceassist/config/tsconfig.base.json", "compilerOptions": { "outDir": "./dist" }, "include": ["src"] }
React configuration (tsconfig.react.json):
{ "extends": "@voiceassist/config/tsconfig.react.json", "compilerOptions": { "outDir": "./dist" }, "include": ["src"] }
i18n
Use the shared i18n configuration:
import { i18nConfig } from "@voiceassist/config/i18n"; // Configure your i18n library with these settings
Configuration Details
Tailwind CSS Tokens
The Tailwind configuration integrates with design tokens:
// Available color scales colors: { primary, // Blue palette secondary, // Purple palette neutral, // Gray palette success, // Green palette error, // Red palette warning, // Yellow palette info, // Cyan palette } // Semantic colors background: { primary, secondary, tertiary, elevated, inverse } text: { primary, secondary, tertiary, disabled, inverse, link } border: { default, subtle, strong, focus }
Dark Mode
Dark mode is configured using the class strategy:
darkMode: ["class", '[data-theme="dark"]'];
Use with ThemeProvider from @voiceassist/ui.
Dependencies
@voiceassist/design-tokens- Design token definitions
@voiceassist/design-tokens
Design tokens package for VoiceAssist applications. Provides a centralized, type-safe design system with colors, typography, spacing, and other visual primitives.
Installation
This package is part of the VoiceAssist monorepo and is automatically available to all apps via pnpm workspaces.
# In any app or package pnpm add @voiceassist/design-tokens
Usage
Colors
import { colors } from "@voiceassist/design-tokens"; // Primary brand color const primary = colors.primary[500]; // #0080FF // Semantic colors const success = colors.success[500]; // #00C369 const error = colors.error[500]; // #FF0000 // Background colors const bg = colors.background.primary; // #FFFFFF
Typography
import { typography } from "@voiceassist/design-tokens"; // Font families const sansFont = typography.fontFamily.sans; const monoFont = typography.fontFamily.mono; // Font sizes const bodySize = typography.fontSize.base; // 1rem (16px) const headingSize = typography.fontSize["3xl"]; // 1.875rem (30px) // Font weights const bold = typography.fontWeight.bold; // 700
Spacing
import { spacing, borderRadius, shadows, zIndex } from "@voiceassist/design-tokens"; // Spacing (4px/8px grid) const sm = spacing[2]; // 0.5rem (8px) const md = spacing[4]; // 1rem (16px) const lg = spacing[8]; // 2rem (32px) // Border radius const rounded = borderRadius.md; // 0.375rem (6px) // Shadows const cardShadow = shadows.md; // Z-index const modalZ = zIndex.modal; // 1400
Design Principles
Color Palette
- Medical Blue (#0080FF): Primary brand color, evokes trust and professionalism
- Medical Teal (#00AFAF): Secondary color, provides visual interest
- Professional Grays: Neutral tones for text and backgrounds
- Semantic Colors: Success (green), error (red), warning (amber), info (blue)
Typography
- System Fonts: Native fonts for optimal performance and familiarity
- Rem Units: All font sizes use rem for accessibility
- Clear Hierarchy: 10 predefined sizes from xs (12px) to 7xl (72px)
Spacing
- 4px/8px Grid: All spacing follows a consistent grid
- Rem Units: Ensures accessibility with user font-size preferences
- Generous Scale: Ranges from 2px (0.5) to 384px (96)
Tailwind Integration
These tokens are designed to integrate seamlessly with Tailwind CSS. See the @voiceassist/config package for the Tailwind configuration.
Themed usage
Use the designSystem export for a WCAG-conscious bundle of light/dark palettes, elevation, focus, and spacing tokens:
import { designSystem } from "@voiceassist/design-tokens"; const cardBackground = designSystem.light.colors.surface.card; // WCAG AA on text.primary const focusRing = designSystem.light.focus.strong; // 3px blue outline const darkShadow = designSystem.dark.elevation.lg;
All text/background pairs in the palette have been verified for WCAG 2.1 AA contrast, and focus ring tokens are 3px/2px outlines for keyboard visibility.
TypeScript Support
All tokens are fully typed with TypeScript for autocomplete and type safety:
import type { ColorCategory, FontSize, SpacingToken } from "@voiceassist/design-tokens"; const category: ColorCategory = "primary"; const size: FontSize = "lg";
Module Exports
The package provides individual module exports for tree-shaking:
// Import everything import { colors, typography, spacing } from "@voiceassist/design-tokens"; // Or import specific modules import { lightColors, darkColors } from "@voiceassist/design-tokens/colors"; import { typography } from "@voiceassist/design-tokens/typography"; import { spacing } from "@voiceassist/design-tokens/spacing"; import { animations, transitions } from "@voiceassist/design-tokens/animations"; import { breakpoints, mediaQueries } from "@voiceassist/design-tokens/breakpoints"; import { shadows, zIndex } from "@voiceassist/design-tokens/elevation";
Development
# Build pnpm build # Watch mode pnpm dev # Type check pnpm type-check
Contributing
When adding new tokens:
- Follow the existing naming conventions
- Maintain the 4px/8px grid for spacing
- Update TypeScript types
- Document new tokens in this README
- Rebuild the package:
pnpm build
@voiceassist/telemetry
Shared telemetry utilities for VoiceAssist applications. Provides unified error tracking, performance monitoring, and logging.
Installation
pnpm add @voiceassist/telemetry
Features
- Sentry integration for error tracking
- Web Vitals monitoring (CLS, FCP, FID, INP, LCP, TTFB)
- Grafana Loki integration for log aggregation
- Unified telemetry client interface
Usage
Basic Setup
import { createTelemetryClient } from "@voiceassist/telemetry"; const telemetry = createTelemetryClient({ sentryDsn: process.env.SENTRY_DSN, grafanaUrl: process.env.GRAFANA_LOKI_URL, grafanaToken: process.env.GRAFANA_TOKEN, release: "1.0.0", environment: "production", app: "web-app", context: { userId: currentUser?.id, }, });
Error Tracking
// Capture errors try { await riskyOperation(); } catch (error) { telemetry.captureError(error, { component: "ChatPanel", action: "sendMessage", }); } // Capture messages telemetry.captureMessage("User completed onboarding", "info");
Web Vitals
// Initialize web vitals tracking // Call this once in your app entry point telemetry.trackWebVitals();
This automatically tracks:
| Metric | Description |
|---|---|
| CLS | Cumulative Layout Shift |
| FCP | First Contentful Paint |
| FID | First Input Delay |
| INP | Interaction to Next Paint |
| LCP | Largest Contentful Paint |
| TTFB | Time to First Byte |
Flushing Before Page Unload
// Ensure all events are sent before page unload window.addEventListener("beforeunload", async () => { await telemetry.flush(); });
Configuration Options
interface TelemetryOptions { // Sentry DSN for error tracking sentryDsn?: string; // Grafana Loki URL for log aggregation grafanaUrl?: string; // Auth token for Grafana grafanaToken?: string; // Release version release?: string; // Environment (production, staging, development) environment?: string; // Application name app?: string; // Additional context for all events context?: Record<string, unknown>; }
API Reference
TelemetryClient
interface TelemetryClient { // Capture an error with optional context captureError: (error: unknown, context?: Record<string, unknown>) => void; // Capture a message with severity level captureMessage: (message: string, level?: SeverityLevel) => void; // Start tracking Web Vitals trackWebVitals: () => void; // Flush pending events (returns true if successful) flush: () => Promise<boolean>; }
Severity Levels
fatal- Application crasherror- Error conditionswarning- Warning conditionsinfo- Informational messagesdebug- Debug information
Integration with React
// App.tsx import { createTelemetryClient } from '@voiceassist/telemetry'; import { useEffect } from 'react'; const telemetry = createTelemetryClient({ sentryDsn: import.meta.env.VITE_SENTRY_DSN, environment: import.meta.env.MODE, app: 'web-app', }); function App() { useEffect(() => { telemetry.trackWebVitals(); }, []); return <YourApp />; }
Dependencies
@sentry/browser- Error trackingweb-vitals- Core Web Vitals measurement
Development
# Build pnpm build # Watch mode pnpm dev
@voiceassist/types
Shared TypeScript type definitions for VoiceAssist applications.
Installation
pnpm add @voiceassist/types
Overview
This package provides centralized type definitions used across all VoiceAssist frontend applications and the API client. It ensures type consistency between the web app, admin panel, and documentation site.
Type Categories
User & Authentication
import type { User, UserRole, AuthTokens, LoginRequest, LoginResponse, TokenResponse } from "@voiceassist/types"; // User roles type UserRole = "admin" | "physician" | "staff" | "patient";
Chat & Conversations
import type { Message, Conversation, Citation, Branch, CreateBranchRequest } from "@voiceassist/types"; // Message with optional citations and attachments interface Message { id: string; conversationId?: string; role: "user" | "assistant" | "system"; content: string; citations?: Citation[]; attachments?: string[]; timestamp: number; parentId?: string; // For branching branchId?: string; }
Clinical Context (HIPAA-compliant)
import type { ClinicalContext, ClinicalContextCreate, ClinicalContextUpdate, Vitals } from "@voiceassist/types"; interface Vitals { temperature?: number; // Celsius heartRate?: number; // BPM bloodPressure?: string; // "120/80" respiratoryRate?: number; spo2?: number; // Percentage }
Knowledge Base
import type { Document, DocumentStatus, SearchResult, KnowledgeBaseEntry } from "@voiceassist/types"; type DocumentStatus = "pending" | "processing" | "indexed" | "failed";
Folders & Organization
import type { Folder, CreateFolderRequest, UpdateFolderRequest } from "@voiceassist/types";
Sharing
import type { ShareRequest, ShareResponse, ShareLink } from "@voiceassist/types";
Attachments
import type { Attachment, AttachmentUploadResponse, UploadProgress } from "@voiceassist/types";
Voice
import type { VoiceConfig, TranscriptionResult } from "@voiceassist/types";
WebSocket Events
import type { WebSocketEvent, WebSocketEventType, WebSocketError, WebSocketErrorCode, ConnectionStatus, ChatStreamChunk, } from "@voiceassist/types"; type WebSocketEventType = | "delta" | "chunk" | "message.done" | "user_message.created" | "history" | "connected" | "error" | "ping" | "pong"; type ConnectionStatus = "connecting" | "connected" | "reconnecting" | "disconnected" | "failed";
API Responses
import type { ApiResponse, ApiError, ApiMeta, PaginatedResponse } from "@voiceassist/types"; // Standard API envelope interface ApiResponse<T = unknown> { success: boolean; data?: T; error?: ApiError; meta?: ApiMeta; }
Admin Types
import type { SystemMetrics, AuditLogEntry } from "@voiceassist/types";
Utility Types
import type { Nullable, Optional, DeepPartial } from "@voiceassist/types"; // Helper types type Nullable<T> = T | null; type Optional<T> = T | undefined; type DeepPartial<T> = { [P in keyof T]?: DeepPartial<T[P]> };
Usage Example
import type { User, Conversation, Message } from "@voiceassist/types"; function displayConversation(conversation: Conversation, messages: Message[]) { console.log(`Conversation: ${conversation.title}`); messages.forEach((msg) => { console.log(`[${msg.role}]: ${msg.content}`); }); } async function getCurrentUser(): Promise<User> { const response = await fetch("/api/users/me"); return response.json(); }
Development
# Build pnpm build # Watch mode pnpm dev # Type check pnpm type-check
@voiceassist/ui
Shared React component library for VoiceAssist applications. Built with Radix UI primitives and Tailwind CSS.
Installation
pnpm add @voiceassist/ui
Peer Dependencies
pnpm add react react-dom react-i18next
Features
- Accessible components built on Radix UI
- Consistent styling with Tailwind CSS
- Dark mode support via ThemeProvider
- Medical-specific components (HIPAA-compliant)
- Storybook documentation
- Comprehensive test coverage
Components
Core Components
import { Button, Input, Label, Card, Badge, Avatar, Spinner, Skeleton, IconButton } from "@voiceassist/ui";
Layout Components
import { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } from "@voiceassist/ui";
Form Components
import { Input, Label, Select, SelectTrigger, SelectContent, SelectItem } from "@voiceassist/ui";
Overlay Components
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, } from "@voiceassist/ui";
Data Display
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell, Badge, Avatar, AvatarGroup, } from "@voiceassist/ui";
Feedback Components
import { FeedbackRating, FeedbackForm, Spinner, SpinnerOverlay, Skeleton } from "@voiceassist/ui";
Medical Components
import { VitalSignCard, MedicationList, MedicationItem, AlertBanner } from "@voiceassist/ui";
Providers
import { ThemeProvider, useTheme } from "@voiceassist/ui";
Usage Examples
Button
import { Button } from '@voiceassist/ui'; <Button variant="default" size="md"> Click me </Button> <Button variant="destructive" size="sm"> Delete </Button> <Button variant="outline" disabled> Disabled </Button>
Card
import { Card, CardHeader, CardTitle, CardContent } from "@voiceassist/ui"; <Card> <CardHeader> <CardTitle>Patient Summary</CardTitle> </CardHeader> <CardContent> <p>Content goes here</p> </CardContent> </Card>;
Dialog
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, Button } from "@voiceassist/ui"; <Dialog> <DialogTrigger asChild> <Button>Open Dialog</Button> </DialogTrigger> <DialogContent> <DialogHeader> <DialogTitle>Confirm Action</DialogTitle> </DialogHeader> <p>Are you sure you want to proceed?</p> </DialogContent> </Dialog>;
ThemeProvider
import { ThemeProvider, useTheme } from "@voiceassist/ui"; function App() { return ( <ThemeProvider defaultTheme="system"> <YourApp /> </ThemeProvider> ); } function ThemeToggle() { const { theme, setTheme } = useTheme(); return <button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>Toggle Theme</button>; }
Medical Components
import { VitalSignCard, AlertBanner } from '@voiceassist/ui'; <VitalSignCard label="Heart Rate" value={72} unit="bpm" status="normal" /> <AlertBanner severity="warning" title="Drug Interaction" message="Potential interaction between medications" actions={[ { label: 'Review', onClick: () => {} } ]} />
Utilities
cn() - Class Name Utility
import { cn } from "@voiceassist/ui"; // Merge Tailwind classes with conflict resolution const className = cn("px-4 py-2", isActive && "bg-primary text-white", className);
Development
# Build pnpm build # Watch mode pnpm dev # Type check pnpm type-check # Run tests pnpm test # Run tests in watch mode pnpm test:watch # Run Storybook pnpm storybook # Build Storybook pnpm build-storybook
Storybook
View component documentation and interactive examples:
pnpm storybook
Opens at http://localhost:6006
Testing
Components include comprehensive tests using Vitest and Testing Library:
# Run all tests pnpm test # Run with coverage pnpm test:coverage # Interactive UI pnpm test:ui
Dependencies
@radix-ui/*- Accessible UI primitives@voiceassist/design-tokens- Design tokensclass-variance-authority- Variant managementclsx+tailwind-merge- Class name utilities
@voiceassist/utils
Shared utility functions for VoiceAssist applications.
Installation
pnpm add @voiceassist/utils
Features
- String manipulation utilities
- Date/time formatting
- Array helpers
- Object utilities
- Validation functions
- PHI detection for HIPAA compliance
- Debounce and throttle
Utilities
String Utilities
import { capitalize, truncate, kebabCase, camelCase } from "@voiceassist/utils"; capitalize("hello"); // 'Hello' truncate("Long text here", 8); // 'Long ...' kebabCase("myVariable"); // 'my-variable' camelCase("my-variable"); // 'myVariable'
Date/Time Utilities
import { formatDate, relativeTime } from "@voiceassist/utils"; formatDate(new Date(), "short"); // '11/27/2025' formatDate(new Date(), "long"); // 'November 27, 2025, 10:30 AM' relativeTime(new Date(Date.now() - 3600000)); // '1 hour ago' relativeTime(new Date(Date.now() - 120000)); // '2 minutes ago'
Array Utilities
import { chunk, unique, shuffle } from "@voiceassist/utils"; chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]] unique([1, 2, 2, 3, 3, 3]); // [1, 2, 3] shuffle([1, 2, 3, 4, 5]); // Random order
Object Utilities
import { deepClone, pick, omit } from "@voiceassist/utils"; const obj = { a: 1, b: 2, c: 3 }; deepClone(obj); // New object with same values pick(obj, ["a", "b"]); // { a: 1, b: 2 } omit(obj, ["c"]); // { a: 1, b: 2 }
Validation Utilities
import { isValidEmail, isValidUrl, isEmpty } from "@voiceassist/utils"; isValidEmail("user@example.com"); // true isValidUrl("https://asimo.io"); // true isEmpty(null); // true isEmpty(""); // true isEmpty([]); // true isEmpty({}); // true isEmpty("hello"); // false
Formatting Utilities
import { formatBytes, formatNumber } from "@voiceassist/utils"; formatBytes(1024); // '1 KB' formatBytes(1048576); // '1 MB' formatBytes(1073741824); // '1 GB' formatNumber(1234567); // '1,234,567'
Debounce & Throttle
import { debounce, throttle } from "@voiceassist/utils"; // Debounce - wait 300ms after last call const debouncedSearch = debounce((query: string) => { fetchResults(query); }, 300); // Throttle - max once per 100ms const throttledScroll = throttle(() => { updateScrollPosition(); }, 100);
PHI Detection (HIPAA Compliance)
import { containsPHI, redactPHI } from "@voiceassist/utils"; // Check if text contains potential PHI containsPHI("SSN: 123-45-6789"); // true containsPHI("Hello world"); // false // Redact PHI from text redactPHI("Call me at 555-123-4567"); // 'Call me at [REDACTED_PHONE]' redactPHI("SSN: 123-45-6789, DOB: 01/15/1990"); // 'SSN: [REDACTED_SSN], DOB: [REDACTED_DOB]'
Detected PHI patterns:
- Social Security Numbers (SSN)
- Phone numbers
- Email addresses
- Medical Record Numbers (MRN)
- Dates of birth (DOB)
API Reference
String Functions
| Function | Description |
|---|---|
capitalize(str) | Capitalize first letter |
truncate(str, maxLength) | Truncate with ellipsis |
kebabCase(str) | Convert to kebab-case |
camelCase(str) | Convert to camelCase |
Date Functions
| Function | Description |
|---|---|
formatDate(date, format) | Format date ('short' or 'long') |
relativeTime(date) | Relative time string |
Array Functions
| Function | Description |
|---|---|
chunk(array, size) | Split into chunks |
unique(array) | Remove duplicates |
shuffle(array) | Random shuffle |
Object Functions
| Function | Description |
|---|---|
deepClone(obj) | Deep clone object |
pick(obj, keys) | Pick specific keys |
omit(obj, keys) | Omit specific keys |
Validation Functions
| Function | Description |
|---|---|
isValidEmail(email) | Validate email format |
isValidUrl(url) | Validate URL format |
isEmpty(value) | Check if empty |
Formatting Functions
| Function | Description |
|---|---|
formatBytes(bytes) | Human-readable file size |
formatNumber(num) | Number with separators |
Rate Limiting
| Function | Description |
|---|---|
debounce(fn, wait) | Debounce function calls |
throttle(fn, limit) | Throttle function calls |
PHI Functions
| Function | Description |
|---|---|
containsPHI(text) | Check for PHI |
redactPHI(text) | Redact PHI from text |
Development
# Build pnpm build # Watch mode pnpm dev # Type check pnpm type-check # Run tests pnpm test