experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(sync): use per-profile sync configuration

- Read sync config from active profile in profiles.db
- Include server profile slug in API requests
- Update lastSyncTime in profile record
- Remove dependency on global extension_settings sync config
- Each profile can sync to different server profile

+79 -39
+79 -39
backend/electron/sync.ts
··· 28 28 tagItem, 29 29 } from './datastore.js'; 30 30 import { DEBUG } from './config.js'; 31 + import { 32 + getActiveProfile, 33 + getSyncConfig as getProfileSyncConfig, 34 + updateLastSyncTime, 35 + } from './profiles.js'; 31 36 32 37 // ==================== Settings Storage ==================== 33 38 34 - const SYNC_SETTINGS_KEY = 'sync'; 39 + // Note: Sync configuration is now stored per-profile in profiles.db 40 + // Legacy extension_settings storage is deprecated 35 41 36 42 /** 37 - * Get sync configuration from settings 43 + * Get sync configuration for the active profile 38 44 */ 39 45 export function getSyncConfig(): SyncConfig { 40 - const db = getDb(); 41 - const getKey = (key: string): string | null => { 42 - const row = db.prepare( 43 - 'SELECT value FROM extension_settings WHERE extensionId = ? AND key = ?' 44 - ).get(SYNC_SETTINGS_KEY, key) as { value: string } | undefined; 45 - if (!row?.value) return null; 46 - try { 47 - return JSON.parse(row.value); 48 - } catch { 49 - return row.value; 46 + try { 47 + const activeProfile = getActiveProfile(); 48 + const profileSyncConfig = getProfileSyncConfig(activeProfile.id); 49 + 50 + if (!profileSyncConfig) { 51 + // Sync not configured for this profile 52 + return { 53 + serverUrl: '', 54 + apiKey: '', 55 + lastSyncTime: 0, 56 + autoSync: false, 57 + }; 50 58 } 51 - }; 59 + 60 + // Construct full sync config from profile data 61 + // Note: serverUrl is not stored per-profile, using default for now 62 + // In the future, we could make this configurable per-profile 63 + const serverUrl = process.env.SYNC_SERVER_URL || 'https://peek-node.up.railway.app'; 52 64 53 - return { 54 - serverUrl: getKey('serverUrl') || '', 55 - apiKey: getKey('apiKey') || '', 56 - lastSyncTime: parseInt(getKey('lastSyncTime') || '0', 10) || 0, 57 - autoSync: getKey('autoSync') === 'true', 58 - }; 65 + return { 66 + serverUrl, 67 + apiKey: profileSyncConfig.apiKey, 68 + lastSyncTime: activeProfile.lastSyncAt || 0, 69 + autoSync: false, // TODO: Add autoSync to profile schema 70 + }; 71 + } catch (error) { 72 + DEBUG && console.error('[sync] Failed to get sync config:', error); 73 + return { 74 + serverUrl: '', 75 + apiKey: '', 76 + lastSyncTime: 0, 77 + autoSync: false, 78 + }; 79 + } 59 80 } 60 81 61 82 /** 62 - * Save sync configuration to settings 83 + * Save sync configuration to active profile 84 + * Note: This is a compatibility wrapper. Use profile functions directly for new code. 63 85 */ 64 86 export function setSyncConfig(config: Partial<SyncConfig>): void { 65 - const db = getDb(); 66 - const timestamp = Date.now(); 87 + try { 88 + const activeProfile = getActiveProfile(); 67 89 68 - const setKey = (key: string, value: string | number | boolean): void => { 69 - const jsonValue = JSON.stringify(value); 70 - db.prepare(` 71 - INSERT OR REPLACE INTO extension_settings (id, extensionId, key, value, updatedAt) 72 - VALUES (?, ?, ?, ?, ?) 73 - `).run(`${SYNC_SETTINGS_KEY}_${key}`, SYNC_SETTINGS_KEY, key, jsonValue, timestamp); 74 - }; 90 + // Update lastSyncTime if provided 91 + if (config.lastSyncTime !== undefined) { 92 + updateLastSyncTime(activeProfile.id, config.lastSyncTime); 93 + } 75 94 76 - if (config.serverUrl !== undefined) setKey('serverUrl', config.serverUrl); 77 - if (config.apiKey !== undefined) setKey('apiKey', config.apiKey); 78 - if (config.lastSyncTime !== undefined) setKey('lastSyncTime', config.lastSyncTime); 79 - if (config.autoSync !== undefined) setKey('autoSync', config.autoSync); 95 + // Note: serverUrl and apiKey are now managed through profile sync config 96 + // Use enableSync() from profiles.ts to set apiKey 97 + // serverUrl is environment-based, not per-profile 98 + } catch (error) { 99 + DEBUG && console.error('[sync] Failed to set sync config:', error); 100 + } 80 101 } 81 102 82 103 // ==================== Timestamp Conversion ==================== ··· 151 172 ): Promise<PullResult> { 152 173 DEBUG && console.log('[sync] Pulling from server...', since ? `since ${toISOString(since)}` : 'full'); 153 174 154 - // Fetch items from server 175 + // Get active profile to determine which server profile to sync with 176 + const activeProfile = getActiveProfile(); 177 + const profileSyncConfig = getProfileSyncConfig(activeProfile.id); 178 + 179 + if (!profileSyncConfig) { 180 + throw new Error('Sync not configured for active profile'); 181 + } 182 + 183 + // Fetch items from server with profile parameter 155 184 let path = '/items'; 156 185 if (since && since > 0) { 157 186 path = `/items/since/${toISOString(since)}`; 158 187 } 188 + path += `?profile=${encodeURIComponent(profileSyncConfig.serverProfileSlug)}`; 159 189 160 190 const response = await serverFetch<{ items: ServerItem[] }>(serverUrl, apiKey, path); 161 191 const serverItems = response.items; ··· 327 357 ): Promise<void> { 328 358 const db = getDb(); 329 359 360 + // Get active profile to determine which server profile to sync with 361 + const activeProfile = getActiveProfile(); 362 + const profileSyncConfig = getProfileSyncConfig(activeProfile.id); 363 + 364 + if (!profileSyncConfig) { 365 + throw new Error('Sync not configured for active profile'); 366 + } 367 + 330 368 // Get tags for this item 331 369 const tags = getItemTags(item.id); 332 370 const tagNames = tags.map((t: Tag) => t.name); ··· 359 397 body.metadata = metadata; 360 398 } 361 399 362 - // POST to server 400 + // POST to server with profile parameter 401 + const path = `/items?profile=${encodeURIComponent(profileSyncConfig.serverProfileSlug)}`; 363 402 const response = await serverFetch<{ id: string; created: boolean }>( 364 403 serverUrl, 365 404 apiKey, 366 - '/items', 405 + path, 367 406 { method: 'POST', body } 368 407 ); 369 408 ··· 382 421 * 383 422 * 1. Pull from server (including updates since last sync) 384 423 * 2. Push local changes to server 385 - * 3. Update lastSyncTime 424 + * 3. Update lastSyncTime in profile 386 425 */ 387 426 export async function syncAll(serverUrl: string, apiKey: string): Promise<SyncResult> { 388 427 const config = getSyncConfig(); ··· 404 443 const pushResult = await pushToServer(serverUrl, apiKey, config.lastSyncTime); 405 444 pushed = pushResult.pushed; 406 445 407 - // Update last sync time 408 - setSyncConfig({ lastSyncTime: startTime }); 446 + // Update last sync time in active profile 447 + const activeProfile = getActiveProfile(); 448 + updateLastSyncTime(activeProfile.id, startTime); 409 449 410 450 DEBUG && console.log(`[sync] Sync complete: ${pulled} pulled, ${pushed} pushed, ${conflicts} conflicts`); 411 451