|
| 1 | +# Design Document |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This design outlines the migration from direct REST API calls using superagent to the official Microsoft Graph SDK (@microsoft/microsoft-graph-client) for OneNote operations. The migration will maintain all existing functionality while leveraging the SDK's built-in features including automatic retries, better error handling, and improved authentication integration. |
| 6 | + |
| 7 | +The current system uses direct HTTP calls to Microsoft Graph endpoints for OneNote operations including retrieving sections, pages, page content, and image downloads. The new implementation will use the Graph SDK's fluent API while preserving the exact same behavior and data flow. |
| 8 | + |
| 9 | +## Architecture |
| 10 | + |
| 11 | +### Current Architecture |
| 12 | +``` |
| 13 | +MSAL Authentication → superagent HTTP calls → OneNote REST API |
| 14 | +``` |
| 15 | + |
| 16 | +### New Architecture |
| 17 | +``` |
| 18 | +MSAL Authentication → Graph SDK Client → OneNote REST API |
| 19 | +``` |
| 20 | + |
| 21 | +### Authentication Integration |
| 22 | + |
| 23 | +The Graph SDK will integrate with the existing MSAL authentication system through a custom authentication provider that bridges the current token management with the SDK's authentication interface. |
| 24 | + |
| 25 | +```javascript |
| 26 | +class MSALAuthenticationProvider { |
| 27 | + async getAccessToken() { |
| 28 | + const onenoteData = localStorage.getItem('onenote'); |
| 29 | + if (!onenoteData || !onenoteData.accessToken) { |
| 30 | + throw new Error('No access token available'); |
| 31 | + } |
| 32 | + return onenoteData.accessToken; |
| 33 | + } |
| 34 | +} |
| 35 | +``` |
| 36 | + |
| 37 | +## Components and Interfaces |
| 38 | + |
| 39 | +### 1. Authentication Provider Bridge |
| 40 | + |
| 41 | +**Purpose**: Bridge existing MSAL token management with Graph SDK authentication requirements |
| 42 | + |
| 43 | +**Implementation**: |
| 44 | +- Implements the Graph SDK's `AuthenticationProvider` interface |
| 45 | +- Retrieves tokens from existing localStorage cache |
| 46 | +- Handles token expiration by delegating to existing refresh mechanisms |
| 47 | + |
| 48 | +### 2. Graph Client Factory |
| 49 | + |
| 50 | +**Purpose**: Create and configure the Microsoft Graph client instance |
| 51 | + |
| 52 | +**Implementation**: |
| 53 | +```javascript |
| 54 | +function createGraphClient() { |
| 55 | + const authProvider = new MSALAuthenticationProvider(); |
| 56 | + |
| 57 | + return Client.initWithMiddleware({ |
| 58 | + authProvider, |
| 59 | + defaultVersion: 'v1.0', |
| 60 | + debugLogging: process.env.NODE_ENV === 'development' |
| 61 | + }); |
| 62 | +} |
| 63 | +``` |
| 64 | + |
| 65 | +### 3. OneNote Service Layer |
| 66 | + |
| 67 | +**Purpose**: Encapsulate all OneNote operations using the Graph SDK |
| 68 | + |
| 69 | +**Key Methods**: |
| 70 | +- `getSections(notebookName, sectionName)` - Find section by notebook and name |
| 71 | +- `getPageCount(sectionId)` - Get total page count for a section |
| 72 | +- `getPages(sectionId, options)` - Get pages with pagination |
| 73 | +- `getPagePreview(pageId)` - Get page preview content |
| 74 | +- `getPageContent(pageId)` - Get full page HTML content |
| 75 | +- `downloadImage(imageUrl)` - Download images from Graph endpoints |
| 76 | + |
| 77 | +### 4. Migration Wrapper |
| 78 | + |
| 79 | +**Purpose**: Provide backward compatibility during migration |
| 80 | + |
| 81 | +**Implementation**: Maintains the same function signatures as existing code while internally using the Graph SDK. |
| 82 | + |
| 83 | +## Data Models |
| 84 | + |
| 85 | +### Section Model |
| 86 | +```javascript |
| 87 | +{ |
| 88 | + id: string, |
| 89 | + displayName: string, |
| 90 | + pagesUrl: string, |
| 91 | + parentNotebook: { |
| 92 | + displayName: string, |
| 93 | + sectionsUrl: string |
| 94 | + } |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +### Page Model |
| 99 | +```javascript |
| 100 | +{ |
| 101 | + id: string, |
| 102 | + title: string, |
| 103 | + self: string, |
| 104 | + links: { |
| 105 | + oneNoteClientUrl: { href: string }, |
| 106 | + oneNoteWebUrl: { href: string } |
| 107 | + } |
| 108 | +} |
| 109 | +``` |
| 110 | + |
| 111 | +### Page Preview Model |
| 112 | +```javascript |
| 113 | +{ |
| 114 | + previewText: string, |
| 115 | + links: { |
| 116 | + previewImageUrl?: { href: string } |
| 117 | + } |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +## Error Handling |
| 122 | + |
| 123 | +### SDK Error Mapping |
| 124 | + |
| 125 | +The Graph SDK provides enhanced error handling that will be mapped to maintain compatibility with existing error handling patterns: |
| 126 | + |
| 127 | +```javascript |
| 128 | +function mapGraphError(error) { |
| 129 | + // Map Graph SDK errors to existing error format |
| 130 | + if (error.code === 'InvalidAuthenticationToken') { |
| 131 | + throw new Error('Token refresh failed - device login required'); |
| 132 | + } |
| 133 | + |
| 134 | + if (error.code === 'TooManyRequests') { |
| 135 | + // SDK handles retries automatically, but we can add custom logic |
| 136 | + throw new Error('Rate limit exceeded'); |
| 137 | + } |
| 138 | + |
| 139 | + // Preserve original error structure for unknown errors |
| 140 | + throw error; |
| 141 | +} |
| 142 | +``` |
| 143 | + |
| 144 | +### Timeout Configuration |
| 145 | + |
| 146 | +Configure SDK timeouts to match existing behavior: |
| 147 | + |
| 148 | +```javascript |
| 149 | +const client = Client.initWithMiddleware({ |
| 150 | + authProvider, |
| 151 | + middleware: [ |
| 152 | + new TimeoutHandler({ |
| 153 | + timeout: 120000 // 120 seconds to match existing TIMEOUTS.response |
| 154 | + }) |
| 155 | + ] |
| 156 | +}); |
| 157 | +``` |
| 158 | + |
| 159 | +## Testing Strategy |
| 160 | + |
| 161 | +### Unit Tests |
| 162 | + |
| 163 | +1. **Authentication Provider Tests** |
| 164 | + - Test token retrieval from localStorage |
| 165 | + - Test error handling when tokens are missing/expired |
| 166 | + - Test integration with existing MSAL flow |
| 167 | + |
| 168 | +2. **OneNote Service Tests** |
| 169 | + - Mock Graph SDK client responses |
| 170 | + - Test all OneNote operations (sections, pages, content, images) |
| 171 | + - Verify data transformation matches existing format |
| 172 | + - Test error scenarios and mapping |
| 173 | + |
| 174 | +3. **Integration Tests** |
| 175 | + - Test complete flow from authentication to data retrieval |
| 176 | + - Verify backward compatibility with existing function signatures |
| 177 | + - Test timeout and retry behavior |
| 178 | + |
| 179 | +### Migration Testing |
| 180 | + |
| 181 | +1. **Parallel Testing** |
| 182 | + - Run both old and new implementations side-by-side |
| 183 | + - Compare outputs to ensure identical behavior |
| 184 | + - Measure performance differences |
| 185 | + |
| 186 | +2. **Feature Parity Tests** |
| 187 | + - Random note selection produces same distribution |
| 188 | + - Sequential note tracking works identically |
| 189 | + - Image download maintains size limits and streaming |
| 190 | + - Recent note filtering behaves the same |
| 191 | + |
| 192 | +## Implementation Plan |
| 193 | + |
| 194 | +### Phase 1: Foundation |
| 195 | +- Install Graph SDK and fetch polyfill dependencies |
| 196 | +- Create authentication provider bridge |
| 197 | +- Set up Graph client factory with proper configuration |
| 198 | + |
| 199 | +### Phase 2: Core Services |
| 200 | +- Implement OneNote service layer using Graph SDK |
| 201 | +- Create migration wrapper maintaining existing interfaces |
| 202 | +- Add comprehensive error handling and mapping |
| 203 | + |
| 204 | +### Phase 3: Feature Migration |
| 205 | +- Replace section lookup functionality |
| 206 | +- Replace page counting and retrieval |
| 207 | +- Replace page preview and content operations |
| 208 | +- Replace image download functionality |
| 209 | + |
| 210 | +### Phase 4: Testing & Validation |
| 211 | +- Implement comprehensive test suite |
| 212 | +- Run parallel testing to verify behavior |
| 213 | +- Performance testing and optimization |
| 214 | +- Remove superagent dependency if no longer needed |
| 215 | + |
| 216 | +## Configuration Changes |
| 217 | + |
| 218 | +### Package.json Updates |
| 219 | +```json |
| 220 | +{ |
| 221 | + "dependencies": { |
| 222 | + "@microsoft/microsoft-graph-client": "^3.0.7", |
| 223 | + "isomorphic-fetch": "^3.0.0" |
| 224 | + } |
| 225 | +} |
| 226 | +``` |
| 227 | + |
| 228 | +### Environment Variables |
| 229 | +No new environment variables required - existing MS Graph configuration will be reused. |
| 230 | + |
| 231 | +## Backward Compatibility |
| 232 | + |
| 233 | +The migration maintains 100% backward compatibility by: |
| 234 | + |
| 235 | +1. **Preserving Function Signatures**: All existing function calls work unchanged |
| 236 | +2. **Maintaining Data Structures**: Response objects have identical structure |
| 237 | +3. **Keeping Error Patterns**: Error messages and types remain consistent |
| 238 | +4. **Preserving Behavior**: Random selection, sequential tracking, and caching work identically |
| 239 | + |
| 240 | +## Performance Considerations |
| 241 | + |
| 242 | +### Expected Improvements |
| 243 | +- **Automatic Retries**: SDK handles transient failures automatically |
| 244 | +- **Connection Pooling**: Better HTTP connection management |
| 245 | +- **Request Optimization**: SDK optimizes Graph API calls |
| 246 | + |
| 247 | +### Monitoring Points |
| 248 | +- Response times for OneNote operations |
| 249 | +- Memory usage during image downloads |
| 250 | +- Error rates and retry patterns |
| 251 | +- Token refresh frequency |
| 252 | + |
| 253 | +## Security Considerations |
| 254 | + |
| 255 | +### Token Handling |
| 256 | +- Graph SDK never stores tokens - relies on our authentication provider |
| 257 | +- Existing MSAL security model remains unchanged |
| 258 | +- Token refresh logic preserved exactly |
| 259 | + |
| 260 | +### Image Downloads |
| 261 | +- Maintain existing 3MB size limits |
| 262 | +- Preserve streaming download behavior for large files |
| 263 | +- Keep existing timeout protections |
0 commit comments