Skip to content

Commit

Permalink
Add import env var API endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
ericallam committed May 6, 2024
1 parent c1e3664 commit a337bbb
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { ActionFunctionArgs, json } from "@remix-run/server-runtime";
import { ImportEnvironmentVariablesRequestBody } from "@trigger.dev/core/v3";
import { parse } from "dotenv";
import { z } from "zod";
import { prisma } from "~/db.server";
import { findProjectByRef } from "~/models/project.server";
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
import { EnvironmentVariablesRepository } from "~/v3/environmentVariables/environmentVariablesRepository.server";

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

export async function action({ params, request }: ActionFunctionArgs) {
const parsedParams = ParamsSchema.safeParse(params);

if (!parsedParams.success) {
return json({ error: "Invalid params" }, { status: 400 });
}

const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);

if (!authenticationResult) {
return json({ error: "Invalid or Missing API key" }, { status: 401 });
}

const user = await prisma.user.findUnique({
where: {
id: authenticationResult.userId,
},
});

if (!user) {
return json({ error: "Invalid or Missing API key" }, { status: 401 });
}

const project = await findProjectByRef(parsedParams.data.projectRef, user.id);

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

const environment = await prisma.runtimeEnvironment.findFirst({
where: {
projectId: project.id,
slug: parsedParams.data.slug,
},
});

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

const repository = new EnvironmentVariablesRepository();

const body = await parseImportBody(request);

const result = await repository.create(project.id, user.id, {
overwrite: body.overwrite === true ? true : false,
environmentIds: [environment.id],
variables: Object.entries(body.variables).map(([key, value]) => ({
key,
value,
})),
});

if (result.success) {
return json({ success: true });
} else {
return json({ error: result.error, variableErrors: result.variableErrors }, { status: 400 });
}
}

async function parseImportBody(request: Request): Promise<ImportEnvironmentVariablesRequestBody> {
const contentType = request.headers.get("content-type") ?? "application/json";

if (contentType.includes("application/octet-stream")) {
// We have a "dotenv" formatted file uploaded
const buffer = await request.arrayBuffer();

const variables = parse(Buffer.from(buffer));

const overwrite = request.headers.get("x-overwrite") === "true";

return { variables, overwrite };
} else {
const rawBody = await request.json();

const body = ImportEnvironmentVariablesRequestBody.safeParse(rawBody);

if (!body.success) {
throw json({ error: "Invalid body" }, { status: 400 });
}

return body.data;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ export class EnvironmentVariablesRepository implements Repository {
return { success: false as const, error: `Environment not found` };
}

// Check to see if any of the variables are `TRIGGER_SECRET_KEY` or `TRIGGER_API_URL`
const triggerKeys = options.variables.map((v) => v.key);
if (triggerKeys.includes("TRIGGER_SECRET_KEY") || triggerKeys.includes("TRIGGER_API_URL")) {
return {
success: false as const,
error: `You cannot set the variables TRIGGER_SECRET_KEY or TRIGGER_API_URL as they will be set automatically`,
};
}

//get rid of empty variables
const values = options.variables.filter((v) => v.key.trim() !== "" && v.value.trim() !== "");
if (values.length === 0) {
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/v3/schemas/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,3 +379,12 @@ export const UpdateEnvironmentVariableRequestBody = z.object({
export type UpdateEnvironmentVariableRequestBody = z.infer<
typeof UpdateEnvironmentVariableRequestBody
>;

export const ImportEnvironmentVariablesRequestBody = z.object({
variables: z.record(z.string()),
overwrite: z.boolean().optional(),
});

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

0 comments on commit a337bbb

Please sign in to comment.