experiments in a post-browser web
10
fork

Configure Feed

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

refactor(main): delete dead external-extension startup loops + createExtensionWindow

+4 -135
+3 -132
backend/electron/main.ts
··· 17 17 import { initPage } from './page-glue.js'; 18 18 import { initCore, getCoreBackgroundWindow } from './core-glue.js'; 19 19 import { initTestFixture } from './test-fixture-glue.js'; 20 - import { discoverExtensions, loadExtensionManifest, isBuiltinExtensionEnabled, getExternalExtensions, type ExtensionManifest, type ManifestCommand, type ManifestShortcut } from './extensions.js'; 20 + import { discoverExtensions, loadExtensionManifest, isBuiltinExtensionEnabled, type ExtensionManifest, type ManifestCommand, type ManifestShortcut } from './extensions.js'; 21 21 import { initializeFeatures, type FeatureStartupResult } from './feature-startup.js'; 22 22 import { ensureTileIpcHandlers } from './tile-compat.js'; 23 23 import { getLoadedTileIds, getTileManifest, getAllTileWindows, unloadAllTiles, relaunchTile } from './tile-launcher.js'; ··· 1106 1106 } 1107 1107 1108 1108 /** 1109 - * Create an extension window 1110 - * 1111 - * Legacy v1 path — creates a BrowserWindow for a registered extension with the 1112 - * v1 `preload.js`. Still used by `reloadExtension()` (features-manager UI reload 1113 - * button via `api.extensions.reload()`) and `loadDevExtension()` (CLI 1114 - * `--load-extension` flag). The two startup-path callers below 1115 - * (`externalBuiltinIds` + `enabledExternalExts` loops in `loadExtensions()`) 1116 - * are empty in practice — all features in `features/` are v2 and get loaded 1117 - * via `loadV2Tile()`; the `extensions` DB table is superseded by the v2 1118 - * feature registry. See Phase 2.5 #3 audit in AGENT_REPORT.md and 1119 - * `docs/v1-removal-plan.md`. 1120 - * 1121 - * Full removal requires a `relaunchTile(tileId)` helper in tile-launcher.ts — 1122 - * tracked as Phase 2.5 #3b. 1123 - */ 1124 - async function createExtensionWindow(extId: string): Promise<BrowserWindow | null> { 1125 - if (extensionWindows.has(extId)) { 1126 - DEBUG && console.log(`[ext:win] Extension ${extId} already has a window`); 1127 - return extensionWindows.get(extId)!.win; 1128 - } 1129 - 1130 - const extPath = getExtensionPath(extId); 1131 - if (!extPath) { 1132 - console.error(`[ext:win] Extension path not found: ${extId}`); 1133 - return null; 1134 - } 1135 - 1136 - const manifest = loadExtensionManifest(extPath); 1137 - 1138 - DEBUG && console.log(`[ext:win] Creating window for extension: ${extId}`); 1139 - 1140 - // Use profile-specific session for isolation 1141 - const profileSession = getProfileSession(); 1142 - 1143 - const win = new BrowserWindow({ 1144 - show: false, 1145 - backgroundColor: getSystemThemeBackgroundColor(), 1146 - webPreferences: { 1147 - preload: config.preloadPath, 1148 - session: profileSession, 1149 - // Disable same-origin policy so extensions can fetch() cross-origin. 1150 - // These windows only load trusted extension code (peek://ext/{id}/...) — 1151 - // never user-provided URLs. corsEnabled:false on the scheme isn't sufficient 1152 - // for peek://ext origins (only peek://app gets implicit cross-origin access). 1153 - webSecurity: false, 1154 - } 1155 - }); 1156 - 1157 - // Forward console logs 1158 - win.webContents.on('console-message', (event) => { 1159 - DEBUG && console.log(`[ext:${extId}] ${event.message}`); 1160 - }); 1161 - 1162 - // Track crashes 1163 - win.webContents.on('render-process-gone', (event, details) => { 1164 - console.error(`[ext:win] Extension ${extId} crashed (reason: ${details.reason})`); 1165 - const entry = extensionWindows.get(extId); 1166 - if (entry) { 1167 - entry.status = 'crashed'; 1168 - } 1169 - }); 1170 - 1171 - // Track close 1172 - win.on('closed', () => { 1173 - DEBUG && console.log(`[ext:win] Extension ${extId} window closed`); 1174 - extensionWindows.delete(extId); 1175 - }); 1176 - 1177 - extensionWindows.set(extId, { win, manifest, status: 'loading' }); 1178 - 1179 - try { 1180 - await win.loadURL(`peek://ext/${extId}/background.html`); 1181 - DEBUG && console.log(`[ext:win] Extension ${extId} loaded successfully`); 1182 - const entry = extensionWindows.get(extId); 1183 - if (entry) { 1184 - entry.status = 'running'; 1185 - } 1186 - 1187 - // Open devtools for extension in debug mode (not in tests or headless) 1188 - if (config.isDev && !isTestProfile() && !isHeadless()) { 1189 - win.webContents.openDevTools({ mode: 'detach', activate: false }); 1190 - } 1191 - 1192 - return win; 1193 - } catch (error) { 1194 - console.error(`[ext:win] Failed to load extension ${extId}:`, error); 1195 - extensionWindows.delete(extId); 1196 - win.destroy(); 1197 - return null; 1198 - } 1199 - } 1200 - 1201 - /** 1202 1109 * Create the consolidated extension host window 1203 1110 * All extensions load as iframes within this single window 1204 1111 */ ··· 1374 1281 console.error('[ext] Feature startup failed, falling back to legacy-only loading:', err); 1375 1282 } 1376 1283 1377 - // Get all registered extension IDs 1378 - const registeredExtIds = getRegisteredExtensionIds(); 1379 - 1380 - // External built-in extensions: registered IDs not in the consolidated list and not loaded by 1381 - // the v2 tile system. All CONSOLIDATED_EXTENSION_IDS features are v2, so this only catches 1382 - // any remaining v1 external extensions (e.g. 'example') that aren't in v2FeatureIds. 1383 - const externalBuiltinIds = registeredExtIds.filter(id => 1384 - !CONSOLIDATED_EXTENSION_IDS.includes(id) && isBuiltinExtensionEnabled(id) && !v2FeatureIds.has(id) 1385 - ); 1386 - 1387 - // Get external extensions from datastore 1388 - const externalExts = getExternalExtensions(); 1389 - const enabledExternalExts = externalExts.filter(ext => ext.enabled && ext.path); 1390 - 1391 - DEBUG && console.log(`[ext] Startup: ${externalBuiltinIds.length + enabledExternalExts.length} external`); 1392 - 1393 1284 // Phase 1: Early 1394 1285 publish('system', scopes.GLOBAL, 'ext:startup:phase', { phase: 'early' }); 1395 1286 ··· 1408 1299 // would try to load the v2 tile through the v1 iframe path. 1409 1300 registerLazyEventInterceptors({ skipExtensions: v2FeatureIds }); 1410 1301 1411 - // Load external built-in extensions (like 'example') as separate windows 1412 - // Skip declarative-only extensions — they don't need background pages 1413 - for (const extId of externalBuiltinIds) { 1414 - if (isDeclarativeOnly(extId)) continue; 1415 - try { await createExtensionWindow(extId); } catch (e) { 1416 - console.error(`[ext] Failed to load external built-in extension ${extId}:`, e); 1417 - } 1418 - } 1419 - 1420 - // Load external extensions from datastore as separate windows 1421 - for (const ext of enabledExternalExts) { 1422 - if (!extensionWindows.has(ext.id)) { 1423 - registerExtensionPath(ext.id, ext.path!); 1424 - try { await createExtensionWindow(ext.id); } catch (e) { 1425 - console.error(`[ext] Failed to load external extension ${ext.id}:`, e); 1426 - } 1427 - } 1428 - } 1429 - 1430 - const totalCount = externalBuiltinIds.length + enabledExternalExts.length; 1431 1302 DEBUG && console.log(`[ext:timing] hybrid total: ${Date.now() - extStart}ms`); 1432 1303 1433 1304 // Phase 3: UI ··· 1435 1306 1436 1307 // Phase 4: Complete 1437 1308 publish('system', scopes.GLOBAL, 'ext:startup:phase', { phase: 'complete' }); 1438 - publish('system', scopes.GLOBAL, 'ext:all-loaded', { count: totalCount }); 1309 + publish('system', scopes.GLOBAL, 'ext:all-loaded', { count: 0 }); 1439 1310 1440 - return totalCount; 1311 + return 0; 1441 1312 } 1442 1313 1443 1314 /**
+1 -3
backend/electron/tile-launcher.ts
··· 616 616 * Relaunch a tile — re-read the manifest from disk, close the old window 617 617 * (if any), revoke its tokens, then call `launchTile()` with the fresh manifest. 618 618 * 619 - * This is the v2 replacement for `createExtensionWindow(extId)` used by 620 - * `reloadExtension()` and `loadDevExtension()` in main.ts. See Phase 2.5 #3b 621 - * in `docs/v1-removal-plan.md`. 619 + * Used by `reloadExtension()` and `loadDevExtension()` in main.ts. 622 620 * 623 621 * Edge cases: 624 622 * - Tile not currently running (no window): just launches fresh.