Skip to content

Latest commit

 

History

History
1852 lines (1352 loc) · 71.6 KB

File metadata and controls

1852 lines (1352 loc) · 71.6 KB

Codebase Documentation

Generated from the provided project files.

1. Executive Summary

Page Capture is a Chrome Manifest V3 extension for capturing full pages or scrollable areas, then exporting PNG, image PDF, or native selectable-text PDF output. Its primary users are people who need full-page captures, scrollable-element captures, document-like page exports, lightweight annotation tools, or a native browser PDF with selectable text.

Core functionality:

  • Capture the top-level page by scrolling the window and stitching visible slices.
  • Capture scrollable containers by auto-detecting an element, dragging a rectangle, or clicking an element.
  • Save a native full-page PDF through Chrome DevTools Protocol Page.printToPDF; this does not stitch screenshot images and preserves selectable text where Chrome prints text as text.
  • Open an extension-hosted editor for crop, drawing, shape, eraser, and text annotations.
  • Export editor output as PNG, paged PDF, continuous PDF, or detected document pages.
  • Redact common sensitive fields and user-provided CSS selectors before capture.
  • Run local syntax checks and a Playwright-based extension test harness.

Technology stack:

  • Chrome Extension Manifest V3.
  • Vanilla JavaScript ES modules.
  • Chrome extension APIs: runtime, tabs, scripting, storage, downloads, offscreen, debugger.
  • Offscreen document and browser canvas APIs.
  • jsPDF 4.2.1 vendored in extension/lib/jspdf.umd.min.js.
  • Poppins font files vendored under extension/fonts/.
  • Playwright for browser-based extension tests.
  • Node.js scripts for syntax validation.

High-level architecture:

  • The popup collects settings and sends a START_CAPTURE message to the background service worker.
  • The background service worker orchestrates capture, injects the content script, coordinates offscreen rendering, opens the editor, and starts downloads.
  • The content script manipulates the target page during capture: scrolling, selection, redaction, sticky hiding, scroll locking, and HUD display.
  • The offscreen document stores captured slices and builds previews/exports using canvas and jsPDF.
  • The editor page displays previews and captures user edits before requesting export.

Current maturity:

  • Inferred: This is a functional local-development Chrome extension with automated syntax and browser harness tests.
  • It has CI configuration and dependency audit checks.
  • It does not yet have production packaging, Chrome Web Store release automation, load/performance tests, or exhaustive native PDF regression tests.

2. Project Structure Overview

Path Type Purpose Key Dependencies
README.md Documentation Short project entry point and verification commands. docs/codebase-documentation.md
CONTRIBUTING.md Documentation Contributor setup, checks, and change guidelines. npm scripts, extension conventions
SECURITY.md Documentation Vulnerability reporting guidance and security notes. GitHub Security Advisories/issues
docs/codebase-documentation.md Documentation Full codebase documentation. Project source files
docs/release-checklist.md Documentation GitHub publication, release, manifest, manual QA, and store packaging checklist. README, manifest, npm scripts
package.json Configuration Node metadata and test scripts. @playwright/test, scripts/check-syntax.mjs
package-lock.json Configuration Locked dependency graph for npm. npm
playwright.config.js Testing config Configures Playwright browser tests under tests/browser. @playwright/test
.github/workflows/ci.yml CI config Runs syntax check, npm audit, and browser tests on push/PR. GitHub Actions, Node 22, Playwright Chromium
.gitignore Configuration Ignores OS/editor files, node modules, build output, extension packages, temp files, and env files. Git
.gitattributes Configuration Normalizes text line endings and marks binary assets. Git
.editorconfig Configuration Documents shared editor whitespace and line-ending behavior. EditorConfig-compatible editors
scripts/check-syntax.mjs Testing utility Recursively checks JavaScript syntax with node --check, excluding vendored jsPDF. Node fs, path, child_process
extension/manifest.json Core extension config Defines MV3 extension name, popup, service worker, icons, and permissions. Chrome MV3
extension/popup.html Core UI Popup form for mode and capture settings. ui.css, popup.css, popup.js
extension/popup.js Core UI logic Loads/stores settings and sends START_CAPTURE. common.js, form-utils.js, Chrome storage/runtime APIs
extension/popup.css Styling Popup-specific layout and sizing. ui.css variables
extension/editor.html Core UI Extension-hosted editor page. ui.css, editor.css, editor.js
extension/editor.js Core UI logic Loads preview, handles tools, annotations, crop, zoom, undo, export. CanvasRenderer, EditorToolLogic, form-utils.js, common.js, Chrome runtime API
extension/editor.css Styling Editor workspace, panels, tool controls, canvas layout. ui.css variables
extension/ui.css Shared styling Global black/white theme, Poppins fonts, forms, buttons, shared link buttons. Vendored fonts
extension/background.js Core orchestration Message router, capture coordinator, editor/download lifecycle, and native PDF download flow. Chrome tabs/runtime/scripting/storage/downloads/offscreen APIs, native-pdf.js
extension/content.js Core page integration Runs in target tabs to collect metrics, scroll, select containers, redact content, freeze animations, show HUD. DOM APIs, Chrome runtime connect/sendMessage
extension/offscreen.html Core offscreen host Loads offscreen runtime. offscreen.js
extension/offscreen.js Core rendering runtime Stores capture slices, builds previews, detects pages, builds exports, returns object URLs. SessionManager, image-ops.js, page-detect.js, pdf-builder.js
extension/form-utils.js Supporting utility Maps settings to popup/editor forms and reads forms back into objects. DOM form elements
extension/lib/utils/common.js Supporting utility Default settings, allowlists, normalization, deep merge, filename helpers. None beyond JS runtime
extension/lib/core/session.js Core state Holds captured slices and export session state in offscreen context. computeSourceRect()
extension/lib/core/image-ops.js Core rendering utility Bitmap decoding, canvas cropping, slice stitching, preview and raster export helpers. Canvas, FileReader, ImageBitmap
extension/lib/core/pdf-builder.js Core export utility Converts captured slices and annotations into jsPDF PDF or PNG blobs. jsPDF, image-ops.js, page-detect.js, common.js
extension/lib/core/native-pdf.js Core native export utility Wraps Chrome DevTools Protocol Page.printToPDF and native PDF sizing/error handling. Chrome debugger API
extension/lib/core/page-detect.js Core document detection Detects document-like page rectangles from raster luminance analysis. Canvas image data, image-ops.js
extension/lib/ui/canvas-renderer.js Editor UI utility Draws preview image, annotations, crop overlay, and selection handles. Canvas
extension/lib/ui/editor-tools.js Editor UI utility Hit-testing, selection handles, geometry helpers. DOM pointer event geometry
extension/lib/jspdf.umd.min.js Vendored runtime jsPDF library used for PDF output. jsPDF license file
extension/lib/jspdf-LICENSE.txt License jsPDF license text. None
extension/fonts/* Vendored runtime assets Poppins ExtraLight and bold font files plus license. ui.css
extension/public/logo.png Asset Extension icon used in manifest. manifest.json
extension/THIRD_PARTY.md Documentation Runtime third-party notices for jsPDF and Poppins. Vendored assets
extension/tests/runner.html Test harness UI Extension-internal automated test page. runner.js
extension/tests/runner.js Test harness logic Tests settings normalization, manifest permissions, offscreen validation, PDF/PNG export cases. Chrome runtime/offscreen APIs
extension/tests/e2e-bridge.html Test helper page Extension page for future E2E capture bridging. e2e-bridge.js
extension/tests/e2e-bridge.js Test helper logic Opens target tabs and drives capture/export through runtime messages. Chrome tabs/runtime APIs
tests/browser/extension-runner.spec.js Browser test Loads unpacked extension in Chromium and runs extension/tests/runner.html. Playwright

3. System Architecture

This project is a client-only Chrome extension. There is no backend server, database, ORM, server API layer, or server-side authentication flow visible in the provided code.

Architecture layers:

  • Browser extension UI: popup and editor pages.
  • Background service worker: central coordinator and message router.
  • Content script: page-facing code that runs in the active tab.
  • Offscreen document: hidden extension document for canvas, bitmap, blob, and PDF work.
  • Shared utilities: settings normalization, form mapping, image operations, PDF building, page detection, editor hit-testing.
  • Test harness: browser-loaded extension page driven by Playwright.

ASCII architecture diagram:

User
  |
  v
Popup UI
  | START_CAPTURE
  v
Background service worker
  | inject/send messages                         | build/download
  v                                              v
Content script in active tab  <---- slices ----  Offscreen document
  |                                              |
  | page metrics, scroll, selection              | SessionManager
  | redaction, HUD, sticky hiding                | image-ops, page-detect, pdf-builder
  |
  +---- native PDF mode ----> chrome.debugger Page.printToPDF

Background service worker
  |
  v
Editor page
  | GET_EDITOR_DATA / EXPORT_CAPTURE
  v
Background + offscreen export/download

Client-server interaction:

  • Not applicable. There is no server.

API layer:

  • There are no HTTP APIs.
  • The internal API is Chrome extension message passing through chrome.runtime.sendMessage, chrome.tabs.sendMessage, and chrome.runtime.onMessage.

Service/business logic layer:

  • extension/background.js is the service/orchestration layer.
  • extension/offscreen.js, extension/lib/core/pdf-builder.js, extension/lib/core/image-ops.js, and extension/lib/core/page-detect.js provide rendering/export logic.
  • extension/lib/core/native-pdf.js owns the Chrome DevTools Protocol native PDF print flow used by background.js.

Data access layer:

  • There is no database.
  • Persistent settings are stored in chrome.storage.local.
  • Current editor/capture session data is stored in memory and mirrored to chrome.storage.session as pendingCapture.

Authentication/authorization:

  • No user login or roles exist.
  • Security boundaries are Chrome extension permissions and sender checks.
  • getTrustedDebugOptions() only accepts debug tab overrides from extension pages.

External dependencies:

  • Runtime: Chrome extension platform and vendored jsPDF/Poppins.
  • Development/test: @playwright/test.
  • No remote APIs are called by application code.

Configuration/environment variables:

  • No .env variables are used.
  • EXTENSION_HEADLESS=1 can alter Playwright's persistent Chromium launch mode.

Error handling strategy:

  • Message handlers catch async errors and return { error: error.message }.
  • The background worker notifies the popup/editor with CAPTURE_ERROR, CAPTURE_CANCELLED, and CAPTURE_DONE.
  • Content-script HUD displays failure messages during normal capture modes.
  • Offscreen validation rejects malformed slices and unknown messages.

Logging strategy:

  • There is no structured application logging.
  • Test output comes from npm/Playwright and the extension test page.
  • Chrome extension runtime errors are inspected through Chrome extension service worker/page DevTools.

Security boundaries:

  • The extension avoids <all_urls> host permissions.
  • Active page access relies on activeTab and content-script injection for the active tab.
  • debugger is required for native PDF export and is attached only during that operation, then detached in finally.

4. Codebase Walkthrough

Manifest and Permissions

Files:

  • extension/manifest.json

Responsibilities:

  • Declares Manifest V3.
  • Names the extension Page Capture.
  • Describes the extension as capturing full pages or scrollable areas and saving PNG, image PDF, or native selectable-text PDF output.
  • Registers popup.html as the default action popup.
  • Registers background.js as a module service worker.
  • Declares icon assets.
  • Declares required permissions: activeTab, debugger, scripting, storage, downloads, offscreen.

Important implementation detail:

  • debugger is required because Chrome does not allow that permission to be optional. It is needed for Page.printToPDF.
  • There are no host permissions and no <all_urls> grant.

Security implications:

  • debugger is powerful and increases permission warning severity.
  • The implementation mitigates by attaching only during native PDF export and detaching in finally.

Popup

Files:

  • extension/popup.html
  • extension/popup.js
  • extension/popup.css
  • extension/form-utils.js
  • extension/lib/utils/common.js

Responsibilities:

  • Presents capture mode controls.
  • Captures user settings for page capture, scrollable box capture, redaction, waits, safety limits, and export behavior.
  • Loads existing settings from chrome.storage.local.
  • Normalizes settings through mergeSettings().
  • Persists updated settings.
  • Sends START_CAPTURE to background.js.
  • Receives progress and completion messages from the background worker.
  • Shows two icon-only external links: GitHub repository and "Check out my website".

Main flow:

  1. popup.js calls init().
  2. init() reads settings from chrome.storage.local.
  3. mergeSettings() applies defaults and clamps/allowlists values.
  4. populateCaptureForm() updates DOM controls.
  5. On submit, readCaptureForm() creates a partial settings object.
  6. deepMerge() merges the partial values into normalized stored settings.
  7. chrome.runtime.sendMessage() sends START_CAPTURE.

Edge cases handled:

  • If old stored defaults version is detected, some defaults are reset.
  • Missing selected mode falls back to full.
  • Capture status is restored when background emits completion/error/cancel events.

Known gaps:

  • There is no explicit UI warning for debugger permission before native PDF export.
  • There is no settings import/export feature.

Background Service Worker

File:

  • extension/background.js

Responsibilities:

  • Owns capture lifecycle.
  • Prevents concurrent capture/editor sessions with captureInProgress and editorInProgress.
  • Injects the content script if needed.
  • Opens and closes the offscreen document.
  • Routes messages to tab/offscreen/editor/popup contexts.
  • Captures full-page screenshots by scrolling and using chrome.tabs.captureVisibleTab.
  • Captures scrollable boxes by selecting and scrolling container content.
  • Starts native PDF downloads and delegates Chrome DevTools Protocol printing to extension/lib/core/native-pdf.js.
  • Opens editor and stores pending capture metadata.
  • Handles editor export and cancellation.
  • Validates export payload structure.
  • Starts downloads and waits for download completion.

Important constants:

  • MAX_EXPORT_ANNOTATIONS = 500
  • MAX_PATH_POINTS = 10000
  • MAX_TEXT_LENGTH = 20000
  • native-pdf.js owns native print constants such as MAX_NATIVE_PDF_DIMENSION_IN = 200 and NATIVE_PDF_GUARD_BAND_PX = 32
  • Capture throttle starts at 200ms, backs off to 1200ms, and recovers by 0.92.

Non-obvious logic:

  • Native PDF mode (mode === 'fullText') bypasses offscreen image capture and editor. It prepares page redaction/background options, calls downloadNativePagePdf(), which delegates printing to printPageToPdf() in native-pdf.js, restores page changes, and downloads directly.
  • Screenshot modes call PREPARE_CAPTURE, collect page metrics, scroll/capture slices, send slices to offscreen, restore the page, then open the editor.
  • captureVisibleClean() attempts a capture; if capture quota is hit, it backs off and retries.
  • waitForDownloadCompletion() both listens to downloads.onChanged and polls the download item to avoid missing instant completion events.
  • getTrustedDebugOptions() only accepts test/debug tab overrides from extension pages, not arbitrary senders.

Failure modes:

  • Restricted pages cannot be scripted or debugged.
  • Chrome capture quota can force retry/backoff.
  • Device pixel ratio changes during capture abort the capture.
  • Excessive slice count or height throws user-facing errors.
  • Downloads can be interrupted.

Security notes:

  • Sender validation exists for debug options.
  • Export annotation payloads are normalized and capped.
  • Native PDF errors are converted into safer user-facing messages.

Content Script

File:

  • extension/content.js

Responsibilities:

  • Handles GET_METRICS, PREPARE_CAPTURE, RESTORE_CAPTURE, SCROLL_TO, SELECT_SCROLL_CONTAINER, SCROLL_CONTAINER, HUD_*, and selection messages.
  • Measures page and viewport dimensions.
  • Scrolls top-level windows and containers.
  • Supports iframe-related selection metadata.
  • Shows capture HUD and selection overlay.
  • Freezes animations and optionally hides sticky/fixed elements.
  • Applies redaction to common sensitive fields and custom selectors.
  • Suppresses backgrounds when requested.
  • Locks scroll during capture where needed.
  • Waits for images and layout stability.
  • Maintains a keepalive port during long captures.

Important functions:

  • getMetrics(): returns viewport/page dimensions and DPR.
  • prepareCapture(): applies capture-side page mutations.
  • restoreCapture(): reverses those mutations.
  • handleScrollTo(): scrolls the window and waits for stability.
  • beginSelection(): resolves scrollable target selection.
  • autoDetectScrollContainer(): finds the best scrollable element.
  • applyRedaction(): masks sensitive fields and user selectors.
  • waitForStability(): waits for images/idle timing around viewport changes.

Assumptions:

  • Page DOM is accessible through the content script.
  • Cross-origin iframe internals are not directly accessible.
  • Visible captured pixels are sufficient for screenshot/export modes.

Edge cases handled:

  • Scrollable container selection cancellation.
  • Sticky/fixed restoration.
  • Background restoration.
  • Scroll-lock restoration.
  • Cross-origin iframe selection metadata fallback.

Known gaps:

  • Redaction is heuristic and cannot detect every site-specific secret.
  • CSS selector errors in custom redaction are guarded by parsing, but semantic mistakes remain user responsibility.

Offscreen Runtime

Files:

  • extension/offscreen.html
  • extension/offscreen.js
  • extension/lib/core/session.js
  • extension/lib/core/image-ops.js
  • extension/lib/core/pdf-builder.js
  • extension/lib/core/page-detect.js

Responsibilities:

  • Holds capture slices in SessionManager.
  • Converts data URLs from captureVisibleTab into ImageBitmap objects.
  • Builds editor previews.
  • Detects page rectangles for document-like exports.
  • Builds PDF/PNG blobs and object URLs.
  • Validates slice payloads, crop rectangles, manual page rectangles, and numeric ranges.

Important message types:

  • RESET_SESSION
  • ADD_SLICE
  • DETECT_PAGES
  • SET_MANUAL_PAGE_RECT
  • SET_CROP_RECT
  • BUILD_PREVIEW
  • BUILD_EXPORT
  • BUILD_AND_DOWNLOAD_EXPORT
  • BUILD_PDF
  • BUILD_AND_DOWNLOAD_PDF
  • GET_SESSION_METRICS

Non-obvious logic:

  • Object URLs are revoked after 60 seconds.
  • normalizeSlicePayload() rejects non-image data URLs.
  • Slice DPR is clamped to 0.25 through 8.
  • Session bitmaps are closed on reset to release memory.

Editor

Files:

  • extension/editor.html
  • extension/editor.js
  • extension/editor.css
  • extension/lib/ui/canvas-renderer.js
  • extension/lib/ui/editor-tools.js

Responsibilities:

  • Loads pending capture data through GET_EDITOR_DATA.
  • Requests preview image from offscreen.
  • Renders preview image and annotations on a canvas.
  • Supports selection, crop, draw, shape, erase, and text tools.
  • Maintains undo state for annotations.
  • Supports zoom and preview scale controls.
  • Reads export settings and sends EXPORT_CAPTURE.
  • Shows GitHub and website icon links.

Important implementation choices:

  • Editor annotations are stored in preview/base coordinates and scaled for rendering.
  • CanvasRenderer draws background, annotations, active action, crop overlay, and selection overlay.
  • EditorToolLogic centralizes hit testing and geometry so editor UI code does not duplicate shape math.
  • Text editing uses a positioned text input over the canvas, then commits to annotation data.

Failure modes:

  • Preview loading may fail if there is no pending capture or offscreen runtime fails.
  • Export can fail because of canvas size, PDF size, malformed edits, or download interruption.

Shared Utilities

Files:

  • extension/lib/utils/common.js
  • extension/form-utils.js

Responsibilities:

  • Define defaults and allowlists.
  • Normalize settings and prevent unsafe merge keys.
  • Clamp numeric settings.
  • Sanitize filenames.
  • Convert forms to/from settings objects.

Important security detail:

  • deepMerge() skips __proto__, prototype, and constructor keys to reduce prototype pollution risk.

5. API Documentation

There are no HTTP routes or REST endpoints in the provided code. The internal API is Chrome extension messaging.

START_CAPTURE

Purpose:
Starts a capture or native PDF export.

Transport:
chrome.runtime.sendMessage() to background.js.

Auth required: No app auth. Requires extension context and Chrome permissions.

Request body:

{
  "target": "background",
  "type": "START_CAPTURE",
  "options": {
    "mode": "full"
  }
}

Success response:

{
  "ok": true,
  "editor": true
}

For native PDF:

{
  "ok": true,
  "downloaded": true
}

Possible errors:

Status Cause Response
Not applicable Capture already running { "error": "A capture or editor is already running." }
Not applicable Restricted page { "error": "Native PDF export cannot access this page. Try a normal web page tab." }
Not applicable Download interrupted { "error": "Download was interrupted." }

Related files:

  • extension/popup.js
  • extension/background.js
  • extension/content.js
  • extension/offscreen.js

GET_EDITOR_DATA

Purpose:
Returns pending capture metadata to the editor page.

Transport:
chrome.runtime.sendMessage() to background.js.

Request body:

{
  "target": "background",
  "type": "GET_EDITOR_DATA"
}

Success response:

{
  "settings": {},
  "mode": "full",
  "tabId": 123,
  "tabTitle": "Example"
}

Possible errors:

Status Cause Response
Not applicable No pending capture { "error": "No capture is waiting for editing." }

EXPORT_CAPTURE

Purpose:
Exports edited capture data from the editor.

Transport:
chrome.runtime.sendMessage() to background.js.

Request body:

{
  "target": "background",
  "type": "EXPORT_CAPTURE",
  "payload": {
    "settings": {},
    "edits": {
      "cropRect": null,
      "annotations": []
    }
  }
}

Success response:

{
  "ok": true,
  "downloaded": true
}

Possible errors:

Status Cause Response
Not applicable No pending capture { "error": "No capture is waiting for export." }
Not applicable Invalid export { "error": "Failed to build export." }
Not applicable Download interrupted { "error": "Download was interrupted." }

CANCEL_EDITOR

Purpose:
Closes or finalizes the editor state and clears pending capture.

Transport:
chrome.runtime.sendMessage() to background.js.

Request body:

{
  "target": "background",
  "type": "CANCEL_EDITOR"
}

Success response:

{
  "ok": true
}

GET_METRICS

Purpose:
Returns target page dimensions, viewport dimensions, DPR, and scrollability.

Transport:
chrome.tabs.sendMessage() to content.js.

Request body:

{
  "type": "GET_METRICS"
}

Success response:
Shape is inferred from content.js: viewport width/height, total width/height, scroll position, DPR, and scrollability metadata.

PREPARE_CAPTURE and RESTORE_CAPTURE

Purpose:
Apply and undo page mutations for capture.

Transport:
chrome.tabs.sendMessage() to content.js.

Request body:

{
  "type": "PREPARE_CAPTURE",
  "options": {}
}

Effects:

  • Freezes animations when configured.
  • Hides sticky/fixed elements when configured.
  • Applies redaction when configured.
  • Suppresses backgrounds when requested.
  • Starts content keepalive.

RESTORE_CAPTURE reverses these effects.

SCROLL_TO

Purpose:
Scrolls the target page to a specific y coordinate and waits for stability.

Transport:
chrome.tabs.sendMessage() to content.js.

Request body:

{
  "type": "SCROLL_TO",
  "y": 1200,
  "waitMs": 150
}

Possible errors:

Cause Response
Page cannot scroll as expected Error propagated to background
DPR changes Background throws Page zoom or display scale changed during capture.

SELECT_SCROLL_CONTAINER

Purpose:
Selects a scrollable region using auto, rectangle, or element selection mode.

Transport:
chrome.tabs.sendMessage() to content.js.

Request body:

{
  "type": "SELECT_SCROLL_CONTAINER",
  "selectionMode": "auto",
  "message": "Select a scrollable area"
}

Possible errors:

Cause Response
User cancels Selection cancelled error
No scrollable container found Error propagated to background

Offscreen Messages

All offscreen messages use:

{
  "target": "offscreen",
  "type": "MESSAGE_NAME",
  "payload": {}
}
Type Purpose Main Validation
RESET_SESSION Clears existing bitmaps and starts a mode. Mode must be full, box, fullText, or null.
ADD_SLICE Converts an image data URL into an ImageBitmap and stores it. dataUrl must start with data:image/; cropRect required.
DETECT_PAGES Runs page detection on captured slices. Uses document options and max page limit.
SET_MANUAL_PAGE_RECT Stores a manually selected page rectangle. Rect must be positive.
SET_CROP_RECT Stores editor crop rectangle. Rect must be positive or null.
BUILD_PREVIEW Builds preview data URL from slices. Requires at least one slice.
BUILD_EXPORT Builds PDF/PNG and returns data URL. Delegates to buildExportBlob().
BUILD_AND_DOWNLOAD_EXPORT Builds blob and returns object URL/filename. Object URL is revoked after 60 seconds.
BUILD_PDF Builds PDF and returns buffer plus metrics. Delegates to buildPdf().
GET_SESSION_METRICS Returns slice count and dimensions. None.

6. Data Model and Database Documentation

There is no database, schema, ORM, migration system, or persistent user model visible in the provided code.

Persistent data:

  • chrome.storage.local.settings: user capture/export settings.
  • chrome.storage.session.pendingCapture: transient editor metadata.

In-memory data:

  • SessionManager.session.slices: captured ImageBitmap slices and metadata.
  • SessionManager.session.detectedCandidates: page detection candidates.
  • SessionManager.session.detectedPages: ordered detected pages.
  • SessionManager.session.manualRect: manually selected document page rectangle.
  • SessionManager.session.cropRect: editor crop rectangle.
  • Editor annotations in editor.js memory until export.

Settings model:

Field Type Source Notes
mode string DEFAULT_SETTINGS.mode full, box, or fullText.
pdf.pageSize string DEFAULT_SETTINGS.pdf One of A3/A4/A5/Legal/Letter/Tabloid/Ledger.
pdf.orientation string DEFAULT_SETTINGS.pdf portrait or landscape.
pdf.margins string DEFAULT_SETTINGS.pdf none, small, normal.
pdf.scaleMode string DEFAULT_SETTINGS.pdf fit, 100, custom.
pdf.scale number DEFAULT_SETTINGS.pdf Clamped 0.1 to 3.
pdf.layout string DEFAULT_SETTINGS.pdf paged, continuous, detected.
capture.disableAnimations boolean DEFAULT_SETTINGS.capture Default true.
capture.hideSticky boolean DEFAULT_SETTINGS.capture Default false.
capture.redactSensitive boolean DEFAULT_SETTINGS.capture Default false.
capture.redactSelectors string DEFAULT_SETTINGS.capture Max 500 chars.
capture.overlap number DEFAULT_SETTINGS.capture Clamped 20 to 200.
scrollBox.selectionMode string DEFAULT_SETTINGS.scrollBox auto, rect, element.
document.maxPages number DEFAULT_SETTINGS.document Clamped 1 to 500; default 200.
safety.maxSlices number DEFAULT_SETTINGS.safety Clamped 1 to 1000; default 400.
safety.maxHeight number DEFAULT_SETTINGS.safety Clamped 1000 to 500000; default 300000.
safety.maxExportPixels number DEFAULT_SETTINGS.safety Clamped 1000000 to 500000000; default 120000000.
filename.pattern string DEFAULT_SETTINGS.filename Max 180 chars; supports {title} and {date}.

Annotation model:

Type Fields Notes
path points, color, strokeWidth Points capped in background export normalization.
rect x, y, width, height, color, strokeWidth, fillColor Shape annotation.
ellipse Same as rect Shape annotation.
triangle Same as rect Shape annotation.
arrow Same as rect Shape annotation.
text x, y, text, color, fontSize, text style fields Text length capped in background export normalization.

Sensitive fields:

  • There are no saved passwords or tokens.
  • Captured page pixels/PDFs may include sensitive information from the active page unless redaction is configured.
  • chrome.storage.local.settings can contain custom redaction selectors and preferences, but not user secrets by design.

7. Authentication and Authorization

There is no application-level authentication or authorization.

Login/register flow:

  • Not visible from provided code.

Token/session handling:

  • Not visible from provided code.

Password handling:

  • Not visible from provided code.

Protected routes:

  • No HTTP routes exist.

Permission-based access:

  • Chrome extension permissions gate access to browser APIs.
  • activeTab allows temporary access to the active tab after user interaction.
  • scripting allows the extension to inject content.js.
  • storage persists settings and pending session metadata.
  • downloads starts file downloads.
  • offscreen allows hidden rendering/export runtime.
  • debugger allows native PDF export through DevTools Protocol.

Authorization decisions:

  • getTrustedDebugOptions() ensures test/debug tab override options only come from extension pages.
  • Content and offscreen handlers require message target values where appropriate.

Common failure cases:

  • Chrome restricted pages cannot be scripted.
  • Another debugger already attached to a tab prevents native PDF export.
  • User can deny or remove extension permissions outside this code.

8. Data Flow Documentation

Full Page Screenshot Capture Flow

  1. Trigger: user selects Full Page (scroll window) in popup and submits.
  2. Entry point: popup.js onSubmit().
  3. Files/functions:
    • popup.js: onSubmit()
    • background.js: startCapture(), captureFullPage(), captureVisibleClean(), openEditor()
    • content.js: getMetrics(), prepareCapture(), handleScrollTo(), restoreCapture()
    • offscreen.js: RESET_SESSION, ADD_SLICE
  4. Sequence:
Popup -> Background: START_CAPTURE
Background -> Content: PREPARE_CAPTURE
Background -> Content: GET_METRICS
Background -> Offscreen: RESET_SESSION
loop:
  Background -> Content: SCROLL_TO
  Background -> Chrome tabs API: captureVisibleTab
  Background -> Offscreen: ADD_SLICE
Background -> Content: RESTORE_CAPTURE
Background -> Editor: open editor.html
  1. Data transformations:
    • Visible screenshot data URL becomes ImageBitmap.
    • Slice metadata records crop rectangle, scroll offset, crop top/bottom, and DPR.
  2. Output:
    • Editor opens with pending capture.
  3. Failure cases:
    • DPR changes.
    • Too many slices.
    • Capture height exceeds safety limit.
    • Chrome capture quota requires retry or eventually fails.

Scrollable Box Capture Flow

  1. Trigger: user selects Scrollable Box.
  2. Entry point: background.js captureScrollableBox().
  3. Files/functions:
    • content.js: beginSelection(), autoDetectScrollContainer(), selectRect(), selectElement(), handleScrollContainer()
    • background.js: captureScrollableSelection()
    • offscreen.js: ADD_SLICE
  4. Sequence:
Background -> Content: SELECT_SCROLL_CONTAINER
Content -> User: overlay selection if needed
Background -> Content: SCROLL_CONTAINER for each scroll position
Background -> Chrome: captureVisibleTab
Background -> Offscreen: ADD_SLICE with cropRect from selection
Background -> Editor: open editor.html
  1. Data transformations:
    • Element/rectangle geometry is clamped to viewport.
    • Captured viewport image is cropped by offscreen/PDF rendering using cropRect.
  2. Output:
    • Editor opens with scrollable region capture.
  3. Failure cases:
    • No scrollable element found.
    • Selection cancelled.
    • Cross-origin iframe internals unavailable.

Native Full Page PDF Flow

  1. Trigger: user selects Native Full Page PDF.
  2. Entry point: background.js startCapture().
  3. Files/functions:
    • background.js: downloadNativePagePdf()
    • native-pdf.js: printPageToPdf(), native size resolution, DevTools Protocol error mapping
    • content.js: prepareCapture(), restoreCapture()
  4. Sequence:
Popup -> Background: START_CAPTURE mode fullText
Background -> Content: PREPARE_CAPTURE
Background -> chrome.debugger: attach
Background -> DevTools Protocol: Page.enable, Runtime.enable
Background -> DevTools Protocol: Emulation.setEmulatedMedia screen
Background -> DevTools Protocol: Page.getLayoutMetrics
Background -> DevTools Protocol: Runtime.evaluate DOM scroll dimensions
Background -> DevTools Protocol: Page.printToPDF
Background -> chrome.debugger: detach
Background -> Chrome downloads: download data URL PDF
Background -> Content: RESTORE_CAPTURE
  1. Data transformations:
    • CSS pixel dimensions are converted to inches using 96 CSS px = 1 inch.
    • A 32px guard band is added to reduce blank trailing page risk.
    • A single page range is requested when not dimension-capped.
  2. Output:
    • PDF downloaded directly, no editor.
  3. Failure cases:
    • Restricted pages.
    • Another debugger attached.
    • Chrome print engine paginates extreme pages.
    • Canvas-rendered text remains graphics.

Editor Export Flow

  1. Trigger: user clicks export in editor.
  2. Entry point: editor.js onExport().
  3. Files/functions:
    • form-utils.js: readExportForm()
    • background.js: handleExportCapture(), downloadCaptureExport()
    • offscreen.js: BUILD_AND_DOWNLOAD_EXPORT
    • pdf-builder.js: buildExportBlob(), buildPdf()
  4. Sequence:
Editor -> Background: EXPORT_CAPTURE with settings and edits
Background -> Offscreen: BUILD_AND_DOWNLOAD_EXPORT
Offscreen -> pdf-builder/image-ops: build Blob
Offscreen -> Background: object URL and filename
Background -> Chrome downloads: download
Background -> Editor: EXPORT_DONE or EXPORT_ERROR
Background: finalize editor state
  1. Data transformations:
    • Editor annotations are normalized/capped.
    • Crop rect is normalized.
    • PDF/PNG blob is created in offscreen context.
  2. Output:
    • Downloaded file.
  3. Failure cases:
    • Export pixel cap exceeded.
    • Browser canvas dimension cap exceeded.
    • No captured content.
    • Download interrupted.

Test Execution Flow

  1. Trigger: npm run test:browser.
  2. Entry point: tests/browser/extension-runner.spec.js.
  3. Files/functions:
    • Playwright persistent Chromium context.
    • extension/tests/runner.html
    • extension/tests/runner.js runTests()
  4. Sequence:
npm -> Playwright
Playwright -> Chromium persistent context with extension loaded
Playwright -> extension/tests/runner.html
Runner -> offscreen API and runtime messages
Runner -> assertions
Playwright -> fail/pass result
  1. Output:
    • Playwright pass/fail result.
  2. Failure cases:
    • Chromium extension launch fails.
    • Offscreen API unavailable.
    • Export metrics/assertions fail.

9. Function/Class-Level Documentation

startCapture()

File: extension/background.js

Purpose:
Main capture entry point. Normalizes mode, resolves the active tab, prepares the page, dispatches either native PDF export or screenshot capture, restores page state, opens editor or downloads output, and reports status.

Parameters:

Name Type Required Description
options object No User settings and optional test debug target.
sender object No Chrome message sender for debug option trust checks.

Returns:
Promise resolving to { ok: true, editor: true }, { ok: true, downloaded: true }, { cancelled: true }, or { error }.

Side effects:
Injects content script, creates offscreen document, scrolls page, captures visible tab, opens editor tab, starts downloads, mutates page during capture then restores it.

Dependencies:
mergeSettings(), ensureContentScript(), sendToTab(), ensureOffscreenDocument(), captureFullPage(), captureScrollableBox(), downloadNativePagePdf().

Errors:
Converts thrown errors into popup notifications and response objects.

captureFullPage()

File: extension/background.js

Purpose:
Scrolls a top-level page and captures visible slices with overlap.

Parameters:

Name Type Required Description
tabId number Yes Target tab.
windowId number Yes Window for captureVisibleTab.
settings object Yes Normalized settings.
metrics object Yes Page metrics from content script.

Returns:
Promise resolving to { modeOverride }.

Side effects:
Scrolls the target page and sends slices to offscreen.

Failure modes:
Too many slices, excessive height, DPR instability, quota failures.

captureScrollableSelection()

File: extension/background.js

Purpose:
Captures selected scrollable element/region by scrolling its content and cropping visible tab images.

Parameters:
Target tab/window, settings, selection metadata, and capture options.

Returns:
Promise resolving to { modeOverride }.

Side effects:
Scrolls selected container and sends cropped slice metadata to offscreen.

printPageToPdf()

File: extension/lib/core/native-pdf.js

Purpose:
Uses Chrome DevTools Protocol to print a tab to PDF without screenshot stitching.

Parameters:

Name Type Required Description
tabId number Yes Target tab.
settings object Yes PDF settings.

Returns:
Base64 PDF data from Chrome.

Side effects:
Attaches debugger, enables DevTools domains, emulates screen media, calls Page.printToPDF, then detaches debugger.

Errors:
Restricted page, debugger conflict, missing PDF data.

waitForDownloadCompletion()

File: extension/background.js

Purpose:
Waits for Chrome download completion or interruption.

Parameters:
downloadId from chrome.downloads.download().

Returns:
complete, interrupted, or timeout.

Notes:
Uses both downloads.onChanged and polling because generated file downloads can complete before listeners observe a state transition.

prepareCapture()

File: extension/content.js

Purpose:
Applies page-side capture settings before screenshot or native PDF export.

Parameters:
Capture options object.

Side effects:
Freezes animations, hides sticky elements, redacts sensitive fields, suppresses backgrounds, starts keepalive, adds Escape cancel handler.

restoreCapture()

File: extension/content.js

Purpose:
Restores all page mutations made by prepareCapture().

Side effects:
Restores hidden elements, redacted nodes, animation styles, backgrounds, scroll locks, overlays, HUD, and keepalive.

getMetrics()

File: extension/content.js

Purpose:
Computes viewport and page dimensions used by full-page capture.

Returns:
Metrics including viewport dimensions, total dimensions, scroll state, DPR, and scrollability.

beginSelection()

File: extension/content.js

Purpose:
Starts scrollable container selection in auto, rectangle, or element mode.

Returns:
Selection metadata with crop rect and scroll dimensions.

SessionManager

File: extension/lib/core/session.js

Purpose:
Owns offscreen capture session state.

Constructor:
Initializes empty session by calling reset().

Important methods:

Method Purpose
reset(mode) Clears slices and closes bitmaps.
addSlice(slice) Appends an image slice and metadata.
getMetrics() Returns slice count, base dimensions, mode, and DPR.

Side effects:
Closes ImageBitmap resources on reset.

buildExportBlob()

File: extension/lib/core/pdf-builder.js

Purpose:
Builds either PNG/JPEG-style image blob or PDF blob from captured slices and editor edits.

Parameters:
slices, export payload, and sessionGlobal.

Returns:
{ blob, mime }.

Errors:
No captured content, export pixel cap exceeded, PDF generation failure.

buildPdf()

File: extension/lib/core/pdf-builder.js

Purpose:
Builds PDF output in paged, continuous, or detected layout.

Parameters:
Captured slices, export payload, and session state.

Returns:
Object containing PDF buffer and optional debug metrics.

Dependencies:
jsPDF, detectPages(), image stitching helpers, annotation drawing helpers.

detectPages()

File: extension/lib/core/page-detect.js

Purpose:
Detects document-like page rectangles from captured raster slices.

Parameters:
Captured slices and options for profile, dedupe, and max pages.

Returns:
ordered, candidates, pageCount, and candidateCount.

Algorithm:
Downsamples bitmap to max width 320, computes luminance, estimates page/background contrast, segments rows/columns, falls back to borderless detection when needed, and sorts/dedupes candidates.

mergeSettings()

File: extension/lib/utils/common.js

Purpose:
Combines defaults and overrides, then normalizes the result.

Security notes:
Calls deepMerge(), which ignores __proto__, prototype, and constructor.

normalizeSettings()

File: extension/lib/utils/common.js

Purpose:
Allowlists string options, clamps numeric values, normalizes layout flags, and applies defaults.

Returns:
Complete normalized settings object.

CanvasRenderer

File: extension/lib/ui/canvas-renderer.js

Purpose:
Renders editor preview canvas with background image, annotations, active action, crop overlay, and selection overlay.

Important methods:

Method Purpose
init(width, height) Sets canvas dimensions.
setAnnotations(list) Stores annotations and re-renders.
setCropRect(rect) Stores crop rect and re-renders.
updateZoom(zoom) Changes displayed CSS size.
render() Draws the full canvas state.

EditorToolLogic

File: extension/lib/ui/editor-tools.js

Purpose:
Provides geometry and hit-testing logic for annotations and selection handles.

Important methods:

Method Purpose
getCanvasPoint(event, canvas) Converts pointer event to canvas coordinates.
hitTestAnnotation(point, annotation) Tests whether a point hits an annotation.
findAnnotationIndex(point, annotations) Finds top-most annotation at a point.
getSelectionHandle(point, annotation) Detects resize handle hit.

10. Configuration and Environment Variables

No .env file or runtime environment variables are required by application code.

Variable Required Example Purpose Security Notes
EXTENSION_HEADLESS No 1 When set to 1, Playwright extension test launches persistent Chromium with headless: true. Test-only.

Package scripts:

Script Command Purpose
npm test npm run test:syntax Default syntax-only test.
npm run test:syntax node scripts/check-syntax.mjs Checks JS syntax with Node.
npm run test:browser playwright test Runs extension browser harness.
npm run test:ci syntax, audit, browser Local equivalent of CI checks.

Manifest permissions:

Permission Purpose Security Notes
activeTab Temporary active tab access after user action. Avoids broad host permissions.
debugger Native PDF export through Page.printToPDF. Powerful permission; attach/detach tightly.
scripting Inject content.js. Needed for page capture.
storage Store settings and pending capture metadata. Do not store secrets.
downloads Save generated files. Filenames are sanitized.
offscreen Build previews and exports in hidden document. Needed for canvas/blob work.

11. Error Handling and Validation

Validation strategy:

  • Settings are normalized in common.js.
  • Offscreen slice and rectangle payloads are validated in offscreen.js.
  • Export edits are normalized and capped in background.js.
  • Filenames are sanitized in buildFilename() and sanitizeFilename().
  • Content script parses custom selector lists and ignores invalid selector fragments.

Common validation failures:

  • Unknown mode falls back to full.
  • Invalid numeric settings fall back to defaults or are clamped.
  • Invalid offscreen slice data URL throws Invalid slice image data.
  • Missing crop metadata throws Invalid slice crop metadata.
  • Too-large raster export throws an export size error.

Error response format:

  • Internal messages usually return { error: "message" }.
  • Successful messages usually return { ok: true } plus optional fields.
  • There is no HTTP status code layer.

Exception handling approach:

  • background.js wraps capture flow in try/catch/finally.
  • offscreen.js wraps async handlers and returns errors through sendResponse.
  • popup.js and editor.js display user-facing status text.

Known gaps:

  • There is no typed schema library for runtime messages.
  • There is no central error class taxonomy.
  • There is no structured error telemetry.

Suggested improvements:

  • Add a small message schema module for START_CAPTURE, EXPORT_CAPTURE, offscreen messages, and content messages.
  • Add predictable error codes alongside user-facing messages.
  • Add tests for failure states: restricted pages, interrupted download, native debugger conflict.

12. Logging, Monitoring, and Debugging

What is logged:

  • There is no structured runtime logging in source code.
  • Test logs are emitted by npm and Playwright.
  • Extension runtime errors are visible in Chrome extension DevTools.

Where to inspect logs locally:

  • Popup: right-click popup, inspect.
  • Background service worker: chrome://extensions -> Page Capture -> service worker inspect.
  • Editor/offscreen/test pages: inspect extension pages directly.
  • Playwright traces: retained on test failure per playwright.config.js.

Debugging common issues:

Issue Where to look Likely cause
Extension does not load chrome://extensions Wrong folder selected; select extension/, not repo root.
Native PDF fails Background service worker console Restricted page or debugger conflict.
Capture stops midway Popup/HUD/background console DPR change, capture quota, excessive page height.
Export fails Editor status/offscreen console Canvas size or export pixel cap.
Tests fail locally Playwright output Chromium install, extension load, offscreen API availability.

Suggested monitoring metrics:

  • Not visible from provided code.
  • Inferred: useful local metrics would include slice count, total capture height, export duration, PDF page count, download outcome, and memory-related failures.

Health checks:

  • Not visible from provided code.

13. Security Documentation

Authentication risks:

  • No app authentication exists. This is acceptable for a local Chrome extension, but there are no user accounts or identity checks.

Authorization risks:

  • debugger is broad and powerful. The implementation uses it only in native PDF flow and detaches in finally.
  • getTrustedDebugOptions() limits tab override options to extension pages.
  • No <all_urls> permission is present, reducing broad page access.

Input validation risks:

  • Settings normalization is strong for known settings.
  • Full message schema validation is still incomplete. Unknown message types now receive explicit errors in the background service worker, content script, and offscreen document, but payload schemas remain distributed and incomplete.
  • Editor annotations are capped and normalized during export, which limits memory abuse.

Sensitive data exposure:

  • Captures may include sensitive visible page content.
  • Redaction exists but is opt-in and heuristic.
  • Downloads are saved through Chrome downloads API, outside extension control after save.

Secrets management:

  • .env and .env.* are ignored.
  • No hardcoded secrets were visible in provided application code.

Password storage:

  • Not applicable.

Token expiration and refresh:

  • Not applicable.

CORS:

  • No network API calls are made by application code.
  • Not applicable from provided code.

Rate limiting:

  • There is capture throttling around captureVisibleTab.
  • There is no user-level or request-level rate limiting because there is no server.

SQL/NoSQL injection:

  • No database or query layer exists.

XSS/CSRF:

  • No remote HTML is intentionally inserted into extension pages.
  • Extension pages use static HTML and text content.
  • Content script manipulates target pages, but does not render untrusted page HTML into extension UI.

File upload risks:

  • No file upload feature exists.

Dependency risks:

  • Runtime jsPDF is vendored. It should be periodically reviewed and updated.
  • Playwright is dev-only.
  • npm audit --omit=optional is part of CI.

Recommended improvements:

  • Add runtime schemas for all message types.
  • Add tests for malformed message payloads and content-script message edge cases.
  • Add a user-facing warning near native PDF mode explaining debugger use.
  • Add a safer "redaction preview" or default redaction option for sensitive contexts.
  • Add dependency update automation.

14. Testing Documentation

Test framework:

  • Node syntax checker script.
  • Playwright browser tests.
  • Extension-internal test harness in extension/tests/runner.js.

Test files:

  • scripts/check-syntax.mjs
  • tests/browser/extension-runner.spec.js
  • extension/tests/runner.html
  • extension/tests/runner.js
  • extension/tests/e2e-bridge.html
  • extension/tests/e2e-bridge.js

How to run:

npm run test:syntax
npm run test:browser
npm run test:ci

What is covered:

  • JS syntax for non-vendored project JS files.
  • Manifest permissions: required debugger, no optional debugger, no <all_urls>.
  • Settings normalization and prototype pollution guard.
  • Offscreen invalid slice rejection and unknown-message error response.
  • Continuous PDF export single page behavior.
  • PNG export behavior.
  • Detected/manual PDF crop export behavior.
  • High-DPR continuous PDF behavior.
  • Tall continuous PDF scaling behavior.

What is not covered:

  • Real active-tab capture against a normal website.
  • Native Page.printToPDF output text selection.
  • Restricted Chrome pages.
  • Download interruption.
  • Cross-origin iframe behavior.
  • Manual editor interactions through pointer events.
  • Visual regression screenshots.
  • Performance/load behavior on very tall pages.

Test coverage table:

Feature Existing Tests Missing Tests Priority
Settings normalization testSettingsNormalization() UI migration edge cases Medium
Manifest permissions testManifestPermissions() Chrome permission prompt UX Low
Message/offscreen validation Invalid slice and unknown-message tests Full malformed payload matrix and content-script edge cases High
Continuous PDF Several PDF metrics tests Visual/text extraction assertions High
Detected/manual PDF crop Synthetic crop export test Real detected-page fixture coverage Medium
PNG export PNG export test JPEG lossy branch Medium
Native PDF Mode preserved and manifest permission Real Page.printToPDF E2E with text extraction High
Editor Not directly covered Pointer interaction tests High
Scrollable box Not directly covered Auto/rect/element E2E High
Redaction Not directly covered Sensitive input/custom selector capture tests High

Mocking/stubbing strategy:

  • The extension test harness uses real extension APIs where possible.
  • It builds synthetic canvas slices instead of capturing real web pages for most export tests.

15. Build, Run, and Deployment Guide

Prerequisites:

  • Google Chrome or Chromium.
  • Node.js compatible with the project. CI uses Node 22.
  • npm.

Installation:

npm ci
npx playwright install chromium

Local development setup:

  1. Open chrome://extensions.
  2. Enable Developer mode.
  3. Click Load unpacked.
  4. Select the extension/ directory.

Run:

  • The extension runs directly from files in extension/.
  • There is no build step.

Test:

npm run test:syntax
npm run test:browser
npm audit --omit=optional

Production build:

  • Not visible from provided code.
  • Inferred: package the extension/ directory as a Chrome extension zip after excluding dev/test files if desired.

Deployment assumptions:

  • No server deployment.
  • Chrome Web Store packaging/signing workflow is not visible from provided code.

Common setup errors:

Error Cause Fix
Manifest missing/unreadable Loaded repo root instead of extension folder. Load extension/.
debugger optional warning Old manifest cached or invalid manifest version. Reload extension after manifest update.
Browser test fails to launch Playwright Chromium missing. Run npx playwright install chromium.
Extension page cannot access target Restricted page. Test on a normal web page.

16. Dependency Documentation

Dependency Type Used For Location Risks/Notes
Chrome extension APIs Runtime platform Extension UI, service worker, content scripts, downloads, offscreen, native PDF. extension/*.js, manifest.json API behavior differs across Chrome versions.
jsPDF 4.2.1 Vendored runtime Building image-based PDF exports. extension/lib/jspdf.umd.min.js, pdf-builder.js Keep license and update periodically.
Poppins fonts Vendored runtime asset Black/white minimal UI typography. extension/fonts, ui.css Adds package size; no remote font dependency.
@playwright/test 1.59.1 Development only Browser extension test harness. package.json, tests/browser Needs installed Chromium.
Node.js Development only Syntax checker and npm scripts. scripts/check-syntax.mjs CI uses Node 22.

Possible alternatives:

  • Use TypeScript plus a schema validator for stronger message contracts.
  • Use a smaller PDF library only if it supports required PDF layout and image embedding needs.
  • Use Chrome native PDF only for text-PDF mode, as currently done, because image-mode editor exports need raster composition.

17. Design Decisions and Trade-offs

Manifest V3:

  • Chosen by Chrome extension platform requirements.
  • Trade-off: service worker lifetime requires keepalive patterns and session persistence.

No build step:

  • Simpler local development and unpacked loading.
  • Trade-off: no bundler checks, no tree shaking, and vendored assets must be manually maintained.

Offscreen document:

  • Needed for canvas, blobs, and PDF generation outside the service worker.
  • Trade-off: extra message boundary and object URL lifecycle to manage.

Scroll-stitch image capture:

  • Works for rendered pixels and editor annotations.
  • Trade-off: cannot preserve selectable text and is sensitive to sticky elements, animations, lazy loading, DPR changes, and capture quotas.

Native PDF mode:

  • Preserves selectable text where Chrome can print text.
  • Trade-off: requires debugger permission and follows Chrome print behavior rather than exact screenshot pixels.

Settings normalization:

  • Lightweight manual allowlists avoid bringing in a runtime schema dependency.
  • Trade-off: message schemas are still distributed across modules.

Black/white Poppins UI:

  • Provides a minimal visual identity.
  • Trade-off: low color vocabulary requires careful affordance styling for errors and states.

Known technical debt:

  • background.js is still large and combines orchestration, downloads, export validation, and editor lifecycle, though native PDF printing has been moved to native-pdf.js.
  • Message contracts are implicit.
  • Native PDF has limited automated coverage.

18. Extension Guide

Add a New Capture Mode

Expected files:

  • extension/lib/utils/common.js: add mode to ALLOWED.mode and defaults if needed.
  • extension/popup.html: add radio option.
  • extension/form-utils.js: ensure form read/populate supports it.
  • extension/background.js: branch inside startCapture().
  • extension/offscreen.js: allow mode if offscreen uses it.
  • extension/tests/runner.js: add normalization and behavior tests.

Common mistakes:

  • Forgetting to normalize mode.
  • Letting new mode fall through to image capture logic incorrectly.
  • Failing to restore page mutations after errors.

Add a New Export Format

Expected files:

  • extension/lib/utils/common.js: add to ALLOWED.exportFormat.
  • extension/form-utils.js: add form mapping.
  • extension/editor.html: add UI control.
  • extension/lib/core/pdf-builder.js or new export module: implement blob creation.
  • extension/offscreen.js: route export build.
  • extension/tests/runner.js: add export test.

Common mistakes:

  • Returning data URLs instead of object URLs for large files.
  • Forgetting download filename extension.
  • Skipping size limits.

Add a New Editor Tool

Expected files:

  • extension/editor.html: add tool button and controls.
  • extension/editor.js: add tool state, pointer behavior, undo behavior, export annotation data.
  • extension/lib/ui/canvas-renderer.js: draw annotation preview.
  • extension/lib/ui/editor-tools.js: hit testing and selection handles.
  • extension/lib/core/pdf-builder.js: draw annotation in final export.
  • extension/tests/runner.js: add export serialization test if possible.

Common mistakes:

  • Drawing tool in preview but not in export.
  • Forgetting scale conversions between preview and base coordinates.
  • Letting annotations grow unbounded.

Add Message Validation

Expected files:

  • New extension/lib/utils/messages.js or similar.
  • Use it from background.js, content.js, offscreen.js, popup.js, and editor.js.

Common mistakes:

  • Validating only popup messages while editor/offscreen messages remain loose.
  • Rejecting legacy stored settings without migration.

Add Tests

Expected files:

  • extension/tests/runner.js for extension-internal logic.
  • tests/browser/*.spec.js for Playwright browser tests.
  • Potential fixture pages under tests/fixtures or extension test pages.

Common mistakes:

  • Testing only pure functions while skipping extension API flows.
  • Not running tests with extension loaded.

19. Maintenance Notes

Code conventions:

  • Vanilla ES modules.
  • Existing style uses two-space indentation in many UI/background files and four-space indentation in some core utility files. Keep local file style.
  • Prefer small focused helpers over broad rewrites.
  • Avoid remote runtime dependencies because extension runs unpacked with vendored assets.

Naming conventions:

  • Message names use uppercase strings such as START_CAPTURE.
  • Settings use camelCase nested objects.
  • Mode values are lowercase strings: full, box, fullText.

Folder conventions:

  • Core capture/export logic belongs under extension/lib/core.
  • UI-only helper logic belongs under extension/lib/ui.
  • Shared settings/form utilities are top-level extension modules or under lib/utils.
  • Browser tests live under tests/browser.
  • Extension-internal tests live under extension/tests.

Fragile areas:

  • Native PDF sizing and page range logic.
  • Capture scroll overlap/cropping math.
  • DPR stability assumptions.
  • Cross-origin iframe handling.
  • Large canvas/PDF memory usage.
  • Service worker/offscreen lifetime behavior.

Upgrade considerations:

  • jsPDF upgrades need PDF compatibility tests for paged, continuous, detected pages, annotations, and high-DPR output.
  • Chrome API changes can affect offscreen documents and debugger commands.
  • Playwright upgrades can affect extension launch behavior.

Refactoring opportunities:

  • Split remaining background.js responsibilities into capture, download, editor session, and message router modules.
  • Extract shared message validators.
  • Add typed documentation comments or TypeScript gradually.
  • Add automated fixture pages for capture scenarios.

20. Known Limitations and Improvement Roadmap

Current limitations:

  • Native PDF requires debugger permission.
  • Native PDF follows Chrome print behavior, not exact screenshot rendering.
  • Screenshot modes are raster and cannot preserve selectable page text.
  • Redaction is heuristic and opt-in.
  • Very long pages can hit canvas, PDF, memory, or Chrome print limits.
  • Cross-origin iframe content is limited.
  • No production packaging workflow is visible.
  • No structured logging/telemetry.
  • No full runtime schema validation.

Roadmap:

Priority Improvement Reason Suggested Approach
High Add message schema validation Reduces malformed message risk. Central messages.js validators used by all contexts.
High Add native PDF E2E test Current requested behavior depends on Chrome print behavior. Use a local fixture page, export native PDF, verify page count/text.
High Add editor interaction tests Editor is a core user workflow. Playwright pointer tests on extension editor page.
High Add redaction tests Prevents sensitive data leakage regressions. Fixture page with password/token fields and custom selectors.
Medium Continue splitting background.js Native PDF printing is now isolated; downloads, image capture, and editor session logic remain in the service worker. Move download/capture/editor functions to focused modules after adding fixture-based E2E tests.
Medium Add visual regression tests Captures are visual by nature. Use Playwright screenshots for popup/editor and fixture exports.
Medium Add packaging script Reduces release mistakes. Zip curated extension/ files, exclude tests if desired.
Medium Add dependency update process jsPDF is vendored. Document update script/checklist and add release tests.
Low Improve user-facing permission explanation debugger warning can surprise users. Add concise note near native PDF mode.

21. Operational Constraints, Limits, and Scalability

Hard-coded and configuration-based limits:

Constraint Current Value Source in Code Impact Risk Level Suggested Improvement
Max configured slices Default 400, clamp 1 to 1000 extension/lib/utils/common.js DEFAULT_SETTINGS.safety.maxSlices, normalizeSettings() Long pages stop when estimated slices exceed limit. Medium Surface estimated slice count before capture.
Max configured capture height Default 300000, clamp 1000 to 500000 CSS px common.js, background.js enforceSliceLimits() Very long pages fail early. Medium Add per-site presets and clearer UI warning.
Max export pixels Default 120000000, clamp 1000000 to 500000000 common.js, pdf-builder.js enforceExportPixelLimit() Large PNG/JPEG exports are blocked. Medium Estimate export size in editor before export.
Max annotations 500 background.js MAX_EXPORT_ANNOTATIONS Extra annotations are ignored during export normalization. Low Show warning when limit reached.
Max path points 10000 background.js MAX_PATH_POINTS Long freehand paths are truncated. Low Simplify paths as user draws.
Max text annotation length 20000 background.js MAX_TEXT_LENGTH Huge text annotations are truncated. Low Add UI counter or cap input.
Native PDF max dimension 200 inches native-pdf.js MAX_NATIVE_PDF_DIMENSION_IN Very tall/wide native PDF pages may scale or paginate. Medium Add explicit native PDF page count warning.
Native PDF guard band 32 CSS px native-pdf.js NATIVE_PDF_GUARD_BAND_PX Reduces blank trailing page risk. Low Add native PDF regression tests.
Native PDF CSS px per inch 96 native-pdf.js CSS_PX_PER_IN Converts layout metrics to print paper dimensions. Low Keep aligned with Chrome print assumptions.
Capture throttle 200ms min, 1200ms max, 1.5 backoff, 0.92 recover background.js CAPTURE_THROTTLE Slows capture to avoid Chrome quota. Medium Record quota retry metrics.
Download wait timeout 120000ms background.js waitForDownloadCompletion() Long/stuck downloads resolve as timeout. Medium Return timeout-specific UI message.
Offscreen keepalive ping 20000ms offscreen.js Keeps offscreen communication alive. Low Monitor service worker/offscreen lifecycle failures.
Content keepalive ping Not fully visible in summary table; implementation exists in content.js content.js startKeepAlive() Helps long capture sessions. Medium Add tests for long capture lifecycle.
Preview max canvas height 12000 px image-ops.js MAX_CANVAS_HEIGHT Previews are downscaled for very tall captures. Low Display preview scale to user.
Export max canvas height 32767 px image-ops.js MAX_EXPORT_CANVAS_HEIGHT Raster export fails above browser canvas limits. Medium Auto-suggest PDF for large exports.
PDF image max height 2048 px pdf-builder.js MAX_PDF_IMAGE_PX_HEIGHT PDF image chunks are constrained. Medium Document chunking algorithm in code comments.
PDF image max width 3000 px pdf-builder.js MAX_PDF_IMAGE_PX_WIDTH Wide content is chunked/scaled. Medium Add wide-page export tests.
PDF image max pixels 6000000 pdf-builder.js MAX_PDF_IMAGE_PIXELS Controls image chunk size in PDF. Medium Tune with performance tests.
PDF max dimension 14400 pt pdf-builder.js MAX_PDF_DIMENSION_PT Continuous PDF may scale to fit jsPDF/PDF limits. Medium Warn when scaling changes final dimensions.
Document max pages Default 200, clamp 1 to 500 common.js document settings Detected page output is capped. Medium Add UI message when candidate pages exceed cap.
Redact selector length 500 chars common.js normalizeSettings() Long custom selector list is truncated. Low Validate per-selector and show errors.
Filename pattern length 180 chars common.js normalizeSettings() Long filename patterns are truncated. Low Show preview filename.
Object URL revoke delay 60000ms offscreen.js Downloads must start before URL revoked. Medium Revoke after download confirmation when possible.

Unknown or infrastructure limits:

Constraint Current Value Source in Code Impact Risk Level Suggested Improvement
Maximum concurrent users Not visible from provided code No server/infrastructure config Extension runs per browser profile; no shared server concurrency. Low Not applicable unless backend is added.
Maximum requests per second Not visible from provided code No HTTP server No server RPS limit. Chrome capture API quota still applies. Medium Keep capture throttle and add retry metrics.
API payload size limit Not visible from provided code Chrome message APIs used Large messages can fail or affect memory. Medium Prefer object URLs/blob handles over large data URLs.
File upload size limit Not applicable No upload feature None. Low Not needed unless upload/import is added.
Database connection pool Not applicable No database None. Low Not needed unless backend is added.
Memory ceiling Not visible from provided code Browser/runtime dependent Large captures can exhaust renderer/offscreen memory. High Add measured memory/performance tests.
CPU-intensive operations Inferred estimate Canvas stitching, luminance detection, PDF generation Large exports can block extension pages/offscreen. Medium Use chunking and progress reporting.
Long-running operation timeout Partial: download timeout 120000ms; waits configured background.js, common.js Captures may run until user cancels or limits hit. Medium Add global capture timeout setting.
Cache size/TTL Not visible from provided code No cache beyond object URL revoke Memory retained until session reset. Medium Add explicit cleanup on all terminal paths.
Session/token expiration Not applicable No auth None. Low Not needed unless auth added.
Storage limits Not visible from provided code Chrome storage APIs Settings are small; session metadata is small. Low Avoid storing slice data in storage.
Deployment platform limits Not visible from provided code No deployment config beyond CI Chrome extension store constraints unknown. Medium Add packaging/release docs.
Third-party API limits Chrome API dependent Chrome tabs/debugger/downloads APIs Capture quotas and debugger behavior are browser-defined. Medium Test on supported Chrome versions.

Behavior when limits are exceeded:

  • Capture safety limits throw and show popup/HUD error.
  • Export pixel/canvas limits throw and show editor export error.
  • Native PDF dimension cap scales or paginates depending on Chrome print behavior.
  • Download timeout currently resolves to timeout; interrupted downloads throw in caller paths where checked.

Documentation Gaps

  • No automated Chrome Web Store packaging script or store listing files were provided.
  • No production deployment configuration exists because this is a client-only extension.
  • No fixture pages for real capture scenarios were provided.
  • No performance profiles, memory traces, or load tests were provided.
  • No browser compatibility matrix was provided.
  • No user-facing privacy policy or store listing copy was provided.
  • No project license has been selected.
  • No design source files were provided.
  • No typed schemas or generated API documentation are present.

Suggested Next Documentation Tasks

  • Add docs/testing-fixtures.md documenting recommended local pages for sticky headers, lazy images, iframes, long pages, and sensitive fields.
  • Add docs/native-pdf-compatibility.md with Chrome version behavior, page-size limits, selectable text expectations, and known print-layout differences.
  • Add docs/privacy-policy.md or store listing copy before Chrome Web Store submission.
  • Add inline JSDoc to native-pdf.js native PDF helpers and background.js capture orchestration helpers.
  • Add diagrams for editor annotation coordinate conversion and PDF chunking after those modules are split or typed.