experiments in a post-browser web

feat(extension): add server and key commands for sync config

+105 -4
+48 -1
backend/extension/background.js
··· 5 5 */ 6 6 7 7 import { openDatabase } from './datastore.js'; 8 - import { ensureDefaultProfile, getCurrentProfile, getSyncConfig, updateProfileEnvironment } from './profiles.js'; 8 + import { ensureDefaultProfile, getCurrentProfile, getSyncConfig, updateProfileEnvironment, enableSync } from './profiles.js'; 9 + import { setConfig as setEngineConfig } from './engine.js'; 9 10 import { syncAll, getSyncConfig as getFullSyncConfig, getSyncStatus } from './sync.js'; 10 11 import { DATASTORE_VERSION, PROTOCOL_VERSION } from './version.js'; 11 12 import { getEnvironment } from './environment.js'; ··· 151 152 152 153 if (message.type === 'get-history-stats') { 153 154 handleGetHistoryStats().then(sendResponse); 155 + return true; 156 + } 157 + 158 + if (message.type === 'set-server') { 159 + handleSetServer(message.data).then(sendResponse); 160 + return true; 161 + } 162 + 163 + if (message.type === 'set-api-key') { 164 + handleSetApiKey(message.data).then(sendResponse); 154 165 return true; 155 166 } 156 167 }); ··· 381 392 return { success: false, error: error.message }; 382 393 } 383 394 } 395 + 396 + async function handleSetServer(data) { 397 + const { serverUrl } = data; 398 + 399 + try { 400 + await setEngineConfig({ serverUrl }); 401 + return { success: true }; 402 + } catch (error) { 403 + console.error('[peek:bg] Set server error:', error); 404 + return { success: false, error: error.message }; 405 + } 406 + } 407 + 408 + async function handleSetApiKey(data) { 409 + const { apiKey } = data; 410 + 411 + if (!apiKey) { 412 + return { success: false, error: 'API key is required' }; 413 + } 414 + 415 + try { 416 + const profileResult = await getCurrentProfile(); 417 + if (!profileResult.success || !profileResult.data) { 418 + return { success: false, error: 'No active profile' }; 419 + } 420 + 421 + const profile = profileResult.data; 422 + // Enable sync with the API key (serverProfileId defaults to 'default') 423 + await enableSync(profile.id, apiKey, 'default'); 424 + 425 + return { success: true }; 426 + } catch (error) { 427 + console.error('[peek:bg] Set API key error:', error); 428 + return { success: false, error: error.message }; 429 + } 430 + }
+1 -1
backend/extension/popup.html
··· 202 202 <div class="command-row"> 203 203 <div class="command-display" id="command-display"> 204 204 <input id="command-input" type="text" autofocus spellcheck="false" /> 205 - <div id="command-text" class="placeholder">tag, note, or search...</div> 205 + <div id="command-text" class="placeholder">tag, note, search, server, key...</div> 206 206 </div> 207 207 <div class="feedback" id="feedback"> 208 208 <span class="feedback-icon" id="feedback-icon"></span>
+56 -2
backend/extension/popup.js
··· 4 4 * Shows success/error feedback before closing 5 5 */ 6 6 7 - const COMMANDS = ['tag', 'note', 'search']; 7 + const COMMANDS = ['tag', 'note', 'search', 'server', 'key']; 8 8 9 9 let state = { 10 10 typed: '', ··· 75 75 76 76 if (!state.typed) { 77 77 commandText.classList.add('placeholder'); 78 - commandText.textContent = 'tag, note, or search...'; 78 + commandText.textContent = 'tag, note, search, server, key...'; 79 79 return; 80 80 } 81 81 ··· 113 113 saveNote(args); 114 114 } else if (cmd === 'search' && args) { 115 115 performSearch(args); 116 + } else if (cmd === 'server' && args) { 117 + setServer(args); 118 + } else if (cmd === 'key' && args) { 119 + setApiKey(args); 116 120 } else if (state.match && !args) { 117 121 commandInput.value = state.match + ' '; 118 122 state.typed = commandInput.value; ··· 177 181 }).then(response => { 178 182 console.log('Search results:', response); 179 183 }).catch(err => console.error('Search failed:', err)); 184 + } 185 + 186 + async function setServer(url) { 187 + // Normalize URL 188 + let serverUrl = url.trim(); 189 + if (serverUrl && !serverUrl.startsWith('http')) { 190 + serverUrl = 'https://' + serverUrl; 191 + } 192 + 193 + try { 194 + const response = await chrome.runtime.sendMessage({ 195 + type: 'set-server', 196 + data: { serverUrl } 197 + }); 198 + 199 + if (response?.success) { 200 + showFeedback('success', 'Server set'); 201 + setTimeout(() => { 202 + loadSyncStatus(); 203 + window.close(); 204 + }, 600); 205 + } else { 206 + showFeedback('error', response?.error || 'Failed to set server'); 207 + } 208 + } catch (err) { 209 + console.error('Failed to set server:', err); 210 + showFeedback('error', 'Failed to set server'); 211 + } 212 + } 213 + 214 + async function setApiKey(apiKey) { 215 + try { 216 + const response = await chrome.runtime.sendMessage({ 217 + type: 'set-api-key', 218 + data: { apiKey: apiKey.trim() } 219 + }); 220 + 221 + if (response?.success) { 222 + showFeedback('success', 'API key set'); 223 + setTimeout(() => { 224 + loadSyncStatus(); 225 + window.close(); 226 + }, 600); 227 + } else { 228 + showFeedback('error', response?.error || 'Failed to set API key'); 229 + } 230 + } catch (err) { 231 + console.error('Failed to set API key:', err); 232 + showFeedback('error', 'Failed to set API key'); 233 + } 180 234 } 181 235 182 236 // ==================== Sync Status ====================