Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions 5 .changeset/project-environments-endpoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@trigger.dev/core": patch
---

Add `GetProjectEnvironmentsResponseBody` and `ProjectEnvironment` schemas for the new `GET /api/v1/projects/{projectRef}/environments` endpoint, which lists the parent environments (dev, staging, preview, prod) a personal access token can access for a project. Dev is scoped to the token owner and branch (preview child) environments are excluded.
71 changes: 71 additions & 0 deletions 71 apps/webapp/app/routes/api.v1.projects.$projectRef.environments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { json } from "@remix-run/server-runtime";
import { type GetProjectEnvironmentsResponseBody } from "@trigger.dev/core/v3";
import { z } from "zod";
import { $replica } from "~/db.server";
import { findProjectByRef } from "~/models/project.server";
import { createLoaderPATApiRoute } from "~/services/routeBuilders/apiBuilder.server";
import { sortEnvironments } from "~/utils/environmentSort";

const ParamsSchema = z.object({
projectRef: z.string(),
});

export const loader = createLoaderPATApiRoute(
{
params: ParamsSchema,
corsStrategy: "all",
// Resolve projectRef → org so the PAT plugin can ground its role-floor
// calculation. Membership is enforced by the plugin (`authenticatePat`
// rejects users who aren't members of the target org) and again by
// `findProjectByRef` below.
context: async (params) => {
const project = await $replica.project.findFirst({
where: { externalRef: params.projectRef },
select: { organizationId: true },
});
return project ? { organizationId: project.organizationId } : {};
},
authorization: { action: "read", resource: () => ({ type: "environments" }) },
},
async ({ params, authentication }) => {
const project = await findProjectByRef(params.projectRef, authentication.userId);

if (!project) {
return json({ error: "Project not found" }, { status: 404 });
}

const environments = await $replica.runtimeEnvironment.findMany({
where: {
projectId: project.id,
// Only base/parent environments. Branch children (preview branches)
// are excluded — syncs target the parent and branches override elsewhere.
parentEnvironmentId: null,
archivedAt: null,
OR: [
{ type: { in: ["STAGING", "PRODUCTION", "PREVIEW"] } },
// dev is per-user: only return the caller's own dev environment
{ type: "DEVELOPMENT", orgMember: { userId: authentication.userId } },
],
},
select: {
id: true,
slug: true,
type: true,
isBranchableEnvironment: true,
branchName: true,
paused: true,
},
});

const result: GetProjectEnvironmentsResponseBody = sortEnvironments(environments).map((env) => ({
id: env.id,
slug: env.slug,
type: env.type,
isBranchableEnvironment: env.isBranchableEnvironment,
branchName: env.branchName,
paused: env.paused,
}));

return json(result);
}
);
17 changes: 17 additions & 0 deletions 17 packages/core/src/v3/schemas/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ export const GetProjectEnvResponse = z.object({

export type GetProjectEnvResponse = z.infer<typeof GetProjectEnvResponse>;

export const ProjectEnvironment = z.object({
id: z.string(),
/// The slug used as the environment identifier in env var endpoints (e.g. "dev", "stg", "prod", "preview")
slug: z.string(),
type: z.enum(["DEVELOPMENT", "STAGING", "PREVIEW", "PRODUCTION"]),
/// Whether this is the branchable parent (preview); individual branches are not returned
isBranchableEnvironment: z.boolean(),
branchName: z.string().nullable(),
paused: z.boolean(),
});

export type ProjectEnvironment = z.infer<typeof ProjectEnvironment>;

export const GetProjectEnvironmentsResponseBody = z.array(ProjectEnvironment);

export type GetProjectEnvironmentsResponseBody = z.infer<typeof GetProjectEnvironmentsResponseBody>;

// Zod schema for the response body type
export const GetWorkerTaskResponse = z.object({
id: z.string(),
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.