Skip to content
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
6 changes: 3 additions & 3 deletions apps/site/src/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { env } from "cloudflare:workers";
import { mcp } from "@better-auth/mcp";
import { betterAuth } from "better-auth";
import { emailOTP, jwt, magicLink } from "better-auth/plugins";
import { sendCodingCatEmail } from "@/lib/email";
import { sendCodingCatAuthEmail } from "@/lib/email";

export const BETTER_AUTH_SECRET =
(env as unknown as { BETTER_AUTH_SECRET?: string })?.BETTER_AUTH_SECRET ||
Expand Down Expand Up @@ -211,7 +211,7 @@ function buildPortalAuthPlugins() {
</div>
`;

await sendCodingCatEmail({
await sendCodingCatAuthEmail({
to: email,
subject,
text,
Expand Down Expand Up @@ -260,7 +260,7 @@ function buildPortalAuthPlugins() {
</div>
`;

await sendCodingCatEmail({
await sendCodingCatAuthEmail({
to: email,
subject,
text,
Expand Down
31 changes: 31 additions & 0 deletions apps/site/src/lib/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,37 @@ export async function sendCodingCatEmailDetailed(
};
}

/**
* Sign-in codes and magic links are the one exception to the disabled
* automated sending above: nobody can sign in without them. They go through
* Cloudflare Email Sending, which requires `from` on the onboarded
* codingcat.dev domain.
*/
export async function sendCodingCatAuthEmail(opts: {
to: string;
subject: string;
text: string;
html: string;
}): Promise<void> {
const workerEnv = (env ?? {}) as unknown as { EMAIL?: SendEmailBinding };
if (!workerEnv.EMAIL) {
throw new Error("EMAIL binding is not configured");
}
try {
await workerEnv.EMAIL.send({
to: opts.to,
from: { email: "noreply@codingcat.dev", name: "CodingCat.dev" },
subject: opts.subject,
text: opts.text,
html: opts.html,
});
} catch (error) {
const code = (error as { code?: string })?.code ?? "unknown";
console.error(`Sign-in email failed: ${code}`);
throw error;
}
}

export async function sendCodingCatEmail(
opts: CodingCatEmailOptions,
): Promise<boolean> {
Expand Down
4 changes: 1 addition & 3 deletions apps/site/src/lib/google-calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ async function syncPrivateShadowCalendarBlocks(opts: {
"Private Calendar Block synced from alex@codingcat.dev",
`Room: ${studioOrMeet}`,
`Guest: ${opts.guestName} (${opts.company})`,
...(opts.portalUrl
? [`Guest Studio Portal: ${opts.portalUrl}`]
: []),
...(opts.portalUrl ? [`Guest Studio Portal: ${opts.portalUrl}`] : []),
].join("\n"),
location: studioOrMeet,
status: "confirmed",
Expand Down
4 changes: 2 additions & 2 deletions apps/site/src/pages/api/portal/notes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,7 @@ export const POST: APIRoute = async ({ request, url }) => {
headline:
chatMessage && noteType === "call_note"
? `Call Notes & Next Steps for ${company} x CodingCat.dev`
: `Alex Patterson Updated Your Shared Run-of-Show & Notes`,
: "Alex Patterson Updated Your Shared Run-of-Show & Notes",
introParagraph: chatMessage
? `I just posted new notes${newAttachments.length > 0 ? " and shared files" : ""} in your CodingCat.dev Studio Portal: "${chatMessage.slice(0, 280)}${chatMessage.length > 280 ? "..." : ""}". You can reply, drop files into the chat, or edit the shared Run-of-Show directly in your portal below.`
: "I just updated our shared Pre-Call Notes and 5-Part Run-of-Show outline in your CodingCat.dev Studio Portal. Take a look below and feel free to edit or leave a comment directly in the portal!",
Expand Down Expand Up @@ -913,7 +913,7 @@ export const POST: APIRoute = async ({ request, url }) => {
? `${resolvedAuthorName} Posted a Note in the Studio Portal`
: `${resolvedAuthorName} Updated the Shared Run-of-Show`,
introParagraph: isFeedback
? `${resolvedAuthorName} (${verifiedEmail || guestEmail}) just submitted feedback on the CodingCat.dev Booking & Studio Portal${feedbackRating ? ` (Rating: ${feedbackRating}/5)` : ""}${feedbackTopics.length > 0 ? ` [${feedbackTopics.join(", ")}]` : ""}${newAttachments.length > 0 ? ` with an annotated screen capture synced to Sanity Media Library` : ""}.`
? `${resolvedAuthorName} (${verifiedEmail || guestEmail}) just submitted feedback on the CodingCat.dev Booking & Studio Portal${feedbackRating ? ` (Rating: ${feedbackRating}/5)` : ""}${feedbackTopics.length > 0 ? ` [${feedbackTopics.join(", ")}]` : ""}${newAttachments.length > 0 ? " with an annotated screen capture synced to Sanity Media Library" : ""}.`
: chatMessage
? `${resolvedAuthorName} (${verifiedEmail || guestEmail}) just posted a message${newAttachments.length > 0 ? ` and dropped ${newAttachments.length} attachment(s)` : ""} in the ${company} Studio Portal: "${chatMessage}".`
: `${resolvedAuthorName} (${verifiedEmail || guestEmail}) just edited the shared Run-of-Show / Pre-Call Notes in the ${company} Studio Portal.`,
Expand Down
Loading