fix(notifier): don't construct Resend without an API key (CI crash)
lib/notifier.ts eagerly did `new Resend(process.env.RESEND_API_KEY)` whenever NODE_ENV !== "development". Resend v4's constructor throws on a missing key, so in any env without RESEND_API_KEY (CI, non-dev test runs) merely importing the module crashed — surfaced by crew-records.test.ts once Phase 4c pulled requisition-service → notifier into the crew actions' import graph. Construct the client only when a key is present; otherwise fall back to console logging (the send branches now gate on `!resend` instead of `isDev`). Verified by running the full integration suite with RESEND_API_KEY unset (195 pass). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4e71863c57
commit
712e040fc2
1 changed files with 8 additions and 5 deletions
|
|
@ -3,7 +3,10 @@ import { db } from "@/lib/db";
|
||||||
import type { PurchaseOrder, User } from "@prisma/client";
|
import type { PurchaseOrder, User } from "@prisma/client";
|
||||||
|
|
||||||
const isDev = process.env.NODE_ENV === "development";
|
const isDev = process.env.NODE_ENV === "development";
|
||||||
const resend = isDev ? null : new Resend(process.env.RESEND_API_KEY);
|
// Construct the Resend client only when a key is actually present — in dev, CI,
|
||||||
|
// or any env without RESEND_API_KEY we fall back to console logging (the Resend
|
||||||
|
// v4 constructor throws on a missing key). `canSend` gates the real send path.
|
||||||
|
const resend = !isDev && process.env.RESEND_API_KEY ? new Resend(process.env.RESEND_API_KEY) : null;
|
||||||
const FROM = `${process.env.EMAIL_FROM_NAME ?? "PPMS"} <${process.env.EMAIL_FROM ?? "noreply@ppms.pelagiamarine.com"}>`;
|
const FROM = `${process.env.EMAIL_FROM_NAME ?? "PPMS"} <${process.env.EMAIL_FROM ?? "noreply@ppms.pelagiamarine.com"}>`;
|
||||||
const APP_URL = (process.env.NEXTAUTH_URL ?? "https://portal.pelagiamarine.com").replace(/\/$/, "");
|
const APP_URL = (process.env.NEXTAUTH_URL ?? "https://portal.pelagiamarine.com").replace(/\/$/, "");
|
||||||
|
|
||||||
|
|
@ -84,13 +87,13 @@ export async function notify({ event, po, recipients, note }: NotifyParams) {
|
||||||
const link = buildInAppLink(event, po, recipient);
|
const link = buildInAppLink(event, po, recipient);
|
||||||
|
|
||||||
let status = "sent";
|
let status = "sent";
|
||||||
if (isDev) {
|
if (!resend) {
|
||||||
console.log(
|
console.log(
|
||||||
`\n📧 [DEV EMAIL] To: ${recipient.email}\n Subject: ${subject}\n Body: ${buildEmailBody(event, po, note)}\n Link: ${APP_URL}${link}\n`
|
`\n📧 [DEV EMAIL] To: ${recipient.email}\n Subject: ${subject}\n Body: ${buildEmailBody(event, po, note)}\n Link: ${APP_URL}${link}\n`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const { error } = await resend!.emails.send({
|
const { error } = await resend.emails.send({
|
||||||
from: FROM,
|
from: FROM,
|
||||||
to: recipient.email,
|
to: recipient.email,
|
||||||
subject,
|
subject,
|
||||||
|
|
@ -441,13 +444,13 @@ export async function notifyCrew({ event, recipients, subject, body, link }: Cre
|
||||||
await Promise.allSettled(
|
await Promise.allSettled(
|
||||||
recipients.map(async (recipient) => {
|
recipients.map(async (recipient) => {
|
||||||
let status = "sent";
|
let status = "sent";
|
||||||
if (isDev) {
|
if (!resend) {
|
||||||
console.log(
|
console.log(
|
||||||
`\n📧 [DEV EMAIL] To: ${recipient.email}\n Subject: ${subject}\n Body: ${body}\n Link: ${APP_URL}${link ?? ""}\n`
|
`\n📧 [DEV EMAIL] To: ${recipient.email}\n Subject: ${subject}\n Body: ${body}\n Link: ${APP_URL}${link ?? ""}\n`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const { error } = await resend!.emails.send({
|
const { error } = await resend.emails.send({
|
||||||
from: FROM,
|
from: FROM,
|
||||||
to: recipient.email,
|
to: recipient.email,
|
||||||
subject,
|
subject,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue