trails/apps/journal/app/routes/api.sync.push.$provider.$routeId.ts
Ullrich Schäfer b9aac2859a
Drop auth.server.ts re-exports + rename to .server.ts convention (task 5.2)
Two cleanups in one pass:

1. Update import paths app-wide from `~/lib/auth.server` to
   `~/lib/auth/session.server` for the four session helpers
   (sessionStorage, createSession, getSessionUser, destroySession).
   ~40 files: 33 simple path swaps where the file imported only session
   symbols, 5 splits where it also imported per-method auth functions
   (auth.verify.tsx, api.settings.email.ts, activities.\$id.tsx,
   routes.\$id.tsx, auth.accept-terms.tsx) — those keep one import
   from auth.server (for verifyMagicToken, canView, recordTermsAcceptance,
   etc.) and gain a second import from auth/session.server.
   Two more files used relative paths and were missed by the first
   grep pass (lib/oauth.server.ts and routes/oauth.authorize.tsx) —
   migrated too.
   The @deprecated re-exports block in auth.server.ts is gone.

2. Rename the new auth files to follow the project's `.server.ts`
   convention so Vite/React Router treat them as server-only (they
   read process.env.SESSION_SECRET, hit the DB, etc. — must NOT enter
   the client bundle):
   - auth/session.ts → auth/session.server.ts
   - auth/completion.ts → auth/completion.server.ts
   - auth/completion.test.ts → auth/completion.server.test.ts
   Done with `git mv` so blame is preserved.

Verified: typecheck + lint green; 126 unit tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 03:01:30 +02:00

56 lines
2.1 KiB
TypeScript

import { redirect, data } from "react-router";
import type { Route } from "./+types/api.sync.push.$provider.$routeId";
import { getSessionUser } from "~/lib/auth/session.server";
import { getManifest } from "~/lib/connected-services";
import { pushRouteToProvider } from "~/lib/connected-services/push-action.server";
import { encodeOAuthState } from "~/lib/connected-services/oauth-state.server";
export async function action({ params, request }: Route.ActionArgs) {
const user = await getSessionUser(request);
if (!user) return redirect("/auth/login");
const manifest = getManifest(params.provider);
if (!manifest) return data({ error: "Unknown provider" }, { status: 404 });
const returnTo = `/routes/${params.routeId}`;
const outcome = await pushRouteToProvider({
userId: user.id,
providerId: manifest.id,
routeId: params.routeId,
});
switch (outcome.status) {
case "success":
return redirect(`${returnTo}?push=success`);
case "scope_missing": {
if (!manifest.buildAuthUrl) {
return redirect(`${returnTo}?push=needs_permission`);
}
const origin = process.env.ORIGIN ?? "http://localhost:3000";
const redirectUri = `${origin}/api/sync/callback/${manifest.id}`;
const state = encodeOAuthState({
pushAfter: { routeId: params.routeId },
returnTo,
});
return redirect(manifest.buildAuthUrl(redirectUri, state));
}
case "needs_relink":
return redirect(`${returnTo}?push=needs_permission`);
case "no_connection":
return redirect(`${returnTo}?push=no_connection`);
case "no_geometry":
return redirect(`${returnTo}?push=no_geometry`);
case "not_owner":
return data({ error: "Forbidden" }, { status: 403 });
case "not_found":
return data({ error: "Not found" }, { status: 404 });
case "unsupported_provider":
return data({ error: "Provider does not support push" }, { status: 400 });
case "error":
return redirect(`${returnTo}?push=error&code=${outcome.code}`);
}
}
export function loader() {
return data({ error: "Method not allowed" }, { status: 405 });
}