11 KiB
11 KiB
NoteFlow TypeScript API Layer
Location
client/src/api/
Architecture
Multi-adapter design with fallback chain:
- TauriAdapter (
adapters/tauri/) - Primary: Rust IPC to gRPC - CachedAdapter (
adapters/cached/) - Fallback: Read-only cache - MockAdapter (
adapters/mock/) - Development: Simulated responses
API Interface (interface.ts)
interface NoteFlowAPI {
// Connection
connect(serverUrl?: string): Promise<ServerInfo>;
disconnect(): Promise<void>;
isConnected(): Promise<boolean>;
getEffectiveServerUrl(): Promise<EffectiveServerUrl>;
getServerInfo(): Promise<ServerInfo>;
// Identity (Sprint 16)
getCurrentUser(): Promise<GetCurrentUserResponse>;
listWorkspaces(): Promise<ListWorkspacesResponse>;
switchWorkspace(workspaceId: string): Promise<SwitchWorkspaceResponse>;
getWorkspaceSettings(request): Promise<GetWorkspaceSettingsResponse>;
updateWorkspaceSettings(request): Promise<GetWorkspaceSettingsResponse>;
// Authentication
initiateAuthLogin(provider, redirectUri?): Promise<InitiateAuthLoginResponse>;
completeAuthLogin(provider, code, state): Promise<CompleteAuthLoginResponse>;
logout(provider?): Promise<LogoutResponse>;
// Projects (Sprint 18)
createProject(request): Promise<Project>;
getProject(request): Promise<Project>;
listProjects(request): Promise<ListProjectsResponse>;
updateProject(request): Promise<Project>;
archiveProject(projectId): Promise<Project>;
setActiveProject(request): Promise<void>;
addProjectMember(request): Promise<ProjectMembership>;
// ... more project methods
// Meetings
createMeeting(request): Promise<Meeting>;
getMeeting(request): Promise<Meeting>;
listMeetings(request): Promise<ListMeetingsResponse>;
stopMeeting(meetingId): Promise<Meeting>;
deleteMeeting(meetingId): Promise<boolean>;
// Streaming
startTranscription(meetingId): Promise<TranscriptionStream>;
getStreamState(): Promise<StreamStateInfo>;
resetStreamState(): Promise<StreamStateInfo>;
// Summary & AI
generateSummary(meetingId, forceRegenerate?): Promise<Summary>;
grantCloudConsent(): Promise<void>;
revokeCloudConsent(): Promise<void>;
getCloudConsentStatus(): Promise<CloudConsentStatus>;
askAssistant(request): Promise<AskAssistantResponse>;
streamAssistant(request): Promise<void>;
// ASR & Streaming Config
getAsrConfiguration(): Promise<ASRConfiguration>;
updateAsrConfiguration(request): Promise<UpdateASRConfigurationResult>;
getStreamingConfiguration(): Promise<StreamingConfiguration>;
updateStreamingConfiguration(request): Promise<StreamingConfiguration>;
// HuggingFace Token
setHuggingFaceToken(request): Promise<SetHuggingFaceTokenResult>;
getHuggingFaceTokenStatus(): Promise<HuggingFaceTokenStatus>;
deleteHuggingFaceToken(): Promise<boolean>;
validateHuggingFaceToken(): Promise<ValidateHuggingFaceTokenResult>;
// Annotations
listAnnotations(meetingId, startTime?, endTime?): Promise<Annotation[]>;
addAnnotation(request): Promise<Annotation>;
updateAnnotation(request): Promise<Annotation>;
deleteAnnotation(annotationId): Promise<boolean>;
// Export
exportTranscript(meetingId, format): Promise<ExportResult>;
saveExportFile(content, defaultName, extension): Promise<boolean>;
// Playback (desktop)
startPlayback(meetingId, startTime?): Promise<void>;
pausePlayback(): Promise<void>;
stopPlayback(): Promise<void>;
seekPlayback(position): Promise<PlaybackInfo>;
getPlaybackState(): Promise<PlaybackInfo>;
// Diarization
refineSpeakers(meetingId, numSpeakers?): Promise<DiarizationJobStatus>;
getDiarizationJobStatus(jobId): Promise<DiarizationJobStatus>;
renameSpeaker(meetingId, oldSpeakerId, newName): Promise<boolean>;
cancelDiarization(jobId): Promise<CancelDiarizationResult>;
getActiveDiarizationJobs(): Promise<DiarizationJobStatus[]>;
// Audio Devices (desktop)
listAudioDevices(): Promise<AudioDeviceInfo[]>;
getDefaultAudioDevice(isInput): Promise<AudioDeviceInfo | null>;
selectAudioDevice(deviceId, isInput): Promise<void>;
listLoopbackDevices(): Promise<AudioDeviceInfo[]>;
setSystemAudioDevice(deviceId): Promise<void>;
setDualCaptureEnabled(enabled): Promise<void>;
getDualCaptureConfig(): Promise<DualCaptureConfigInfo>;
// Triggers (desktop)
setTriggerEnabled(enabled): Promise<void>;
snoozeTriggers(minutes?): Promise<void>;
getTriggerStatus(): Promise<TriggerStatus>;
dismissTrigger(): Promise<void>;
acceptTrigger(title?): Promise<Meeting>;
// Entities (NER)
extractEntities(meetingId, forceRefresh?): Promise<ExtractEntitiesResponse>;
updateEntity(meetingId, entityId, text?, category?): Promise<ExtractedEntity>;
deleteEntity(meetingId, entityId): Promise<boolean>;
// Calendar
listCalendarEvents(hoursAhead?, limit?, provider?): Promise<ListCalendarEventsResponse>;
getCalendarProviders(): Promise<GetCalendarProvidersResponse>;
initiateCalendarAuth(provider, redirectUri?): Promise<InitiateCalendarAuthResponse>;
completeCalendarAuth(provider, code, state): Promise<CompleteCalendarAuthResponse>;
getOAuthConnectionStatus(provider): Promise<GetOAuthConnectionStatusResponse>;
disconnectCalendar(provider): Promise<DisconnectOAuthResponse>;
// Webhooks
registerWebhook(request): Promise<RegisteredWebhook>;
listWebhooks(enabledOnly?): Promise<ListWebhooksResponse>;
updateWebhook(request): Promise<RegisteredWebhook>;
deleteWebhook(webhookId): Promise<DeleteWebhookResponse>;
getWebhookDeliveries(webhookId, limit?): Promise<GetWebhookDeliveriesResponse>;
// Integration Sync
startIntegrationSync(integrationId): Promise<StartIntegrationSyncResponse>;
getSyncStatus(syncRunId): Promise<GetSyncStatusResponse>;
listSyncHistory(integrationId, limit?, offset?): Promise<ListSyncHistoryResponse>;
getUserIntegrations(): Promise<GetUserIntegrationsResponse>;
// Observability
getRecentLogs(request?): Promise<GetRecentLogsResponse>;
getPerformanceMetrics(request?): Promise<GetPerformanceMetricsResponse>;
runConnectionDiagnostics(): Promise<ConnectionDiagnostics>;
// OIDC Provider Management (Sprint 17)
registerOidcProvider(request): Promise<OidcProviderApi>;
listOidcProviders(workspaceId?, enabledOnly?): Promise<ListOidcProvidersResponse>;
getOidcProvider(providerId): Promise<OidcProviderApi>;
updateOidcProvider(request): Promise<OidcProviderApi>;
deleteOidcProvider(providerId): Promise<DeleteOidcProviderResponse>;
listOidcPresets(): Promise<ListOidcPresetsResponse>;
// Tasks (Strategy B)
listTasks(request): Promise<ListTasksResponse>;
createTask(request): Promise<Task>;
updateTask(request): Promise<Task>;
// Analytics (Strategy B)
getAnalyticsOverview(request): Promise<AnalyticsOverview>;
listSpeakerStats(request): Promise<ListSpeakerStatsResponse>;
getEntityAnalytics(request): Promise<EntityAnalytics>;
// Summarization Templates
listSummarizationTemplates(request): Promise<ListSummarizationTemplatesResponse>;
createSummarizationTemplate(request): Promise<SummarizationTemplateMutationResponse>;
updateSummarizationTemplate(request): Promise<SummarizationTemplateMutationResponse>;
archiveSummarizationTemplate(request): Promise<SummarizationTemplate>;
// Installed Apps (desktop)
listInstalledApps(options?): Promise<ListInstalledAppsResponse>;
invalidateAppCache(): Promise<void>;
// Testing (E2E)
checkTestEnvironment(): Promise<TestEnvironmentInfo>;
injectTestAudio(meetingId, config): Promise<TestAudioResult>;
injectTestTone(meetingId, frequencyHz, durationSeconds, sampleRate?): Promise<TestAudioResult>;
}
Adapter Structure
Tauri Adapter (adapters/tauri/)
tauri/
├── api.ts # Main adapter implementation
├── index.ts # Exports
├── stream.ts # Transcription streaming
├── environment.ts # Environment detection
├── constants.ts # Tauri constants
├── types.ts # Adapter-specific types
├── utils.ts # Utility functions
└── sections/ # Domain-specific sections
├── core.ts
├── meetings.ts
├── summarization.ts
├── diarization.ts
├── projects.ts
├── calendar.ts
├── webhooks.ts
├── preferences.ts
├── observability.ts
├── integrations.ts
├── entities.ts
├── exporting.ts
├── apps.ts
├── triggers.ts
└── playback.ts
Cached Adapter (adapters/cached/)
Read-only offline access with cache TTL.
cached/
├── index.ts # Main cached adapter
├── base.ts # Base cache utilities
├── defaults.ts # Default values
├── readonly.ts # Read-only rejection helper
├── meetings.ts, projects.ts, annotations.ts, templates.ts
├── webhooks.ts, preferences.ts, diarization.ts
├── playback.ts, streaming.ts, triggers.ts
├── apps.ts, audio.ts, asr.ts, calendar.ts
├── entities.ts, observability.ts, huggingface.ts
Mock Adapter (adapters/mock/)
Development/testing with simulated data.
mock/
├── index.ts # Main mock adapter
├── stream.ts # Mock transcription stream
└── data.ts # Mock data generators
Core Module (core/)
core/
├── connection.ts # Connection state management
├── reconnection.ts # Auto-reconnection logic
├── streams.ts # TranscriptionStream type
├── helpers.ts # Utility helpers
├── constants.ts # API constants
├── errors.ts # Error handling
└── index.ts # Exports
Type Definitions (types/)
types/
├── core.ts # Core types (Meeting, Segment, Summary, etc.)
├── enums.ts # Enum definitions
├── errors.ts # Error types
├── projects.ts # Project types
├── diagnostics.ts # Diagnostics types
├── testing.ts # Testing types
├── index.ts # Re-exports
└── requests/ # Request type definitions
├── meetings.ts
├── annotations.ts
├── templates.ts
├── preferences.ts
├── integrations.ts
├── oidc.ts
├── ai.ts
├── assistant.ts
├── audio.ts
├── recording-apps.ts
└── triggers.ts
API Initialization (index.ts)
// Auto-initialization on module load
export async function initializeAPI(): Promise<NoteFlowAPI> {
try {
const tauriAPI = await initializeTauriAPI();
setAPIInstance(tauriAPI);
await tauriAPI.connect();
setConnectionMode('connected');
startReconnection();
return tauriAPI;
} catch {
// Fall back to mock in browser
setConnectionMode('mock');
setAPIInstance(mockAPI);
return mockAPI;
}
}
export function getAPI(): NoteFlowAPI {
if (!apiInstance) throw new Error('API not initialized');
return apiInstance;
}
Usage Pattern
import { getAPI } from '@/api';
const api = getAPI();
const meeting = await api.createMeeting({ title: 'Sprint Planning' });
const stream = await api.startTranscription(meeting.id);
stream.onUpdate((update) => {
if (update.update_type === 'final') {
console.log('New segment:', update.segment);
}
});
// Send audio chunks
stream.send({ audio_data: audioBuffer });