Skip to content

Commit 0adf1cf

Browse files
authored
Merge pull request #821 from CodingCatDev/fix/portal-otp-email
fix(site): send portal sign-in codes and magic links via Cloudflare Email Sending
2 parents 6a69d71 + 8a62e3a commit 0adf1cf

4 files changed

Lines changed: 37 additions & 8 deletions

File tree

‎apps/site/src/lib/auth.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { env } from "cloudflare:workers";
22
import { mcp } from "@better-auth/mcp";
33
import { betterAuth } from "better-auth";
44
import { emailOTP, jwt, magicLink } from "better-auth/plugins";
5-
import { sendCodingCatEmail } from "@/lib/email";
5+
import { sendCodingCatAuthEmail } from "@/lib/email";
66

77
export const BETTER_AUTH_SECRET =
88
(env as unknown as { BETTER_AUTH_SECRET?: string })?.BETTER_AUTH_SECRET ||
@@ -211,7 +211,7 @@ function buildPortalAuthPlugins() {
211211
</div>
212212
`;
213213

214-
await sendCodingCatEmail({
214+
await sendCodingCatAuthEmail({
215215
to: email,
216216
subject,
217217
text,
@@ -260,7 +260,7 @@ function buildPortalAuthPlugins() {
260260
</div>
261261
`;
262262

263-
await sendCodingCatEmail({
263+
await sendCodingCatAuthEmail({
264264
to: email,
265265
subject,
266266
text,

‎apps/site/src/lib/email.ts‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,37 @@ export async function sendCodingCatEmailDetailed(
424424
};
425425
}
426426

427+
/**
428+
* Sign-in codes and magic links are the one exception to the disabled
429+
* automated sending above: nobody can sign in without them. They go through
430+
* Cloudflare Email Sending, which requires `from` on the onboarded
431+
* codingcat.dev domain.
432+
*/
433+
export async function sendCodingCatAuthEmail(opts: {
434+
to: string;
435+
subject: string;
436+
text: string;
437+
html: string;
438+
}): Promise<void> {
439+
const workerEnv = (env ?? {}) as unknown as { EMAIL?: SendEmailBinding };
440+
if (!workerEnv.EMAIL) {
441+
throw new Error("EMAIL binding is not configured");
442+
}
443+
try {
444+
await workerEnv.EMAIL.send({
445+
to: opts.to,
446+
from: { email: "noreply@codingcat.dev", name: "CodingCat.dev" },
447+
subject: opts.subject,
448+
text: opts.text,
449+
html: opts.html,
450+
});
451+
} catch (error) {
452+
const code = (error as { code?: string })?.code ?? "unknown";
453+
console.error(`Sign-in email failed: ${code}`);
454+
throw error;
455+
}
456+
}
457+
427458
export async function sendCodingCatEmail(
428459
opts: CodingCatEmailOptions,
429460
): Promise<boolean> {

‎apps/site/src/lib/google-calendar.ts‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ async function syncPrivateShadowCalendarBlocks(opts: {
3939
"Private Calendar Block synced from alex@codingcat.dev",
4040
`Room: ${studioOrMeet}`,
4141
`Guest: ${opts.guestName} (${opts.company})`,
42-
...(opts.portalUrl
43-
? [`Guest Studio Portal: ${opts.portalUrl}`]
44-
: []),
42+
...(opts.portalUrl ? [`Guest Studio Portal: ${opts.portalUrl}`] : []),
4543
].join("\n"),
4644
location: studioOrMeet,
4745
status: "confirmed",

‎apps/site/src/pages/api/portal/notes.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ export const POST: APIRoute = async ({ request, url }) => {
851851
headline:
852852
chatMessage && noteType === "call_note"
853853
? `Call Notes & Next Steps for ${company} x CodingCat.dev`
854-
: `Alex Patterson Updated Your Shared Run-of-Show & Notes`,
854+
: "Alex Patterson Updated Your Shared Run-of-Show & Notes",
855855
introParagraph: chatMessage
856856
? `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.`
857857
: "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!",
@@ -913,7 +913,7 @@ export const POST: APIRoute = async ({ request, url }) => {
913913
? `${resolvedAuthorName} Posted a Note in the Studio Portal`
914914
: `${resolvedAuthorName} Updated the Shared Run-of-Show`,
915915
introParagraph: isFeedback
916-
? `${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` : ""}.`
916+
? `${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" : ""}.`
917917
: chatMessage
918918
? `${resolvedAuthorName} (${verifiedEmail || guestEmail}) just posted a message${newAttachments.length > 0 ? ` and dropped ${newAttachments.length} attachment(s)` : ""} in the ${company} Studio Portal: "${chatMessage}".`
919919
: `${resolvedAuthorName} (${verifiedEmail || guestEmail}) just edited the shared Run-of-Show / Pre-Call Notes in the ${company} Studio Portal.`,

0 commit comments

Comments
 (0)