Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

separate email package #272

Merged
merged 3 commits into from
May 16, 2024
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
11 changes: 9 additions & 2 deletions apps/web/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ export default defineConfig({
// @ts-expect-error: SS's types are wrong. This is piped into Solid's Vite plugin so all options are not required.
solid: {
// We don't wanna apply Solid's JSX transform to the React emails.
exclude: ["src/emails/*", "src/components/OTPInput/react.tsx"],
exclude: [
"src/emails/*",
"src/components/OTPInput/react.tsx",
"../../packages/email/**",
],
},
vite: ({ router }) => ({
envDir: monorepoRoot,
Expand All @@ -27,7 +31,7 @@ export default defineConfig({
},
build: {
// Safari mobile has problems with newer syntax
target: "es2015",
target: "es2020",
},
plugins: [
devtools(),
Expand All @@ -52,6 +56,9 @@ export default defineConfig({
rollupConfig: {
external: ["cloudflare:sockets"],
},
esbuild: {
options: { target: "es2020" },
},
},
});

Expand Down
4 changes: 1 addition & 3 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@lucia-auth/adapter-drizzle": "^1.0.7",
"@mattrax/configuration-schemas": "workspace:*",
"@mattrax/drizzle-to-rs": "workspace:*",
"@mattrax/email": "workspace:*",
"@mattrax/ms-graph": "workspace:*",
"@mattrax/mysql-planetscale": "workspace:*",
"@mattrax/policy-composer": "workspace:*",
Expand All @@ -28,9 +29,6 @@
"@microsoft/microsoft-graph-client": "^3.0.7",
"@paralleldrive/cuid2": "^2.2.2",
"@planetscale/database": "^1.16.0",
"@react-email/components": "0.0.16",
"@react-email/render": "^0.0.12",
"@react-email/tailwind": "^0.0.15",
"@solid-mediakit/trpc": "^3.0.2",
"@solid-primitives/context": "^0.2.3",
"@solid-primitives/date": "^2.0.21",
Expand Down
48 changes: 21 additions & 27 deletions apps/web/src/api/emails.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,32 @@
import { z } from "zod";
import { type RequestSchema } from "@mattrax/email";
import { AwsClient } from "aws4fetch";
import { env } from "~/env";

const REQUEST_SCHEMA = z
.object({
to: z.string(),
subject: z.string(),
})
.and(
z.union([
z.object({
type: z.literal("tenantAdminInvite"),
invitedByEmail: z.string(),
tenantName: z.string(),
inviteLink: z.string(),
}),
z.object({
type: z.literal("loginCode"),
code: z.string(),
}),
z.object({
type: z.literal("userEnrollmentInvite"),
tenantName: z.string(),
}),
]),
);

export type RequestSchema = z.infer<typeof REQUEST_SCHEMA>;
const aws =
env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY
? new AwsClient({
region: "us-east-1",
accessKeyId: env.AWS_ACCESS_KEY_ID,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
})
: undefined;

export async function sendEmail(args: RequestSchema) {
if (env.FROM_ADDRESS === "console") {
console.log("SEND EMAIL", args);
return;
}

if (!aws) {
const msg = "AWS client not setup but 'FROM_ADDRESS' provided!";
console.error(msg);
throw new Error(msg);
}

// We lazy load to keep React + React email outta the main bundle
await (await import("../emails/index").then((mod) => mod._sender))(args);
await (await import("@mattrax/email").then((mod) => mod._sender))(
args,
aws,
env.FROM_ADDRESS,
);
}
6 changes: 3 additions & 3 deletions apps/web/src/api/trpc/routers/policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const policyRouter = createTRPCRouter({

return {
// The differences between the policies state and the last deployed version
diff: generatePolicyDiff(lastVersion?.data ?? {}, policy.data),
diff: generatePolicyDiff(lastVersion?.data ?? ({} as any), policy.data),
...omit(policy, ["tenantPk"]),
};
}),
Expand Down Expand Up @@ -244,8 +244,8 @@ export const policyRouter = createTRPCRouter({
.limit(1);

if (
generatePolicyDiff(lastVersion?.data ?? {}, ctx.policy.data).length ===
0
generatePolicyDiff(lastVersion?.data ?? ({} as any), ctx.policy.data)
.length === 0
)
throw new Error("policy has not changed");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,12 @@ function CreateApplicationSheet(props: ParentProps) {

const [search, setSearch] = createSignal("");

const query = createQuery(
queryOptions(() => ({
...APPLICATION_TARGETS[form.getFieldValue("targetType")].queryOptions(
search,
),
enabled: open(),
})),
);
const query = createQuery(() => ({
...APPLICATION_TARGETS[form.getFieldValue("targetType")].queryOptions(
search,
),
enabled: open(),
}));

createEffect(() => {
const results = query.data?.results;
Expand Down
149 changes: 76 additions & 73 deletions apps/web/src/app/api/cli/policy/[policyId].ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ import { generatePolicyDiff } from "~/api/trpc/routers/policy";
export async function GET({ params }: APIEvent) {
throw new Error("THE CLI IS NOT SUPPORTED YET");

const policyId = params.policyId as string;
// const policyId = params.policyId as string;

// TODO: Auth and Authz
// // TODO: Auth and Authz

const [policy] = await db
.select({
name: policies.name,
data: policies.data,
})
.from(policies)
.where(eq(policies.id, policyId));
// const [policy] = await db
// .select({
// name: policies.name,
// data: policies.data,
// })
// .from(policies)
// .where(eq(policies.id, policyId));

return policy;
// return policy;
}

const schema = z.object({
Expand All @@ -35,67 +35,70 @@ const schema = z.object({
export async function POST({ request, params }: APIEvent) {
throw new Error("THE CLI IS NOT SUPPORTED YET");

const policyId = params.policyId as string;
const body = schema.safeParse(await request.json());

if (!body.success)
return new Response("Error parsing request!", {
status: 400,
});

const [policy] = await db
.select({
pk: policies.pk,
tenantPk: policies.tenantPk,
data: policies.data,
})
.from(policies)
.where(eq(policies.id, policyId));
if (!policy)
return new Response("404: Policy not found", {
status: 404,
});

// TODO: Auth and Authz
const authorId = 2;

const [lastVersion] = await db
.select({ data: policyDeploy.data })
.from(policyDeploy)
.where(and(eq(policyDeploy.policyPk, policy.pk)))
.orderBy(desc(policyDeploy.doneAt))
.limit(1);

if (generatePolicyDiff(lastVersion?.data ?? {}, body.data.data).length === 0)
return Response.json(["unchanged", null]);

const updatePolicy = () =>
db
.update(policies)
.set({
name: body.data.name,
data: body.data.data,
})
.where(eq(policies.id, policyId));

if (body.data.comment) {
const comment = body.data.comment;

const versionId = createId();
await db.transaction(async (db) => {
await updatePolicy();
await db.insert(policyDeploy).values({
id: versionId,
policyPk: policy.pk,
data: body.data.data,
comment,
author: authorId,
});
});

return Response.json(["deployed", versionId]);
}

await updatePolicy();
return Response.json(["updated", null]);
// const policyId = params.policyId as string;
// const body = schema.safeParse(await request.json());

// if (!body.success)
// return new Response("Error parsing request!", {
// status: 400,
// });

// const [policy] = await db
// .select({
// pk: policies.pk,
// tenantPk: policies.tenantPk,
// data: policies.data,
// })
// .from(policies)
// .where(eq(policies.id, policyId));
// if (!policy)
// return new Response("404: Policy not found", {
// status: 404,
// });

// // TODO: Auth and Authz
// const authorId = 2;

// const [lastVersion] = await db
// .select({ data: policyDeploy.data })
// .from(policyDeploy)
// .where(and(eq(policyDeploy.policyPk, policy.pk)))
// .orderBy(desc(policyDeploy.doneAt))
// .limit(1);

// if (
// generatePolicyDiff(lastVersion?.data ?? ({} as any), body.data.data)
// .length === 0
// )
// return Response.json(["unchanged", null]);

// const updatePolicy = () =>
// db
// .update(policies)
// .set({
// name: body.data.name,
// data: body.data.data,
// })
// .where(eq(policies.id, policyId));

// if (body.data.comment) {
// const comment = body.data.comment;

// const versionId = createId();
// await db.transaction(async (db) => {
// await updatePolicy();
// await db.insert(policyDeploy).values({
// id: versionId,
// policyPk: policy.pk,
// data: body.data.data,
// comment,
// author: authorId,
// });
// });

// return Response.json(["deployed", versionId]);
// }

// await updatePolicy();
// return Response.json(["updated", null]);
}
2 changes: 1 addition & 1 deletion apps/web/src/lib/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getObjectKeys } from "~/api/utils";
import { trpc } from ".";

export const features = {
// visual_editor: "Policy Visual Editor",
visual_editor: "Policy Visual Editor",
} as const;

export type Features = keyof typeof features;
Expand Down
1 change: 1 addition & 0 deletions apps/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"exclude": ["node_modules", "dist"],
"references": [
{ "path": "../../packages/ui" },
{ "path": "../../packages/email" },
{ "path": "../../packages/trpc-server-function" }
]
}
11 changes: 0 additions & 11 deletions biome.fix.json

This file was deleted.

19 changes: 19 additions & 0 deletions packages/email/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@mattrax/email",
"type": "module",
"private": true,
"sideEffects": false,
"main": "./src/index.ts",
"types": "./src/index.ts",
"dependencies": {
"@react-email/components": "0.0.16",
"@react-email/render": "^0.0.12",
"@react-email/tailwind": "^0.0.15",
"aws4fetch": "^1.0.18",
"react": "^18.2.0",
"zod": "^3.22.5"
},
"devDependencies": {
"@types/react": "^18.2.79"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// @ts-nocheck // TODO: Typescript
/** @jsx React.createElement */
// @jsxImportSource react

// biome-ignore lint: don't remove React
import React from "react";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// @ts-nocheck // TODO: Typescript
/** @jsx React.createElement */
// @jsxImportSource react

// biome-ignore lint: don't remove React
import React from "react";
Expand All @@ -23,7 +22,7 @@ interface Props {
inviteLink: string;
}

export function TenantAdminInvite(props: Props) {
function TenantAdminInvite(props: Props) {
const previewText = `Join ${props.tenantName} on Mattrax`;

return (
Expand Down
Loading
Loading