Files
noteflow/.rag/07-typescript-api-layer.md

11 KiB

NoteFlow TypeScript API Layer

Location

client/src/api/

Architecture

Multi-adapter design with fallback chain:

  1. TauriAdapter (adapters/tauri/) - Primary: Rust IPC to gRPC
  2. CachedAdapter (adapters/cached/) - Fallback: Read-only cache
  3. 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 });