fix: review pass — docs, a11y, shortcut handler, and e2e#3
Merged
Conversation
Now that the CLI is going away, no consumer needs the JSON registry. Remove the /r/[name] route, the build.ts that emitted those JSON files, and the pretest/prebuild scripts that ran it. Drop the matching e2e tests. Replace the CLI-themed CTAs on the marketing page with copy-paste language (browse the components / read the docs), point the registry-items cards at their docs pages, and rewrite the install checklist as four manual steps with the new /api/wristkit-sync path. Sidestep the recurring webpack warning "docs is not exported from velite-data" by reading .velite/docs.json directly through a small lib/docs.ts shim. Drop the velite-data path alias and stale d.ts. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move handlers/healthkit-handler to handlers/wristkit-sync-handler and update the install path to app/api/wristkit-sync/route.ts so the public surface matches the brand. Tighten the template every wristkit user installs: - Constant-time API key compare via crypto.timingSafeEqual, with length check up front. - Per-IP rate limit (30 requests / 5 min) in an in-memory bucket, with a comment pointing at @vercel/firewall or @upstash/ratelimit for production-grade traffic. - Content-Type check (415) and Content-Length cap at 256 KB (413). - Try/catch around the insert returning a safe 500 instead of letting Postgres errors bubble out. - value: finite, 0..1_000_000; unit max 16; source max 64; strict schemas so unknown keys 400 instead of silently dropping. createDb now memoizes the postgres client per process so warm function instances reuse the connection. Tests cover the new 415, 429, and strict-schema branches (now 17 tests total). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
loadTodayActivity accepts { tz, goals } so the day boundary and the
displayed time match the user's locale instead of the server's
(usually UTC). Goals default to 600/30/8000 and are overridable.
queries.ts now uses the IANA timezone to compute startOfToday, and
treats null vs 0 correctly (kcal[0]?.value != null) so a real 0-step
day no longer flips to "partial". lastSync is taken from recordedAt
instead of ingestedAt so a backfill of yesterday's data still reads
as stale.
TodayData now carries lastSyncIso, lastSyncLabel and hoursSinceSync
pre-computed on the server, eliminating the hydration mismatch from
Date.now()/getHours() running on both sides. The Stale card no
longer needs a separate lastSync prop.
states.tsx swaps the Apple-style red/green/blue for the entrepta
violet (#7c6bff) / emerald (#10b981) / amber (#f59e0b), so the
component a user copies looks like the demo they saw on the site.
Tests updated to match the new TodayData shape; 17 still pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a headers() block to next.config.mjs covering CSP (default-src self plus the inline+eval Next needs for hydration), X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy, HSTS, and a Permissions-Policy that closes camera, mic, geolocation and the interest-cohort tracker. The /shortcut route now reads from apps/web/public/wristkit-sync.shortcut (populated by the prebuild copy step) instead of climbing two levels out of the deployment package. The previous path silently 404s on Vercel because files outside apps/web are not bundled into the serverless function. Wrap MdxContent in an error boundary so a broken doc no longer blanks out the whole docs page. Boundary logs the stack and shows a small inline alert with the error message. DB pooling is already covered by the lazy singleton added in the handler hardening commit. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add schemas/0002_dedupe.sql with a UNIQUE index on (user_id, metric, recorded_at) NULLS NOT DISTINCT, so a re-run of the iOS Shortcut against the same day cannot insert duplicate rows. The migration includes a commented-out cleanup CTE for tables that already drift. Mirror the unique index in lib/schema.ts via uniqueIndex so the drizzle schema stays in sync. Rename the registry meta from healthkit-schema to wristkit-schema to match the brand, and list both SQL files in the install plan. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
lib/registry-files.ts reads the actual source files from packages/registry at request/build time and exposes typed bundles for the today-activity-card component, the sync handler, and the two SQL migrations. The path is normalized and the read is asserted to stay inside the monorepo. components/docs/registry-file-bundle.tsx renders those files in entrepta Tabs with a CodeBlock per file, showing the destination path and a copy button. Section heading and intro line are passed in by the docs page. apps/web/app/docs/[[...slug]]/page.tsx wires the bundles in for /docs/components/today-activity-card and /docs/installation, after the MDX content. Other slugs render unchanged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drop every CLI reference. The new story is: copy the files shown on this site into your project, set two env vars, run the SQL on Supabase, install the Shortcut. Index, installation, shortcut setup, FAQ, today-activity-card, concepts/registry, concepts/component-states and concepts/data-model are all rewritten: - /api/healthkit is now /api/wristkit-sync everywhere - installation flow points at the file bundles rendered after the MDX - TodayActivityCard docs show every state as a live demo plus the new tz / goals options - component-states snippet now declares the data object before branching on it (the old snippet referenced an undefined variable) - data-model documents the new uniqueIndex - registry concept page explains why the CLI is gone - FAQ swaps "update the component" guidance from a CLI command to diffing the copy on the site Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the global 'outline: none !important' override with a ':focus:not(:focus-visible)' selector so mouse clicks stay quiet but keyboard focus still gets the global ring on inputs, buttons, menu items, options, tabs and cmdk items. Components that ship their own focus-visible styling (Button, code-block copy, etc.) already override the ring with their own indicator. Add a SkipLink (CSS-only, slides in on focus) and wire it into the marketing page and the docs layout. The marketing top bar becomes a <header>; <main> gets id="main-content" with tabIndex=-1 so the skip target is reachable. The docs sidebar is wrapped in a <nav aria-label="Documentation"> and its <main> mirrors the same pattern with id="docs-content". Other a11y polish: - MDX h1 is remapped to h2 to avoid two H1s on doc pages, since the page header already renders the title as h1. - MDX links now have underline (not color-only) for users who can't perceive color. - TodayActivityCardLoading announces itself with role=status and an aria-label. - Badge solid-error: white-on-rose contrast was ~3.4:1; now uses bg-canvas (dark) which clears AA at small text. - code-block adds aria-label on <pre> and a polite aria-live region that announces "Copied to clipboard". - External links in TopNavLink and SiteFooter get aria-hidden on the visual arrow and an sr-only "(opens in new tab)" notice. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two SQL files share the same dest ("Supabase SQL Editor") so React
warned about duplicate keys and the second tab would silently take
over the first. Switch the key + Tabs value to the source path,
which is always unique on disk, and label each tab with the source
filename. The CodeBlock still shows the dest as the filename label.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tailwind v4's preflight clobbers the inline transform on .skip-link so the "skip to content" pill was visible on every page load. Hide it the same way most a11y libraries do: position fixed at top: -100px and animate top back to 8px on focus. Same UX, no transform involved. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The iOS Shortcut posts { steps, moveKcal, exerciseMin } — not the
samples array we had documented. Update the validator, handler, tests,
docs, and hero preview to the real shape, and point the download URL at
the canonical iCloud Shortcut.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Strip the made-up marketing copy from the demo (.tsx suffix, Ln/Col, "strength day", retry button) and drop the partial state — it can't exist with the flat Shortcut payload. The error card is now generic so it doesn't leak which kind of error occurred (auth, db, anything). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Step 3 of the install guide references "SQL migrations" but the bundle rendered after "Route handler", so readers scanning top-to-bottom hit the wrong one first and assumed the SQL was missing. Swap the order and name each bundle explicitly in the prose. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Readers reported scrolling past the bundle at the bottom and assuming the SQL was missing. Drop the SQL bundle, paste the two migrations (plus the optional dedupe CTE) inline next to the instructions, and link to /docs/concepts/data-model for the design rationale. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Embed all lib, handler and component code directly in the page so the user never navigates away to copy files - Remove the RegistryFileBundle that was appending the route handler a second time at the bottom of the page - Replace the direct connection URL example with the Transaction pooler format and explain why the direct URL fails on Vercel (ENOTFOUND) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add optional `transform` to `RegistryFileSpec` so registry file content can be rewritten at load time without touching the source files. - Use it on load.ts to replace the monorepo-internal `./queries` shim with `@/lib/wristkit/queries`, the path users actually have in their projects. - Define `RegistryFile` as a plain struct (no `transform` field) so the return value serialises cleanly when passed to Client Components. - Fix the path-traversal guard: append `path.sep` to ROOT before `startsWith` so a sibling directory whose name shares the ROOT prefix can't bypass it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The /shortcut route reads from public/ at runtime, but only prebuild was copying the file there. Adding predev ensures the file exists when playwright starts the server with `pnpm dev`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove all CLI references. The install flow is now manual: copy files from the docs, run SQL in Supabase, download the iOS Shortcut. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Consolidates fixes from a full review pass across the monorepo.
Docs
Shortcut / handler
Components
A11y
topinstead oftransform)DX / infra