chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
import { json, type LoaderFunctionArgs } from "@remix-run/server-runtime";
|
||||
import { type WhoAmIResponse } from "@trigger.dev/core/v3";
|
||||
import { prisma } from "~/db.server";
|
||||
import { env } from "~/env.server";
|
||||
import { v3ProjectPath } from "~/utils/pathBuilder";
|
||||
import { authenticateRequest } from "~/services/apiAuth.server";
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const authenticationResult = await authenticateRequest(request, {
|
||||
personalAccessToken: true,
|
||||
organizationAccessToken: true,
|
||||
apiKey: false,
|
||||
});
|
||||
|
||||
if (!authenticationResult) {
|
||||
return json({ error: "Invalid or Missing Access Token" }, { status: 401 });
|
||||
}
|
||||
|
||||
const url = new URL(request.url);
|
||||
const projectRef = url.searchParams.get("projectRef") ?? undefined;
|
||||
|
||||
switch (authenticationResult.type) {
|
||||
case "personalAccessToken": {
|
||||
const result = await getIdentityFromPAT(authenticationResult.result.userId, projectRef);
|
||||
if (!result.success) {
|
||||
if (result.error === "user_not_found") {
|
||||
return json({ error: "User not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
return json({ error: result.error }, { status: 401 });
|
||||
}
|
||||
return json(result.result);
|
||||
}
|
||||
case "organizationAccessToken": {
|
||||
const result = await getIdentityFromOAT(
|
||||
authenticationResult.result.organizationId,
|
||||
projectRef
|
||||
);
|
||||
return json(result.result);
|
||||
}
|
||||
default: {
|
||||
authenticationResult satisfies never;
|
||||
return json({ error: "Invalid or Missing Access Token" }, { status: 401 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getIdentityFromPAT(
|
||||
userId: string,
|
||||
projectRef: string | undefined
|
||||
): Promise<
|
||||
{ success: true; result: WhoAmIResponse } | { success: false; error: "user_not_found" }
|
||||
> {
|
||||
const user = await prisma.user.findFirst({
|
||||
select: {
|
||||
email: true,
|
||||
},
|
||||
where: {
|
||||
id: userId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return { success: false, error: "user_not_found" };
|
||||
}
|
||||
|
||||
const userDetails = {
|
||||
userId,
|
||||
email: user.email,
|
||||
dashboardUrl: env.APP_ORIGIN,
|
||||
} satisfies WhoAmIResponse;
|
||||
|
||||
if (!projectRef) {
|
||||
return {
|
||||
success: true,
|
||||
result: userDetails,
|
||||
};
|
||||
}
|
||||
|
||||
const orgs = await prisma.organization.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
where: {
|
||||
members: {
|
||||
some: {
|
||||
userId,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (orgs.length === 0) {
|
||||
return {
|
||||
success: true,
|
||||
result: userDetails,
|
||||
};
|
||||
}
|
||||
|
||||
const project = await prisma.project.findFirst({
|
||||
select: {
|
||||
externalRef: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
organization: {
|
||||
select: {
|
||||
slug: true,
|
||||
title: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
where: {
|
||||
externalRef: projectRef,
|
||||
organizationId: {
|
||||
in: orgs.map((org) => org.id),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
return {
|
||||
success: true,
|
||||
result: userDetails,
|
||||
};
|
||||
}
|
||||
|
||||
const projectPath = v3ProjectPath({ slug: project.organization.slug }, { slug: project.slug });
|
||||
|
||||
return {
|
||||
success: true,
|
||||
result: {
|
||||
...userDetails,
|
||||
project: {
|
||||
url: new URL(projectPath, env.APP_ORIGIN).href,
|
||||
name: project.name,
|
||||
orgTitle: project.organization.title,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function getIdentityFromOAT(
|
||||
organizationId: string,
|
||||
projectRef: string | undefined
|
||||
): Promise<{ success: true; result: WhoAmIResponse }> {
|
||||
// Organization auth tokens are currently only used internally for the build server.
|
||||
// We will eventually expose them in the application as well, as they are useful beyond the build server.
|
||||
// At that point we will need a v3 whoami endpoint that properly handles org auth tokens.
|
||||
// For now, we just return a dummy user id and email and keep using the existing v2 whoami endpoint.
|
||||
const orgDetails = {
|
||||
userId: `org_${organizationId}`,
|
||||
email: "not_applicable@trigger.dev",
|
||||
dashboardUrl: env.APP_ORIGIN,
|
||||
} satisfies WhoAmIResponse;
|
||||
|
||||
if (!projectRef) {
|
||||
return {
|
||||
success: true,
|
||||
result: orgDetails,
|
||||
};
|
||||
}
|
||||
|
||||
const project = await prisma.project.findFirst({
|
||||
select: {
|
||||
externalRef: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
organization: {
|
||||
select: {
|
||||
slug: true,
|
||||
title: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
where: {
|
||||
externalRef: projectRef,
|
||||
organizationId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
return {
|
||||
success: true,
|
||||
result: orgDetails,
|
||||
};
|
||||
}
|
||||
|
||||
const projectPath = v3ProjectPath(project.organization, project);
|
||||
return {
|
||||
success: true,
|
||||
result: {
|
||||
...orgDetails,
|
||||
project: {
|
||||
url: new URL(projectPath, env.APP_ORIGIN).href,
|
||||
name: project.name,
|
||||
orgTitle: project.organization.title,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user