Simplify middleware and remove unused code
- Remove unused orgMemberMiddleware (org procedures use helper functions) - Remove orgMemberProcedure from base.ts - Simplify superuserMiddleware using inline concat syntax - Import OrgInfo/OrgMembership from context.ts instead of redefining Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,5 @@
|
|||||||
|
|
||||||
export { authMiddleware } from "./auth.js";
|
export { authMiddleware } from "./auth.js";
|
||||||
export { loginRequestMiddleware } from "./login-request.js";
|
export { loginRequestMiddleware } from "./login-request.js";
|
||||||
export { orgMemberMiddleware } from "./org-member.js";
|
|
||||||
export { os } from "./os.js";
|
export { os } from "./os.js";
|
||||||
export { superuserMiddleware } from "./superuser.js";
|
export { superuserMiddleware } from "./superuser.js";
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
/**
|
|
||||||
* Org member middleware - authenticates and verifies org membership
|
|
||||||
*
|
|
||||||
* This middleware chains authMiddleware first, then looks up the org
|
|
||||||
* and verifies the user is a member. Adds org and membership to context.
|
|
||||||
*
|
|
||||||
* Input must include `slug` (the org slug).
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type {
|
|
||||||
AuthenticatedContext,
|
|
||||||
OrgInfo,
|
|
||||||
OrgMembership,
|
|
||||||
} from "../context.js";
|
|
||||||
import { ORPCError } from "@orpc/server";
|
|
||||||
import { authMiddleware } from "./auth.js";
|
|
||||||
import { os } from "./os.js";
|
|
||||||
|
|
||||||
interface OrgSlugInput {
|
|
||||||
slug: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const orgMemberCheck = os.middleware(
|
|
||||||
async (
|
|
||||||
{
|
|
||||||
context,
|
|
||||||
next,
|
|
||||||
}: {
|
|
||||||
context: AuthenticatedContext;
|
|
||||||
next: (opts: {
|
|
||||||
context: { org: OrgInfo; membership: OrgMembership };
|
|
||||||
}) => Promise<unknown>;
|
|
||||||
},
|
|
||||||
input: OrgSlugInput,
|
|
||||||
) => {
|
|
||||||
const { db } = context;
|
|
||||||
const { slug } = input;
|
|
||||||
|
|
||||||
// Look up org by slug
|
|
||||||
const org = await db
|
|
||||||
.selectFrom("orgs")
|
|
||||||
.select(["id", "slug", "display_name", "logo_url", "created_at"])
|
|
||||||
.where("slug", "=", slug)
|
|
||||||
.executeTakeFirst();
|
|
||||||
|
|
||||||
if (!org) {
|
|
||||||
throw new ORPCError("NOT_FOUND", { message: "Organization not found" });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check user membership
|
|
||||||
const membership = await db
|
|
||||||
.selectFrom("org_members")
|
|
||||||
.select(["id", "role", "created_at"])
|
|
||||||
.where("org_id", "=", org.id)
|
|
||||||
.where("user_id", "=", context.user.id)
|
|
||||||
.executeTakeFirst();
|
|
||||||
|
|
||||||
if (!membership) {
|
|
||||||
throw new ORPCError("FORBIDDEN", {
|
|
||||||
message: "You are not a member of this organization",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const orgInfo: OrgInfo = {
|
|
||||||
id: org.id,
|
|
||||||
slug: org.slug,
|
|
||||||
displayName: org.display_name,
|
|
||||||
logoUrl: org.logo_url,
|
|
||||||
createdAt: org.created_at,
|
|
||||||
};
|
|
||||||
|
|
||||||
const membershipInfo: OrgMembership = {
|
|
||||||
id: membership.id,
|
|
||||||
role: membership.role,
|
|
||||||
createdAt: membership.created_at,
|
|
||||||
};
|
|
||||||
|
|
||||||
return next({
|
|
||||||
context: {
|
|
||||||
org: orgInfo,
|
|
||||||
membership: membershipInfo,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export const orgMemberMiddleware = authMiddleware.concat(orgMemberCheck);
|
|
||||||
@@ -4,19 +4,11 @@
|
|||||||
* This middleware chains authMiddleware first, then checks for superuser.
|
* This middleware chains authMiddleware first, then checks for superuser.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { AuthenticatedContext } from "../context.js";
|
|
||||||
import { ORPCError } from "@orpc/server";
|
import { ORPCError } from "@orpc/server";
|
||||||
import { authMiddleware } from "./auth.js";
|
import { authMiddleware } from "./auth.js";
|
||||||
import { os } from "./os.js";
|
|
||||||
|
|
||||||
const superuserCheck = os.middleware(
|
export const superuserMiddleware = authMiddleware.concat(
|
||||||
async ({
|
async ({ context, next }) => {
|
||||||
context,
|
|
||||||
next,
|
|
||||||
}: {
|
|
||||||
context: AuthenticatedContext;
|
|
||||||
next: () => Promise<unknown>;
|
|
||||||
}) => {
|
|
||||||
if (!context.user.isSuperuser) {
|
if (!context.user.isSuperuser) {
|
||||||
throw new ORPCError("FORBIDDEN", {
|
throw new ORPCError("FORBIDDEN", {
|
||||||
message: "Superuser access required",
|
message: "Superuser access required",
|
||||||
@@ -25,5 +17,3 @@ const superuserCheck = os.middleware(
|
|||||||
return next();
|
return next();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const superuserMiddleware = authMiddleware.concat(superuserCheck);
|
|
||||||
|
|||||||
@@ -9,35 +9,21 @@ import type {
|
|||||||
APIContext,
|
APIContext,
|
||||||
AuthenticatedContext,
|
AuthenticatedContext,
|
||||||
LoginRequestContext,
|
LoginRequestContext,
|
||||||
OrgMemberContext,
|
|
||||||
} from "../context.js";
|
} from "../context.js";
|
||||||
import {
|
import {
|
||||||
authMiddleware,
|
authMiddleware,
|
||||||
loginRequestMiddleware,
|
loginRequestMiddleware,
|
||||||
orgMemberMiddleware,
|
|
||||||
os,
|
os,
|
||||||
superuserMiddleware,
|
superuserMiddleware,
|
||||||
} from "../middlewares/index.js";
|
} from "../middlewares/index.js";
|
||||||
|
|
||||||
// Re-export middlewares and os
|
// Re-export middlewares and os
|
||||||
export {
|
export { authMiddleware, loginRequestMiddleware, os, superuserMiddleware };
|
||||||
authMiddleware,
|
|
||||||
loginRequestMiddleware,
|
|
||||||
orgMemberMiddleware,
|
|
||||||
os,
|
|
||||||
superuserMiddleware,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pre-configured procedures with middleware applied
|
// Pre-configured procedures with middleware applied
|
||||||
export const authedProcedure = os.use(authMiddleware);
|
export const authedProcedure = os.use(authMiddleware);
|
||||||
export const superuserProcedure = os.use(superuserMiddleware);
|
export const superuserProcedure = os.use(superuserMiddleware);
|
||||||
export const loginRequestProcedure = os.use(loginRequestMiddleware);
|
export const loginRequestProcedure = os.use(loginRequestMiddleware);
|
||||||
export const orgMemberProcedure = os.use(orgMemberMiddleware);
|
|
||||||
|
|
||||||
// Type exports for use in procedure files
|
// Type exports for use in procedure files
|
||||||
export type {
|
export type { APIContext, AuthenticatedContext, LoginRequestContext };
|
||||||
APIContext,
|
|
||||||
AuthenticatedContext,
|
|
||||||
LoginRequestContext,
|
|
||||||
OrgMemberContext,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -3,27 +3,13 @@
|
|||||||
* Provides org lookup, membership verification, and role checks
|
* Provides org lookup, membership verification, and role checks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { OrgInfo, OrgMembership } from "../../context.js";
|
||||||
import type { DB, OrgRole } from "@reviq/db-schema";
|
import type { DB, OrgRole } from "@reviq/db-schema";
|
||||||
import type { Kysely } from "kysely";
|
import type { Kysely } from "kysely";
|
||||||
import { ORPCError } from "@orpc/server";
|
import { ORPCError } from "@orpc/server";
|
||||||
|
|
||||||
// ===== Types =====
|
// Re-export types for convenience
|
||||||
|
export type { OrgInfo, OrgMembership };
|
||||||
/** Org info returned from lookup */
|
|
||||||
export interface OrgInfo {
|
|
||||||
id: number;
|
|
||||||
slug: string;
|
|
||||||
displayName: string;
|
|
||||||
logoUrl: string | null;
|
|
||||||
createdAt: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** User's membership in an org */
|
|
||||||
export interface OrgMembership {
|
|
||||||
id: number;
|
|
||||||
role: OrgRole;
|
|
||||||
createdAt: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Role Hierarchy =====
|
// ===== Role Hierarchy =====
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user