From ae0f3d6683d4605d89ecc61d58d9014b0dcabf4f Mon Sep 17 00:00:00 2001 From: Thad Miller Date: Thu, 28 May 2026 14:42:50 -0400 Subject: [PATCH] [bugfix] allow local clerk to work --- src/middleware.ts | 56 +++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/middleware.ts b/src/middleware.ts index 9246b0d..d908e2a 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,7 +1,6 @@ import { clerkMiddleware, createRouteMatcher, clerkClient } from '@clerk/astro/server'; -import type { MiddlewareNext } from 'astro'; import 'dotenv/config'; - + declare global { namespace App { interface Locals { @@ -9,19 +8,23 @@ declare global { } } } - + const isProtectedRoute = createRouteMatcher(['/pokemon']); const isAdminRoute = createRouteMatcher(['/admin']); - + const TARGET_ORG_ID = "org_3Baav9czkRLLlC7g89oJWqRRulK"; - +const ADMIN_ORG_IDS = new Set([ + "org_3Baav9czkRLLlC7g89oJWqRRulK", + "org_3ABdwuK3qD7Saq590ZMQWY7AvVz", +]); + export const onRequest = clerkMiddleware(async (auth, context, next) => { const { isAuthenticated, userId, redirectToSignIn, has } = auth(); - + if (!isAuthenticated && isProtectedRoute(context.request)) { return redirectToSignIn(); } - + // ── Inventory visibility check ────────────────────────────────────────────── // Resolves to true if the user belongs to the target org OR has the feature const canAddInventory = process.env.INVENTORY_ACCESS === 'true' || @@ -33,27 +36,38 @@ export const onRequest = clerkMiddleware(async (auth, context, next) => { (await getUserOrgIds(context, userId)).includes(TARGET_ORG_ID) ) ); - + // Expose the flag to your Astro pages via locals context.locals.canAddInventory = Boolean(canAddInventory); - + // ── Admin route guard ─────────────────────────────────────────── if (isAdminRoute(context.request)) { if (!isAuthenticated || !userId) { return redirectToSignIn(); } - + try { const client = await clerkClient(context); - const memberships = await client.organizations.getOrganizationMembershipList({ - organizationId: TARGET_ORG_ID, - }); - - const userMembership = memberships.data.find( - (m) => m.publicUserData?.userId === userId + const userOrgIds = await getUserOrgIds(context, userId); + const matchingOrgIds = userOrgIds.filter((id) => ADMIN_ORG_IDS.has(id)); + + if (matchingOrgIds.length === 0) { + return new Response(null, { status: 404 }); + } + + const membershipLists = await Promise.all( + matchingOrgIds.map((orgId) => + client.organizations.getOrganizationMembershipList({ organizationId: orgId }) + ) ); - - if (!userMembership || userMembership.role !== "org:admin") { + + const isAdmin = membershipLists.some((list) => + list.data.some( + (m) => m.publicUserData?.userId === userId && m.role === "org:admin" + ) + ); + + if (!isAdmin) { return new Response(null, { status: 404 }); } } catch (e) { @@ -61,10 +75,10 @@ export const onRequest = clerkMiddleware(async (auth, context, next) => { return context.redirect("/"); } } - + return next(); }); - + // ── Helper: fetch all org IDs the current user belongs to ─────────────────── async function getUserOrgIds(context: any, userId: string): Promise { try { @@ -75,4 +89,4 @@ async function getUserOrgIds(context: any, userId: string): Promise { console.error("Failed to fetch user org memberships:", e); return []; } -} +} \ No newline at end of file