Journal server (Phase 1.4 + 1.5): - Add oauth_clients, oauth_codes, oauth_tokens tables to journal schema - Implement GET /oauth/authorize with PKCE flow and login redirect - Implement POST /oauth/token (authorization_code + refresh_token grants) - Add validateBearerToken() + getAuthenticatedUser() middleware - Seed trails-cool-mobile as trusted OAuth client on server startup - Add GET /.well-known/trails-cool discovery endpoint - Add returnTo support to login page and magic link verify - Add @trails-cool/api workspace dependency to journal Mobile app (Phase 1.5 + 1.6): - Login screen with server URL input and discovery validation - OAuth2 PKCE login via expo-web-browser with expo-crypto for Hermes - Token storage in expo-secure-store with auto-refresh on 401 - API client with bearer token injection and typed errors - Server URL persistence with localhost default in dev mode - API version compatibility check on app foreground - Log out + switch server on Profile tab - iOS ATS exception for local networking Tests: - PKCE crypto verification, OAuthError, token generation - Discovery endpoint response shape - API version semver compatibility - API client error types Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
36 lines
2 KiB
TypeScript
36 lines
2 KiB
TypeScript
import { type RouteConfig, index, route } from "@react-router/dev/routes";
|
|
|
|
export default [
|
|
index("routes/home.tsx"),
|
|
route(".well-known/trails-cool", "routes/api.well-known.trails-cool.ts"),
|
|
route("oauth/authorize", "routes/oauth.authorize.tsx"),
|
|
route("oauth/token", "routes/oauth.token.ts"),
|
|
route("auth/register", "routes/auth.register.tsx"),
|
|
route("auth/login", "routes/auth.login.tsx"),
|
|
route("auth/verify", "routes/auth.verify.tsx"),
|
|
route("auth/logout", "routes/auth.logout.tsx"),
|
|
route("api/auth/register", "routes/api.auth.register.ts"),
|
|
route("api/auth/login", "routes/api.auth.login.ts"),
|
|
route("routes", "routes/routes._index.tsx"),
|
|
route("routes/new", "routes/routes.new.tsx"),
|
|
route("routes/:id", "routes/routes.$id.tsx"),
|
|
route("routes/:id/edit", "routes/routes.$id.edit.tsx"),
|
|
route("api/routes/:id/callback", "routes/api.routes.$id.callback.ts"),
|
|
route("api/routes/:id/edit-in-planner", "routes/api.routes.$id.edit-in-planner.ts"),
|
|
route("api/routes/:id/gpx", "routes/api.routes.$id.gpx.ts"),
|
|
route("activities", "routes/activities._index.tsx"),
|
|
route("activities/new", "routes/activities.new.tsx"),
|
|
route("activities/:id", "routes/activities.$id.tsx"),
|
|
route("users/:username", "routes/users.$username.tsx"),
|
|
route("settings", "routes/settings.tsx"),
|
|
route("api/settings/profile", "routes/api.settings.profile.ts"),
|
|
route("api/settings/email", "routes/api.settings.email.ts"),
|
|
route("api/settings/passkey/delete", "routes/api.settings.passkey.delete.ts"),
|
|
route("api/settings/delete-account", "routes/api.settings.delete-account.ts"),
|
|
route("sync/import/:provider", "routes/sync.import.$provider.tsx"),
|
|
route("api/sync/connect/:provider", "routes/api.sync.connect.$provider.ts"),
|
|
route("api/sync/callback/:provider", "routes/api.sync.callback.$provider.ts"),
|
|
route("api/sync/disconnect/:provider", "routes/api.sync.disconnect.$provider.ts"),
|
|
route("api/sync/webhook/:provider", "routes/api.sync.webhook.$provider.ts"),
|
|
route("privacy", "routes/privacy.tsx"),
|
|
] satisfies RouteConfig;
|