Skip to content

Release/v0.3.0#7

Merged
Lykhoyda merged 5 commits intomainfrom
release/v0.3.0
Apr 22, 2026
Merged

Release/v0.3.0#7
Lykhoyda merged 5 commits intomainfrom
release/v0.3.0

Conversation

@Lykhoyda
Copy link
Copy Markdown
Owner

No description provided.

## Feature — expandable Recent Activity cards

Clicking a Recent Activity entry in the popup now expands it to show
the data we already had in storage but weren't rendering:

- Full address (copyable via browser selection, mono font)
- Absolute timestamp (formatDate)
- Site hostname (if a URL was recorded)
- Blocked / Allowed status with icon
- Threats list (human-formatted)

Implementation:
- `RecentScan` gains optional `threats`, `url`, `blocked` — the fields
  were already written to storage via `recordScan`; we just widen the
  popup's view of them
- `RecentActivity.tsx`: semantic `<button class="activity-main">` for
  the summary row + sibling `.activity-details` block on expand
- Module-level `expandedKey` signal so the expanded state persists
  across the signal-driven re-renders (and across closing / reopening
  the popup within the same session)
- `expand_more` chevron rotates 180deg via CSS transition

CSS:
- `.activity-item` restructured into summary + details stack
- Focus-visible outline on the clickable row (keyboard a11y)
- Expanded state gets `border-radius: top-only` on summary to
  visually connect with details block

Accessibility:
- Uses `<button>` + `aria-expanded` (no `role="button"` hack)
- Enter/Space naturally toggle via native button semantics

## Release — v0.3.0 bundle

- `manifest.json`: version `0.2.0` -> `0.3.0`; refreshed description
  to reflect broader scope (not just EIP-7702)
- `README.md`: detector count 14 -> 23, test counts to current
  (395 core / 375 extension), added replay-risk + phishing domain
  blocking + proxy resolution rows, architecture section now
  mentions fail-closed decision matrix (ADR-013)
- `store-assets/testudo-extension.zip` repackaged

Tests: 375 extension + 395 core pass. Build + lint clean.
Second-pass visual polish based on user feedback ("font size is very
small") and design-skill review. Aesthetic commitment: precision
security terminal — dense but scannable, color-keyed to risk.

Typography:
- Base 13px UI / 12px mono for values (was 9-11px)
- 10px caps tracked labels (was 9px)
- line-height 1.45 on details block for breathing room

Risk-colored accent rail:
- 2px bar at the top of the expanded block via ::before pseudo-element
- color-keyed via data-risk attribute (danger / warn / safe / dim)
- ties the details to the risk badge above without adding chrome

Status as a health pill, not an icon:
- Pill shape (border-radius 999) with color-bg + border
- Replaced Material icon with 6px dot + 3px halo via color-mix
- Halo always matches the text color (red-on-red for blocked,
  teal-on-teal for allowed) — reads as a health indicator

Threats as terminal chips:
- UPPER_SNAKE_CASE preserved (no re-casing) for log-tag feel
- 10px Geist Mono, warn-palette (bg + border + text)
- flex-wrap row so multi-threat cases flow in the 360px popup width

Other refinements:
- Removed duplicate activity-status-icon rule
- Condensed padding and grid gaps (14/12/16 vs 12/8/8)
- Fixed :focus-visible with accent outline

Files:
- popup.html: ~80 lines of CSS refactored
- RecentActivity.tsx: chip-style threats, dot-based status, data-risk hook
- store-assets/testudo-extension.zip: repackaged

Build + lint clean, 375 tests still pass.
Swaps the README header icon from the rasterized PNG to the vector
SVG source. Renders crisply at any resolution on GitHub (the PNG
was 128x128 and got interpolated on retina).
Adds a tiny dotenv loader to rolldown.config.ts that reads
`packages/extension/.env.local` (gitignored) on build. Explicit env
vars still win — the file only sets keys that aren't already defined.

Developers can now:
  cp .env.local.example .env.local
  # paste API key
  yarn build   # picks it up automatically

Previously every build required exporting TESTUDO_API_KEY in the
shell, otherwise the built SW would log a recurring auth_error from
pingApi() and show the `!` badge.

No new dependency — 25-line parser handles KEY=value, quoted values,
and #comments. `.env*.local` is already in .gitignore.
…sync

Chrome was throwing `Uncaught ReferenceError: Cannot access 'c' before
initialization` inside the injected script, locking the wrapped
window.ethereum.request proxy and causing every analyze/check call to
time out with "TESTUDO_ANALYZE_REQUEST timeout".

Root cause: `const timer = setTimeout(...)` was declared AFTER the
onResponse subscription, but the subscription's callback referenced
`timer` inside `clearTimeout(timer)`. If the response listener fired
synchronously (any sync reply path from content.ts — e.g. the invalid-
address early-return, or cross-world CustomEvent dispatch racing inside
the same tick), the callback hit a TDZ on the uninitialized `const`.

Minified, `timer` became `c`, hence the cryptic error. The stack made
it look like a channel bug, but the channel is fine — the request and
response events are on distinct nonce-scoped names.

Fix: hoist `let timer` above the subscription. Null-check it in the
callback. Classic pattern for mutual-reference closures.

Regression was latent (sync reply paths exist in content.ts for invalid
addresses) but was exposed after S-16 shipped chainId through the
payload — possibly because Chrome's cross-world CustomEvent dispatch
tightened, or because some test-dapp flow now exercises the sync
branch. Fix is TDZ-safe regardless of why sync reply happens.

Tests still 375 passing. Build clean.
@Lykhoyda Lykhoyda merged commit 929dfda into main Apr 22, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant