# Service Catalog

> **Last Updated**: 2025-01-12  
> **Total Services**: 12

## Quick Reference Index

| Service | Location | Purpose | Key Dependencies |
|---------|----------|---------|------------------|
| BackgroundService | `src/background/index.js` | Message routing & initialization | authManager, filevineClient, webApiClient, downloadManager |
| AuthManager | `src/background/auth.js` | Token management & validation | filevineClient, webApiClient, chrome.storage |
| FilevineClient | `src/background/api.js` | Filevine external API client (Bearer tokens) | None (uses fetch) |
| WebApiClient | `src/background/web-api-client.js` | Filevine web app API client (cookies) | None (uses fetch) |
| CookieInterceptor | `src/background/cookie-interceptor.js` | Intercepts ASP.NET cookies | chrome.cookies, authManager |
| DownloadManager | `src/background/downloads.js` | Download queue & storage | filevineClient, webApiClient, IndexedDB |
| ContentScript | `src/content/index.bundle.js` | Content script entry point | TokenDetector, TokenExtractor |
| TokenDetector | `src/content/detector.js` | Session/page change detection | None |
| TokenExtractor | `src/content/extractor.js` | Token extraction from page | None |
| PopupController | `src/popup/popup.js` | Popup UI controller | chrome.runtime messaging |
| ViewerRegistry | `src/viewers/registry.js` | Viewer registration system | None |
| Constants | `src/lib/constants.js` | Shared constants | None |

---

## BackgroundService

**Location**: `src/background/index.js`  
**Created**: 2025-01-12  
**Last Modified**: 2025-01-12

### Purpose

Entry point for the background service worker. Handles message routing between popup, content scripts, and background services. Initializes all background managers on extension load.

### Public Interface

```javascript
// No public exports - runs as service worker entry point

// Message handler (internal)
async function handleMessage(message, sender) {
  // Routes messages by type to appropriate handlers
}

// Exported for testing
export { handleMessage };
```

### Dependencies

| Dependency | Type | Purpose |
|------------|------|---------|
| `authManager` | Service | Authentication state management |
| `filevineClient` | Service | Filevine API communication |
| `downloadManager` | Service | Download queue and file storage |
| `chrome.runtime` | API | Extension messaging |
| `chrome.storage` | API | Session storage |

### Used By (Dependents)

| Component | How It Uses This Service |
|-----------|--------------------------|
| Chrome Extension Runtime | Loads as service worker entry point |
| Popup | Sends messages via chrome.runtime.sendMessage |
| Content Scripts | Sends messages via chrome.runtime.sendMessage |

### Configuration

| Variable | Purpose | Default |
|----------|---------|---------|
| N/A | Uses constants from `lib/constants.js` | — |

### Error Handling

| Error | Cause | Handling |
|-------|-------|----------|
| Message handler error | Unhandled exception | Catch and return error message |
| Unknown message type | Invalid message type | Log warning, return error |

### Performance Characteristics

| Operation | Typical Latency | Notes |
|-----------|-----------------|-------|
| Message routing | < 1ms | Synchronous routing |
| Auth check | < 5ms | In-memory check |
| API passthrough | Varies | Depends on API call |

### Data Flow

```
Message → Route by type → Call handler → Return response
```

See: `DATA_FLOW.md#message-routing` for details

---

## AuthManager

**Location**: `src/background/auth.js`  
**Created**: 2025-01-12  
**Last Modified**: 2025-01-12

### Purpose

Manages authentication tokens, validates sessions, and handles token extraction from content scripts. Critical component that ensures all API calls have proper authentication headers.

### Public Interface

```javascript
class AuthManager {
  async initialize() → Auth | null
  async processTokens({ accessToken, orgId }) → Auth
  parseJwt(token) → Claims | null
  isExpired() → boolean
  isAuthenticated() → boolean
  getState() → AuthState
  async switchOrg(orgId) → Auth
  async clearAuth() → void
  addListener(callback) → UnsubscribeFunction
}
```

### Dependencies

| Dependency | Type | Purpose |
|------------|------|---------|
| `filevineClient` | Service | Initialize API client with credentials |
| `chrome.storage.session` | API | Store auth tokens (cleared on browser close) |
| `API_BASE_URL` | Constant | Filevine API endpoint |
| `ENDPOINTS.GET_USER_ORGS` | Constant | Get numeric user ID |

### Used By (Dependents)

| Component | How It Uses This Service |
|-----------|--------------------------|
| `BackgroundService` | Checks auth before API calls |
| `FilevineClient` | Receives credentials via setCredentials |
| `PopupController` | Checks auth state for UI |

### Configuration

| Variable | Purpose | Default |
|----------|---------|---------|
| Token expiry buffer | Early expiry check | 5 minutes before actual expiry |

### Error Handling

| Error | Cause | Handling |
|-------|-------|----------|
| Invalid JWT format | Malformed token | Return null, log error |
| GetUserOrgsWithToken fails | API error | Throw error, don't store auth |
| Token expired | Expired token | Clear auth, return expired state |

### Performance Characteristics

| Operation | Typical Latency | Notes |
|-----------|-----------------|-------|
| Initialize from storage | < 10ms | Read from chrome.storage |
| Process tokens | 200-500ms | Includes API call to GetUserOrgsWithToken |
| JWT parsing | < 1ms | In-memory decode |
| Auth check | < 1ms | In-memory check |

### Data Flow

```
Content Script → Extract tokens → processTokens() → GetUserOrgsWithToken API → Store auth → Initialize API client
```

See: `DATA_FLOW.md#authentication-flow` for full diagram

### Testing Notes

- Unit tests: Mock chrome.storage and fetch
- Integration tests: Test with real JWT tokens
- Edge cases: Expired tokens, invalid format, API failures

### Recent Changes

- 2025-01-12: Added `processCookieAuth()` for cookie-based authentication
- 2025-01-12: Added `usingWebApi` flag to auth state
- 2025-01-12: Updated to extract `userId` from `ownerID` in `/api/orgs` response

---

## FilevineClient

**Location**: `src/background/api.js`  
**Created**: 2025-01-12  
**Last Modified**: 2025-01-12

### Purpose

Handles all HTTP communication with Filevine API. Implements rate limiting, retry logic, and ensures all requests include required headers (x-fv-userid, x-fv-orgid, x-fv-sessionid).

### Public Interface

```javascript
class FilevineClient {
  setCredentials({ accessToken, userId, orgId, sessionId }) → void
  isAuthenticated() → boolean
  async request(method, endpoint, { params, data }) → Response
  async getProjects({ limit, offset, search }) → Projects
  async getProject(projectId) → Project
  async getProjectDocuments(projectId, { limit, offset }) → Documents
  async getDocumentDownloadUrl(docId) → DownloadInfo
  async getProjectTypes() → ProjectTypes
}
```

### Dependencies

| Dependency | Type | Purpose |
|------------|------|---------|
| `API_BASE_URL` | Constant | Base API URL |
| `ENDPOINTS` | Constant | API endpoint paths |
| `RATE_LIMITS` | Constant | Rate limiting configuration |
| `fetch` | Native API | HTTP requests |

### Used By (Dependents)

| Component | How It Uses This Service |
|-----------|--------------------------|
| `AuthManager` | Calls GetUserOrgsWithToken |
| `DownloadManager` | Gets presigned S3 URLs |
| `BackgroundService` | All API operations |

### Configuration

| Variable | Purpose | Default |
|----------|---------|---------|
| `RATE_LIMITS.BURST_PER_MINUTE` | Max requests per minute | 100 |
| `RATE_LIMITS.MAX_RETRIES` | Retry attempts | 3 |
| `RATE_LIMITS.RETRY_DELAY_MS` | Retry delay | 1000ms |

### Error Handling

| Error | Cause | Handling |
|-------|-------|----------|
| 429 Rate Limited | Too many requests | Wait for Retry-After, retry |
| API Error | Non-200 response | Throw error with status and message |
| Network error | Fetch fails | Retry with exponential backoff |
| Not authenticated | Missing credentials | Throw error before request |

### Performance Characteristics

| Operation | Typical Latency | Notes |
|-----------|-----------------|-------|
| getProjects | 200-500ms | Depends on result count |
| getProjectDocuments | 300-800ms | Depends on document count |
| getDocumentDownloadUrl | 100-300ms | Presigned URL generation |
| Rate limiting delay | 0-600ms | Based on request spacing |

### Data Flow

```
Request → Check auth → Build headers → Rate limit → Fetch → Retry on error → Return response
```

See: `DATA_FLOW.md#api-request-flow` for details

### Critical Implementation Notes

1. **Base URL**: Must use `https://api.filevineapp.com/fv-app/v2` (NOT api.filevine.io)
2. **User ID**: Must be NUMERIC from GetUserOrgsWithToken (NOT UUID from JWT)
3. **Endpoints**: Use PascalCase (`/Projects` not `/projects`)
4. **Headers**: All three x-fv-* headers required on every call

---

## DownloadManager

**Location**: `src/background/downloads.js`  
**Created**: 2025-01-12  
**Last Modified**: 2025-01-12

### Purpose

Manages file download queue, tracks progress, and stores downloaded files in IndexedDB. Handles concurrent downloads with configurable limits and provides file retrieval for viewers.

### Public Interface

```javascript
class DownloadManager {
  async initializeDb() → IDBDatabase
  async queueDownload({ docId, projectId, filename, mimeType, autoOpen }) → QueueResult
  async getFile(docId) → File | null
  async openFile(docId) → OpenResult
  async deleteFile(docId) → void
  async clearAllFiles() → void
  getState() → DownloadState
  cancelDownload(docId) → CancelResult
}
```

### Dependencies

| Dependency | Type | Purpose |
|------------|------|---------|
| `filevineClient` | Service | Get presigned S3 download URLs (Bearer token auth) |
| `webApiClient` | Service | Get download URLs (cookie-based auth) |
| `authManager` | Service | Check which auth method is in use |
| `IndexedDB` | Native API | File blob storage |
| `chrome.tabs` | API | Open viewer tabs |

### Used By (Dependents)

| Component | How It Uses This Service |
|-----------|--------------------------|
| `BackgroundService` | Download operations |
| `PopupController` | Download queue UI |

### Configuration

| Variable | Purpose | Default |
|----------|---------|---------|
| `maxConcurrent` | Max simultaneous downloads | 3 |
| `dbName` | IndexedDB database name | 'filevine_docs' |

### Error Handling

| Error | Cause | Handling |
|-------|-------|----------|
| Download URL fetch fails | API error | Mark download as error, notify |
| S3 fetch fails | Network/S3 error | Mark download as error, retry not implemented |
| IndexedDB error | Storage error | Log error, mark download as error |
| File not found | docId doesn't exist | Return null |

### Performance Characteristics

| Operation | Typical Latency | Notes |
|-----------|-----------------|-------|
| Queue download | < 10ms | In-memory queue add |
| Get presigned URL | 100-300ms | API call |
| Download file | Varies | Depends on file size and network |
| Store in IndexedDB | 50-200ms | Depends on file size |
| Get file from DB | 10-50ms | IndexedDB read |

### Data Flow

```
Queue → Get presigned URL → Fetch from S3 → Track progress → Store in IndexedDB → Notify completion → Auto-open if requested
```

See: `DATA_FLOW.md#download-flow` for full diagram

### Testing Notes

- Mock IndexedDB for unit tests
- Test concurrent download limits
- Test large file handling
- Test storage cleanup

### Recent Changes

- 2025-01-12: Updated to use web API client when using cookie-based auth
- 2025-01-12: Added support for multiple download endpoint patterns

---

## ContentScript

**Location**: `src/content/index.js`  
**Created**: 2025-01-12  
**Last Modified**: 2025-01-12

### Purpose

Entry point for content scripts injected into Filevine pages. Coordinates token detection and extraction, then sends tokens to background service worker.

### Public Interface

```javascript
// No public exports - runs as content script

async function initialize() → void
function isFilevineUrl(url) → boolean
async function sendTokensToBackground(tokens) → void
function showConnectionStatus(status, message) → void
```

### Dependencies

| Dependency | Type | Purpose |
|------------|------|---------|
| `TokenDetector` | Service | Detect page changes and session events |
| `TokenExtractor` | Service | Extract tokens from page context |
| `chrome.runtime` | API | Send messages to background |

### Used By (Dependents)

| Component | How It Uses This Service |
|-----------|--------------------------|
| Chrome Extension Runtime | Injected into Filevine pages |

### Configuration

| Variable | Purpose | Default |
|----------|---------|---------|
| N/A | Uses constants from `lib/constants.js` | — |

### Error Handling

| Error | Cause | Handling |
|-------|-------|----------|
| Not Filevine URL | Wrong page | Skip initialization |
| Token send fails | Background unavailable | Log error |

### Performance Characteristics

| Operation | Typical Latency | Notes |
|-----------|-----------------|-------|
| Initialize | < 50ms | Setup interception and detection |
| Extract tokens | 10-100ms | Depends on extraction method |
| Send to background | < 10ms | Message passing |

### Data Flow

```
Page Load → Check URL → Setup interception → Extract tokens → Send to background → Listen for changes
```

See: `DATA_FLOW.md#content-script-flow` for details

---

## TokenDetector

**Location**: `src/content/detector.js`  
**Created**: 2025-01-12  
**Last Modified**: 2025-01-12

### Purpose

Watches for page changes, DOM mutations, and storage events that might indicate authentication state changes in the Filevine SPA.

### Public Interface

```javascript
class TokenDetector {
  watchForChanges(callback) → void
  isLoggedIn() → boolean
  getPageContext() → PageContext
  disconnect() → void
}
```

### Dependencies

| Dependency | Type | Purpose |
|------------|------|---------|
| `window.history` | Native API | Detect SPA navigation |
| `MutationObserver` | Native API | Watch DOM changes |
| `window.storage` | Native API | Listen for storage events |

### Used By (Dependents)

| Component | How It Uses This Service |
|-----------|--------------------------|
| `ContentScript` | Detects when to re-extract tokens |

### Configuration

| Variable | Purpose | Default |
|----------|---------|---------|
| URL change debounce | Debounce URL change callbacks | 500ms |
| DOM change debounce | Debounce DOM change callbacks | 1000ms |

### Error Handling

| Error | Cause | Handling |
|-------|-------|----------|
| Observer errors | DOM mutation errors | Ignore, continue watching |

### Performance Characteristics

| Operation | Typical Latency | Notes |
|-----------|-----------------|-------|
| Setup watchers | < 10ms | Register observers |
| URL change detection | < 1ms | Override history methods |
| DOM mutation check | < 5ms | Pattern matching on mutations |

### Data Flow

```
Page Change → Detect (URL/DOM/Storage) → Debounce → Callback → Re-extract tokens
```

---

## TokenExtractor

**Location**: `src/content/extractor.js`  
**Created**: 2025-01-12  
**Last Modified**: 2025-01-12

### Purpose

Extracts authentication tokens from Filevine page context using multiple strategies: network interception, localStorage, sessionStorage, page state, and OIDC patterns.

### Public Interface

```javascript
class TokenExtractor {
  setupInterception() → void
  async extractTokens() → Tokens | null
  extractFromStorage() → Tokens | null
  extractFromPageState() → Tokens | null
  extractFromOidc() → Tokens | null
  extractOrgIdFromPage() → string | null
  onTokenReceived(callback) → UnsubscribeFunction
}
```

### Dependencies

| Dependency | Type | Purpose |
|------------|------|---------|
| `window.fetch` | Native API | Intercept network requests |
| `XMLHttpRequest` | Native API | Intercept XHR requests |
| `localStorage` | Native API | Read stored tokens |
| `sessionStorage` | Native API | Read stored tokens |
| `window.postMessage` | Native API | Receive intercepted tokens |

### Used By (Dependents)

| Component | How It Uses This Service |
|-----------|--------------------------|
| `ContentScript` | Extracts tokens for background |

### Configuration

| Variable | Purpose | Default |
|----------|---------|---------|
| Token key patterns | Storage keys to search | ['fv_access_token', 'access_token', ...] |

### Error Handling

| Error | Cause | Handling |
|-------|-------|----------|
| Storage access denied | CORS/security | Try next method |
| JSON parse error | Invalid storage value | Try next method |
| Interception fails | Script injection blocked | Fall back to storage methods |

### Performance Characteristics

| Operation | Typical Latency | Notes |
|-----------|-----------------|-------|
| Setup interception | < 20ms | Inject script, add listeners |
| Extract from storage | 10-50ms | Search multiple keys |
| Extract from page state | 5-20ms | Check window properties |
| Network interception | Real-time | Captures tokens as they're received |

### Data Flow

```
Setup → Intercept network → Try storage → Try page state → Try OIDC → Return tokens
```

### Critical Implementation Notes

1. **Priority Order**: Network interception > localStorage > sessionStorage > page state > OIDC
2. **Network Interception**: Most reliable but requires script injection
3. **Storage Methods**: May fail due to CORS or security policies
4. **JWT Detection**: Checks for 3-part dot-separated format

---

## PopupController

**Location**: `src/popup/popup.js`  
**Created**: 2025-01-12  
**Last Modified**: 2025-01-12

### Purpose

Manages the extension popup UI including project browsing, file selection, download management, and connection status display.

### Public Interface

```javascript
class PopupController {
  async init() → void
  async checkAuthState() → void
  async loadProjects(search) → void
  async selectProject(projectId) → void
  async loadDocuments(projectId) → void
  async downloadDocument(docId) → void
  async switchOrg(orgId) → void
  toggleDownloadsPanel() → void
  async clearDownloads() → void
}
```

### Dependencies

| Dependency | Type | Purpose |
|------------|------|---------|
| `chrome.runtime` | API | Send messages to background |
| `DOM` | Native API | UI manipulation |
| `MESSAGE_TYPES` | Constant | Message type constants |
| `CONNECTION_STATE` | Constant | Connection state constants |

### Used By (Dependents)

| Component | How It Uses This Service |
|-----------|--------------------------|
| Popup HTML | Initialized on DOMContentLoaded |

### Configuration

| Variable | Purpose | Default |
|----------|---------|---------|
| Search debounce | Debounce project search | 300ms |
| Projects limit | Max projects per request | 50 |
| Documents limit | Max documents per request | 100 |

### Error Handling

| Error | Cause | Handling |
|-------|-------|----------|
| Auth check fails | Background unavailable | Show error state |
| Load projects fails | API error | Show error message in UI |
| Download fails | API/storage error | Show alert to user |

### Performance Characteristics

| Operation | Typical Latency | Notes |
|-----------|-----------------|-------|
| Initialize | < 50ms | Cache DOM elements, attach listeners |
| Check auth | 10-50ms | Message to background |
| Load projects | 200-500ms | Depends on API response |
| Render list | 10-50ms | Depends on item count |

### Data Flow

```
Init → Check auth → Load projects → User selects → Load documents → Download → Update UI
```

See: `DATA_FLOW.md#popup-flow` for details

---

## ViewerRegistry

**Location**: `src/viewers/registry.js`  
**Created**: 2025-01-12  
**Last Modified**: 2025-01-12

### Purpose

Manages file viewer plugins and routes files to appropriate viewers based on file extension and MIME type.

### Public Interface

```javascript
class ViewerRegistry {
  register(viewer) → void
  getViewerForFile(metadata) → Viewer | null
  getAll() → Viewer[]
  isSupported(metadata) → boolean
}
```

### Dependencies

| Dependency | Type | Purpose |
|------------|------|---------|
| `VIEWER_TYPES` | Constant | Built-in viewer definitions |

### Used By (Dependents)

| Component | How It Uses This Service |
|-----------|--------------------------|
| `DownloadManager` | Gets viewer URL for file |
| Future: Viewer plugins | Register custom viewers |

### Configuration

| Variable | Purpose | Default |
|----------|---------|---------|
| N/A | Viewers registered at module load | — |

### Error Handling

| Error | Cause | Handling |
|-------|-------|----------|
| No viewer found | Unsupported file type | Return null, use default blob URL |

### Performance Characteristics

| Operation | Typical Latency | Notes |
|-----------|-----------------|-------|
| Register viewer | < 1ms | Map insertion |
| Get viewer | < 1ms | Map lookup with pattern matching |
| Check support | < 1ms | Same as get viewer |

### Data Flow

```
File metadata → Check extensions → Check MIME types → Check custom handler → Return viewer
```

---

## Constants

**Location**: `src/lib/constants.js`  
**Created**: 2025-01-12  
**Last Modified**: 2025-01-12

### Purpose

Centralized configuration for API endpoints, message types, rate limits, storage keys, and other constants used throughout the extension.

### Public Interface

```javascript
export const API_BASE_URL = '...'
export const ENDPOINTS = { ... }
export const MESSAGE_TYPES = { ... }
export const STORAGE_KEYS = { ... }
export const RATE_LIMITS = { ... }
export const VIEWER_TYPES = { ... }
export const CONNECTION_STATE = { ... }
```

### Dependencies

None (pure constants)

### Used By (Dependents)

| Component | How It Uses This Service |
|-----------|--------------------------|
| All services | Import constants as needed |

### Configuration

| Variable | Purpose | Default |
|----------|---------|---------|
| `API_BASE_URL` | Filevine API base URL | `https://api.filevineapp.com/fv-app/v2` |
| `RATE_LIMITS.BURST_PER_MINUTE` | Rate limit | 100 |
| `RATE_LIMITS.MAX_RETRIES` | Retry attempts | 3 |

### Critical Implementation Notes

1. **API_BASE_URL**: Must be `api.filevineapp.com` (NOT `api.filevine.io`)
2. **ENDPOINTS**: Use PascalCase (e.g., `/Projects` not `/projects`)
3. **MESSAGE_TYPES**: Used for type-safe message passing

---

## Adding a New Service

1. Create file in appropriate `src/` subdirectory
2. Add entry to Quick Reference Index above
3. Add full documentation section using template
4. Update `ARCHITECTURE.md` if it's a major component
5. Update `DATA_FLOW.md` if it changes data flows
6. Add to `DECISIONS.md` if architectural decisions were made
