Changelog
All notable changes to the Network Patch Mapper project will be documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
[Unreleased]
[2026-09-03]
Fixed
- MDX build compatibility — Kept the
@astrojs/mdx8.0.0 upgrade on the current Astro dependency set and added a Vite alias for Astro 7.3.0's missingastro/_internal/loggerexport, while still using the compatible bundled@astrojs/markdown-satteriversion needed to build.mdxpages.
[2026-09-01]
Changed
- Dependencies — Updated all pnpm dependencies including
better-auth(1.6.26 → 1.7.1),@awesome.me/webawesome-pro(3.11.0 → 3.12.0),nanostores(1.4.2 → 1.5.2),wrangler(4.120.0 → 4.125.0),astro(7.2.0 → 7.2.4), and various other patch and minor updates.
Added
- DB migration
0005_account_issuer.sql— Adds theissuercolumn to theaccounttable required by Better Auth 1.7. Backfills all existing credential (email/password) accounts withissuer = 'local:credential'. Better Auth 1.7 scopes account identity by a trusted issuer field; without this migration, existing users would be unable to sign in.
[2026-08-25]
Changed
- 2FA code input — Replaced plain
<input>elements inTwoFactorVerifyModal(both TOTP and backup codes) andTwoFactorSetupModal(step 4 verify code) with the<wa-otp-input>Web Awesome component. Backup codes useformat="#####-#####"withtype="alphanumeric"for a segmented entry experience. Also fixed backup code verification to calltwoFactor.verifyBackupCodeinstead ofverifyTotp.
Fixed
- 2FA modal layout — Backup code
<wa-otp-input>now usessize="xs"with explicit--segment-size: 2emand--segment-gap: 0.2emCSS variables, and::part(segments)setsoverflow: visibleto prevent the last segment from being clipped. - 2FA OTP input style — Added
wa-otp-inputCSS::part()styling toglobal.cssso the OTP segments match the site'swa-inputappearance: consistent borders, backgrounds, rounded corners, focus rings, and dark mode variants. - 2FA verify button — Fixed OTP input state tracking by using stable ref callbacks with
wa-complete,wa-clear, andinputevents, ensuring the Verify button reliably enables once all segments are filled. - Backup code verification — Removed
case="upper"from the backup code OTP input (Better Auth generates mixed-case codes). Also reinserts the dash separator before submission sincewa-otp-inputstrips separators from itsvalueproperty.
[2026-07-20]
Fixed
- CSP inline script hash — Added new Astro 7.1.1-generated inline script hash (
sha256-Ya0pUYrC7nM5Cn/056TyVuEiz6dFGrzmkWzgON0pF0U=) to thescript-srcdirective insrc/utils/csp.tsto resolve a Content-Security-Policy violation introduced by the Astro 7.0.7 → 7.1.1 update.
[2026-07-13]
Fixed
2FA sign-in 500 error — Added
failedVerificationCountandlockedUntilcolumns to thetwoFactordatabase table (migrations/0004_twofactor_lockout.sql). Better Auth's twoFactor plugin now uses these columns for account lockout protection (tracking consecutive failed TOTP attempts). Without them, every correct TOTP code during sign-in resulted in a 500 error because Better Auth tried toUPDATE twoFactor SET failedVerificationCount = 0after successful verification. Also updatedmigrations/0000_full_schema.sqlfor new installations.CSP inline script hashes — Added two new Astro-generated inline script hashes (
sha256-gV+0WW9V47UqmHoPAWTBo5ix/7APsHNqp+G5zHlvj9w=andsha256-JAnFZ+le3YgxnIcqb+wLBW0bqsS57bLsa2bmAoVFQgs=) to thescript-srcdirective insrc/utils/csp.tsto resolve Content-Security-Policy violations that were blocking scripts on the sign-in page.
[2026-06-23]
Changed
Dependencies — Upgraded core framework and tooling packages in
package.json, including Astro 7 (astro,@astrojs/cloudflare,@astrojs/mdx,@astrojs/react) and related dependency updates (@cloudflare/workers-types,@xyflow/react,@typescript-eslint/eslint-plugin,@typescript-eslint/parser,globals).Documentation tech versions — Refreshed
README.md,agents.md, and.github/copilot-instructions.mdto match the current stack and tooling versions, including Astro 7, Better Auth 1.6, Web Awesome Pro 3.9, React Flow 12.11, and the current ESLint plugin versions.
[2026-06-11]
Fixed
- CI workflow pnpm auth and action versions — Updated
.github/workflows/copilot-setup-steps.yml,.github/workflows/eslint-check.yml,.github/workflows/format-check.yml,.github/workflows/release.yml, and.github/workflows/commit-lint.ymlto avoid pnpm 10.34.2 repository.npmrcvariable expansion breakage by settingWEBAWESOME_NPM_TOKENat job level and writing WebAwesome auth to~/.npmrcbeforepnpm/action-setup. Also corrected invalid action versions (actions/checkout@v6/actions/setup-node@v6→@v4) and standardized setup order to checkout → auth config → pnpm setup (v4, version10) → node setup → install.
[2026-05-26]
Fixed
- CSP inline script hash — Added Astro-generated inline script hash
sha256-SaCkFfPruIdTXT8/97JArQmGxiJAL2o4bBDvSgJ5y3Q=toscript-srcinsrc/utils/csp.tsto resolve runtime Content-Security-Policy violations after dependency updates. Also updatedtests/security/xss.test.tshash assertions to include the latest Astro runtime hashes.
[2026-05-01]
Changed
- Web Awesome size values updated — Migrated all WA component
sizeattributes from the deprecatedsmall/medium/largevalues to the news/m/lshorthand introduced in Web Awesome 3.6. Updatedwa-button,wa-input,wa-number-input,wa-textarea,wa-switch,wa-color-picker, andwa-selectTypeScript type definitions insrc/types/web-awesome.d.tsto include the full set of sizes (xs,s,m,l,xl) alongside the deprecated aliases for backwards compatibility.
[2026-04-27]
Fixed
- CSP script-src hash for Astro 6.1.9 — Added missing inline script hash
sha256-BrDhGE1lwa85arfXcrBxSo+n37uVSX5CAROXnIM6Q+g=to thescript-srcdirective insrc/utils/csp.ts. The hash was introduced by the Astro 6.1.9 dependency update and was blocking a framework-generated inline script at runtime.
[2026-04-21]
Fixed
- ESLint
react-hooks/immutabilityerrors —eslint-plugin-react-hooksv7.1.1 introduced a newreact-hooks/immutabilityrule that flags functions accessed in hooks before they are declared. MovedloadUsersinAdminPanel.tsxandhandleTouchEndin bothCabinet.tsxandCabinetList.tsxto be declared before theuseEffecthooks that reference them.
[2026-04-15]
Fixed
- 2FA TOTP verification 500 error — Added the missing
verifiedcolumn to thetwoFactortable across all migrations. Better Auth'stwoFactorplugin requires this column to track whether a user has completed the TOTP setup step. Without it, every correct TOTP code during sign-in triggered a failedUPDATE twoFactor SET verified = true, causing a 500 with a blank response body (shown in the UI as "Invalid verification code"). Incorrect codes still returned the expected 401 "Invalid code" error from Better Auth. Three changes were made: new migration0003_twofactor_verified.sql(ALTER TABLE … ADD COLUMN) for existing databases, and theCREATE TABLE "twoFactor"statement updated in both0000_full_schema.sqland0002_admin_and_2fa.sqlfor new installations. The column defaults to1(true) to keep existing 2FA-enabled users verified.
[2026-04-07]
Added
- FontAwesome icons hosted locally — SVG files are now served from
public/assets/fontawesome/svgs/and loaded via Web Awesome'ssetIconPath()API, eliminating the dependency on the FontAwesome CDN (ka-f.fontawesome.com,ka-p.fontawesome.com).
Changed
- CSP — Removed
ka-f.fontawesome.comandka-p.fontawesome.comfromstyle-src,img-src,font-src, andconnect-srcdirectives insrc/utils/csp.tssince FontAwesome icons are now self-hosted. - CSP dev mode — CSP is now disabled in Vite dev mode (
import.meta.env.DEV) in bothsrc/middleware.tsandsrc/layouts/Layout.astro. Vite's HMR injects inline scripts without nonces that are blocked by the strict CSP, making the dev server unusable. CSP continues to be enforced in production builds. - Web Awesome — Updated to version 3.5.0.
Fixed
- React hydration mismatch —
MainContentnow deferslineVisibilityandviewModestore values until after mount. Both stores read fromlocalStoragesynchronously on the client, causing attribute mismatches (e.g.,variant="primary"vs"neutral"on the lines-visibility button, or flow view vs devices view being rendered) between the server render and the first client render. Matches the mounted-guard pattern already in use byHeaderandNetworkFlowVisualization. - React hydration mismatch (Web Awesome elements) — Added
suppressHydrationWarningto all<wa-icon>and<wa-button>elements in.tsxcomponents. Web Awesome custom elements add default DOM attributes (aria-hidden,library,rotate,style,appearance,size) via theirconnectedCallbackwhen they register, which races with React 18's concurrent hydration scheduler and causes mismatch warnings. UsingsuppressHydrationWarningtells React to skip attribute-level reconciliation on these elements; Web Awesome manages those attributes independently through its own Lit-based reactivity.
[2026-04-02]
Fixed
- CSP inline script hash — Added new Astro-generated inline script hash (
sha256-0I5yW+89TVLK5fxhuiluTUWRJwOp6LyBLVWznCz2+o0=) to thescript-srcCSP directive insrc/utils/csp.ts, resolving Content-Security-Policy violations for a newly emitted Astro inline script. picomatchReDoS vulnerabilities — Updated the pnpmpicomatchoverride from>=2.3.2to>=4.0.4to force all transitive resolutions (both 2.x and 4.x dependents) to the patched 4.0.4 release, resolving CVE-2026-33671 (High) and CVE-2026-33672 (Medium). picomatch 4.x is API-compatible with 2.x; the build and all tests continue to pass with only 4.0.4 in the dependency tree.
[2026-03-26]
Changed
SiteSelector- Migrated site creation from manualkeydown+setTimeoutworkaround to nativeallow-createattribute andwa-createevent on<wa-combobox>(requires Web Awesome Pro 3.4.0+)
Fixed
SiteSelector- Combobox input text is now cleared when the selected site is deleted, preventing stale site name from remaining in the input field
[2026-03-16]
Fixed
- CSP inline script hash — Added new Astro-generated inline script hash (
sha256-HpArP2A4Z5FQRezY979kSGc2G+bnDQ8kqb67BHTEJtU=) to thescript-srcCSP directive insrc/utils/csp.ts, resolving Content-Security-Policy violations and the resulting React hydration error (#418) that appeared after the latest dependency update. /api/data500 resilience — Replaced the module-levelResponseconstant insrc/pages/api/data/index.tswith a factory function (dbNotConfigured()) so each request gets a freshResponseobject, avoiding potential body-stream locking issues in the Cloudflare Workers workerd runtime when the DB binding is unavailable.loadDataFromServererror handling — Refactoredsrc/stores/authStore.tsto checkresponse.okbefore attempting to parse the JSON body. Error responses now use a nested try/catch so an empty or non-JSON body (e.g. a bare 500 from a Worker crash) produces a clear"Server error 500"message instead of a confusingSyntaxError.- Cloudflare Turnstile hydration mismatch (login & contact pages) — The SSR stub for
@marsidev/react-turnstilereturnsnull, but the real component renders a<div>on its very first client render. React 19's stricter hydration detected this server/client mismatch (error #418) on both the/loginand/contactpages, corrupting the React component tree just as Turnstile was initialising and causing Turnstile error 600010. Turnstile's 8-second auto-retry then produced the "eventually succeeds after waiting" behaviour. Fixed inAuthForm.tsx(addedmountedstate) andContactForm.tsx(reused existingisMountedstate and removed the "Loading…" early-return) so that the Turnstile widget is only rendered after React hydration has completed — the first client render now matches the SSR output and error #418 is eliminated. Also addedsetError('')tohandleTurnstileSuccessin both components so any error message set during a failed auto-retry is cleared when the challenge eventually succeeds. - Turnstile transient error UX (login & contact pages) — After the hydration fix, Cloudflare's challenge can still transiently fail (emitting
DOMException: An exception was thrownfromapi.jsin the browser console, corresponding to error 600010). The oldhandleTurnstileErrorcalledsetError('Verification failed. Please try again.'), which showed a misleading permanent-looking red banner while Turnstile was already silently auto-retrying every 8 s, then the banner disappeared on its own when the retry succeeded — confusing UX.handleTurnstileErrorin bothAuthForm.tsxandContactForm.tsxnow only resetsturnstileTokento null (keeping the submit button disabled as expected feedback). The Turnstile widget renders its own retry/error visual state; no separate form-level error banner is needed for transient challenge failures. TheFeature Policy: Skipping unsupported feature name "cross-origin-isolated"console warning is emitted by Cloudflare's ownapi.jsand is not actionable from application code. - Turnstile PAT challenge fallback delay (login & contact pages) — On Firefox and Chrome, Cloudflare Turnstile attempts a Private Access Token (PAT) challenge on load. Because those browsers don't implement Apple's PAT attestation protocol, the challenge immediately returns HTTP 401. Turnstile then waits for
retryIntervalmilliseconds before falling back to the visual/interactive challenge. The defaultretryIntervalis 8000 ms, so the widget appeared to hang for up to 8 seconds — perceived by users as "intermittent" functioning. ReducedretryIntervalto 2000 ms in bothAuthForm.tsxandContactForm.tsxso the fallback to the visual challenge is nearly immediate. Also added consistenttheme: 'auto'toContactForm.tsx's Turnstile widget (it previously passed nooptionsat all). - Turnstile iframe feature permissions (login & contact pages) — Added a
Permissions-PolicyHTTP response header insrc/middleware.tsthat explicitly allows the Cloudflare challenge iframe to useautoplayandkeyboard-mapbrowser features. Without this, strict Firefox configurations (Enhanced Tracking Protection enabled) can silently block those features for cross-origin iframes, causing intermittent challenge failures. Thecross-origin-isolatedfeature name seen in the browser console is a COOP/COEP concept, not aPermissions-Policydirective, and is intentionally excluded.
Changed
astro.config.mjscomment — Updated the explanation for whysecurity.csp(Astro v6's stable CSP API, formerlyexperimental.cspin v5) is not used. The root cause is that Astro's build pipeline always hashesISLAND_STYLESintostyle-srcwhen a renderer (React) is present; per the CSP spec this makes browsers ignore'unsafe-inline', which is required for React and Web Awesome inlinestyle=""attributes. The manual CSP implementation insrc/utils/csp.tsremains the correct approach.
[2026-03-12]
Added
pnpm deployscript — Addeddeploynpm script (astro build && wrangler deploy --config dist/server/wrangler.json) topackage.jsonso deployment uses the adapter-generated Wrangler config (which includes the correctmainentrypoint). This replaces the manualpnpm build && pnpm exec wrangler deployworkflow and avoids the missing-entrypoint issue when runningwranglerwith the rootwrangler.jsonc.
Changed
- commitlint: Added
"Changes before error encountered"to the ignored commit message list alongside"Initial plan", allowing coding agents to use this as a checkpoint commit message when they encounter errors mid-work. - Docs: Updated
README.md,agents.md, and.github/copilot-instructions.mdto reflect the current Astro 6.x tech stack, the removal ofAstro.locals.runtime.envin favour ofimport { env } from "cloudflare:workers", the updatedpnpm previewcommand, Web Awesome Pro v3.3.1, and the presence of Vitest for tests.
Fixed
- Unhandled rejection in
waitUntilemail send — WrappedemailPromisepassed towaitUntilwith.catch()insrc/pages/api/contact.tsso rejections from background email sends are caught and logged rather than becoming unhandled promise rejections. - Build failure after
@astrojs/cloudflarev13 upgrade — Removed the"main"field fromwrangler.jsonc.@astrojs/cloudflarev13 uses@cloudflare/vite-plugininternally, which validates that themainfield points to an existing file before building;dist/_worker.js/index.jsis a build artifact that doesn't exist yet. In v13 the adapter manages the entrypoint automatically. - Changelog page empty after
@astrojs/cloudflarev13 upgrade — Changedsrc/pages/changelog.astroto use Vite's?rawimport query instead ofreadFileSync. The v13 adapter prerenders via aworkerd-based environment whereprocess.cwd()returns/, not the project root, causing the file read to fail. wrangler deventrypoint after@astrojs/cloudflarev13 upgrade — Updated thepreviewscript to use the generateddist/server/wrangler.json(wrangler dev --config dist/server/wrangler.json) and updatedassets.directoryinwrangler.jsoncto./dist/clientto match the v13 adapter output structure.Astro.locals.runtime.envremoved in@astrojs/cloudflarev13 — Migrated all usages of the removedAstro.locals.runtime.envAPI toimport { env } from "cloudflare:workers"as required by Cloudflare adapter v13. Updatedsrc/middleware.ts,src/pages/api/auth/[...all].ts,src/pages/api/data/index.ts,src/pages/api/send-password-reset-email.ts,src/pages/api/contact.ts. Also updatedsrc/env.d.tsto extendCloudflare.Envfor correct typing and removed the generic parameter fromRuntime(no longer accepted in v13).[object Object]on login and contact pages after v13 upgrade —import { env } from "cloudflare:workers"does not resolve correctly in.astropage frontmatter (only in.tsmodules). ThePUBLIC_TURNSTILE_SITE_KEYis now read in the middleware (which is a.tsmodule wherecloudflare:workersworks) and forwarded to pages viaAstro.locals.turnstileSiteKey, matching the same pattern used fornonceandcsp.- Dev server 500 /
[object Object]on login and contact after v13 upgrade —import { env } from 'cloudflare:workers'insrc/middleware.tscaused Vite's SSR dep optimizer to pre-bundleastro/virtual-modules/middleware.jsand produce a cached file that no longer existed on disk, resulting in a 500 on every route inpnpm dev. Fixed by addingcloudflare:workerstovite.optimizeDeps.excludeinastro.config.mjsso Vite treats it as a virtual module rather than bundling it. - "Invalid hook call" React errors in dev server after v13 upgrade — Static
import { Resend } from 'resend'insrc/pages/api/contact.ts(and transitively viaemail.ts) caused Vite's SSR dep optimizer to discoverresendlazily during the first request, triggering a module-runner reload that briefly created two React copies. Fixed by makingcreateResendClientinsrc/lib/email.tsuse a dynamicimport('resend')soresendis never part of the static SSR module graph. waitUntilTypeError after@astrojs/cloudflarev13 upgrade — FixedTypeError: Cannot read properties of undefined (reading 'waitUntil')in the auth and contact API endpoints. In v13,locals.runtime.cfContextis no longer populated at runtime; the execution context'swaitUntilmust now be imported directly viaimport { waitUntil } from "cloudflare:workers". Updatedsrc/pages/api/auth/[...all].tsandsrc/pages/api/contact.ts.[object Object]rendering on SSR pages in workerd runtime — Middleware was constructingnew Response(response.body, { headers: newHeaders })to inject CSP header, but in workerd,response.bodyon streaming SSR responses returns a lockedReadableStream, causing workerd to stringify it to[object Object]. Fixed by usingcontext.response.headers.set()to set the CSP header before callingnext()instead of creating a new Response object. Added conditional check forcontext.responseexistence to handle both SSR requests (where it exists) and prerendering (where it doesn't). This follows the documented Astro pattern for setting response headers in middleware.[object Object]on login and contact pages in Cloudflare Workers (workerd) —@marsidev/react-turnstile(used only on login and contact pages) was bundled into the SSR worker chunk (index_CPUld9CQ.mjs) by Astro 6's Cloudflare adapter, which bundles all imports into a single worker file including browser-only packages. The package referencesdocument,window, andMutationObserverin function bodies that workerd evaluates at module-init time, crashing the worker for those routes. Fixed by adding@marsidev/react-turnstileto thessrBrowserOnlyStubVite plugin inastro.config.mjs, which replaces the package with a no-opTurnstilecomponent (return null) during SSR — matching the existing pattern for Web Awesome components. The real Turnstile widget continues to load from the client bundle after hydration.[object Object]body on all SSR pages in workerd (nodejs_process_v2) — Thenodejs_compatcompatibility flag combined with a compatibility date of2025-11-26activates the Node.js process v2 shim in workerd, which breaks SSR response body streaming and causes the entire page body to be serialized as[object Object]. Fixed by addingdisable_nodejs_process_v2tocompatibility_flagsinwrangler.jsonc, reverting to the v1 process shim that does not exhibit this behavior.
[2026-03-11]
Added
- CSP hash regression tests — Added a Vitest security test (
tests/security/xss.test.ts) that asserts every expected Astro 6 inline script hash is present in thescript-srcCSP directive, so future Astro upgrades will surface CSP breakage at test time rather than silently in production.
Fixed
- CSP inline script hashes — Added new Astro 6 inline script hashes (
globalThis.processinitialiser and Astro islands runtime) to thescript-srcCSP directive insrc/utils/csp.ts, resolving Content-Security-Policy violations that blocked page functionality after the Astro 5 → 6 upgrade. - Cloudflare Workers deploy crash — Removed static
importofspinner.jsfromLayout.astro's<script>block and consolidated the SSR stub into a singlessrBrowserOnlyStubVite plugin inastro.config.mjsthat stubs three categories of SSR-incompatible imports: (1) all@awesome.me/webawesome-pro/dist/componentsimports (custom elements that extendHTMLElement, which crashes Workers on startup); (2)@react-email/render, an optional peer dependency ofresend@6.9.3that is not installed — Wrangler's bundler tries to resolve this dynamic import at bundle time and fails withCould not resolve "@react-email/render"; (3)sharp, which is used at build time only for image compilation but callsdetect-libc → process.report.getReport()at module initialization — an API not implemented in the Cloudflare Workers unenv shim — crashing the Worker on startup. Client builds are completely unaffected by any of these stubs. - Added
spinner.jsdynamic import toLoadingSpinner.tsx,ProfileForm.tsx, andAdminPanel.tsx, which all render<wa-spinner>but previously relied on the now-removed global spinner import inLayout.astro.
Changed
- Astro 5 → 6 upgrade — Upgraded
astrofrom^5.xto^6.0.1and updated all Astro integrations to their compatible major versions:@astrojs/react→^5.0.0@astrojs/cloudflare→^12.6.13@astrojs/mdx→^4.3.14@astrojs/sitemap→^3.7.1
- Dependency updates — Bumped supporting dependencies for compatibility and security:
@cloudflare/workers-types→^4.20260310.1@typescript-eslint/eslint-pluginand@typescript-eslint/parser→^8.57.0lint-staged→^16.3.3
- Added
.wrangler/**to ESLint ignore list to prevent linting of Wrangler's temporary build artifact files generated duringpnpm preview.
[2026-03-06]
Added
- Analytics Page - New
/analyticspage with rich data visualisations for authenticated users- Auth-gated page following the same pattern as
profile.astroandadmin.astro AnalyticsDashboardcomponent reads from Nanostores and respects site filtering- Six chart sub-components using Web Awesome Pro chart elements (auto light/dark themed)
- Port Status doughnut, Connection Types pie, Cabinet Capacity polar area
- Port Utilisation bar chart and Connections Over Time line chart (last 30 days)
- Cabinet Health Radar chart shown for networks with 5+ cabinets
- Empty-state message with icon when no network data is present
- Analytics link added to user dropdown in
UserMenu.tsx /analytics/excluded from the sitemap- Added TypeScript JSX declarations for all new Web Awesome chart components
- Auth-gated page following the same pattern as
Fixed
- Analytics Site Filter - Fixed site filter dropdown not updating chart data when selecting a site
- Changed event handler to use
e.currentTargetinstead ofe.targetto correctly access thewa-selectelement's value - The
changeevent'stargetmay refer to internal elements within the web component, whilecurrentTargetalways refers to the element with the event listener
- Changed event handler to use
[2026-03-05]
Changed
- Toast Notifications - Migrated from custom toast implementation to Web Awesome Pro's
wa-toastcomponent- Replaced custom
Toast.tsxcomponent with newToastContainer.tsxusingwa-toastelement - Maintains same functionality with success, error, and info variants
- Improved accessibility with Web Awesome's built-in toast patterns
- Added custom styling for toast components in
global.cssfollowing project's styling conventions - Fixed SSR hydration issues by loading component in
useEffectwithcustomElements.whenDefined() - Added
wa-toastandwa-toast-itemtype declarations toweb-awesome.d.ts - Added
wa-toastandwa-toast-itemto isolated components section inglobal.css - Implemented guard to verify element is upgraded before calling
create()method
- Replaced custom
Fixed
- Duplicate Toast Notifications - Fixed issue where "Data synced from cloud" toast appeared twice when returning to the tab
- Added
useRefguard inDataInitializercomponent to ensure data initialization only runs once per component lifecycle - Prevents duplicate sync toasts caused by Better Auth's
useSessionhook refetching session data when tab regains focus
- Added
[2026-03-04]
Added
agents.md- Added root-level agent instructions file for Claude coding agent, mirroring the project context already provided in.github/copilot-instructions.md
[2026-03-02]
Changed
- Better Auth 1.5.0 Native D1 Support - Migrated from custom
@nichoth/kysely-d1adapter to Better Auth's built-in native Cloudflare D1 support- Removed
@nichoth/kysely-d1andkyselydependencies (no longer required) - Pass the D1 binding directly to Better Auth (
database: db) — no custom adapter setup needed - Better Auth now handles D1 query execution, batch operations, and introspection natively
- Removed
Security
- Dependabot Vulnerability Fixes - Resolved 8 security vulnerabilities via
pnpm.overrides:- hono upgraded from
4.11.4to override range^4.11.7(currently resolved to4.12.3inpnpm-lock.yaml; resolves CVE-2026-24398, CVE-2026-24472, CVE-2026-24473, CVE-2026-24771 — IP spoofing, cache deception, arbitrary key read, and XSS in error boundary) - ajv (used by
@commitlint/config-validator) upgraded from8.17.1to override range^8.18.0(seepnpm-lock.yamlfor the exact resolved version; resolves CVE-2025-69873 — ReDoS via$datareference) - minimatch upgraded from
3.1.2to override range^3.1.4(currently resolved to3.1.5inpnpm-lock.yaml; resolves 3 ReDoS CVEs — combinatorial backtracking via GLOBSTAR segments, nested*()extglobs, and repeated wildcards)
- hono upgraded from
Fixed
- ESLint accessibility warnings — Resolved all remaining lint warnings:
- Changed resize handle from
role="separator"torole="slider"(interactive role with ARIA value attributes), eliminating the need for the previousjsx-a11y/no-noninteractive-tabindexsuppression comment and resolving the underlying accessibility lint warning - Added
role="region"andaria-labelto the cabinet sidebar container for proper landmark semantics - Added
role="list"to the device grid container sorole="listitem"children have the required parent context - Removed unused
_errorvariable from catch clause insrc/utils/export.ts
- Changed resize handle from
[2026-02-25]
Fixed
- External Device Port Count - External connections now correctly count as 1 used port (source side only) instead of 2, fixing the available ports stat
- Site-Filtered Stats - The statistics bar at the top of the page now filters counts based on the currently selected site
- Cabinet, device, connection, and available port counts reflect only the items belonging to the selected site
- When no site is selected, all items are counted as before
[2026-02-23]
Added
- Site Filtering in Flow View - The React Flow visualization now filters cabinets and connections based on the selected site
- When a site is selected in the sidebar, only cabinets belonging to that site are shown in the flow diagram
- Connections are automatically filtered to only display edges between visible devices
- External connections are hidden when their internal device belongs to a different site
- Selecting no site (clearing the selector) shows all cabinets and connections as before
- Assigning a site to a group now cascades the
siteIdto all descendant groups and all cabinets within those groups - Moving a cabinet into a group automatically assigns the group's site to that cabinet
- Multi-site/Project Management - Organize cabinets and groups by sites or projects
- Site selector using
wa-comboboxcomponent withallow-custom-valueattribute - Create new sites by typing custom values directly in the combobox
- Filter cabinets and groups by selected site in the sidebar
- Automatic site assignment when creating new cabinets and groups
- Sites data included in export/import and cloud sync
- CSS styling for
wa-comboboxcomponent following the established ::part() pattern - Ability to move cabinets and groups between sites via add and edit modals
- Site selector added to EditGroupModal and EditCabinetModal
- Delete site functionality with ConfirmModal component
- Site selector using
- Comprehensive Input Sanitization - All user text inputs sanitized using
escapeHtml()to prevent XSS attacks- Site Management - Site names with length validation (max 100 chars) and duplicate prevention
SiteSelector- Site name input with case-insensitive duplicate detection
- Cabinet/Group Modals - Names and descriptions sanitized in Add/Edit modals
AddCabinetModal,EditCabinetModal- Cabinet name and description fieldsAddGroupModal,EditGroupModal- Group name and description fields
- Device Management - Device names and port labels sanitized
AddDeviceModal- Device name field during creationDevicecomponent - Inline editing of device names and port labels
- Connection Management - External device names, port labels, and connection labels sanitized
CreateConnectionModal- All text fields in create and edit flows
- Admin Panel - Ban reason textarea sanitized before storage
- Authentication - User names sanitized during signup and profile updates
AuthForm- Name field during user registrationProfileForm- Name field during profile updates- Note: Passwords are NOT sanitized (hashed server-side instead)
- Note: Numeric inputs (port counts, ban hours) are validated for range, not sanitized
- Security Tests - Comprehensive test suite in
tests/security/component-input-sanitization.test.ts(46 tests)- Tests all components including sites for proper input sanitization
- XSS payload neutralization (script injection, event handlers, DOM-based XSS)
- Real-world attack scenarios (reflected XSS, stored XSS, polyglot payloads)
- Edge cases (empty strings, special characters, unicode preservation)
- Site-specific validation (length limits, duplicate detection)
- Context-specific XSS prevention (React rendering, localStorage, server transmission)
- Total security test coverage: 190 tests across 6 test suites - all passing ✅
- Site Management - Site names with length validation (max 100 chars) and duplicate prevention
Fixed
Cabinet not cleared on site switch - Selecting a different site now clears the currently displayed cabinet so stale content from the previous site is no longer shown
Recursion in Delete Group - Replaced the recursive
collectChildIdsfunction indeleteGroup()with an iterative BFS traversal (same pattern asupdateGroup), guarded by a visited set to prevent infinite loops from cyclic data in corrupted storesInfinite loop in
isDescendant- Added a visited set to thewhileloop inisDescendant()so cyclicparentGroupIddata cannot cause a browser-freeze infinite loopStack overflow in
renderGroup- Added an ancestors set toCabinetList's recursiverenderGroup()function; if a group ID is already being rendered in the current path (due to cyclic data), the branch returnsnullinstead of recursing infinitelyReact Hydration Mismatch - Resolved hydration errors with Web Awesome components
- Added
suppressHydrationWarningto MainContent container div - Web Awesome components add default attributes during client-side hydration
- Suppressing warnings for expected Web Awesome component behavior in SSR
- Added
Tailwind CSS Spacing - Added
wa-comboboxto Preflight isolation list to prevent dropdown spacing issuesCSP Violations - Added missing script hashes to Content Security Policy
- Added two inline script hashes that were causing CSP errors
- All inline scripts now properly authorized via hash allowlisting
Site Selector UI - Improved consistency and layout
- Changed "Site / Project" header to "Site" to match "Cabinets" header style
- Fixed combobox and delete button being cut off
- Moved delete button to header row instead of inline with combobox
- Delete button now appears to the right of "Site" heading when a site is selected
- Site deletion now uses ConfirmModal component instead of browser confirm() dialog for consistency
- Site deletion modal positioning - Fixed modal rendering within sidebar by using React portal to render at document body level, ensuring it overlays the entire page like other modals in the application
- Layout shift prevention - Delete button now always reserves space in the layout using
invisibleclass when not needed, preventing text misalignment and layout shifts when button appears
[2026-02-12]
Added
File Upload Security Tests (45 tests) - Comprehensive validation of JSON import functionality
- Valid data structure validation (3 tests)
- Invalid JSON format detection (4 tests)
- Cabinet structure validation (6 tests)
- Device validation with type checking (2 tests)
- Port validation with status enum checking (3 tests)
- Connection validation with type enum checking (3 tests)
- XSS and SQL injection payload handling (3 tests)
- JSON bomb protection for large/nested structures (3 tests)
- Group validation with optional fields (4 tests)
- Type safety enforcement for all fields (3 tests)
- Error handling and validation failures (3 tests)
- Security test coverage for JSON import validation
Comprehensive security testing suite now with 144 tests across 5 domains
- SQL Injection Tests (12 tests): Validates parameterized queries protect against 24 attack vectors
- XSS Prevention Tests (29 tests): Validates HTML escaping using production function, CSP with production generator, React protection, URL sanitization
- Authorization Tests (25 tests): Validates authentication, user data isolation, RBAC, session management
- Input Validation Tests (33 tests): Validates email/string/type validation, rate limiting concepts, resource protection
- File Upload Tests (45 tests): Validates JSON structure, type safety, XSS/SQL injection handling, large file support
- Security test coverage expanded across all critical domains
- Added test scripts:
test,test:watch,test:ui,test:security - Updated
SECURITY_ASSESSMENT.mddocumenting comprehensive findings - Test results: 144/144 tests passing
Vitest testing framework
- Configured in
vitest.config.tswith proper path aliases - Test coverage support with v8 provider
- Tests located in
tests/security/directory
- Configured in
Security test suites:
tests/security/sql-injection.test.ts- SQL injection vulnerability testingtests/security/xss.test.ts- Cross-site scripting prevention testingtests/security/authorization.test.ts- Authentication and access control testingtests/security/input-validation.test.ts- Input validation and rate limiting testingtests/security/file-upload.test.ts- File upload security testing
[2026-02-06]
Changed
Replaced
<wa-input type="number">with proper<wa-number-input>Web Awesome component- AddDeviceModal.tsx: Replaced port count input with
<wa-number-input>- Changed string attributes (
min="1",max="96") to numeric props (min={1},max={96}) - Added
step={1}for proper number input behavior - Removed
type="number"attribute (not needed with dedicated component)
- Changed string attributes (
- AdminPanel.tsx: Replaced custom ban hours input with
<wa-number-input>- Changed string attributes to numeric props for min and step
- Improved accessibility and UX with native number input controls
- Device.tsx: Replaced edit port count input with
<wa-number-input>- Refactored modal to use shared
Modalcomponent from@components/Modal - Improved modal structure and accessibility
- Changed string attributes to numeric props
- Refactored modal to use shared
- src/styles/global.css: Added comprehensive
wa-number-inputstyling with::part()selectors- Light mode styling for
::part(base)and::part(input) - Dark mode variants with
.darkprefix - Focus states matching
wa-inputfor consistency - Added reference implementation comments documenting the styling pattern
- Added component to Tailwind CSS reset exclusion list
- Light mode styling for
- src/types/web-awesome.d.ts: Added TypeScript definitions for
<wa-number-input>component- Complete prop types including min, max, step, and number-specific attributes
- Event handler types for React synthetic events and Web Awesome custom events
- AddDeviceModal.tsx: Replaced port count input with
Enhanced Web Awesome component styling documentation
- Added comprehensive "Web Awesome Component Styling Rules" section (~160 lines) to
.github/copilot-instructions.md - Documented critical rules: ALWAYS use CSS
::part()selectors, NEVER use component attributes likeappearanceorfilled - Added component parts reference (base, input, button, etc.) for common Web Awesome components
- Provided step-by-step workflow for styling new Web Awesome components
- Included debugging checklist for styling issues
- Added detailed comment blocks in
src/styles/global.cssexplaining::part()pattern - Documented why
::part()is required (Shadow DOM encapsulation) - Listed common parts for form components (base, input, textarea, etc.)
- Marked
wa-inputandwa-number-inputas reference implementations for proper styling pattern
- Added comprehensive "Web Awesome Component Styling Rules" section (~160 lines) to
[2026-02-05]
Changed
- Updated copilot instructions to reference Web Awesome LLM resources
- Added documentation for
node_modules/@awesome.me/webawesome-pro/dist/llms.txt - Added documentation for
node_modules/@awesome.me/webawesome-pro/dist/skills/webawesome/(agent skills and reference guides) - Added comprehensive Web Awesome UI Components section with usage examples and component categories
- Improved guidance for working with Web Awesome components in Astro and React
- Added documentation for
[2026-01-22]
Added
- ESLint analysis report documenting all 90 warnings across 23 files
- Categorized warnings by difficulty: Easy (24), Medium (49), Moderate to Complex (17)
- Grouped by type: Accessibility (66), TypeScript (17), React (7)
- Provided fix strategies and priority recommendations
- Estimated effort: 7-12 hours total to resolve all warnings
- Created
ESLINT_ANALYSIS.mdwith comprehensive overview
- Reusable Modal component for consistent modal behavior across the application
- Centralized keyboard event handling (Escape key to close)
- Centralized click-outside-to-close functionality
- Configurable options for special cases (e.g., 2FA modals)
- Proper ARIA attributes for accessibility
Fixed
ESLint warnings reduced from 90 to 4 through systematic fixes
- Removed 13 unused variables and imports across 8 files
CookieConsent.tsx: Removed 6 unused error variables in catch blocksDevice.tsx: Removed unusedaddConnectionimportNetworkFlowVisualization.tsx: Removed unusedConnectiontype importToast.tsx: Removed unuseduseEffectimportcontact.ts: Removed unusedRequestWithWaitUntilinterfacenetworkStore.ts: Removed unusedisAuthenticatedimportauth.ts: Renamed unusedotpparameter to_otpfollowing conventionexport.ts: Renamed unusederrorparameter to_errorfollowing convention
- Fixed 7 unescaped apostrophes with HTML entities (
')AuthForm.tsx: Fixed password reset messageProfileForm.tsx: Fixed 3 instances in email and 2FA descriptionsTwoFactorSetupModal.tsx: Fixed 2 instances in setup instructions
- Replaced 6 explicit
anytypes with proper TypeScript typesConnectionLines.tsx: Changed debounce function args tounknown[]for better reusabilityenv.d.ts: Replaced 4anytypes withRecord<string, unknown>for PostHog configauth.ts: Fixed plugins array type to use correct union syntax:Array<ReturnType<typeof admin> | ReturnType<typeof twoFactor> | ReturnType<typeof captcha>>export.ts: ChangedvalidateImportDatato use type guard pattern withunknown
- Fixed 30 modal backdrop accessibility warnings by creating reusable Modal component
- All 9 modal components refactored to use shared Modal component
- Added proper keyboard event handlers (Escape key) with configurable behavior
- Added proper ARIA roles and attributes (role="dialog", aria-modal, aria-labelledby)
- Modal backdrop made non-interactive (removed incorrect role="button" and tabIndex)
- Removed redundant keyboard handler from backdrop
- Modals: AddCabinetModal, AddDeviceModal, AddGroupModal, ConfirmModal, CreateConnectionModal, EditCabinetModal, EditGroupModal, TwoFactorSetupModal, TwoFactorVerifyModal
- ConfirmModal prevents accidental closes during loading operations
- Added
closeOnClickOutside={!isLoading}andcloseOnEscape={!isLoading}to prevent cancellation of in-progress operations
- Added
- Fixed 13 interactive element accessibility warnings by adding keyboard support
- UserMenu: Added keyboard handler (Escape/Enter/Space) to backdrop
- CabinetList: Added keyboard support to drag handles and mobile overlay
- Device: Added keyboard support to editable name, port count, and port labels
- Device: Changed h3 and p elements to divs to allow interactive roles
- Cabinet: Added role="listitem" to draggable device containers
- Modal: Added ESLint suppressions for intentional backdrop behavior
- Fixed 7 label association warnings in CreateConnectionModal
- Changed
<label>elements to<div>elements for display-only fields - Proper semantic HTML usage: labels only used with actual form controls
- Improved accessibility by using appropriate HTML elements
- Changed
- Kept autofocus behavior on 2FA input fields (suppressed 2 ESLint warnings with justification)
- TwoFactorSetupModal and TwoFactorVerifyModal: Input fields auto-focus for better UX
- Users expect to immediately type their 2FA code without clicking
- Intentional UX decision to reduce friction during authentication
- Added ESLint disable comments with clear justification
- Fixed React Hook dependency warnings (2 warnings)
- Cabinet.tsx and CabinetList.tsx: Added ESLint suppressions for touch event handlers
- Touch handlers intentionally stable to avoid re-registering event listeners
- Prevents performance issues from frequent listener registration/deregistration
- Suppressed 6 intentional accessibility patterns with clear justifications
- Cabinet.tsx: Touch handlers on list items for mobile drag-and-drop
- CabinetList.tsx: Drag-and-drop root target and keyboard-accessible resize handle
- Device.tsx: Modal backdrop click handler with keyboard alternative
- Modal.tsx: Backdrop click-to-close with Escape key handling in useEffect
- All suppressions include detailed comments explaining intentional design decisions
- Fixed modal z-index stacking issues (modals appearing behind other elements)
- All modals now use React's
createPortalto render at document.body level - Added SSR safety checks (
typeof document !== 'undefined') - Fixed 8 modals across Device, Cabinet, and CabinetList components
- Modals now properly appear above all page content with z-index 9999
- Prevents modals from being trapped in parent component stacking contexts
- All modals now use React's
- Removed 13 unused variables and imports across 8 files
Modal close button now uses Web Awesome
wa-buttoncomponent withappearance="plain"for consistencyConnection type buttons in CreateConnectionModal now display cursor pointer and change border color on hover to better indicate interactivity
Changed
- Removed connection labels from device/cabinet view to reduce confusion
- Connection labels removed from
ConnectionLines.tsxSVG overlay - Labels remain in flow view (
NetworkFlowVisualization.tsx) where context is clearer - Device view now shows only colored connection lines for cleaner visualization
- Connection labels removed from
- Moved charset declaration out of the AstroSEO section to the start of the head in layout.astro
[2026-01-21]
Fixed
- Prevented
/api/dataAPI calls for unauthenticated users to eliminate 401 console errors- DataInitializer now checks authentication state before attempting to load data from server
- Users who are not logged in no longer trigger unnecessary API requests
- Fixed issue where page content (main content, footer, dev warning banner) would not load for unauthenticated users
- DataInitializer now properly sets
isInitializingto false for unauthenticated users
[2026-01-20]
Changed
- Aligned loading UI across profile and admin panel pages to match main page
- ProfileForm now displays full-screen loading overlay with spinner and "Loading..." message
- AdminPanel now displays full-screen loading overlay with spinner and "Loading..." message
- Improved consistency of loading experience across the application
Fixed
- CSP violations on local dev server - Added missing script hashes for Astro dev mode inline scripts to allow them to execute without CSP errors
[2026-01-19]
Added
- Automated versioning and release management with semantic-release
- Installed semantic-release v23 with GitHub and changelog plugins
- Configured to analyze commits and automatically bump versions
- Generates release notes and GitHub releases
- Updates CHANGELOG.md automatically
- Commits version bumps with
chore(release): X.Y.Z [skip ci]format
- Commit message validation with commitlint
- Installed commitlint v19 with conventional config
- Enforces Conventional Commits format on all commits
- Pre-commit hook validates commit messages via Husky
- CI workflow validates all PR commits
- Supports types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
- Configured header-max-length to 200 characters (increased from default 100)
- Commitizen integration for interactive commit creation
- Added
pnpm commitscript for guided commit message creation - Uses cz-conventional-changelog adapter
- Helps developers write properly formatted commits
- Added
- GitHub Actions workflows for release automation
commit-lint.yml- Validates PR commits against conventional format with WEBAWESOME_NPM_TOKENrelease.yml- Runs semantic-release on main branch pushes with WEBAWESOME_NPM_TOKEN- Updated
trivy-scan.ymlto track commit-lint workflow status in CI/CD report
- CONTRIBUTING.md guide with comprehensive contribution guidelines
- Development workflow and branch naming conventions
- Commit message format with detailed examples (200 character subject limit)
- Code quality standards and tooling
- Dependency management with Depfu configuration prefix
- Troubleshooting section for commit lint failures with fix instructions
- Pull request process and review requirements
- Automated release process explanation
- Updated copilot-instructions.md with commit conventions section
- Conventional Commits format reference
- Commit types and their semantic versioning impact
- Scope guidelines for better commit organization
- Interactive helper usage instructions
- Automated release workflow explanation
Fixed
Added WEBAWESOME_NPM_TOKEN environment variable to commit-lint and release workflows to fix 404 errors when installing private dependencies
Semantic-release workflow conflicts with update-changelog workflow
- Removed
@semantic-release/changelogplugin from.releaserc.jsonto prevent CHANGELOG.md conflicts - Removed
@semantic-release/npmplugin from.releaserc.json(not needed - no npm publishing) - Removed
@semantic-release/gitplugin from.releaserc.jsonto prevent repository file modifications - Removed
@semantic-release/changelogand@semantic-release/gitpackages from devDependencies - Simplified
.releaserc.jsonto only create GitHub releases with version tags - Eliminates "branch behind" errors caused by race conditions between workflows
- Updated CONTRIBUTING.md to reflect that semantic-release no longer updates CHANGELOG.md
- Removed
Race condition between changelog and release workflows causing semantic-release to fail with "local branch main is behind" error
- Added git pull step in release workflow to synchronize with changelog commits before running semantic-release
- Ensures release workflow operates on the latest commit even if changelog workflow commits while release is running
Changed
Disabled commitlint
subject-caserule to allow capital letters in commit messages- Developers can now use proper capitalization for acronyms (API, SQL, HTTP, etc.)
- Proper nouns and technical terms (GitHub, TypeScript, React) are now allowed
- Updated CONTRIBUTING.md with flexible capitalization guidelines
- Maintains conventional commit format while allowing natural language
- Added exception for "Initial plan" commit message pattern
Updated
@commitlint/clifrom^19.8.1to^20.3.1Updated
@commitlint/config-conventionalfrom^19.8.1to^20.3.1Updated
semantic-releasefrom^23.1.1to^25.0.2Updated Node.js requirement from v22 to v24 (LTS) across all CI workflows
Updated documentation to reflect Node.js v24 (LTS) requirement
[2026-01-16]
Added
- Integrated ESLint with Astro plugin support for improved code quality and consistency
- Installed ESLint v9 with flat config format
- Added TypeScript ESLint plugin for TypeScript-specific linting rules
- Added React plugins (eslint-plugin-react, eslint-plugin-react-hooks) with React 19 compatibility
- Added JSX accessibility plugin (eslint-plugin-jsx-a11y) for accessibility best practices
- Added eslint-config-prettier to ensure ESLint and Prettier work together without conflicts
- Configured global variables for browser and Node.js environments
- Added
lintandlint:fixnpm scripts - Updated lint-staged to run ESLint before Prettier on staged files
- Added ESLint GitHub Actions workflow for automated CI/CD checks on pull requests
- Added Trivy security scanning workflow for automated vulnerability detection
- Scans for vulnerabilities in dependencies, secrets, and misconfigurations
- Runs on pull requests and main branch pushes
- Posts consolidated CI/CD status report as PR comment showing Format Check, ESLint Check, and Trivy scan results
- Includes detailed vulnerability listings with CVE IDs, package names, and descriptions
- Comment automatically updates when results change
- Fails build on CRITICAL and HIGH severity issues
[2026-01-15]
Added
- Implemented Content Security Policy (CSP) using meta tags for primary enforcement, with Cloudflare Workers middleware setting equivalent HTTP headers as a fallback
- Uses nonce-based protection for inline scripts (dark mode toggle, PostHog analytics)
- Allows
'unsafe-inline'for styles to support React component inline style attributes - Properly configured for all external resources (PostHog, Cloudflare Turnstile, Web Awesome)
- Includes CSP directives and security headers (via both meta tags and HTTP headers):
object-src 'none',base-uri 'self',form-action 'self',frame-ancestors 'none',upgrade-insecure-requests
Changed
- Migrated from Astro's experimental CSP to middleware-based CSP for better control
- Astro's CSP automatically generates hashes for
<style>tags, which causes browsers to ignore'unsafe-inline'per CSP specification - Middleware-based CSP allows proper handling of inline style attributes used by React components
- Astro's CSP automatically generates hashes for
- Updated
Layout.astroto use nonce for inline scripts - Updated
posthog.astroto accept and use nonce prop
Removed
- Removed experimental Content Security Policy (CSP) configuration from
astro.config.mjs
[2026-01-13]
Added
- Enabled Astro's experimental Content Security Policy (CSP) feature to enhance security against XSS and code injection attacks
- Configured CSP directives for external resources including PostHog analytics and Cloudflare Turnstile
- Added SHA-256 hashes for inline scripts (dark mode toggle and PostHog tracking) to allow them under CSP
- Added
style-src 'unsafe-inline'directive to support React component inline styles
Fixed
- Fixed CSP blocking Web Awesome icons by adding
ka-f.fontawesome.comandka-p.fontawesome.comto bothimg-srcandconnect-srcdirectives (icons are loaded via XHR/fetch) - Fixed CSP blocking PostHog analytics scripts by adding both
https://ph.network-patch-mapper.comandhttps://ph-assets.i.posthog.comtoscript-srcresources - Fixed CSP blocking Cloudflare Turnstile by adding
https://challenges.cloudflare.comtoscript-srcresources
[2026-01-12]
Added
Added loading spinner (
wa-spinner) displayed during app initialization to prevent layout shifts and improve user experienceCreated
LoadingSpinnercomponent that shows a centered spinner with "Loading..." text while data is being initializedAdded
isInitializingstate atom tonetworkStoreto track data initialization statusAdded support for patch panel internal connections - patch panels can now connect ports to other ports on the same device (e.g., Port 5 to Port 6 on Patch 1)
Patch panel ports can now be connected to any port on the same device (except the same port) via the connection modal
Changed
Updated
initializeDatafunction to properly set loading state before and after data initializationModified main index page to include the
LoadingSpinnercomponentUpdated
wa-spinnercomponent to use font-size for sizing instead of incorrectsizeattribute (follows Web Awesome documentation)Increased loading text size from
text-smtotext-lgfor better readabilityChanged spinner color customization to use CSS custom properties
--indicator-colorand--track-colorinstead of Tailwind text color classes (follows Web Awesome documentation)Moved spinner component import to Layout.astro head to ensure it loads immediately when the page loads, improving visibility during initialization
Updated existing
wa-spinnercomponents in UserMenu, AdminPanel, and ProfileForm to remove deprecatedsizeattribute and use font-size classes insteadUpdated all spinner components (LoadingSpinner, AdminPanel, ProfileForm) to use CSS variables (
var(--color-primary-600)andcolor-mix()) for colors, ensuring consistency across the applicationUpdated connection modal to include the source device in available devices when creating internal connections from a patch panel
Modified port selection logic to exclude the source port when connecting to the same device (prevents a port from connecting to itself)
Switches continue to be restricted from connecting to ports on the same device (unchanged behavior)
All port connections now use the connection modal for consistency
Fixed
- Removed incorrect
sizeattribute fromwa-spinnerTypeScript definitions - spinner sizing is controlled via font-size as per Web Awesome documentation
[2026-01-05]
Added
- Created centralized
uiStorefor managing UI preferences like sidebar width
Changed
- Sidebar width changes are now persisted immediately to localStorage and synced to cloud (with 1-second debounce) for authenticated users
Removed
- Removed legacy standalone
sidebarWidthlocalStorage key in favor of centralizedNetworkDatastorage
Fixed
- Fixed sidebar width not persisting across page refreshes for both authenticated and non-authenticated users
- Sidebar width is now properly synced to the D1 database for authenticated users
- Resolved React rendering issue where inline width style wasn't being applied to the sidebar DOM element
- Fixed sidebar width responsiveness on mobile devices - sidebar now uses a fixed 256px width on mobile (< 768px) to prevent overflow and usability issues, while maintaining variable width on desktop
[2025-12-29]
Fixed
- Fixed password manager autofill issue where credentials autofilled by password managers (like Bitwarden) were not being read correctly, causing login failures
- Forms now read values directly from DOM elements at submission time to handle password manager autofill that doesn't trigger input events
- Applied fix to AuthForm, ResetPasswordForm, ProfileForm, and ContactForm components
- Added
autocomplete,nameattributes to form inputs to help password managers properly identify and autofill email/username and password fields- Email fields now use
autocomplete="username"to help password managers recognize them - Password fields use
autocomplete="current-password"for login andautocomplete="new-password"for signup/password change - All form inputs now have appropriate
nameattributes
- Email fields now use
[2025-12-24]
Fixed
- Port, view toggle and label edit buttons now have pointer cursor to make it easier to recognise them as buttons
[2025-12-23]
Changed
- Updated device action buttons (edit, rename, delete) to use Web Awesome
wa-buttoncomponents withappearance="plain"for consistent styling - Device action buttons now use
button-no-hoverattribute to prevent background color changes on hover - Added custom CSS styling for device buttons with proper hover states and dark mode support
- Device buttons now styled consistently with cabinet, group, and admin panel buttons
- Reduced CSS duplication by consolidating repeated styles:
- Consolidated button sizing (24x24px for cabinet/group/device buttons, 40x40px for admin buttons) into shared rules
- Consolidated button variant base styles (border-radius, padding, font-weight, transition, border) for brand/danger/neutral variants
- Consolidated header button hover states (dark mode toggle, user menu, profile settings)
- Consolidated form control label styling across inputs, textareas, and selects
- Updated admin panel action buttons to use Web Awesome icon buttons with
appearance="plain"for consistent styling - Admin action buttons (change role, ban/unban, delete) now styled consistently with header, user menu, and cabinet/group buttons
- Added custom CSS styling for admin action buttons with proper hover states and dark mode support
- Replaced all Font Awesome icons with Web Awesome
wa-iconcomponents throughout the application - Removed Font Awesome CDN script from Layout component
- Updated icon names to use Web Awesome icon names (e.g.,
fa-times→xmark,fa-arrow-left→arrow-left) - Updated README.md to remove Font Awesome from tech stack
- Updated header buttons to use
wa-buttonin dark mode and user menu - Updated cookie consent banner button text from "Continue without cookies"/"Accept cookies" to "Necessary cookies only"/"Accept All cookies"
- Enhanced cookie consent banner message to explain that cookies are used for essential site functionality including authentication when creating or logging into an account
Fixed
- Changelog workflow now properly merges duplicate subsection headers (e.g.,
### Changed) when multiple PRs are merged on the same day, preventing duplicate sections in the changelog
[2025-12-22]
Added
- Group assignment dropdown to AddCabinetModal allowing cabinets to be added to existing groups
- Input length validation with
maxlengthattributes across multiple modal text inputs and textareas - Touch-based drag and drop support for mobile devices
- Added touch event handlers for device reordering within cabinets
- Added touch event handlers for cabinet drag and drop in sidebar
- Added touch event handlers for group drag and drop in sidebar
- Created
touchDrag.tsutility module with reusable touch drag functions
- Group selection dropdown in Edit Cabinet modal
- Added ability to move cabinets to different groups when editing
- Added "None" option to move cabinets to root level
Changed
- Refactored CabinetList component to use Web Awesome
wa-button,wa-icon, andwa-button-groupcomponents instead of standard HTML button elements - Updated cabinet and group action buttons (edit, delete, add) to use Web Awesome components with custom styling
- Improved button attribute naming for group action buttons (
button-edit-group,button-delete-group) - Updated dependencies:
@cloudflare/workers-typesto 4.20241218.0 andwranglerto 3.100.0 - Updated group selection implementation in Edit Cabinet modal to match Add Cabinet modal pattern
- Made
wa-selectuncontrolled by removingvalueprop to allow Web Awesome to manage its own state - Read group value directly from element ref at submit time instead of using React state
- Changed
clearableattribute towith-clearfor proper Web Awesome syntax - Improved visual indication of nested groups with '├─' prefix
- Made
- Updated
.github/copilot-instructions.mdto document Prettier formatting configuration, EditorConfig settings, Husky/lint-staged pre-commit hooks, and CI workflows introduced in PR #118 - Improved port click behavior in Device component: clicking a different port on the same device now opens the connection modal instead of showing an error toast
Fixed
- Fixed z-index issue for mobile sidebar
- Fixed mobile logo size
- Mobile drag and drop functionality for devices, cabinets, and groups
- Devices can now be reordered within cabinets on touchscreen devices
- Cabinets can now be moved between groups on touchscreen devices
- Groups can now be reorganized on touchscreen devices
- Added global touchend/touchcancel listeners to handle edge cases when touch ends outside draggable elements
- Page scrolling during mobile drag operations
- Added
preventDefault()in touch start handlers to prevent scrolling when dragging - Added
touch-action: noneCSS to grip handle elements for complete scroll prevention - Prevents browser's default scroll behavior from interfering with drag gestures
- Added
- Group selection in Edit Cabinet modal now properly updates cabinet's group assignment
- Always initializes select element value, even for cabinets without a group
- Removed duplicate toast message (updateCabinet already shows one)
- Delete device confirmation modal z-index stacking
- Wrapped ConfirmModal with createPortal to render at document body level
- Modal now appears above sidebar and stats bar instead of being hidden beneath them
- Code quality improvements
- Removed redundant pointer-events setting in touchDrag utility
- Fixed edge case where ghost elements could remain on screen if touch ended outside draggable area
Removed
- Removed obsolete "Cannot connect ports on the same device" error toast that was replaced by connection modal validation
[2025-12-19]
Added
- Comprehensive SEO metadata including canonical URLs, charset, and image alt text for better search engine optimization
- Twitter Card metadata with card type, title, description, image, and image alt text for enhanced social media sharing
- Open Graph metadata with proper URL, siteName, locale, and image alt text for better social media previews
- Description, title, and image props to Layout component for per-page SEO customization
- Keywords meta tag with relevant terms for improved search engine discoverability
- Author and robots meta tags for better search engine crawling
- Theme color meta tags that adapt to light and dark mode preferences
Changed
- Improved default meta description to be more descriptive and keyword-rich
- Enhanced Open Graph configuration with required URL field and image alt text
- Added siteName property to Open Graph metadata for better brand recognition
- Updated all
wa-buttoncomponents to use theloadingattribute instead of custom loading text with spinner icons for consistent button behavior - Replaced Font Awesome spinner icons (
fa-spinner) with Web Awesomewa-spinnercomponent in the UserMenu component - Standardized loading states across all forms (AuthForm, ContactForm, ResetPasswordForm, ProfileForm, TwoFactorSetupModal, TwoFactorVerifyModal, ConfirmModal)
- Refactored WebAwesome button custom styling to use opt-in
data-custom-styleattribute instead of global styling, allowing native WebAwesome button appearances (likeappearance="plain",appearance="outlined",appearance="filled") to work correctly alongside custom-styled buttons - Updated variant-specific button styles (brand, danger, neutral) to also require
data-custom-styleattribute, ensuring complete opt-in behavior for all custom styling - Changed custom button variant from
primarytobrandto align with WebAwesome's native variant naming conventions
Fixed
- Removed duplicate charset meta tag that was redundant with SEO component
- Header and stats bar scroll behavior on main page. Stats bar is now sticky and header collapses/reappears on scroll. Header remains sticky on MDX and profile pages.
- User menu dropdown now displays correctly above the stats bar. Fixed z-index stacking context issues by adding proper positioning and using correct Tailwind v4 arbitrary value syntax.
- Corrected TypeScript type definitions for
wa-buttonto include only valid WebAwesome appearance values:"accent","filled","outlined","filled-outlined", and"plain" - Fixed invalid
variant="text"usage in ProfileForm to usevariant="neutral"for native WebAwesome styling - Fixed ConfirmModal variant logic to use
'brand'instead of'primary'
[2025-12-18]
Added
- New logo as an SVG in the header, changes colours between dark and light themes
- Network Patch Mapper logo to all email templates for consistent branding
- Logo appears in verification emails, password reset emails, email change confirmations, and contact form notifications
Changed
- Updated brand color from #2563eb to #2b65e8 across the application
- Updated primary button color in email templates to use new brand color
- Updated favicon.svg to use new brand color
- Updated CSS theme variables and Web Awesome component styling with new brand color
Fixed
- Port labels now update correctly when edited. Fixed event listener attachment timing issue in Device component.
- CSS files are now named based on their source (e.g.,
global.[hash].css) instead of being named after the first page that imports them (e.g.,privacy-policy.[hash].css)
[2025-12-17]
Added
- Remember me switch on login page using wa-switch component
Changed
- wa-switch on the contact page to use span inside the switch
- bump packages to newer versions
- Moved to
@awesome.me/webawesome-pro@3.1.0in place of@awesome.me/webawesome@3.1.0
[2025-12-16]
Changed
- Updated web-awesome.d.ts with complete type declarations for all Web Awesome components used in the application
- Added wa-tooltip component declarations with all placement and trigger options
- Added wa-callout component declarations for future use (variant, open, closable, duration, event handlers)
- Added wa-select and wa-option component declarations for future use with complete property and event support
- Added wa-dialog component declarations for future use (label, open, without-header, light-dismiss, contained, event handlers)
- Enhanced wa-icon with family and variant properties for Font Awesome icon customization
- Added React synthetic event handlers (onInput, onChange, onBlur, onKeyDown, etc.) to wa-input and wa-textarea for better React integration
- Added with-caret property to wa-button for dropdown support
- Added slot attribute to wa-icon for proper slotted content support
Fixed
- Admin panel search box now works correctly by using React's onInput synthetic events instead of manual addEventListener
[2025-12-15]
Added
- Changelog link to Footer component for easy access to version history
- Privacy Policy link to cookie banner
- Header logo and title now clickable to navigate to homepage
- Footer component with consistent styling across all pages
- CHANGELOG.md file with complete project history
- Changelog page at
/changelogdisplaying the CHANGELOG.md content - Copilot instructions updated to require changelog maintenance
- Mobile sidebar toggle with circular arrow button for opening/closing sidebar on small screens
- Footer hide/show feature with circular buttons and localStorage persistence of state
- SidebarToggle component for mobile navigation control
- Migrated all buttons, inputs, and avatar components to Web Awesome library
- Integrated Web Awesome components across the entire application
- Web Awesome type definitions and CSS styling for custom component parts
Changed
- Footer component simplified by removing hide/show toggle functionality and unused state
- MDXLayout now uses Footer component instead of manual footer markup
- Removed version field from package.json
- Updated Privacy Policy with login information
- Import paths in index.astro updated to use path aliases for consistency
- Two-factor authentication now handled via modals instead of separate pages
- Mobile layout fixes for full-width main content on small screens (sidebar uses fixed positioning)
- Responsive toolbar buttons: icon-only display on mobile devices (< 640px), full text on larger screens
- Device grid breakpoint adjustments for improved mobile screen support (3→4→6→8 columns)
- Container changed from h-screen to min-h-screen for flexible content height
- Reduced padding on mobile: 12px vs 24px on desktop for more visible content
- Toolbar gaps and spacing reduced for compact mobile view
- Footer show button positioned on bottom-right
- Sidebar completely removed from document flow on mobile, overlays content when opened
- Added min-h-0 to flex child to enable proper scrolling behavior
- Web Awesome button loading attribute replaces manual spinner rendering
- Web Awesome inputs use label slots pattern (
<span slot="label">) - Event handling for Web Awesome components uses refs with addEventListener
- Password inputs now use wa-input with password-toggle attribute
- Improved email sending on Cloudflare Workers using ExecutionContext.waitUntil
- Better Auth email callbacks now properly handle async operations with waitUntil
Fixed
- Email input class styling in ProfileForm (removed background color classes)
- Minlength attributes on inputs (add proper maxlength and pattern for backup codes)
- TwoFactor components reverted to use HTML inputs except password input in setup modal
- TwoFactorVerifyModal input validation with without-spin-buttons, pattern validation, and minlength/maxlength
- TwoFactorVerifyModal to use type="number" for authenticator codes, type="text" for backup codes
- TwoFactorVerifyModal properly filters digits and reads value at submission
- TwoFactorVerifyModal digit filtering and enabled verify button
- Web Awesome components now use proper closing tags instead of self-closing tags
- Password input event handling in TwoFactorSetupModal by re-attaching listeners on step changes
- Icon slot imports and wa-icon usage in UserMenu
Removed
- Two-factor authentication pages (two-factor-setup.astro, two-factor.astro) - replaced with modal components
- Footer hide/show toggle functionality with circular buttons and localStorage persistence
- Unused state variables and event handlers from Footer component
- package-lock.json deleted (project uses pnpm exclusively)
[2025-12-12]
Added
- Blue color (#3b82f6) added to color picker swatches
- Contact form with Resend email integration and Turnstile CAPTCHA
- Contact page with form component and API endpoint
- wa-switch component for terms and conditions agreement
- Cookie consent component with proper EU-compliant styling
- Terms & Conditions and Privacy Policy pages with MDX support
- Better Auth email functionality with Resend integration
- Environment variable requirements for email functionality (FROM_EMAIL, CONTACT_EMAIL)
- Web Awesome components migration across 21 of 22 components
- MDX layout with proper prose styling for documentation pages
Changed
- Cookie consent buttons now use neutral variant for EU compliance
- Button variants properly mapped (primary, neutral, danger) in Web Awesome migration
- ProfileForm updated to use Web Awesome components as the final migrated component
- All password fields include password-toggle attribute for UX improvement
- Forgot password button re-enabled after waitUntil implementation fix
- ContactForm to use Web Awesome components (wa-input, wa-textarea, wa-button)
- ContactForm uses Web Awesome label slots and fixed event handling with refs
- Minlength attributes now use strings for web standards compliance
- Complete migration: ProfileForm to use Web Awesome components - ALL components now migrated
- TwoFactorSetupModal to use Web Awesome with loading attribute for spinners
- TwoFactorSetup to use Web Awesome inputs and buttons
- Device.tsx to use Web Awesome inputs and buttons with icons
- TwoFactorVerifyModal to use Web Awesome input and buttons
- AdminPanel to use Web Awesome inputs and textarea
- CreateConnectionModal to use Web Awesome inputs and buttons with icons
- All buttons, inputs, and avatar to Web Awesome components
- Group modal components to use Web Awesome
- TwoFactorVerify and cabinet modal components to use Web Awesome
- ConfirmModal, ResetPasswordForm, and CookieConsent to use Web Awesome components
- UserMenu and AuthForm to use Web Awesome components
- MainContent buttons updated with Web Awesome components
Fixed
- CSS isolation for Web Awesome components from Tailwind Preflight resets (changed all property to revert-layer in global styles)
- Icon slot naming from 'prefix' to 'start' as per Web Awesome specs
- Label spacing and use wa-icon in button prefix slots (Cabinet, AddDeviceModal)
- Web Awesome styling issues: avatar shape, textarea background, duplicate asterisks
- Duplicate CSS rules for dark mode buttons removed
- Close button appearance and improved password input event handling in TwoFactorSetupModal
- Password input by reading value directly from element at form submission
- Password input in ProfileForm and added password-toggle to all password fields
- Type safety improvements for waitUntil implementation
- Event listener patterns for Web Awesome components in React
- Form submission patterns to read Web Awesome input values directly from refs
- 404 error by adding prerender=false to contact API route
- Label styling in ContactForm component (removed unnecessary block and margin-bottom classes)
- ContactForm validation, error handling, and UI improvements
- Accessibility improvements and require FROM_EMAIL config
- ContactForm asterisks from labels and added CONTACT_EMAIL env var
Security
- HTML content in emails properly escaped using escapeHtml helper to prevent XSS
- Turnstile CAPTCHA integration for contact form spam prevention
- Security policy (SECURITY.md) updated with new reporting methods
[2025-12-11]
Added
- wa-tooltip component for port hover interactions with fade-in transitions
- 2FA modal components (TwoFactorSetupModal, TwoFactorVerifyModal) replacing separate pages
- QR code generation using react-qr-code package for 2FA setup
- 2FA backup codes display in setup flow
- Accessibility attributes (role, aria-label) to modal components
- Named constants for setTimeout delays in 2FA flows
Changed
- 2FA modals prevent ESC key and click-outside closing during critical flows
- TwoFactorSetup page updated with react-qr-code package
Fixed
- QR code scanning in 2FA setup modal (disabled ESC/click-outside closing)
- QR code import corrected to use default import pattern (replaced Web Awesome QR code with react-qr-code package)
- Delays added to state transitions for better UX
- Extracted delay constant and removed unused import
[2025-12-10]
Added
- Sitemap integration with @astrojs/sitemap for improved SEO
- Open Graph meta tags and default OG image (network-patch-mapper-og.jpg)
- MIT License (LICENSE.md)
- SECURITY.md policy document
- robots.txt for search engine crawling
- Unified Header.tsx component with back button support across all pages
- Simple header component for account and MDX pages
- Legal document pages (terms.mdx, privacy-policy.mdx) with proper styling
- Custom swatches to color picker in CreateConnectionModal
- htmlFor attributes to all form labels for better accessibility
- Slot-based label styling for wa-color-picker to match other form labels
Changed
- Page titles updated for legal documents to include "Network Patch Mapper" branding
- Header component refactored with sticky positioning and scroll visibility detection
- Sitemap filtering using regex to exclude authentication and admin pages
- MDX layout footer now includes links to Privacy Policy and Terms & Conditions
- Sitemap filter refactored with regex (simplified from multiple explicit URL checks)
- Vulnerability reporting method updated in SECURITY.md
- Web Awesome link updated to point to official website
Fixed
- Scroll visibility logic in header component (added aria-label to back button)
- TypeScript syntax errors in Header component
- Form label associations (htmlFor attributes) for accessibility
- MDX page titles now render correctly from frontmatter (MDX title prop by accessing frontmatter)
- Web Awesome components to use proper closing tags instead of self-closing tags
Documentation
- README updated with Web Awesome and React Flow information
- Setup documentation consolidated with combined migration file approach
- Dependencies updated in package.json (astro-seo, @cloudflare/workers-types, resend)
- package-lock.json removed in favor of pnpm-lock.yaml
- Cleaned up trailing whitespaces and addressed code review feedback
Note to contributors: When making changes, please update this changelog according to the Keep a Changelog format. Group changes by type (Added, Changed, Deprecated, Removed, Fixed, Security) and be specific about what changed.