Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
213b444
Merge remote-tracking branch 'origin/main' into dev
hoangsvit Jul 21, 2026
5614201
Merge remote-tracking branch 'origin/main' into dev
hoangsvit Jul 21, 2026
b353f92
fix: align inline helper with WXT environment
hoangsvit Jul 23, 2026
7f54aaf
test: verify production inline helper manifest
hoangsvit Jul 23, 2026
c34f7e8
ci: run checks for pull requests into dev
hoangsvit Jul 23, 2026
9a00ad6
style: format code with Prettier
deepsource-autofix[bot] Jul 23, 2026
7a2c078
fix: avoid console usage in manifest verifier
hoangsvit Jul 23, 2026
e134d88
Merge pull request #77 from ePlus-DEV/agent/fix-inline-popup-producti…
hoangsvit Jul 23, 2026
4ed6cb5
refactor: remove custom WXT development flag
hoangsvit Jul 23, 2026
1a98dac
chore: add one-time WXT environment cleanup
hoangsvit Jul 23, 2026
aff50e8
refactor: use WXT runtime environment directly
eplus-bot Jul 23, 2026
d19795e
test: verify WXT manifest scope by mode
hoangsvit Jul 23, 2026
874a63c
test: verify WXT development and production scopes
hoangsvit Jul 23, 2026
eb8212b
refactor: replace production-only manifest verifier
hoangsvit Jul 23, 2026
d380e3c
chore: no-op placeholder
hoangsvit Jul 23, 2026
f314e5e
chore: remove accidental placeholder
hoangsvit Jul 23, 2026
6604e91
style: format code with Prettier
deepsource-autofix[bot] Jul 23, 2026
ec7471e
chore: align content script with WXT mode
hoangsvit Jul 23, 2026
bfff3c1
fix: make one-time WXT mode replacement format-safe
hoangsvit Jul 23, 2026
cc6a0cf
fix: align content script with WXT build mode
eplus-bot Jul 23, 2026
dec94a3
refactor: centralize WXT mode names
hoangsvit Jul 23, 2026
f2c0085
chore: move content matches to WXT manifest generation
hoangsvit Jul 23, 2026
80ad957
refactor: keep content script matches static
eplus-bot Jul 23, 2026
44c1240
fix: generate inline content scope from WXT mode
hoangsvit Jul 23, 2026
f010e83
style: format code with Prettier
deepsource-autofix[bot] Jul 23, 2026
0166c1d
ci: upload manifest diagnostics on failure
hoangsvit Jul 23, 2026
6537b8e
chore: capture WXT development manifest
hoangsvit Jul 23, 2026
ee06b84
chore: capture generated development manifest
eplus-bot Jul 23, 2026
20be629
fix: select generated manifests by WXT mode
hoangsvit Jul 23, 2026
8e50290
style: format code with Prettier
deepsource-autofix[bot] Jul 23, 2026
13ea6e0
ci: remove temporary manifest diagnostics
hoangsvit Jul 23, 2026
924a3d4
chore: remove temporary manifest capture
hoangsvit Jul 23, 2026
d6f488d
ci: remove development-mode extension build
hoangsvit Jul 23, 2026
f777b10
refactor: initialize manifest verifier options safely
hoangsvit Jul 23, 2026
c8b436b
Merge pull request #79 from ePlus-DEV/agent/cleanup-wxt-environment-c…
hoangsvit Jul 23, 2026
64f1634
fix: reject unexpected development URL patterns
hoangsvit Jul 23, 2026
cbf7e6d
style: format code with Prettier
deepsource-autofix[bot] Jul 23, 2026
6961b9e
Merge pull request #80 from ePlus-DEV/agent/restrict-dev-manifest-all…
hoangsvit Jul 23, 2026
291128c
fix: validate only inline helper manifest scope
hoangsvit Jul 23, 2026
7ea4a2a
test: expose manifest validator for unit coverage
hoangsvit Jul 23, 2026
1410452
style: format code with Prettier
deepsource-autofix[bot] Jul 23, 2026
cbc4b67
test: include Node manifest validator specs
hoangsvit Jul 23, 2026
0c101d5
test: cover manifest scope validation regressions
hoangsvit Jul 23, 2026
3a34dcd
style: format code with Prettier
deepsource-autofix[bot] Jul 23, 2026
ff42dbe
test: share manifest scope constants with specs
hoangsvit Jul 23, 2026
37231c6
test: cover missing and valid production manifests
hoangsvit Jul 23, 2026
9730377
feat: paginate disabled inline sites
hoangsvit Jul 23, 2026
81621a8
feat: add disabled-site filtering
hoangsvit Jul 23, 2026
e83862d
test: cover disabled-site filtering
hoangsvit Jul 23, 2026
beb45d8
chore: set extension version to 1.3.2
hoangsvit Jul 23, 2026
8149632
chore: apply extension changelog update
hoangsvit Jul 23, 2026
40fe714
chore: trigger extension update workflow
hoangsvit Jul 23, 2026
fbe503f
chore: rerun extension update workflow
hoangsvit Jul 23, 2026
b8ca5f5
chore: run extension update from pull request
hoangsvit Jul 23, 2026
2d2deff
chore: apply pending extension UI updates
hoangsvit Jul 23, 2026
6f8931e
fix: make extension update patch indentation-safe
hoangsvit Jul 23, 2026
99a5b32
feat: update changelog and disabled-sites UI
eplus-bot Jul 23, 2026
12f8122
ci: capture failing test output
hoangsvit Jul 23, 2026
ff92cf9
fix: reuse localized alias search label
hoangsvit Jul 23, 2026
928d0e6
ci: restore standard test workflow
hoangsvit Jul 23, 2026
09ebc7f
fix: clarify disabled-site search states
hoangsvit Jul 23, 2026
32c3f0b
refactor: centralize application version metadata
hoangsvit Jul 23, 2026
ade38e7
test: prevent user-facing version hardcoding
hoangsvit Jul 23, 2026
cf60a11
chore: apply automatic version source update
hoangsvit Jul 23, 2026
0c35b8a
refactor: source displayed version from package metadata
eplus-bot Jul 23, 2026
2294c69
chore: capture version test diagnostics
hoangsvit Jul 23, 2026
71dfa36
fix: resolve version test paths from repository root
hoangsvit Jul 23, 2026
fd551dd
chore: restore standard CI workflow
hoangsvit Jul 23, 2026
3874758
docs: make issue version placeholder release-neutral
hoangsvit Jul 23, 2026
e435ec1
feat: resolve web version from latest GitHub release
hoangsvit Jul 23, 2026
588cc18
feat: allow web builds to inject release version
hoangsvit Jul 23, 2026
6554efc
feat: inject latest GitHub release into web build
hoangsvit Jul 23, 2026
76c17bb
test: cover GitHub release version resolution
hoangsvit Jul 23, 2026
83838b1
ci: authenticate GitHub release lookup for Pages
hoangsvit Jul 23, 2026
f2ba703
ci: authenticate release lookup for web previews
hoangsvit Jul 23, 2026
d7a22c2
Refactor code structure for improved readability and maintainability
hoangsvit Jul 24, 2026
94eff46
feat: enhance development manifest validation and add test for runtim…
hoangsvit Jul 24, 2026
31a6fc0
Merge pull request #82 from ePlus-DEV/feat/update-extension-changelog…
hoangsvit Jul 24, 2026
f2e9683
feat: add environment configuration for inline helper and enhance man…
hoangsvit Jul 24, 2026
67c4ec5
feat: update inline helper match patterns and improve URL handling in…
hoangsvit Jul 24, 2026
9584a32
ci: apply CodeRabbit fixes for PR 78
hoangsvit Jul 24, 2026
1801a5f
ci: finalize CodeRabbit fixes for PR 78
hoangsvit Jul 24, 2026
64a91ee
ci: harden PR 78 fix applicator
hoangsvit Jul 24, 2026
9a770d3
Merge 64a91eee98654ee386187a9959af5bea464de9f0 into e134f662443c5e8a0…
hoangsvit Jul 24, 2026
e7f2280
fix: address CodeRabbit release findings
eplus-bot Jul 24, 2026
0c61496
feat: add localized user guide labels
hoangsvit Jul 24, 2026
96789a6
feat: add tracked user guide link
hoangsvit Jul 24, 2026
e156a8a
feat: add localized user guide action to popup header
hoangsvit Jul 24, 2026
c01b230
test: cover localized user guide labels
hoangsvit Jul 24, 2026
73bb4a6
test: cover user guide tab navigation
hoangsvit Jul 24, 2026
527fba0
chore: prepare inline guide link patch
hoangsvit Jul 24, 2026
ef95855
feat: add user guide link to inline popup
github-actions[bot] Jul 24, 2026
c40d80d
fix: guard browser locale resolution for user guide
hoangsvit Jul 24, 2026
bb89f81
fix: handle user guide navigation failures
hoangsvit Jul 24, 2026
7cb836a
fix: handle popup guide navigation errors
hoangsvit Jul 24, 2026
38f72aa
test: cover user guide navigation fallbacks
hoangsvit Jul 24, 2026
9ba3333
test: cover browser locale resolution for user guide
hoangsvit Jul 24, 2026
9c69c7e
chore: prepare inline guide CSS cleanup
hoangsvit Jul 24, 2026
7387184
style: align inline popup guide action
github-actions[bot] Jul 24, 2026
7bf49f4
chore: add one-shot WXT locale migration
hoangsvit Jul 24, 2026
4e471c2
fix: simplify generated locale coverage test
hoangsvit Jul 24, 2026
73ce83a
chore: prepare WXT locale migration trigger
hoangsvit Jul 24, 2026
88f95c9
chore: keep WXT locale migration ready
hoangsvit Jul 24, 2026
99c4c2d
chore: add one-shot WXT locale migration script
hoangsvit Jul 24, 2026
825c707
fix: simplify WXT locale migration workflow
hoangsvit Jul 24, 2026
5b36146
refactor: use WXT locales for user guide labels
github-actions[bot] Jul 24, 2026
0b81a66
test: document WXT locale coverage callbacks
hoangsvit Jul 24, 2026
a4dca27
Merge pull request #85 from ePlus-DEV/feat/add-user-guide-links
hoangsvit Jul 24, 2026
65282dc
feat: add user guide button to Settings and remove from PopupHeader
hoangsvit Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Extra Chrome match patterns for the inline helper in development builds.
#
# Required format: scheme://host/path
# - Use *:// to match both HTTP and HTTPS.
# - Use *. before a domain to include the root domain and its subdomains.
# - End with /* to match every path on the site.
# - Separate multiple patterns with commas or whitespace.
#
# Valid:
# *://*.w3schools.com/*
# https://example.com/*
# http://localhost/*
# http://127.0.0.1/*
#
# Invalid:
# https://www.w3schools.com/ (missing * after the final slash)
# www.w3schools.com (missing scheme and path)
WXT_INLINE_DEV_MATCHES=http://localhost/*,http://127.0.0.1/*,*://*.w3schools.com/*

# Release build configuration for Chrome and Firefox extensions. These values are used by the build scripts to package and submit the extensions to their respective stores. Fill in the appropriate values for your extension.
CHROME_EXTENSION_ID=
CHROME_CLIENT_ID=
CHROME_CLIENT_SECRET=
CHROME_REFRESH_TOKEN=
CHROME_PUBLISH_TARGET="default"
CHROME_SKIP_SUBMIT_REVIEW=false
FIREFOX_EXTENSION_ID=
FIREFOX_JWT_ISSUER=
FIREFOX_JWT_SECRET=
FIREFOX_CHANNEL="listed"
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ body:
id: extension-version
attributes:
label: Extension version
placeholder: "Example: v1.2.0"
placeholder: "Example: vX.Y.Z"

- type: dropdown
id: mode
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CI

on:
push:
branches: [main]
branches: [main, dev]
pull_request:
branches: [main]
branches: [main, dev]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
Expand Down Expand Up @@ -74,8 +74,11 @@ jobs:
- name: Run tests
run: yarn test

- name: Build extension
- name: Build production extension
run: yarn build

- name: Verify production inline helper scope
run: node scripts/verify-manifest-scope.mjs production chrome

- name: Build website
run: yarn workspace gmail-alias-toolkit-web build
2 changes: 2 additions & 0 deletions .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ jobs:
build:
name: Build website
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ github.token }}

steps:
- name: Checkout
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/pr-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ jobs:
name: Build preview site
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest

steps:
- name: Checkout production site
uses: actions/checkout@v7
Expand All @@ -53,6 +52,8 @@ jobs:

- name: Build production site
working-directory: main-site
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
yarn install --immutable --mode=skip-build
yarn exec wxt prepare
Expand Down
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ Run the Firefox development build:
yarn dev:firefox
```

To test the inline helper on additional local or remote sites, copy
`.env.example` to `.env.development.local` and set comma- or whitespace-separated
match patterns:

```dotenv
WXT_INLINE_DEV_MATCHES=http://localhost/*,http://127.0.0.1/*,*://*.w3schools.com/*
```

These patterns are added to the default development sites. Restart the
development server after changing the value. Each entry must use Chrome's
`scheme://host/path` match-pattern format; use `*://*.example.com/*` for a
domain and all its subdomains.

## Build

Build for Chrome:
Expand Down
28 changes: 28 additions & 0 deletions entrypoints/content/email-helper.css
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,36 @@ input.gmail-alias-input-preview::placeholder {
color: #2563eb;
}

.gmail-alias-popup-user-guide {
position: relative;
display: flex;
width: 28px;
height: 28px;
box-sizing: border-box;
align-items: center;
justify-content: center;
padding: 0;
border: 1px solid #bfdbfe;
border-radius: 7px;
background: #eff6ff;
color: #2563eb;
cursor: pointer;
text-decoration: none;
}

.gmail-alias-popup-user-guide:hover,
.gmail-alias-popup-user-guide:focus-visible {
border-color: #93c5fd;
background: #dbeafe;
color: #1d4ed8;
outline: none;
}
.gmail-alias-popup-disable-site {
position: relative;
display: flex;
width: 28px;
height: 28px;
box-sizing: border-box;
align-items: center;
justify-content: center;
padding: 0;
Expand All @@ -284,6 +309,7 @@ input.gmail-alias-input-preview::placeholder {
color: #b91c1c;
}

.gmail-alias-popup-user-guide::after,
.gmail-alias-popup-disable-site::after {
position: absolute;
z-index: 2;
Expand All @@ -310,6 +336,8 @@ input.gmail-alias-input-preview::placeholder {
white-space: normal;
}

.gmail-alias-popup-user-guide:hover::after,
.gmail-alias-popup-user-guide:focus-visible::after,
.gmail-alias-popup-disable-site:hover::after,
.gmail-alias-popup-disable-site:focus-visible::after {
opacity: 1;
Expand Down
51 changes: 40 additions & 11 deletions entrypoints/content/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
parseDisabledInlineSites,
} from "src/utils/inlineSiteSettings";
import { t } from "../../lib/i18n";
import { USER_GUIDE_URL } from "src/utils/externalLinks";
import {
getPreviousAliasForWebsite,
generateSuggestionsForWebsite,
Expand Down Expand Up @@ -39,9 +40,31 @@ interface EmailInputElement extends HTMLInputElement {

let inlineDisabledForCurrentSite = false;

/** Resolves a usable website URL inside regular and about:blank/srcdoc frames. */
function currentPageUrl(): string {
const ancestorOrigins = window.location.ancestorOrigins
? Array.from(window.location.ancestorOrigins)
: [];
const candidates = [
window.location.href,
document.referrer,
...ancestorOrigins.reverse(),
];

return (
candidates.find((candidate) => normalizeHostname(candidate) !== null) ||
window.location.href
);
}

/** Gets the normalized hostname for the current site. */
const currentSiteHostname = () =>
normalizeSiteHostname(window.location.hostname);
function currentSiteHostname(): string {
try {
return normalizeSiteHostname(new URL(currentPageUrl()).hostname);
} catch {
return normalizeSiteHostname(window.location.hostname);
}
}

/** Removes all inline helper icons and popups from the page. */
function removeInlineHelpers() {
Expand Down Expand Up @@ -120,7 +143,8 @@ function resolveActiveEmail(accountData: StoredAccountData): string {

/** Fetch suggestion data for current page. */
async function fetchSuggestions(): Promise<SuggestionData | null> {
const normalized = normalizeHostname(window.location.href);
const pageUrl = currentPageUrl();
const normalized = normalizeHostname(pageUrl);
if (!normalized) return null;

let email: string | null = null;
Expand All @@ -136,8 +160,8 @@ async function fetchSuggestions(): Promise<SuggestionData | null> {
}

const [previousResult, suggestionsResult] = await Promise.allSettled([
getPreviousAliasForWebsite(email, window.location.href),
generateSuggestionsForWebsite(email, window.location.href),
getPreviousAliasForWebsite(email, pageUrl),
generateSuggestionsForWebsite(email, pageUrl),
]);

return {
Expand Down Expand Up @@ -217,12 +241,20 @@ function createPopup(
nextPage: escapeHtml(t("nextPage")),
disableInlineForSite: escapeHtml(t("disableInlineForSite")),
extensionName: escapeHtml(t("extensionName")),
userGuide: escapeHtml(t("userGuide")),
reportReview: escapeHtml(t("reportReview")),
};
popup.innerHTML = `
<div class="gmail-alias-popup-header" style="display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border-bottom: 1px solid #e5e7eb; background: #f9fafb; border-radius: 8px 8px 0 0;">
<span class="gmail-alias-popup-title" title="${safeWebsite}" style="font-weight: 600; font-size: 13px; color: #374151;">${labels.extensionName}</span>
<div class="gmail-alias-popup-header-actions" style="display: flex; align-items: center; gap: 6px;">
<a class="gmail-alias-popup-user-guide" href="${USER_GUIDE_URL}" target="_blank" rel="noopener noreferrer" data-tooltip="${labels.userGuide}" aria-label="${labels.userGuide}">
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10" />
<path d="M9.1 9a3 3 0 1 1 5.83 1c0 2-3 2-3 4" />
<path d="M12 18h.01" />
</svg>
</a>
<button class="gmail-alias-popup-disable-site" type="button" data-tooltip="${labels.disableInlineForSite}" aria-label="${labels.disableInlineForSite}">
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12Z" />
Expand Down Expand Up @@ -1580,13 +1612,10 @@ function observeDOM() {
return observer;
}

const DEV_SITES = ["*://*.miro.com/*", "*://selfh.st/*", "*://gumroad.com/*"];

// @ts-expect-error __DEV_MODE__ injected by Vite at build time
const contentScriptMatches = __DEV_MODE__ ? DEV_SITES : ["<all_urls>"];

export default defineContentScript({
matches: contentScriptMatches,
matches: ["<all_urls>"],
// Keep the helper in the top document so third-party embedded frames
// cannot receive alias suggestions or extension UI.
async main() {
const disabledSitesResult = await browser.storage.local.get(
INLINE_DISABLED_SITES_KEY,
Expand Down
Loading