# Content Scripts and Userscripts System Design Comprehensive design for a Greasemonkey/Tampermonkey-compatible content scripts system for Peek, inspired by [quoid/userscripts](https://github.com/quoid/userscripts) Safari extension. **Last Updated:** 2026-02-10 **Status:** Phase 1 implemented (see `feat(scripts): implement Phase 1 of userscripts/content scripts system`). Phases 2+ pending. --- ## 1. Executive Summary This document outlines a **content scripts/userscripts system** for Peek that enables users to write, manage, and execute JavaScript against web pages. The system combines: 1. **Metadata-driven execution** (Greasemonkey/Tampermonkey pattern) 2. **Integrated development environment** (editor extension integration) 3. **Datastore persistence** (consistent with Peek architecture) 4. **Dual execution modes** (Peek pages + web pages) 5. **Rich UI** (scripts list, code editor, live preview) ### Key Features - **Script Management**: Create, edit, enable/disable, import/export scripts - **Execution Engine**: Run scripts on matching URLs with timeout protection - **GM_* API Compatibility**: Basic Greasemonkey API layer (GM_getValue, GM_setValue, etc.) - **Three-Panel UI**: Scripts list (left), editor (center), preview/test (right) - **Background Automation**: Scheduled execution with cron-like scheduling - **Import/Export**: Support for .user.js format (Greasemonkey/Tampermonkey) --- ## 2. Reference Implementation: quoid/userscripts ### 2.1 Analysis of quoid/userscripts **Key Observations**: - Clean three-panel layout: script list, editor, settings - Metadata-driven script matching (`@match`, `@exclude-match`) - Support for standard Greasemonkey headers - Simple enable/disable toggles per script - Import/export as `.user.js` files - Execution contexts: document-start, document-end, document-idle - Basic GM_* API compatibility **What We'll Adopt**: - Three-panel UI pattern (adapted to Peek's editor extension) - Metadata-driven matching system - Import/export .user.js format - Execution timing controls (run-at) **What We'll Improve**: - Live preview panel showing execution results - Integration with Peek's datastore for persistence - Scheduled background execution - Execution history and analytics - Test mode with URL input --- ## 3. Architecture Overview ### 3.1 Core Components ``` ┌─────────────────────────────────────────────────────────────┐ │ Scripts Extension │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │ │ Scripts │ │ Script │ │ Background │ │ │ │ Manager UI │ │ Executor │ │ Scheduler │ │ │ │ │ │ │ │ │ │ │ │ - List │ │ - Pattern │ │ - Cron-like │ │ │ │ - CRUD ops │ │ - Injection │ │ - Auto-exec │ │ │ │ - Import/ │ │ - Timeout │ │ - History │ │ │ │ Export │ │ - GM_* API │ │ │ │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │ │ ├─────────────────────────────────────────────────────────────┤ │ Datastore Tables │ ├─────────────────────────────────────────────────────────────┤ │ - scripts: Script metadata (name, code, match patterns) │ │ - scripts_data: Execution history and results │ └─────────────────────────────────────────────────────────────┘ ``` ### 3.2 Data Flow 1. **Script Creation**: User creates script via UI → saved to `scripts` table 2. **Page Load**: Peek opens URL → executor checks match patterns → runs matching scripts 3. **Manual Execution**: User clicks "Test on This Page" → executor runs against test URL 4. **Scheduled Execution**: Background scheduler checks intervals → runs matching scripts 5. **Result Storage**: Execution completes → result logged to `scripts_data` table --- ## 4. User Interface Design ### 4.1 Three-Panel Layout ``` ┌────────────────────────────────────────────────────────────────────────┐ │ Scripts Manager [Minimize] [_] [x] │ ├────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌──────────────────────────┐ ┌─────────────────────┐ │ │ │ Scripts │ │ Editor │ │ Preview / Tests │ │ │ │ │ │ │ │ │ │ │ │ [+] New │ │ Name: ___________ │ │ Test URL: │ │ │ │ │ │ Match: ___________ │ │ https://example.com │ │ │ │ ✓ Script 1 │ │ Run-at: [document-end] ▼│ │ │ │ │ │ 24ms │ │ │ │ [Test on This Page] │ │ │ │ 2h ago │ │ ┌──────────────────────┐ │ │ │ │ │ │ │ │ │ 1 // ==UserScript== │ │ │ ┌─────────────────┐ │ │ │ │ ✗ Script 2 │ │ │ 2 // @name Test │ │ │ │ Status: Success │ │ │ │ │ ERROR │ │ │ 3 // │ │ │ │ Time: 42ms │ │ │ │ │ Never │ │ │ 4 │ │ │ │ │ │ │ │ │ │ │ │ 5 let h = doc... │ │ │ │ Result: │ │ │ │ │ ◊ Script 3 │ │ │ 6 return h │ │ │ │ { │ │ │ │ │ disabled │ │ │ │ │ │ │ "data": [..], │ │ │ │ │ 42ms │ │ │ │ │ │ │ "count": 15 │ │ │ │ │ │ │ └──────────────────────┘ │ │ │ } │ │ │ │ │ ⓘ Script 4 │ │ [Save] [Revert] [Delete] │ │ │ │ │ │ │ │ no change │ │ │ │ │ [Copy Result] │ │ │ │ │ 15min ago │ │ │ │ │ [Copy JSON] │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ⚙ Settings │ │ │ │ └─────────────────┘ │ │ │ │ 📝 History │ │ │ │ │ │ │ │ ⓘ About │ │ │ │ Execution History: │ │ │ │ │ │ │ │ ┌─────────────────┐ │ │ │ │ [RUN ALL] │ │ │ │ │ Latest 5 Runs: │ │ │ │ │ │ │ │ │ │ ✓ 2m ago │ │ │ │ │ │ │ │ │ │ ✓ 1h ago │ │ │ │ │ │ │ │ │ │ ✓ 1d ago │ │ │ │ │ │ │ │ │ │ ✗ 3d ago │ │ │ │ │ │ │ │ │ │ ✓ 1w ago │ │ │ │ │ │ │ │ │ └─────────────────┘ │ │ │ └─────────────┘ └──────────────────────────┘ └─────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────┘ ``` ### 4.2 Script List Features Each script shows: - **Checkbox** (enable/disable) - **Icon** (type: web-scraper, data-transform, automation, utility) - **Name** + truncated description - **Status indicator**: - Green checkmark: Last execution successful - Red X: Last execution failed - Orange warning: Last execution but data unchanged - Gray: Never executed - **Execution time badge** (e.g., "24ms") - **Last run timestamp** (e.g., "2 hours ago") Right-click context menu: - Edit - Delete - Duplicate - Export as JSON - View history - Debug (dev console for this script) ### 4.3 Script Creation Workflow 1. **Click [+ New]** → Opens new script editor 2. **Set metadata**: - Name: "My Data Scraper" - Match patterns: `https://news.example.com/*` - Run-at: document-end 3. **Write code**: ```javascript // Extract all headlines const headlines = Array.from( document.querySelectorAll('h2.headline') ).map(el => el.textContent); console.log('Found headlines:', headlines); // Return data to Peek { headlines, count: headlines.length } ``` 4. **Test on Page**: Enter test URL, hit "Test on This Page" 5. **Save** → Stored in datastore, ready for auto-execution ### 4.4 Preview Panel States **When no test has been run:** ``` Test URL: [https://___________________] [Test on This Page] Instructions: 1. Enter a URL to test 2. Click "Test on This Page" 3. Results will appear here ``` **During execution:** ``` Testing: https://example.com ⏳ Running... (2s) ``` **After success:** ``` ✓ Success Execution time: 342ms Result: { "headlines": [ "Story 1", "Story 2" ], "count": 15 } [Copy Result] [Copy JSON] ↓ Changed from last run Previous: count: 12 ``` **After error:** ``` ✗ Error at line 5 TypeError: Cannot read property 'querySelectorAll' of undefined Stack: at Object. (eval:5:13) at runScript (executor.js:45:12) [Show Full Error] ``` --- ## 5. Script Execution Engine ### 5.1 Execution Modes **Two Execution Modes**: 1. **Peek Pages** (peek://ext/*, peek://app/*): - Direct execution in renderer process - Full DOM access, no sandboxing needed - Used for testing/preview 2. **Web Pages** (https://*, http://*): - Injected as `