Reveal URLs — Arhitektūra
Šis dokuments apraksta, kā ir strukturēts Reveal URLs paplašinājums un kā
darbojas tā pamatloģika, līdzstrādniekiem un tehniskiem lasītājiem. Tajā
pastāvīgi ir atsauces uz reāliem failiem un simboliem formā path
symbol, lai katru apgalvojumu varētu pārbaudīt pirmkodā. Lietotājam
paredzētajam aprakstam skatiet manual. Manuālās pārbaudes
soļiem skatiet
manual test plan.
Pārskats
Reveal URLs ir viena MV3 WebExtension, kas tiek veidota Chrome, Edge, Opera,
Firefox un Thunderbird no vienas kopīgas, tīras kodola bāzes. Safari ir
atlikts uz vēlāku posmu: tam ir manifest un to var build-ot, ja tas tiek
norādīts atsevišķi, taču tas nav iekļauts ne noklusētajā build-ā, ne CI.
Paplašinājums atklāj katras saites galamērķa URL blakus pašai saitei
renderētā e-pastā un iezīmē saiti, kuras redzamais teksts nosauc citu
registrable domēnu nekā tas, kurš atrodas tās href.
Repozitorijs ir pnpm un TypeScript monorepo, ko raksturo
pnpm-workspace.yaml un package.json, bet "private": true liedz to
publiskot kā pakotni. Bundling tiek vadīts ar tooling/build.mjs, kas
kompilē kopīgās pakotnes un plānos entry points katram engine ielādējamā
dist/<target>/ direktorijā. webextension-polyfill tiek iepakots katrā
script bundle, nevis atstāts kā runtime global.
Divi native e-pasta papildinājumi paplašina to pašu noteikšanas loģiku uz
virsmām, kuras WebExtension nesasniedz: Outlook Add-in uz Office.js un
Gmail Add-on uz Apps Script CardService. Abi atkārtoti izmanto tikai
PURE analīzi no packages/core/src/findings.ts, ar analyseAnchors,
analyseHtml, neitrālo modeli Finding[], loģiku hostMismatch un
registrable domēna noteikšanu ar tldts. Atšķiras tikai host adapteris un
attēlošana. Outlook izmanto DOMParser un darbojas client-side. Gmail
izmanto node-html-parser un darbojas server-side Google Apps Script V8
infrastruktūrā. Tā kā neviena no šīm platformām neļauj mainīt izlasītā
ziņojuma DOM, abi rāda paneli vai karti ar atradumiem, nevis inline
annotation. linkProcessor.ts DOM-mutation ceļš un REVEAL_URLS_CSS
tur netiek izmantoti. Relatīvs href tiek atrisināts tikai pret uzticamu
<base href> pašā e-pastā un citādi tiek izlaists.
Koda bāze skaidri nošķir atbildības:
packages/coresatur PURE loģiku bez browser APIs, bez storage un bez markup sinks. Tas ir vienīgais patiesības avots saites annotation, config pārbaudei un host salīdzināšanai.packages/webextaptin šo kodolu ar WebExtension APIs, content lifecycle, dynamic registration, options UI un background wiring.extensions/<engine>glabā katra engine plānos entry points un tomanifest.json.toolingglabā build, version-stamping un ikonu skriptus.featuresglabā Cucumber BDD scenārijus un test doubles.
Repozitorija izkārtojums
packages/core — tīrais kodols
Neviens modulis šeit neimportē extension API kā browser.*, chrome.* vai
messenger.*, un neviens neizmanto string-to-markup DOM sinks kā
innerHTML vai insertAdjacentHTML. Šis noteikums tiek mehāniski
nodrošināts ar packages/core/test/purity.test.ts, kas savāc src/**/*.ts,
izņem komentāru saturu ar stripComments un pārbauda, ka ne
EXTENSION_API_PATTERN, ne UNSAFE_DOM_PATTERN nesakrīt ar nevienu moduli.
Publiskā virsma tiek reeksportēta no packages/core/src/index.ts, un vienīgā
runtime atkarība ir tldts.
Galvenie moduļi ir:
packages/core/src/config.ts— shēmasConfigunSiteRule, noklusējuma vērtības un funnelnormaliseConfigpackages/core/src/matchPattern.ts— rakstu gramatika, matcher un specificitātes noteikumipackages/core/src/linkProcessor.ts— annotator dokumenta līmenīpackages/core/src/hostMismatch.ts— registrable domēna neatbilstības pārbaudepackages/core/src/styles.tsunpackages/core/src/contrast.ts— injectable stylesheet un kontrasta loģikapackages/core/src/safeColour.ts— predikātsisSafeColour
packages/webext — browser API ietvari
Šie moduļi DRĪKST izmantot browser.*, un tā ir vienīgā vieta, kur tiek
skartas WebExtension APIs. Publiskā virsma tiek reeksportēta no
packages/webext/src/index.ts. Šeit atrodas content.ts,
contentRegistration.ts, storage.ts, background.ts, toolbarAction.ts,
messageDisplay.ts, messageDisplayBackground.ts un options/options.ts.
extensions/<engine> — plāni ieejas punkti un manifesti
Katrs engine nes savu manifest.json un savu icons/. Chrome, Firefox un
Thunderbird papildus nes src/ direktoriju ar entry points. Edge, Opera un
Safari nes tikai manifestus un ikonas un atkārtoti izmanto Chrome src/.
Piemēram, extensions/chrome/src/content.ts satur tikai
void createContentController().bootstrap();, bet
extensions/chrome/src/background.ts izsauc registerBackground,
registerContentReconciliation un registerToolbarToggle.
extensions/thunderbird/src/background.ts izsauc registerBackground un
registerMessageDisplay. extensions/_template ir scaffold, nevis build target.
tooling, features un smoke testi
tooling ietver build.mjs, version.mjs un icons.mjs. features
ietver Gherkin scenārijus, step definitions un uzticamos doubles failos
features/support/webext.ts un features/support/world.ts. Katram engine ir
arī extensions/<engine>/test/manifest.smoke.test.mjs, bet _template
izmanto template.smoke.test.mjs.
Atklāšanas plūsma
Content ceļš sākas engine entry pointā, piemēram,
extensions/chrome/src/content.ts, kas izsauc
createContentController().bootstrap() no packages/webext/src/content.ts.
Bootstrap
createContentController bootstrap tiek izpildīts reizi katram frame.
Tas iegūst frame savā kontrolē pirms jebkura await ar claimBootstrap,
ielādē config caur loadConfigWithRetry, injicē stylesheet ar
injectStyles tikai pēc veiksmīga lasījuma un atjauno marķieri ar
releaseBootstrap, ja ielāde pilnībā neizdodas. Kad config.enabled ir
ieslēgts, tas izsauc start, bet jebkurā gadījumā reģistrē listeneri
onConfigChanged.
Aktīvās vietnes noteikuma atrisināšana
start un applyConfig izmanto resolveSiteRule, lai izlemtu, vai un kur
veikt annotation. Vispirms tiek pārbaudīta paša dokumenta atrašanās vieta ar
resolveForHref, kas filtrē config.sites līdz ieslēgtajiem noteikumiem un
atstāj izvēli selectMostSpecific ziņā. Ja dokuments nesakrīt un tā izcelsme
ir opaque vai inherited, kā to pārbauda hasOpaqueOrigin, seko fallback ar
readTopHref, readOpenerHref un readReferrer, aizsargāts pret
cross-origin lasījumiem.
Ierobežošana līdz satura saknei un izmaiņu novērošana
start saglabā contentRoot, izveido annotator ar createAnnotator(config)
un apstrādā katru sakni no selectRoots(doc, contentRoot), kas ietin
querySelectorAll try/catch blokā, lai nederīgs selector droši pārvērstos par
[]. Pēc tam tas novēro doc.body ar OBSERVER_OPTIONS.
processMutations filtrē katru izmaiņu pēc root, un processAddedNode
aptver mezglus root iekšienē, pašu root un mezglus, kas to satur.
applyConfig veic teardown, restart vai reflow atkarībā no aktīvā noteikuma
un contentRoot izmaiņām.
Vienas saites marķēšana
Annotator dzīvo failā packages/core/src/linkProcessor.ts.
createAnnotator atgriež Annotator ar Map, data-ru tokenu no
generateToken un aktīvo config. process(root) iztīra atvienotos ierakstus,
savāc a[href] elementus ar collectAnchors, atrisina URL ar
resolveAnnotatableUrl, izmanto fast path isAnnotationIntact, kad renderējums
nav mainījies, un aprēķina mismatch ar hostMismatch, pirms izsaukt
annotateAnchor.
annotateAnchor renderē tikai SAFE-DOM. Režīmā "inline" tas pievieno
<span class="reveal-urls-url"> ar textContent un <br>. Režīmā "title"
tas saglabā esošo title, aizstāj to ar URL un, ja mismatch tiek uzsvērts,
pievieno <span class="reveal-urls-warn"> ar REVEAL_URLS_WARN_LABEL.
Izveidotie mezgli saņem data-ru="<token>", un configFingerprint tiek
izmantots reflow iedarbināšanai. truncateUrl strādā pāri
[...displayHref] un izmanto URL_ELLIPSIS.
Host neatbilstība
packages/core/src/hostMismatch.ts hostMismatch salīdzina saites redzamo
tekstu ar tās href registrable domēna līmenī, nevis pēc neapstrādāta host.
extractHostCandidates sadala tekstu tokenos un samazina tos ar
hostCandidate, kas prasa punktu un tldts atpazītu public suffix.
Href host un kandidāti tiek reducēti ar tldts.getDomain. Ikviens kandidāts
ar atšķirīgu domēnu rada mismatch.
Stili un kontrasts
packages/core/src/styles.ts glabā REVEAL_URLS_CSS un helper-us
applyColour, applyFontOverrides un applyContrastBackdrop.
applyContrastBackdrop nolasa elementa aprēķināto krāsu un pirmo opaque
fonu ar getComputedStyle, pēc tam izmanto needsWhiteBackdrop no
packages/core/src/contrast.ts, lai izlemtu, vai uzlikt
style.backgroundColor = "white". contrast.ts sniedz parseColour,
relativeLuminance un contrastRatio.
Konfigurējami host un satura ierobežošana
SiteRule failā packages/core/src/config.ts nosaka, KUR annotation
darbojas caur match un allFrames, un KURŠ container to ierobežo caur
contentRoot, kopā ar enabled un atzīmi builtin. DEFAULT_SITES
aptver Gmail, Proton ar allFrames un abus Outlook host-us. Config
apvieno globālos toggles, colours, font overrides un sarakstu sites.
Match pattern mehānisms
packages/core/src/matchPattern.ts glabā restrictive gramatiku
MATCH_PATTERN: tikai http un https, izvēles *. wildcard host, glob path,
bez port, bez * scheme un bez <all_urls>. matchesPattern salīdzina URL
ar validētu pattern un deleģē path daļu pathGlobMatches.
parsePatternParts sadala pattern host, path, scheme un wildcardHost.
Kad noteikumi pārklājas, darbojas princips "most specific wins".
compareSiteSpecificity sarindo exact host pirms wildcard host, pēc tam
garāku literal host, pēc tam literalāku path ar literalPathLength, un
beigās ASCII tiebreak. selectMostSpecific atgriež viskonkrētāko ieslēgto
noteikumu, kas atbilst URL.
permissions.getAll() var ziņot grants pilnajā WebExtension gramatikā
(<all_urls>, *://*/*, https://*/*, *://*.host/*, https://host/*),
kurus MATCH_PATTERN noraidītu. parseGrantedOrigin pārvērš tos par
GrantedOriginParts, originCovers pārbauda pārklājumu pāri match, un
matchAllowsOriginFallback ziņo, vai path ir precīzi
ORIGIN_FALLBACK_PATH, tas ir, /*.
Dinamiskā reģistrācija
packages/webext/src/contentRegistration.ts reģistrē vienu dynamic content
script katram lietotāja pievienotam noteikumam. Built-ins tiek apkalpoti ar
static content_scripts entries un nekad netiek reģistrēti dinamiski.
desiredContentScripts filtrē config.sites, izmanto isOriginGranted,
originCovers un contentScriptId, un iestata
matchOriginAsFallback: true tikai tad, ja to atļauj
matchAllowsOriginFallback(rule.match).
reconcileContentScriptsOnce nolasa piešķirtās izcelsmes, saglabāto config
un live registrations un saskaņo tās ar property-aware diff.
sameRegistration normalizē gan vēlamo descriptor, gan live read-back.
Tā kā nav updateContentScripts, izmainīts script tiek noņemts un
reģistrēts no jauna. reconcileContentScripts izmanto inFlight promise,
lai serializētu trigger-us, kas var notikt tuvu viens otram.
Skaidri piešķirtas atļaujas plūsma
Static manifesti deklarē optional_host_permissions
(http://*/*, https://*/*), lai lietotājs runtime laikā varētu piešķirt
atļauju papildu host-am. packages/webext/src/options/options.ts addSite
validē visu kandidāta rule ar normaliseSiteRule, iegūst origin ar
matchOrigin un izsauc browser.permissions.request Add pogas click gesture
iekšienē. Tikai pēc apstiprinājuma tiek pievienota rinda builtin:false.
Config, storage un kanoniskais modelis
Vienīgais validācijas funnel
normaliseConfig failā packages/core/src/config.ts ir vienīgais
kanoniskais lasīšanas ceļš. Tas pārveido un ierobežo katru lauku, atgriežas
pie noklusējuma vērtības nederīgu datu gadījumā un nekad nemet exception.
Tas ir būvēts no validatoriem kā normaliseBoolean, normaliseRenderMode,
normaliseMaxLength, normaliseIgnoreHosts, normaliseMatchColour,
normaliseMismatchColour, normaliseCssSize, normaliseFontWeight,
normaliseContentRoot, normaliseMatchPattern un normaliseSites.
normaliseSites izmet nederīgus entries, noņem dublikātus pēc match,
uzspiež builtin: true pārklājošiem built-in noteikumiem un atjauno trūkstošos built-ins.
Glabāšana
packages/webext/src/storage.ts aptin WebExtension storage API.
configArea izmanto browser.storage.sync, ja tas ir pieejams, un pāriet uz
browser.storage.local, piemēram, Thunderbird. getConfig, setConfig un
onConfigChanged vienmēr laiž vērtības cauri normaliseConfig, tāpēc
bojāts store nekad nevar atdot nederīgu Config. Abas add-on formas izmanto
to pašu funnel virs savām host storage sistēmām.
Kanoniskais config modelis un mērķēti atjauninājumi
Trīs write path lasa kanonisko config, izmaina tieši vienu lietu un raksta to atpakaļ, nesaglabājot nepabeigtus form edits:
removeSitefailāoptions.tsaddSitefailāoptions.tstoggleEnabledfailāoptions.ts
toggleEnabled failā packages/webext/src/toolbarAction.ts seko tam pašam
modelim arī background pusē.
Build pa engine un manifesta līgums
tooling/build.mjs vada vienotu esbuild build katram WebExtension target.
Descriptor TARGETS nosaka SOURCE TARGET katram target. Chrome, Firefox un
Thunderbird ir savs src/. Edge, Opera un Safari izmanto chrome kā avotu.
Outlook add-in ir savs avots. ACTIVE_TARGETS, tas ir, Chrome, Edge,
Firefox, Opera un Thunderbird, ir tie, kas tiek build-oti ar --all un
--package. Safari un Outlook tiek build-oti tikai tad, kad ir skaidri
nosaukti, bet Gmail izmanto make build-gmail.
Gmail bundle mērķē Apps Script V8 runtime, kam nav ne ES modules, ne native
URL. Tādēļ tas tiek build-ots kā ESM, pēc tam no tā tiek noņemts
export {…}, lai trigger funkcijas paliktu globālas. Neliels URL
polyfill tiek iekļauts tikai vajadzības gadījumā. buildTarget iztīra
dist/<target>/, nokopē manifest.json un icons/, iesaiņo scripts kā IIFE,
options lapu kā ESM un nokopē options.html un options.css.
tooling/version.mjs stamp-ē versijas. Tas paņem MAJOR.MINOR no root
package.json, atrod augstāko BUILD number un pievieno to katram
target manifestam. Outlook add-in nes gan manifest.json, gan manifest.xml.
tooling/icons.mjs, kas darbojas ar make icons, rasterises
assets/icon.svg failos icon48.png un icon128.png.
Manifesta līgums ir definēts failos
extensions/<engine>/test/manifest.smoke.test.mjs, kur tiek pārbaudīta katra
manifesta forma un katra referenced file esamība.
Internacionalizācija (i18n)
Reveal URLs ir lokalizēts daudzās valodās līdzās angļu valodai. Vienīgais
šī kopuma avots ir packages/core/src/locales.json, kas satur
SUPPORTED_LOCALES, vietējos nosaukumus un noklusējuma valodu. Katrs
neangļu string ir machine-translated un gaida cilvēka pārskatīšanu.
Izcelsmes marķieris atšķiras pa formātiem: _locales to nes
description, site catalogues to pieraksta site/i18n/README.md, bet
tulkotie docs pirmajā rindā nes HTML komentāru.
Ir trīs neatkarīgas lokalizācijas virsmas:
- The options page (AD-1). Statiskā lapa tiek piegādāta angliski, bet
katrs tulkojamais mezgls nes
data-i18n="<key>"vaidata-i18n-<attr>="<key>". Runtime laikāpackages/webext/src/options/locale.tsielādē_locales/<code>/messages.json, pārraksta tekstu artextContentun iestata<html lang>. - The website chrome (AD-2).
tooling/site.mjsrenderē vietnes chrome angliski ardata-i18nun<html lang="en-GB">. Pēc tamsite/scripts/i18n.mjsto aizvieto ar apmeklētāja valodu nosite/i18n/<code>.json. - The documentation pages (AD-8/AD-9). Dokumentācijas lapas tiek
renderētas katram locale build laikā un izmanto lokalizētus failu nosaukumus
no
packages/core/src/site-page-names.json, piemēram,nl/handleiding.html. - Internal-link localisation (Finding 2). Iekšējās docs saites nes
data-doc-link="<page>", un runtime loader tās pārraksta uz tā paša locale sibling variantu, saglabājot#hashun?query.
“Aktīvo vietņu” slēpšana pasta klientā (AD-3)
Mail client target, piemēram, Thunderbird, jau redz visus rendered messages,
tāpēc host-os balstītais “Active sites” redaktors tur ir lieks. Lēmums tiek
nests ar mailClient: true failā tooling/build.mjs.
- Build-time.
copyAssetspārbaudadescriptorFor(target).mailClientun, ja tas ir aktīvs, noņem<section class="sites">arremoveSitesSection(html). - Runtime.
packages/webext/src/options/options.tspiecieš sekcijas trūkumu, nemetOptionsFieldMissingErrorun atjauno saglabātositesvērtību pirms normalisation.
Drošības un privātuma nostāja
- Bez tīkla pieprasījumiem un bez datu iznešanas. Neviens modulis neveic
fetch,XHRvai citus tīkla izsaukumus. Paplašinājums lasa tikai saglabāto config un lapas DOM. - Tikai SAFE-DOM. Annotation un injicētais stylesheet izmanto tikai
createElement,textContentunstyle.*, nevisinnerHTML,insertAdjacentHTMLvaieval. - Visa ārējā ievade tiek normalizēta. Katrs lasījums un rakstījums iet
cauri
normaliseConfig. Krāsas iet caurisSafeColour, raksti caurMATCH_PATTERN, bet content-root selectors tiek ierobežoti arCONTENT_ROOT_PATTERN. - Minimālas privilēģijas. Iebūvētie webmail origin atrodas
host_permissions. Papildu host-i ir opt-in cauroptional_host_permissionsunpermissions.request. - Datu vākšana Gecko vidē. Firefox un Thunderbird manifesti deklarē
browser_specific_settings.gecko.data_collection_permissions.required: ["none"]. - Licence. Projekts ir AGPL-3.0-only, kā norādīts
LICENSEunpackage.json.
Testēšana
- Vitest unit tests aptver
packages/core/test/*unpackages/webext/test/*. - Cucumber BDD scenāriji dzīvo mapē
features/un izmantofeatures/support/webext.tsunfeatures/support/world.ts. - Per-target manifest smoke tests mapē
extensions/<engine>/test/manifest.smoke.test.mjsizmantonode:testun pārbauda manifestu formu un referenced files. - CI failā
.github/workflows/ci.ymlaptur katru push un pull request, jamake test,make bddunmake lintneiziet. Version-stamping un packaging dzīvo failā.github/workflows/release.yml.