Skip to content

fix(web,ci): issue #43 batch P1 — security + correctness (7 items) - #60

Merged
InstaZDLL merged 2 commits into
mainfrom
fix/issue-43-p1-security-correctness
Jun 15, 2026
Merged

fix(web,ci): issue #43 batch P1 — security + correctness (7 items)#60
InstaZDLL merged 2 commits into
mainfrom
fix/issue-43-p1-security-correctness

Conversation

@InstaZDLL

@InstaZDLL InstaZDLL commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Summary

7 P1 findings from CodeRabbit on PR #41 / issue #43, bundled per
the issue's "batch P1 together" guidance.

Changes

File Fix
.github/workflows/ci-web.yml actions/checkout: persist-credentials: false
.github/workflows/label-pr.yml Drop workflow-level pull-requests: write (grant per-job), add concurrency block keyed on PR number
web/src/server-fns/session.ts Try/catch around auth.api.getSession, return null on APIError('UNAUTHORIZED'), rethrow others
web/src/routes/_authed.profiles.$profileId.libraries.$libraryId.artists.tsx Loader logs raw err server-side, surfaces generic message client-side
web/src/routes/_authed.profiles.$profileId.playlists.tsx Same shape — both loaders fix identically
web/src/lib/db.ts Tighten BETTER_AUTH_DB_MAX parse to /^[1-9]\d*$/ so '10foo' fails loud
web/src/components/ThemeToggle.tsx Try/catch around localStorage get/set — Safari private + WebView edge cases
web/.gitignore *.env* + !.env.example so .env.production / .env.staging can't slip through

Test plan

  • bun run typecheck clean
  • bun run lint clean
  • bun run test — 233 pass across 26 files
  • bun run build — SSR + Nitro bundle builds clean
  • prettier --check on the 5 modified web files clean

Refs

Closes 7/24 items of #43. P2 (UX/a11y) and P3+P4 (tooling/tests/
labeler) ride in separate PRs to keep each review ≤200 LOC per
the issue's batching guidance.

Summary by CodeRabbit

  • Bug Fixes

    • Correction de la gestion du changement de thème en mode de navigation privée.
    • Messages d'erreur utilisateur plus génériques et logging amélioré.
    • Meilleure gestion des erreurs d'authentification.
  • Chores

    • Amélioration de la sécurité des workflows GitHub Actions.
    • Meilleure gestion des fichiers d'environnement.
    • Validation renforcée de la configuration de la base de données.

7 findings from the CodeRabbit review on PR #41 / issue #43. Each
is a one-file fix; bundled because they share the same scope
(security / correctness) and the issue itself asked to batch P1
together.

## Changes

- `.github/workflows/ci-web.yml` — `actions/checkout` step grows
  `persist-credentials: false`. Drops the GITHUB_TOKEN from
  `.git/config` after checkout — nothing in the job pushes or makes
  authenticated git calls, so the token would be pure blast radius
  if a downstream step gets compromised.
- `.github/workflows/label-pr.yml` — drop workflow-level
  `pull-requests: write`; grant it per job (scope / type / size)
  so only the steps that actually mutate labels carry the
  privilege. Add a top-level `concurrency` block keyed on PR
  number — five fast rebases collapse to one labeler run instead
  of five overlapping races.
- `web/src/server-fns/session.ts` — wrap `auth.api.getSession` in
  try/catch. Better Auth throws `APIError('UNAUTHORIZED')` for
  expired / missing cookies, which is a normal "not logged in"
  state the `beforeLoad` consumer treats as `null`. Rethrow
  everything else so DB / network failures still surface.
- `web/src/routes/_authed.profiles.$profileId.libraries.$libraryId.artists.tsx`
  and `…playlists.tsx` — loaders no longer echo `err.message`
  back to the UI. Log the raw error server-side via
  `console.error`, return a stable generic message. Same shape on
  both loaders; the fix is mechanically identical.
- `web/src/lib/db.ts` — tighten `BETTER_AUTH_DB_MAX` parse to
  `/^[1-9]\d*$/` so `'10foo'` / `'1e3'` / `' 5 '` fail loud at
  boot instead of silently dropping to `10` / `1` / `5`.
- `web/src/components/ThemeToggle.tsx` — wrap both
  `localStorage.getItem` and `setItem` in try/catch. Safari's
  private browsing + some embedded WebViews throw quota /
  disabled-storage errors that would otherwise crash the toggle's
  render path. Falling back to `'auto'` keeps the UI responsive
  in those contexts.
- `web/.gitignore` — `*.env*` with `!.env.example` negation.
  Catches `.env.production` / `.env.staging` / any other variant
  the prior `.env` / `.env.local` / `.env.*.local` trio missed.

## Validation

- `bun run typecheck` clean.
- `bun run lint` clean.
- `bun run test` — 233 pass across 26 files.
- `bun run build` builds the SSR + Nitro bundle clean.
- `prettier --check` on the 5 modified web files — clean (the
  pre-existing 104-file format drift on `main` is out of scope).

## Refs

Issue #43 — P1 batch (7/7). P2 (UX/a11y) and P3+P4
(tooling/tests/labeler) follow in separate PRs per the issue's
"≤ 200 LOC" guidance.

Signed-off-by: InstaZDLL <github.105mh@8shield.net>
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@InstaZDLL, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 1 hour, 18 minutes, and 53 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f84b1265-deed-4efb-9cdd-54c4f4b3a789

📥 Commits

Reviewing files that changed from the base of the PR and between 2e3b4ff and a640fa1.

📒 Files selected for processing (1)
  • web/.gitignore
📝 Walkthrough

Walkthrough

Ce PR applique un ensemble de corrections de sécurité et de robustesse : suppression des credentials git après checkout CI, permissions minimales dans les workflows, validation stricte de la variable DB via regex, gestion explicite de UNAUTHORIZED dans la session Better Auth, masquage des messages d'erreur internes dans les loaders, et protection des accès localStorage par try/catch.

Modifications

Sécurité CI, configuration et robustesse applicative

Layer / File(s) Résumé
Durcissement des workflows CI
.github/workflows/ci-web.yml, .github/workflows/label-pr.yml
ci-web.yml ajoute persist-credentials: false pour ne pas laisser le GITHUB_TOKEN dans .git/config. label-pr.yml passe aux permissions globales minimales (contents: read), ajoute une concurrence par numéro de PR et déclare pull-requests: write explicitement sur chaque job.
Exclusion .env* et validation du pool DB
web/.gitignore, web/src/lib/db.ts
.gitignore passe à *.env* global avec exception !.env.example. db.ts valide BETTER_AUTH_DB_MAX via regex (entier positif uniquement) et produit un message d'erreur incluant la valeur brute en cas de valeur invalide.
Gestion UNAUTHORIZED dans getCurrentSession
web/src/server-fns/session.ts
Import de APIError depuis better-auth/api et enrobage de auth.api.getSession dans un try/catch : retourne null sur UNAUTHORIZED, re-propage toute autre erreur.
Hardening erreurs loaders et localStorage
web/src/routes/_authed.profiles.$profileId.libraries.$libraryId.artists.tsx, web/src/routes/_authed.profiles.$profileId.playlists.tsx, web/src/components/ThemeToggle.tsx
Les loaders artists et playlists loggent l'erreur complète côté serveur et renvoient un message générique au client. ThemeToggle protège localStorage.getItem et localStorage.setItem par try/catch pour les environnements sans stockage disponible.

🎯 Estimation de l'effort de revue

🎯 2 (Simple) | ⏱️ ~10 minutes

Issues potentiellement liées

  • review follow-up: monorepo merge findings (PR #41) #43 — Ce PR implémente directement l'ensemble des corrections P1 "sécurité / correction" listées dans cette issue : persist-credentials: false, scoping des permissions CI, try/catch sur auth.api.getSession et localStorage, masquage des err.message dans les loaders, validation regex de BETTER_AUTH_DB_MAX, et élargissement du pattern .env*.

Labels suggérés

scope: web, scope: tooling

Poème

🔒 Plus de credentials qui traînent dans .git/config,
Les erreurs se loggent mais restent bien cachées,
localStorage ne jette plus de panic,
UNAUTHORIZED ? Retourne null, bien pensé.
La regex garde le pool DB bien gardé —
Le code est durci, les secrets sont protégés ! 🛡️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Le titre identifie correctement les 7 correctifs P1 (sécurité + correctness) et lie le problème #43, résumant l'objectif principal du changeset.
Description check ✅ Passed La description est complète : elle inclut un résumé clair, un tableau détaillé des changements, un plan de test exhaustif avec tous les tests cochés, et des références précises à l'issue #43.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-43-p1-security-correctness

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added type: fix Bug fix scope: web Embedded web player (React) scope: routes Web routes scope: components Web UI components scope: tooling Build / dev tooling size: m 50-200 lines and removed scope: web Embedded web player (React) scope: routes Web routes scope: components Web UI components scope: tooling Build / dev tooling labels Jun 15, 2026
@InstaZDLL

Copy link
Copy Markdown
Owner Author

@coderabbitai full review please.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== PR `#60` diff ==="
gh pr view 60 --repo InstaZDLL/waveflow-server --json files,additions,deletions,title,body

echo ""
echo "=== Full diff ==="
gh pr diff 60 --repo InstaZDLL/waveflow-server

Length of output: 12571


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check for .envrc usage ==="
fd -H '.envrc' 2>/dev/null || echo "No .envrc found"

echo ""
echo "=== better-auth APIError: check status type ==="
fd -e ts -e d.ts . node_modules/better-auth 2>/dev/null | xargs grep -l 'APIError' 2>/dev/null | head -5 || echo "node_modules not present in sandbox"

echo ""
echo "=== Check existing .env files tracked by git ==="
git ls-files | grep -i 'env' || echo "None"

echo ""
echo "=== Full session.ts current state ==="
cat web/src/server-fns/session.ts

echo ""
echo "=== Full db.ts current state ==="
cat web/src/lib/db.ts

echo ""
echo "=== ThemeToggle.tsx full ==="
cat web/src/components/ThemeToggle.tsx

echo ""
echo "=== Check web/.gitignore for context ==="
cat web/.gitignore

echo ""
echo "=== Check if .env.example exists ==="
fd -H '.env.example' . || echo "No .env.example found"

echo ""
echo "=== label-pr.yml full ==="
cat .github/workflows/label-pr.yml

echo ""
echo "=== Check better-auth version ==="
cat web/package.json | python3 -c "import sys,json; p=json.load(sys.stdin); deps={**p.get('dependencies',{}), **p.get('devDependencies',{})}; print('better-auth:', deps.get('better-auth','not found'))"

Length of output: 13431



@InstaZDLL: Voici la revue complète.


Review of PR #60 — fix(web,ci): issue #43 batch P1

.github/workflows/ci-web.yml

persist-credentials: false — correct, consistent with the rest of the repo's checkout posture.


.github/workflows/label-pr.yml

  • Workflow-level pull-requests: write → dropped to contents: read; per-job escalation added for the three jobs that need it — correct.
  • concurrency keyed on github.event.pull_request.number is valid for pull_request_target (the PR number is always populated there). Correct.

⚠️ web/.gitignore*.env* is slightly over-broad

*.env* matches any filename containing the four-character substring .env (the dot is literal in gitignore globs). This is intentional for .env.production / .env.staging, but it also silently ignores .envrc — a standard direnv file that developers sometimes add to projects.

No .envrc exists in the repo right now (verified), so there's no immediate breakage. But if someone adds one later they'll be confused why git refuses to track it.

A tighter alternative that covers the same cases without the .envrc trap:

.env
.env.*
!.env.example

This matches .env, .env.local, .env.production, .env.staging, etc., while leaving .envrc unaffected.

Minor note: the existing *.local rule (line 4) already covers .env.local, so *.env* makes it doubly excluded — harmless but redundant.


web/src/lib/db.ts

/^[1-9]\d*$/ correctly rejects '10foo', '1e3', ' 5 ', '0', and leading zeros. JSON.stringify(rawMax) in the error message makes whitespace-padding bugs visible. Solid.


web/src/components/ThemeToggle.tsx

Both getItem and setItem wrapped in try/catch with clear fallback semantics. Error swallowing is intentional and well-commented. Correct.


web/src/routes/_authed.profiles.$profileId.libraries.$libraryId.artists.tsx & playlists.tsx

console.error logs the raw error server-side, generic string goes to the client. Correct approach — no internal details leak to the UI.


web/src/server-fns/session.ts

APIError.status in better-auth v1.6.x is a string literal union ('UNAUTHORIZED' | 'FORBIDDEN' | …), so err.status === 'UNAUTHORIZED' is the correct comparison (not numeric 401). The let session + definite-assignment pattern is TypeScript-idiomatic for try/catch; control-flow analysis confirms it's assigned before the if (!session?.user) check (typecheck passes). Correct.


Summary

File Finding Severity
web/.gitignore *.env* would silently ignore .envrc if added; consider .env + .env.* instead Low
All others Correct

The one actionable item is the .gitignore pattern. Everything else is solid — good batch.

@InstaZDLL InstaZDLL self-assigned this Jun 15, 2026
@InstaZDLL

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions github-actions Bot added scope: web Embedded web player (React) scope: routes Web routes scope: components Web UI components scope: tooling Build / dev tooling type: fix Bug fix and removed type: fix Bug fix labels Jun 15, 2026
Follow-up to #60 review. The original `*.env*` pattern caught
every `.env*` variant we wanted, but as a side effect it also
silently ignored `.envrc` — a standard direnv file that a future
contributor might reasonably add to the repo. No `.envrc` exists
today (verified via git ls-files + filesystem check), so this is
prophylactic rather than a current bug.

`.env` + `.env.*` is the tighter pair: it matches `.env`,
`.env.local`, `.env.production`, `.env.staging`, etc., while
leaving `.envrc` (and any other non-`.` suffix) unaffected. The
`!.env.example` negation stays so the bootstrap template still
commits.

Validation: `git check-ignore -v .envrc` returns nothing (not
ignored); `.env.production` / `.env.staging` are still ignored.

Signed-off-by: InstaZDLL <github.105mh@8shield.net>
@github-actions github-actions Bot added type: fix Bug fix and removed type: fix Bug fix labels Jun 15, 2026
@InstaZDLL

Copy link
Copy Markdown
Owner Author

@coderabbitai fix appliqué sur commit a640fa1. Switch *.env*.env + .env.* + !.env.example. .envrc reste tractable, .env.production / .env.staging toujours ignorés. Le doublon avec *.local que tu as noté sur .env.local reste mais c'est harmless.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@InstaZDLL Parfait — le pattern est maintenant précis : .env + .env.* couvre tous les variants de secrets, .envrc reste trackable, et la redondance avec *.local est effectivement sans impact. Fix solide. ✅

(ˆ⌣ˆ)

@InstaZDLL
InstaZDLL merged commit 2b56822 into main Jun 15, 2026
10 checks passed
@InstaZDLL
InstaZDLL deleted the fix/issue-43-p1-security-correctness branch June 15, 2026 18:11
InstaZDLL added a commit that referenced this pull request Jun 15, 2026
P2 batch from CodeRabbit on PR #41 / issue #43. 4 of the 5 P2
items applied; the 5th (styles.css OKLCH unification) is
deferred — see § below.

## Changes

- `web/src/components/PlayerBar.tsx` — `onPointerCancel` now
  commits the pending `seekScrub` instead of dropping it. The
  user already expressed intent by dragging; a system-initiated
  cancel (notification focus steal, gesture-to-scroll promotion)
  shouldn't lose that input.
- `web/src/lib/use-focus-trap.ts` — when `items.length === 0`,
  stamp a transient `tabindex="-1"` on the container before
  `.focus()` so `HTMLElement.focus()` actually runs (it silently
  no-ops on a non-tabbable element, which would let Tab fall
  through to the page underneath). Restore the prior attribute
  state after focus so the DOM contract stays intact for
  subsequent renders.
- `web/src/routes/_authed.profiles.tsx` — pre-format
  `last_used_at` in the loader via
  `Intl.DateTimeFormat('en-US', { timeZone: 'UTC' })`. Drops the
  SSR ↔ client divergence that `new Date(...).toLocaleDateString()`
  produced (Node defaults to system locale + TZ, browser uses the
  user's — React then logs a hydration mismatch and briefly
  flickers the wrong format). The loader also now logs raw err
  + surfaces a generic message, matching the artists / playlists
  loader fix from the P1 batch.
- `web/src/components/Footer.tsx` — display string was
  "AGPL-3.0", the licence file is "AGPL-3.0-only". Mirror the
  SPDX identifier.

## Deferred — styles.css OKLCH unification

The CodeRabbit finding asks the `@theme` block + `:root` fallback
in `styles.css` to consume the OKLCH tokens from
`@waveflow/design-tokens` instead of redefining `--surface`,
`--surface-strong`, `--line`, etc. in `rgba(...)` locally.

In practice this is a real refactor, not a one-liner:

- `design-tokens` currently emits the four base surface HEX
  values (`--color-surface-{dark,light}{,-elevated}`). The
  translucent overlay variables (`--surface`, `--line`, `--chip-bg`,
  …) are NOT in the design-tokens public surface today.
- Pulling them in needs one of:
  - Extend `design-tokens` to emit translucent overlays per
    preset (Sprint-level work; touches every preset definition).
  - Or rewrite `styles.css` to derive them via
    `oklch(from var(--color-surface-light) l c h / 0.72)` —
    works in Chromium 125+, Firefox 128+, Safari 17.2+; OK
    against the WaveFlow web's target matrix but worth a
    deliberate design decision.

Logging this for a follow-up PR rather than slipping a
half-finished refactor through the P2 batch. The other 4 P2
items ship now.

## Validation

- `bun run typecheck` clean.
- `bun run lint` clean.
- `bun run test` — 233 pass across 26 files.
- `prettier --check` on the 4 modified files clean.

## Refs

Closes 4/24 items of #43 (11/24 cumulative with P1 batch in #60).
P3+P4 ride in a separate PR.

Signed-off-by: InstaZDLL <github.105mh@8shield.net>
InstaZDLL added a commit that referenced this pull request Jun 15, 2026
7 findings from CodeRabbit on PR #41 / issue #43 — the P3 tooling
batch (6 items) + the single P4 labeler item, bundled because
they all touch dev / CI infrastructure rather than runtime code.

## Changes

- `web/scripts/db-migrate.ts` — resolve `MIGRATIONS_DIR` relative
  to the script via `fileURLToPath(import.meta.url)` instead of
  `process.cwd()`. After the monorepo merge the script can be
  invoked from the repo root (`bun --cwd=web run db:migrate`);
  the previous CWD anchor broke silently because it pointed at
  `<repo>/db/migrations`, which doesn't exist.
- `web/vitest.config.ts` — `passWithNoTests: false`. The flag
  was a bootstrap-era convenience while the suite was empty; now
  that 230+ tests are landing, a typo in the `include` glob (or
  an accidental file move that breaks discovery) would silently
  pass CI under `true`. Failing loud is the right signal.
- `web/src/routes/sign-up.test.tsx` — three new cases:
  - empty / whitespace-only display name → blocked
  - password at MAX_PASSWORD + 1 (129 chars) → blocked
  - surrounding whitespace on name + email → trimmed before
    `signUp.email` call
- Six route-adjacent test files (`sign-up.test.tsx`,
  `_authed.profiles.$profileId.libraries.$libraryId.albums*`,
  `…artists*`, `…playlists.test.tsx`,
  `…playlists.$playlistId.test.tsx`) — switch
  `React.PropsWithChildren` (which referenced the global
  `React` namespace without an `import * as React`) to a typed
  `PropsWithChildren` imported via `import type { PropsWithChildren }
  from 'react'`. The tests passed before only because the JSX
  transform happens to expose `React` ambient; the explicit
  import locks the contract and is what every other test file
  in the suite already does.
- `web/src/routes/sign-in.test.ts` → `-sign-in.test.ts` —
  TanStack Router's `-`-prefix convention excludes the file
  from the auto-generated route tree. Without the rename the
  router plugin had been incidentally treating
  `sign-in.test.ts` as a candidate route module on every dev
  reload. Kept `.ts` (not `.tsx`) because the test doesn't
  render JSX (`Link: () => null` mock).
- `.github/pull_request_template.md` — first heading `## Summary`
  → `# Summary`. MD041 (first-line-heading) wants H1; the
  template was the only file in the repo tripping it.
- `.github/labeler.yml` — `web/src/routes/sign-in/**` /
  `…sign-up/**` only matched DIRECTORIES; the actual routes are
  `sign-in.tsx` / `sign-up.tsx` files at the root of
  `routes/`. Switch to `sign-in{,/**}` / `sign-up{,/**}` so a
  PR touching either form lights up the auth label.

## Validation

- `bun run typecheck` clean.
- `bun run lint` clean.
- `bun run test` — 236 pass across 26 files (was 233, +3 new
  sign-up boundary cases).
- `prettier --check` on the modified files clean.

## Refs

Closes 7/24 items of #43. Cumulative: 18/24 across the three
batched PRs (#60 P1 + #61 P2 + this).

The 4 P0 items + 1 deferred P2 (styles.css OKLCH unification)
remain. P0 was tagged in the issue as "ship with the archive
PR" — verifying status as a follow-up.

Signed-off-by: InstaZDLL <github.105mh@8shield.net>
InstaZDLL added a commit that referenced this pull request Jun 15, 2026
7 findings from CodeRabbit on PR #41 / issue #43 — the P3 tooling
batch (6 items) + the single P4 labeler item, bundled because
they all touch dev / CI infrastructure rather than runtime code.

## Changes

- `web/scripts/db-migrate.ts` — resolve `MIGRATIONS_DIR` relative
  to the script via `fileURLToPath(import.meta.url)` instead of
  `process.cwd()`. After the monorepo merge the script can be
  invoked from the repo root (`bun --cwd=web run db:migrate`);
  the previous CWD anchor broke silently because it pointed at
  `<repo>/db/migrations`, which doesn't exist.
- `web/vitest.config.ts` — `passWithNoTests: false`. The flag
  was a bootstrap-era convenience while the suite was empty; now
  that 230+ tests are landing, a typo in the `include` glob (or
  an accidental file move that breaks discovery) would silently
  pass CI under `true`. Failing loud is the right signal.
- `web/src/routes/sign-up.test.tsx` — three new cases:
  - empty / whitespace-only display name → blocked
  - password at MAX_PASSWORD + 1 (129 chars) → blocked
  - surrounding whitespace on name + email → trimmed before
    `signUp.email` call
- Six route-adjacent test files (`sign-up.test.tsx`,
  `_authed.profiles.$profileId.libraries.$libraryId.albums*`,
  `…artists*`, `…playlists.test.tsx`,
  `…playlists.$playlistId.test.tsx`) — switch
  `React.PropsWithChildren` (which referenced the global
  `React` namespace without an `import * as React`) to a typed
  `PropsWithChildren` imported via `import type { PropsWithChildren }
  from 'react'`. The tests passed before only because the JSX
  transform happens to expose `React` ambient; the explicit
  import locks the contract and is what every other test file
  in the suite already does.
- `web/src/routes/sign-in.test.ts` → `-sign-in.test.ts` —
  TanStack Router's `-`-prefix convention excludes the file
  from the auto-generated route tree. Without the rename the
  router plugin had been incidentally treating
  `sign-in.test.ts` as a candidate route module on every dev
  reload. Kept `.ts` (not `.tsx`) because the test doesn't
  render JSX (`Link: () => null` mock).
- `.github/pull_request_template.md` — first heading `## Summary`
  → `# Summary`. MD041 (first-line-heading) wants H1; the
  template was the only file in the repo tripping it.
- `.github/labeler.yml` — `web/src/routes/sign-in/**` /
  `…sign-up/**` only matched DIRECTORIES; the actual routes are
  `sign-in.tsx` / `sign-up.tsx` files at the root of
  `routes/`. Switch to `sign-in{,/**}` / `sign-up{,/**}` so a
  PR touching either form lights up the auth label.

## Validation

- `bun run typecheck` clean.
- `bun run lint` clean.
- `bun run test` — 236 pass across 26 files (was 233, +3 new
  sign-up boundary cases).
- `prettier --check` on the modified files clean.

## Refs

Closes 7/24 items of #43. Cumulative: 18/24 across the three
batched PRs (#60 P1 + #61 P2 + this).

The 4 P0 items + 1 deferred P2 (styles.css OKLCH unification)
remain. P0 was tagged in the issue as "ship with the archive
PR" — verifying status as a follow-up.

Signed-off-by: InstaZDLL <github.105mh@8shield.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: components Web UI components scope: routes Web routes scope: tooling Build / dev tooling scope: web Embedded web player (React) size: m 50-200 lines type: fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant