Move the Gaze marketing home from the legacy /marketing/gaze route to
a dedicated gaze subdomain landing page (src/routes/gaze). The new page
adds a richer hero, feature highlights, and a direct .dmg download flow
that resolves a signed S3 URL via the tRPC downloads.getDownloadUrl
endpoint.
Extract the download-resolution logic into a shared, testable
downloadAsset helper (src/lib/download-asset) so current and future
subdomain landing pages (InputHalo, Lineage, …) share one code path.
The helper is pure over an injected DownloadApi + redirect sink, keeping
it unit-testable without importing solid-js / CSRF cookie code.
Replace the old marketing/gaze route with a permanent 308 redirect to
https://gaze.freno.me so existing inbound links keep resolving to the
canonical home.
Add unit tests covering the tRPC call shape, redirect sink, and error
handling.
Refactor sitemap.xml route to read the Host header, determine the active
site, and produce a sitemap scoped to that site's routes with canonical
URLs. Extracts route definitions and XML generation into shared modules.
- src/server/nessa-auth.ts: replace jose HS256 sign/verify with Clerk
session JWT verification via @clerk/backend verifyToken (RS256/JWKS).
signNessaToken removed — frontend now supplies Clerk session tokens.
- src/server/api/utils.ts: createTRPCContext verifies Clerk JWT, resolves
ctx.nessaUserId via SELECT id FROM users WHERE clerkUserId=? on the
shared NessaConnectionFactory. Lookup miss throws typed UNAUTHORIZED
(webhook has not run yet). Invalid/expired tokens are swallowed; the
enforceNessaUser middleware rejects null nessaUserId.
- src/server/api/routers/nessa-community-authz.test.ts: add clerkUserId
lookup tests (seeded match, missing row, mismatched id, local≠clerk).
- src/server/nessa-auth.test.ts: verifyNessaToken unit tests with mocked
@clerk/backend (valid sub, missing sub, malformed/expired/wrong-signature
rejection) plus static audit that signNessaToken is gone.
- src/server/clerk-user-webhook.ts + src/routes/api/clerk-webhook.ts:
Clerk user.created/user.updated webhook handler (Svix signature
verification, idempotent upsert by clerkUserId, lazy ALTER TABLE
migration) with full test suite.
- src/server/api/routers/nessa.ts: remove legacy register/login/google/
apple sign-in mutations (Clerk is now the sole identity provider).
- src/env/server.ts: add NESSA_CLERK_SECRET, NESSA_CLERK_JWT_ISSUER,
NESSA_CLERK_WEBHOOK_SECRET; NESSA_JWT_SECRET moved to optional.
- package.json: add @clerk/backend, svix; lineage/auth.test.ts and
nessa-ownership.test.ts: add Clerk env vars to env mocks.
- .env.example: document Clerk config vars and rotation.
- delete nessa-google-oauth.test.ts (Google auth removed).
ctx.nessaUserId remains the local users.id — router bodies are untouched.