Add typed context and middleware for oRPC procedures
Use implement(contract).$context<APIContext>() for proper type safety in all procedure handlers. Create authMiddleware and loginRequestMiddleware using os.middleware() and apply with .use() on routes requiring auth. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,9 +16,6 @@
|
||||
* e. Return { status: 'completed', redirectTo: '/dashboard' or '/auth/trust-device' }
|
||||
*/
|
||||
|
||||
import type { APIContext } from "../../context.js";
|
||||
import { implement } from "@orpc/server";
|
||||
import { contract } from "@reviq/api-contract";
|
||||
import {
|
||||
COOKIE_NAMES,
|
||||
COOKIE_OPTIONS,
|
||||
@@ -32,8 +29,7 @@ import {
|
||||
isDeviceTrusted,
|
||||
upsertUserDevice,
|
||||
} from "../../utils/session.js";
|
||||
|
||||
const os = implement(contract);
|
||||
import { os } from "../base.js";
|
||||
|
||||
/**
|
||||
* Check if a string looks like a UUID (fake token)
|
||||
@@ -50,11 +46,9 @@ const isUUID = (str: string): boolean => {
|
||||
*/
|
||||
export const loginIfRequestIsCompleted =
|
||||
os.auth.loginIfRequestIsCompleted.handler(async ({ context }) => {
|
||||
const ctx = context as APIContext;
|
||||
|
||||
// Read login request token from cookie
|
||||
const loginRequestToken = getCookie(
|
||||
ctx.reqHeaders,
|
||||
context.reqHeaders,
|
||||
COOKIE_NAMES.LOGIN_REQUEST_TOKEN,
|
||||
);
|
||||
|
||||
@@ -78,7 +72,7 @@ export const loginIfRequestIsCompleted =
|
||||
}
|
||||
|
||||
// Fetch login request from database
|
||||
const loginRequest = await ctx.db
|
||||
const loginRequest = await context.db
|
||||
.selectFrom("login_requests")
|
||||
.select([
|
||||
"id",
|
||||
@@ -115,12 +109,12 @@ export const loginIfRequestIsCompleted =
|
||||
}
|
||||
|
||||
// Get current request info
|
||||
const geo = getGeoInfo(ctx.reqHeaders);
|
||||
const userAgent = getUserAgent(ctx.reqHeaders);
|
||||
const geo = getGeoInfo(context.reqHeaders);
|
||||
const userAgent = getUserAgent(context.reqHeaders);
|
||||
|
||||
// Upsert user device
|
||||
const deviceId = await upsertUserDevice(
|
||||
ctx.db,
|
||||
context.db,
|
||||
userId,
|
||||
deviceFingerprint,
|
||||
geo,
|
||||
@@ -129,13 +123,13 @@ export const loginIfRequestIsCompleted =
|
||||
|
||||
// Check if device is already trusted
|
||||
const deviceTrusted = await isDeviceTrusted(
|
||||
ctx.db,
|
||||
context.db,
|
||||
userId,
|
||||
deviceFingerprint,
|
||||
);
|
||||
|
||||
// Create session with trusted mode = true (email-confirmed login)
|
||||
const session = await createSession(ctx.db, {
|
||||
const session = await createSession(context.db, {
|
||||
userId,
|
||||
deviceId,
|
||||
trustedMode: true,
|
||||
@@ -144,21 +138,21 @@ export const loginIfRequestIsCompleted =
|
||||
});
|
||||
|
||||
// Delete the login request (it's been consumed)
|
||||
await ctx.db
|
||||
await context.db
|
||||
.deleteFrom("login_requests")
|
||||
.where("id", "=", String(loginRequestId))
|
||||
.execute();
|
||||
|
||||
// Set session cookie
|
||||
setCookie(
|
||||
ctx.resHeaders,
|
||||
context.resHeaders,
|
||||
COOKIE_NAMES.SESSION_TOKEN,
|
||||
session.token,
|
||||
COOKIE_OPTIONS.session,
|
||||
);
|
||||
|
||||
// Clear login request cookie
|
||||
deleteCookie(ctx.resHeaders, COOKIE_NAMES.LOGIN_REQUEST_TOKEN);
|
||||
deleteCookie(context.resHeaders, COOKIE_NAMES.LOGIN_REQUEST_TOKEN);
|
||||
|
||||
// Determine redirect path based on device trust status
|
||||
const redirectTo = deviceTrusted ? "/dashboard" : "/auth/trust-device";
|
||||
|
||||
Reference in New Issue
Block a user