experiments in a post-browser web
10
fork

Configure Feed

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

final move to build script + portable backend

+37 -62
+36 -61
index.js backend/electron/entry.ts
··· 1 - // main.js 1 + /** 2 + * Electron Backend Entry Point 3 + * 4 + * This is the main entry point for the Electron application. 5 + * All Electron-specific code lives here. 6 + */ 2 7 3 8 import { app } from 'electron'; 4 - 5 9 import fs from 'node:fs'; 6 10 import path from 'node:path'; 11 + import unhandled from 'electron-unhandled'; 7 12 8 - // Import from compiled TypeScript backend 13 + // Import from local backend modules 9 14 import { 10 15 // Main process orchestration 11 16 configure, ··· 31 36 unregisterLocalShortcut, 32 37 // PubSub 33 38 scopes, 34 - publish as pubsubPublish, 35 - subscribe as pubsubSubscribe, 39 + publish, 40 + subscribe, 36 41 getSystemAddress, 37 42 // IPC 38 43 registerAllHandlers, ··· 45 50 // Window helpers 46 51 setPrefsGetter, 47 52 updateDockVisibility, 48 - } from './dist/backend/electron/index.js'; 49 - import unhandled from 'electron-unhandled'; 53 + } from './index.js'; 50 54 51 55 // Catch unhandled errors and promise rejections without showing alert dialogs 52 56 unhandled({ ··· 56 60 } 57 61 }); 58 62 59 - const __dirname = import.meta.dirname; 63 + // Get the root directory (two levels up from dist/backend/electron/) 64 + const ROOT_DIR = path.resolve(import.meta.dirname, '..', '..', '..'); 60 65 61 - (async () => { 62 - 63 - const DEBUG = process.env.DEBUG || false; 64 - const DEBUG_LEVELS = { 65 - BASIC: 1, 66 - FIRST_RUN: 2 67 - }; 68 - const DEBUG_LEVEL = DEBUG_LEVELS.BASIC; 69 - //const DEBUG_LEVEL = DEBUG_LEVELS.FIRST_RUN; 66 + const DEBUG = !!process.env.DEBUG; 70 67 71 68 // script loaded into every app window 72 - const preloadPath = path.join(__dirname, 'preload.js'); 69 + const preloadPath = path.join(ROOT_DIR, 'preload.js'); 73 70 74 71 const systemAddress = getSystemAddress(); 75 72 ··· 85 82 } 86 83 }; 87 84 88 - const profileIsLegit = p => p != undefined && typeof p == 'string' && p.length > 0; 85 + const profileIsLegit = (p: unknown): p is string => 86 + p !== undefined && typeof p === 'string' && p.length > 0; 89 87 90 88 // Profile selection: 91 89 // 1. Explicit PROFILE env var takes precedence ··· 101 99 setProfile(PROFILE); 102 100 103 101 // Profile dirs are subdir of userData dir 104 - // ..................................... ↓ we set this per profile 105 - // 106 102 // {home} / {appData} / {userData} / {profileDir} 107 - // 108 103 // Chromium's data in a subfolder of profile folder 109 - // 110 - // ................................................. ↓ we set this per profile 111 - // 112 104 // {home} / {appData} / {userData} / {profileDir} / {sessionData} 113 - 114 105 115 106 // specify various app data paths and make if not exist 116 107 const defaultUserDataPath = app.getPath('userData'); 117 108 const profileDataPath = path.join(defaultUserDataPath, PROFILE); 118 109 const sessionDataPath = path.join(profileDataPath, 'chromium'); 119 110 120 - //console.log('udp', defaultUserDataPath); 121 - //console.log('pdp', profileDataPath); 122 - //console.log('sdp', sessionDataPath); 123 - 124 111 // create filesystem 125 - if (!fs.existsSync(sessionDataPath)){ 112 + if (!fs.existsSync(sessionDataPath)) { 126 113 fs.mkdirSync(sessionDataPath, { recursive: true }); 127 114 } 128 115 ··· 130 117 app.setPath('userData', profileDataPath); 131 118 app.setPath('sessionData', sessionDataPath); 132 119 133 - // ***** Datastore ***** 134 - 135 - // Note: getDb, generateId, now, parseUrl, normalizeUrl, calculateFrecency, isValidTable 136 - // are imported directly from backend/electron 137 - 138 120 // ***** Features / Strings ***** 139 121 140 122 const labels = { ··· 156 138 157 139 // app global prefs configurable by user 158 140 // populated during app init 159 - let _prefs = {}; 160 - let _quitShortcut = null; 141 + let _prefs: Record<string, unknown> = {}; 142 + let _quitShortcut: string | null = null; 161 143 162 144 // Set up prefs getter for backend window helpers 163 145 setPrefsGetter(() => _prefs); 164 146 165 - // ***** pubsub ***** 166 - // Wrapper object for backend pubsub functions 167 - const pubsub = { 168 - publish: pubsubPublish, 169 - subscribe: pubsubSubscribe 170 - }; 147 + // Define onQuit as alias to quitApp for use in IPC handlers and shortcuts 148 + const onQuit = quitApp; 171 149 172 150 // ***** init ***** 173 151 ··· 196 174 registerSecondInstanceHandler(); 197 175 198 176 // Discover and register built-in extensions from extensions/ folder 199 - discoverBuiltinExtensions(path.join(__dirname, 'extensions')); 177 + discoverBuiltinExtensions(path.join(ROOT_DIR, 'extensions')); 200 178 201 179 // Register as default handler for http/https URLs (if not already and user hasn't declined) 202 180 // Skip for test profiles to avoid system dialogs during automated testing ··· 216 194 console.log('User previously declined default browser prompt'); 217 195 } 218 196 } 219 - } catch (e) { 197 + } catch { 220 198 // Ignore errors reading pref file 221 199 } 222 200 ··· 239 217 console.log('User declined default browser, saving preference'); 240 218 try { 241 219 fs.writeFileSync(defaultBrowserPrefFile, JSON.stringify({ declined: true, timestamp: Date.now() })); 242 - } catch (e) { 243 - console.error('Failed to save default browser preference:', e); 220 + } catch { 221 + console.error('Failed to save default browser preference'); 244 222 } 245 223 } 246 224 }, 2000); ··· 257 235 258 236 // listen for app prefs to configure ourself 259 237 // TODO: kinda janky, needs rethink 260 - pubsub.subscribe(systemAddress, scopes.SYSTEM, strings.topics.prefs, async msg => { 261 - console.log('PREFS', msg); 238 + subscribe(systemAddress, scopes.SYSTEM, strings.topics.prefs, async (msg: unknown) => { 239 + const prefsMsg = msg as { prefs: Record<string, unknown> }; 240 + console.log('PREFS', prefsMsg); 262 241 263 242 // cache all prefs 264 - _prefs = msg.prefs; 243 + _prefs = prefsMsg.prefs; 265 244 266 245 // Update dock visibility based on pref and visible windows 267 246 updateDockVisibility(); 268 247 269 248 // initialize system tray 270 - if (msg.prefs.showTrayIcon == true) { 249 + if (prefsMsg.prefs.showTrayIcon === true) { 271 250 console.log('showing tray'); 272 - initTray(__dirname, { 251 + initTray(ROOT_DIR, { 273 252 tooltip: labels.tray.tooltip, 274 253 onClick: () => { 275 - pubsub.publish(WEB_CORE_ADDRESS, scopes.GLOBAL, 'open', { 254 + publish(WEB_CORE_ADDRESS, scopes.GLOBAL, 'open', { 276 255 address: SETTINGS_ADDRESS 277 256 }); 278 257 } ··· 280 259 } 281 260 282 261 // update quit shortcut if changed (local shortcut - only works when app has focus) 283 - const newQuitShortcut = msg.prefs.quitShortcut || strings.defaults.quitShortcut; 262 + const newQuitShortcut = (prefsMsg.prefs.quitShortcut as string) || strings.defaults.quitShortcut; 284 263 if (newQuitShortcut !== _quitShortcut) { 285 264 if (_quitShortcut) { 286 265 console.log('unregistering old quit shortcut:', _quitShortcut); ··· 316 295 317 296 // Configure app before ready (registers protocol scheme, sets theme) 318 297 configure({ 319 - rootDir: __dirname, 298 + rootDir: ROOT_DIR, 320 299 preloadPath: preloadPath, 321 300 userDataPath: defaultUserDataPath, 322 301 profile: PROFILE, ··· 327 306 // Register window-all-closed handler 328 307 registerWindowAllClosedHandler(quitApp); 329 308 309 + // Start the app 330 310 app.whenReady().then(onReady); 331 - 332 - // Define onQuit as alias to quitApp for use in IPC handlers and shortcuts 333 - const onQuit = quitApp; 334 - 335 - })();
+1 -1
package.json
··· 2 2 "name": "Peek", 3 3 "version": "0.0.1", 4 4 "description": "Peek is a web user agent for working with the web in a more agent-ish fashion than a browser.", 5 - "main": "index.js", 5 + "main": "dist/backend/electron/entry.js", 6 6 "author": "dietrich ayala", 7 7 "license": "MIT", 8 8 "type": "module",