2070 Commits
Author SHA1 Message Date
Claude ebe2c36ae3 Fix(auth): offer GitHub sign-in in the installed PWA too
GitHub OAuth apps now take several redirect URIs, with optional
wildcard matching, so the PWA's own auth domain can be registered
there like Google's; the menu no longer hides GitHub when the PWA
signs in through a different domain (signInProvidersFor and the
store getter go). The operator notes name both registrations.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 17:04:44 +00:00
Claude 435d9f6413 Chore: drop dead nav locale keys, one isFireBaseSet, page-bg comment
nav.Title / PingTest / MTRTest / RuleTest had no reader in any locale.
The store takes isFireBaseSet from firebase-init.js instead of
recomputing it in checkFirebaseEnv(). The --page-bg comment no longer
claims index.html's colours must match it; they are tuned separately.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 17:02:50 +00:00
jason5ng32 ae52320d3b Improvements 2026-10-06 00:57:30 +08:00
Claude 96525d2fc7 Chore: trim the branch — leftovers, redundancy, comments
A pass over every file the branch touched, after the iOS animation hunt
left tries and reverts behind it. Removed what nothing reaches: the
view-transition rule for a transition no code starts, an unreachable
guard in the transition hook, a no-op KeepAlive key branch, a sign-in
guard the menu already enforces, usage-dialog wrappers that only
forwarded to the store, a duplicated modifier-click check and card
filter (isPlainClick / listedTools), a test that hand-rolled
listedTools, a drawer-era fixture parameter. auth-flow.js folded into
auth-redirect.js. Comments cut to what the code cannot say itself —
file headers of a few lines, the measured iOS reasons, non-obvious
orderings — and stale ones fixed (Nav under KeepAlive, Home.vue
reusing DEFAULT_META, "from Nav", enabledCards). AGENTS.md sections
tightened to the code as it is now.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 16:50:16 +00:00
Claude 47eca1a4f6 Chore(debug): remove the ?debug=nav overlay
The stall it was built to diagnose is fixed (utils/revive-animations.js);
the overlay, its App.vue gate and the event it listened to go.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 16:39:22 +00:00
Claude a4020442f0 Fix(ui): revive the page's CSS animations after a history step
On iOS, accelerated CSS animations running before a swipe-back stay
visually frozen once the gesture lands on the previous page: the frame
rate, the animations' own time and their iteration events all carry on,
but the compositor paints no new frame for them until their layer is
rebuilt (measured with the ?debug=nav overlay; cancel + play, a
display:none round trip or a re-insert revive them, ancestor style
changes do not). A push revives them as a side effect of its page
transition; a history step, where the browser's gesture replaces our
transition, does not. After every navigation that came from popstate,
utils/revive-animations.js cancels, replays and resets to its time each
running CSS animation, two frames after the DOM lands and again at
400ms and 1200ms in case the gesture snapshot is dismissed late.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 16:27:19 +00:00
Claude 2f27e62d19 Chore(debug): temporary ?debug=nav overlay for the iOS Nav animation stall
The Nav's CSS animations (Pulse's globe and ping) stall on iOS after a
swipe-back into the homepage, with KeepAlive and the page transitions
both ruled out and no WebKit available off the device. ?debug=nav
(kept in localStorage, ?debug=off clears) mounts widgets/NavDebug.vue:
live rAF rate, whether the ping animation's time advances and iterates,
reference CSS animations in a fixed panel and in the page flow, the
Nav's hidden state, a timeline of popstate (with hasUAVisualTransition)
/ route / visibility / focus / touch / scroll events, buttons that try
one candidate remedy at a time, and a Copy button for the log. Removed
once the cause is known.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 16:16:08 +00:00
Claude 563c55c6d8 Style: slide between pages with View Transitions
Route changes animate like native navigation: a tool page slides in
from the right, going home slides it back out, tool to tool cross-fades
— utils/page-transition.js decides the direction from the route pair
and wraps the router's DOM update in document.startViewTransition from
router/index.js, so the snapshot, the swap and the scroll restoration
happen before the animation and pages of different heights never
overlap. Nothing animates on a query-only change, under reduced motion,
on a history step the browser already animated (swipe-back), or in a
browser without the API; a navigation arriving mid-transition skips the
running one. The Nav opts out by view-transition-name and stays put
while the page moves.

Reapplied after the Nav's animation stall on iOS proved unrelated: it
reproduces with the transitions removed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 16:10:07 +00:00
Claude 34d69f8ec9 Fix(pwa): keep the iOS status bar opaque in the installed app
Since iOS 26 the system draws its Liquid Glass scroll-edge blur over
the top of a Home Screen web app whose page runs under the status bar,
which black-translucent asked for, and the blur covered the Nav. With
no apple-mobile-web-app-status-bar-style the status bar stays opaque
system chrome above the web view; the strip Nav.vue painted under a
translucent one goes with it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 16:06:07 +00:00
Claude fd9b042019 Revert(ui): drop the page transitions
Reverts the View Transitions hook-up, its keyframes, the Nav naming
and the two diagnostic follow-ups. On iOS the Nav's own animations
(Pulse's globe and ping) stalled after the forward transition and
stayed stalled after a swipe-back, while a transition back home
restored them — the capture of the fixed Nav is the suspect, and the
clean way to confirm it on the device is to run without any of it.

This reverts commits 2a360f0, d6d80da, 38a61fd, 156d0bf and 856f965.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 16:05:37 +00:00
Claude 2a360f0374 Fix(pwa): keep the status-bar strip hit-testable for iOS's edge blur check
iOS 26+ draws its scroll-edge blur over the top of a Home Screen web app
unless a hit test at the top edge finds a fixed, viewport-wide box with
a plain background colour (WebKit's LocalFrameView::fixedContainerEdges,
which honours pointer-events on its first pass). The safe-area strip is
exactly that box; it no longer opts out of hit testing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 15:58:12 +00:00
Claude d6d80dac24 Chore(ui): device-side switch for page transitions
`?vt=off` turns the View Transitions off, `?vt=unnamed` keeps them but
leaves the Nav un-named (it slides with the page), `?vt=default`
restores the normal behaviour; the choice lives in localStorage. WebKit
cannot run in the sandbox and the Nav's animations stall on iOS after
a transition, so this is how the trigger gets bisected on the device.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 15:58:12 +00:00
Claude 38a61fdf92 Fix(ui): restart the Nav's animations after a page transition
WebKit leaves the accelerated CSS animations inside an element captured
under its own view-transition-name stalled once the transition is over:
after the first page transition Pulse's spinning globe and ping only
repainted in half-second jumps (measured frame by frame on iOS 26), and
a swipe back brought the stalled Nav home. Every transition now ends by
cancelling and replaying the running animations in the named elements
(restartAnimations in utils/page-transition.js), which recreates them
on the compositor.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 15:47:43 +00:00
Claude 1c7e7c68cd Fix(auth): give the installed PWA its own auth domain
VITE_FIREBASE_AUTH_DOMAIN stays the shared sign-in domain every browser
uses; the new optional VITE_FIREBASE_PWA_AUTH_DOMAIN is the domain the
installed PWA initialises Firebase with — the site's own host, served
by the /__/auth proxy, so the redirect handler runs inside the PWA
(utils/auth-domain.js). GitHub's OAuth app has one callback, on the
shared domain, so when the PWA domain differs the account menu offers
Google only. .env.example documents both and the console-side steps.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 15:28:57 +00:00
Claude 156d0bff1b Fix(ui): name the Nav for view transitions only while one runs
A view-transition-name makes an element a captured, separately
rendered group, and WebKit kept the Nav's own animations (Pulse's
spinning globe and ping) janky after an iOS swipe-back with the name
always on. The Nav and the status-bar tint now carry their names only
under html[data-page-transition], which the router hook sets before
the snapshot and clears when the transition finishes, so outside one
the Nav is an ordinary fixed element again.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 15:28:57 +00:00
Claude 856f965101 Style: slide between pages with View Transitions
Route changes animate like native navigation: a tool page slides in
from the right, going home slides it back out, tool to tool cross-fades
— utils/page-transition.js decides the direction from the route pair
and wraps the router's DOM update in document.startViewTransition from
router/index.js, so the snapshot, the swap and the scroll restoration
happen before the animation and pages of different heights never
overlap. Nothing animates on a query-only change, under reduced motion,
on a history step the browser already animated (swipe-back), or in a
browser without the API; a navigation arriving mid-transition skips the
running one. The Nav and the iOS status-bar tint opt out by
view-transition-name and stay put while the page moves.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 15:04:12 +00:00
Claude 1c3a36d253 Fix(auth): serve Firebase's auth handler from the site's own origin
The installed iOS PWA opens an out-of-scope authDomain in the system's
in-app browser view, whose storage the PWA's own webview cannot read,
so a redirect sign-in completed there never reached the app. The
frontend server and the Vite dev server now proxy /__/auth/* to
https://<project>.firebaseapp.com (common/firebase-auth-proxy.js),
mounted only when VITE_FIREBASE_PROJECT_ID is set, so with
VITE_FIREBASE_AUTH_DOMAIN set to the site's host the handler runs
in-scope, inside the PWA itself. .env.example documents the three keys
and the console-side requirements (authorized domain, OAuth callback at
https://<host>/__/auth/handler).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 15:02:01 +00:00
Claude e3eaef369f Fix(ui): one scroll offset for section shortcuts and nav links
The w / d / s / c keys scrolled a section 80px below the viewport top
while the nav links used 70px, so the same section landed at two
different spots. SECTION_SCROLL_OFFSET now lives in utils/scroll-to.js
and every section scroll — nav, breadcrumb, keyboard — uses it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 14:51:26 +00:00
Claude 08473e3e54 Fix(auth): sign in by redirect inside the installed PWA
An iOS standalone PWA has no popup with a usable opener, so
signInWithPopup never delivered its result there: the provider sent
the visitor back to the homepage and the app saw no sign-in. The store
now picks the flow (utils/auth-flow.js): popup in a browser tab, as
before; signInWithRedirect in the installed PWA, and as the fallback
when a popup is blocked. A redirect marks its provider in sessionStorage
(utils/auth-redirect.js) and boot consumes the marker before first
render with getRedirectResult, so the first authenticatedFetch carries
the token like the signed-in boot path. The toast host now shows an
alert raised before mount, which a failed redirect return is.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 14:50:45 +00:00
Claude f0d27fe510 Refactor(nav): one navigation bar on every route, breadcrumb in the page
The homepage sections and the advanced tools are peers, so every route
shows the same Nav, rendered once from App.vue alongside the User and
Preferences hosts. What differs is the click: on the homepage a section
link scrolls; elsewhere it navigates home and then scrolls, re-aiming
while the freshly mounted homepage still resizes; an advanced tool
entry opens /tools/<slug> from anywhere (utils/nav-target.js +
composables/use-nav-target.js). The slim page header, its tools menu
and the body padding switch it needed are gone; open sheets close on a
route change.

Tool pages, /privacy and /r/:id carry a breadcrumb above their title
(PageBreadcrumb.vue): Home steps back in history when the homepage is
the previous entry, Advanced Tools goes home to the cards, the current
page is the last crumb. Cards use an arrow instead of the drawer icon.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 14:43:20 +00:00
Claude 2f5d3b426b Feat(tools): open the Advanced Tools as pages
Every way into a tool — the homepage cards, the nav dropdown and mobile
sheet, the keyboard shortcuts, ASN Info's profile link, the banners —
navigates to /tools/<slug>; the bottom drawer, its full-screen toggle
and the ?tool= query it was driven by are gone from Advanced.vue. The
pages stay alive (App.vue / ToolPage.vue), so browser back and forward
move between tools and the homepage, each restored as it was left.

Legacy /?tool=<slug> links redirect to the page in a router beforeEach
(utils/legacy-tool-link.js: known slug → its page with the remaining
query, unknown → the homepage). Persona Check drops noStandalone: with
the homepage kept alive its dependency commands stay registered, so the
page dispatches them in place and only a direct visit navigates home
first. The four sign-in tools no longer close a drawer before opening
the usage dialog, which PageHeader's User hosts.

Changelog entries in the six full locales; frontend/AGENTS.md describes
the page model.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 14:25:02 +00:00
Claude 728dd7d087 Refactor(nav): shared page header with tools and account menus
The pages outside the homepage (/tools/:slug, /privacy, /r/:id) get one
PageHeader: a back button that steps back in history when the previous
entry is the homepage (restoring the kept-alive page and its scroll) and
pushes / otherwise (utils/back-target.js), the brand, a tools menu
grouped by category (ToolsMenu.vue, over listedTools() in
utils/tool-availability.js) so a tool can be switched without going
home, the current page's title, and the account menu. Below `sm` the
row keeps the back arrow, the title and icon triggers.

The account menu is UserMenu.vue, extracted from Nav.vue, which keeps
its look; the header also hosts User and Preferences so sign-in,
benefits & usage and the preferences sheet work on every page. Each
Preferences instance opens only on the page on screen and closes when
its page is left; My Achievements off the homepage navigates home first.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 14:10:34 +00:00
Claude 44e897a48b Refactor(router): keep the homepage and tool pages alive
App.vue wraps the router view in a KeepAlive holding Home and the tool
page, so leaving for /tools/:slug and coming back neither re-runs the
homepage tests nor loses the scroll position; ToolPage (StandaloneTool
renamed) reads its slug reactively — the same instance now switches tool
on in-app navigation — and caches each visited tool per slug in its own
KeepAlive (max 8), dropping them all when the signed-in account goes
away (utils/tool-cache.js).

Cached pages pause while hidden: composables/use-route-active.js gives
useRouteActive / useActiveValue / useActiveEventListener, and the head
writer, the shortcut map, the scroll trackers, the ?q= watchers of ASN
Profile and IP Calculator, the User dialog triggers and the overlay
counter all act only for the page on screen. An overlay still open when
its page is left closes, as its portal lives outside the cached page.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
2026-10-05 13:56:19 +00:00
Jason Ng 16a5ecd5b5 Merge pull request #499 from jason5ng32/fix/radar-cap-dataset-cron
Improvements
2026-10-05 15:09:39 +08:00
jason5ng32 d8426e6017 Improvements 2026-10-05 15:06:00 +08:00
jason5ng32 bbcc53c518 Improvements 2026-10-05 14:59:24 +08:00
jason5ng32 4840c9ce01 Merge branch 'dev' of https://github.com/jason5ng32/MyIP into dev 2026-10-05 14:52:09 +08:00
Jason Ng 13091bf5b5 Merge pull request #498 from jason5ng32/feat/ip-hitlist
Feat/ip hitlist
2026-10-05 14:49:54 +08:00
jason5ng32 b1875562fc Improvements 2026-10-05 14:43:48 +08:00
jason5ng32andClaude Opus 5.5 1dd10fbd2f Chore: point the asn-input / mac-input comments at the moved bridges
The layout refactor moved the two re-export bridges into utils/ip/ and
utils/features/; their header and test comments still named the old
paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 14:41:22 +08:00
Jason Ng 76833b91f3 Merge pull request #497 from jason5ng32/feat/tool-categories
Feat(tools): group the Advanced Tools cards by category
2026-10-05 14:30:38 +08:00
Jason Ng f6903513dc Merge pull request #496 from jason5ng32/refactor/file-layout
Refactor(layout): split backend-only code out of common/, group front…
2026-10-05 14:24:09 +08:00
Jason Ng a185d1844d Merge pull request #495 from jason5ng32/dev
Sync with Dev
v7.7.0
2026-10-05 14:19:18 +08:00
jason5ng32 fa7ec2108e Improvements 2026-10-05 14:17:38 +08:00
jason5ng32andClaude Opus 5.5 deb7f11468 Feat(tools): add the IP Blocklist Check
A new In-depth Checks tool shows which blocklists an IP is on: the
real-time DNSBLs and the threat intelligence lists the private API's
/iphitlist checks. Listings are split by kind, so a VPN or Tor exit
reads as an anonymity mark rather than a bad record; hits stay open with
their reasons and removal links, the remaining lists fold away, and a
legend explains every mark.

/api/ipblocklist proxies the upstream with the caller's headers and a
30s timeout (a cold DNSBL pass outlasts the default 8s), passing sign-in
and quota rejections through. Signed-in users only, original site only,
150 checks a month (ip_hitlist in the usage dialog and the pre-flight
quota gate). Shift+B opens it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 14:15:21 +08:00
jason5ng32andClaude Opus 5.5 8c02ab3d14 Feat(tools): group the Advanced Tools cards by category
Fifteen cards in one flat grid mixed network diagnostics, lookups and the
in-depth checks that only run on IPCheck.ing. Each registry entry now
carries a category, and Advanced.vue renders the cards under three
headed groups: Network Diagnostics, Lookup & Calculation and In-depth
Checks. A group whose tools all fail their gates drops out with its
heading, so a self-hosted deployment simply shows no In-depth Checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 13:24:32 +08:00
jason5ng32andClaude Opus 5.5 c29e48687b Refactor(layout): split backend-only code out of common/, group frontend utils
common/ had become the backend's library: 30 of its 41 modules were
imported by nothing in the frontend, so the name no longer said what
belonged there. It now holds only what the frontend or the build imports
too; backend-only code moved to server/, flat except for datasets/ (the
dataset engine and its readers). The *-db/ dataset directories stay in
common/: self-hosting docs and Docker volumes mount those paths.

frontend/utils/ keeps its app-wide modules at the root and gains ip/
(IP / ASN shaping and validation), report/ (the report pipeline) and
features/ (the pure layer of a single feature). Paths only — no logic
changes. The Dockerfile copies server/, and the AGENTS.md files say where
a new module goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 13:10:02 +08:00
jason5ng32 ec4d536b60 Improvements 2026-10-05 12:20:03 +08:00
jason5ng32 d0e4023ce4 Cache Improvements 2026-10-05 12:17:18 +08:00
jason5ng32 c0cd8418e3 Improvements 2026-10-05 11:58:32 +08:00
jason5ng32 95f4196c88 Improvements 2026-10-05 11:56:44 +08:00
Jason Ng af45bcee18 Merge pull request #494 from jason5ng32/feat/mac-oui-offline
MAC Lookup from the local IEEE registries, with prefix queries and examples
2026-10-05 11:43:36 +08:00
jason5ng32andClaude Opus 5.5 a1bcc62965 Fix(ui): an empty MAC Lookup submit clears the last answer
Returning early on empty input left the previous result and error on
screen. It now clears them first, and the button stays disabled for a
whitespace-only input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:38:08 +08:00
jason5ng32andClaude Opus 5.5 0b4069b1b2 Fix(datasets): defer, not drop, a watcher check during this process's publish
Skipping a row while this process published it also dropped a change
someone else made in that window: no file moved afterwards, so no later
check came. The watcher now looks again once the publish has recorded its
files, and reloads if they are no longer its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:38:08 +08:00
jason5ng32andClaude Opus 5.5 3072941edc Fix(datasets): never take this process's own publish for a foreign change
The watcher told its own publish apart by the fingerprint reloadRow
records, but that lands only after the reload finishes. A settle tick in
between — the state write and a slow reload outlast the settle window, as
on a loaded CI runner — saw new files under an old fingerprint and reloaded
them a second time as a "file change". Rows being published by this
process are now skipped by the watcher until that reload has recorded them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:32:37 +08:00
jason5ng32andClaude Opus 5.5 d3df177df9 Fix(ui): Enter on an empty MAC Lookup input does nothing
The shared parser rejects an empty string, so Enter in the empty field
showed "Invalid physical address". onSubmit now returns early on empty
input, as IP Calculator does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:29:50 +08:00
jason5ng32andClaude Opus 5.5 87d49cec3d Fix(mac): a Company ID's range is not a randomized address
isRand marked every locally administered unicast address, CID ranges
included. A CID is assigned local space (IEEE 802c ELI), so an address a
registered CID covers is no longer reported as random. For the rest the
U/L bit stays the signal: it is the only mark randomization leaves on an
address, and what the previous provider reported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:29:09 +08:00
jason5ng32andClaude Opus 5.5 000d5b4181 Fix(tests): run the MAC Lookup handler over fixture registries
The success test read the checkout's downloaded registries and fell back
to asserting a 503 without them, so CI never exercised a 200. The handler
now comes from createMacChecker(lookup); the tests pass a fixture lookup
for the 200 and a null one for the 503.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:28:13 +08:00
jason5ng32andClaude Opus 5.5 675ad8967b Fix(mac): trailing country code, cut-short files, multicast range
Three review findings in the IEEE registry reader:
- A country code after the postal code now wins over a state code before
  it ("Dover DE 19901 US" → US), except after NL / IT, whose postcodes are
  followed by letters (Dutch letter pairs, Italian provinces). Over the
  live registries this corrects two addresses and changes no other.
- A registry file that stops mid-row, or inside a quoted field, is refused
  as truncated; IEEE ends every row, the last included, with CRLF.
- A multicast query shows its block's multicast range (01:00:5E:…), which
  holds the address asked about, instead of the unicast registration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:28:13 +08:00
jason5ng32andClaude Opus 5.5 e57b9e331d Feat(mac): prefix queries and example pills in MAC Lookup
The form validates with the shared common/mac-input.js parser, so vendor
prefixes go through. A collapsed "See examples" fold under the input, as in
IP Calculator, holds one pill per kind of answer: full address, vendor
prefix, MA-M block, private registration, multicast and randomized. Browsers
expose no MAC address, so there is no "my address" pill. Changelog entry in
every full locale.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:21:12 +08:00