UNPKG

@coursebuilder/core

Version:

Core package for Course Builder

1 lines 12.3 kB
{"version":3,"sources":["../../src/lib/send-verification-request.ts"],"sourcesContent":["import { Theme } from '@auth/core/types'\nimport { render } from '@react-email/components'\n\nimport { NewMemberEmail } from '@coursebuilder/email-templates/emails/new-member'\nimport { PostPurchaseLoginEmail } from '@coursebuilder/email-templates/emails/post-purchase-login'\n\nimport { CourseBuilderAdapter } from '../adapters'\n\nexport type MagicLinkEmailType =\n\t| 'login'\n\t| 'signup'\n\t| 'reset'\n\t| 'purchase'\n\t| 'upgrade'\n\t| 'transfer'\n\nexport type HTMLEmailParams = Record<'url' | 'host' | 'email', string> & {\n\texpires?: Date\n\tmerchantChargeId?: string | null\n}\n\nfunction isValidateEmailServerConfig(server: any) {\n\treturn Boolean(\n\t\tserver &&\n\t\t\tserver.host &&\n\t\t\tserver.port &&\n\t\t\tserver.auth?.user &&\n\t\t\tserver.auth?.pass,\n\t)\n}\n\nexport interface SendVerificationRequestParams {\n\tidentifier: string\n\tname?: string\n\turl: string\n\texpires: Date\n\tprovider: any\n\ttoken: string\n\ttheme?: Theme\n}\n\nexport const sendVerificationRequest = async (\n\tparams: SendVerificationRequestParams & {\n\t\ttype?: MagicLinkEmailType\n\t\tmerchantChargeId?: string | null\n\t\thtml?: (options: HTMLEmailParams, theme?: Theme) => Promise<string>\n\t\ttext?: (options: HTMLEmailParams, theme?: Theme) => Promise<string>\n\t},\n\tadapter: CourseBuilderAdapter,\n) => {\n\tconst {\n\t\tidentifier: email,\n\t\tname,\n\t\turl,\n\t\tprovider,\n\t\ttheme,\n\t\texpires,\n\t\tmerchantChargeId,\n\t\ttype = 'login',\n\t} = params\n\n\tconst { host } = new URL(url)\n\tconsole.log(\n\t\t`[sendVerificationRequest] Initiated. Type: ${type}, Email: ${email}, Host: ${host}${merchantChargeId ? `, MerchantChargeId: ${merchantChargeId}` : ''}`,\n\t)\n\n\tlet text = params.text || defaultText\n\tlet html = params.html || defaultHtml\n\n\tconst { server, from } = provider.options ? provider.options : provider\n\n\tconst { getUserByEmail, findOrCreateUser } = adapter\n\n\tlet subject\n\n\tswitch (type) {\n\t\tcase 'purchase':\n\t\t\tsubject = `Thank you for Purchasing ${\n\t\t\t\tprocess.env.NEXT_PUBLIC_PRODUCT_NAME ||\n\t\t\t\tprocess.env.NEXT_PUBLIC_SITE_TITLE\n\t\t\t} (${host})`\n\t\t\tbreak\n\t\tcase 'transfer':\n\t\t\tsubject = `Accept Your Seat for ${\n\t\t\t\tprocess.env.NEXT_PUBLIC_PRODUCT_NAME ||\n\t\t\t\tprocess.env.NEXT_PUBLIC_SITE_TITLE\n\t\t\t} (${host})`\n\t\t\tbreak\n\t\tcase 'signup':\n\t\t\tsubject = `Welcome to ${\n\t\t\t\tprocess.env.NEXT_PUBLIC_PRODUCT_NAME ||\n\t\t\t\tprocess.env.NEXT_PUBLIC_SITE_TITLE\n\t\t\t} (${host})`\n\t\t\thtml = signUpHtml\n\t\t\ttext = signUpText\n\t\t\tbreak\n\t\tdefault:\n\t\t\tsubject = `Log in to ${\n\t\t\t\tprocess.env.NEXT_PUBLIC_PRODUCT_NAME ||\n\t\t\t\tprocess.env.NEXT_PUBLIC_SITE_TITLE\n\t\t\t} (${host})`\n\t}\n\n\tconsole.log(\n\t\t`[sendVerificationRequest] Determined email subject: \"${subject}\"`,\n\t)\n\n\tlet user: any\n\ttry {\n\t\tuser =\n\t\t\tprocess.env.CREATE_USER_ON_LOGIN !== 'false'\n\t\t\t\t? await findOrCreateUser(email, name)\n\t\t\t\t: await getUserByEmail?.(email)\n\n\t\tif (!user) {\n\t\t\tconsole.warn(\n\t\t\t\t`[sendVerificationRequest] User not found and creation disabled/failed for email: ${email}. Aborting.`,\n\t\t\t)\n\t\t\treturn\n\t\t}\n\t\tconsole.log(\n\t\t\t`[sendVerificationRequest] User found or created for email: ${email}, ID: ${user.id || user?.user?.id || 'unknown'}`,\n\t\t)\n\t} catch (error: any) {\n\t\tconsole.error(\n\t\t\t`[sendVerificationRequest] Error during user lookup/creation for email: ${email}`,\n\t\t\terror,\n\t\t)\n\t\tthrow error\n\t}\n\n\tif (process.env.LOG_VERIFICATION_URL) {\n\t\tconsole.log(`\n👋 MAGIC LINK URL ******************\n`)\n\t\tconsole.log(url)\n\t\tconsole.log(`\n************************************\n`)\n\t}\n\n\tif (process.env.SKIP_EMAIL === 'true') {\n\t\tconsole.warn(\n\t\t\t`[sendVerificationRequest] 🚫 Email sending is disabled via SKIP_EMAIL.`,\n\t\t)\n\t\treturn\n\t}\n\n\tif (!process.env.POSTMARK_API_TOKEN && !process.env.POSTMARK_KEY) {\n\t\tconsole.error(\n\t\t\t'[sendVerificationRequest] 🚫 Missing Postmark API Key (POSTMARK_API_TOKEN or POSTMARK_KEY). Cannot send email.',\n\t\t)\n\t\tthrow new Error('Missing Postmark API Key')\n\t}\n\n\ttry {\n\t\tconst textBody = await text(\n\t\t\t{ url, host, email, expires, merchantChargeId },\n\t\t\ttheme,\n\t\t)\n\t\tconst htmlBody = await html(\n\t\t\t{ url, host, email, expires, merchantChargeId },\n\t\t\ttheme,\n\t\t)\n\n\t\tconsole.log(\n\t\t\t`[sendVerificationRequest] Attempting to send email via Postmark to ${email} from ${from}`,\n\t\t)\n\n\t\tconst res = await fetch('https://api.postmarkapp.com/email', {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\tAccept: 'application/json',\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t'X-Postmark-Server-Token': (process.env.POSTMARK_API_TOKEN ||\n\t\t\t\t\tprocess.env.POSTMARK_KEY) as string,\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tFrom: from,\n\t\t\t\tTo: email,\n\t\t\t\tSubject: subject,\n\t\t\t\tTextBody: textBody,\n\t\t\t\tHtmlBody: htmlBody,\n\t\t\t\tMessageStream: 'outbound',\n\t\t\t}),\n\t\t})\n\n\t\tif (!res.ok) {\n\t\t\tconst errorBody = await res.json()\n\t\t\tconsole.error(\n\t\t\t\t`[sendVerificationRequest] Postmark error sending email to ${email}. Status: ${res.status}`,\n\t\t\t\terrorBody,\n\t\t\t)\n\t\t\tthrow new Error(\n\t\t\t\t`Postmark error: ${res.status} ${JSON.stringify(errorBody)}`,\n\t\t\t)\n\t\t}\n\n\t\tconsole.log(\n\t\t\t`[sendVerificationRequest] ✅ Email successfully sent to ${email} via Postmark. Status: ${res.status}`,\n\t\t)\n\t} catch (error: any) {\n\t\tconsole.error(\n\t\t\t`[sendVerificationRequest] 💥 Failed to send email to ${email}. Error:`,\n\t\t\terror,\n\t\t)\n\t\tthrow error\n\t}\n}\n\nfunction defaultHtml(\n\t{ url, host, email, merchantChargeId }: HTMLEmailParams,\n\ttheme?: Theme,\n) {\n\treturn render(\n\t\tPostPurchaseLoginEmail(\n\t\t\t{\n\t\t\t\turl,\n\t\t\t\thost,\n\t\t\t\temail,\n\t\t\t\tsiteName:\n\t\t\t\t\tprocess.env.NEXT_PUBLIC_PRODUCT_NAME ||\n\t\t\t\t\tprocess.env.NEXT_PUBLIC_SITE_TITLE ||\n\t\t\t\t\t'',\n\t\t\t\t...(merchantChargeId && {\n\t\t\t\t\tinvoiceUrl: `${process.env.COURSEBUILDER_URL}/invoices/${merchantChargeId}`,\n\t\t\t\t}),\n\t\t\t\tpreviewText:\n\t\t\t\t\tprocess.env.NEXT_PUBLIC_PRODUCT_NAME ||\n\t\t\t\t\tprocess.env.NEXT_PUBLIC_SITE_TITLE ||\n\t\t\t\t\t'login link',\n\t\t\t},\n\t\t\ttheme,\n\t\t),\n\t)\n}\n\n// Email Text body (fallback for email clients that don't render HTML, e.g. feature phones)\nasync function defaultText(\n\t{ url, host, email, merchantChargeId }: HTMLEmailParams,\n\ttheme?: Theme,\n) {\n\treturn await render(\n\t\tPostPurchaseLoginEmail(\n\t\t\t{\n\t\t\t\turl,\n\t\t\t\thost,\n\t\t\t\temail,\n\t\t\t\tsiteName:\n\t\t\t\t\tprocess.env.NEXT_PUBLIC_PRODUCT_NAME ||\n\t\t\t\t\tprocess.env.NEXT_PUBLIC_SITE_TITLE ||\n\t\t\t\t\t'',\n\t\t\t\t...(merchantChargeId && {\n\t\t\t\t\tinvoiceUrl: `${process.env.COURSEBUILDER_URL}/invoices/${merchantChargeId}`,\n\t\t\t\t}),\n\t\t\t\tpreviewText:\n\t\t\t\t\tprocess.env.NEXT_PUBLIC_PRODUCT_NAME ||\n\t\t\t\t\tprocess.env.NEXT_PUBLIC_SITE_TITLE ||\n\t\t\t\t\t'login link',\n\t\t\t},\n\t\t\ttheme,\n\t\t),\n\t\t{\n\t\t\tplainText: true,\n\t\t},\n\t)\n}\n\nasync function signUpHtml(\n\t{ url, host, email }: HTMLEmailParams,\n\ttheme?: Theme,\n) {\n\treturn await render(\n\t\tNewMemberEmail({\n\t\t\turl,\n\t\t\thost,\n\t\t\temail,\n\t\t\tsiteName:\n\t\t\t\tprocess.env.NEXT_PUBLIC_PRODUCT_NAME ||\n\t\t\t\tprocess.env.NEXT_PUBLIC_SITE_TITLE ||\n\t\t\t\t'',\n\t\t}),\n\t)\n}\n\n// Email Text body (fallback for email clients that don't render HTML, e.g. feature phones)\nasync function signUpText(\n\t{ url, host, email }: HTMLEmailParams,\n\ttheme?: Theme,\n) {\n\treturn await render(\n\t\tNewMemberEmail({\n\t\t\turl,\n\t\t\thost,\n\t\t\temail,\n\t\t\tsiteName:\n\t\t\t\tprocess.env.NEXT_PUBLIC_PRODUCT_NAME ||\n\t\t\t\tprocess.env.NEXT_PUBLIC_SITE_TITLE ||\n\t\t\t\t'',\n\t\t}),\n\t\t{\n\t\t\tplainText: true,\n\t\t},\n\t)\n}\n"],"mappings":"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","names":["sendVerificationRequest","params","adapter","identifier","email","name","url","provider","theme","expires","merchantChargeId","type","host","URL","console","log","text","defaultText","html","defaultHtml","server","from","options","getUserByEmail","findOrCreateUser","subject","process","env","NEXT_PUBLIC_PRODUCT_NAME","NEXT_PUBLIC_SITE_TITLE","signUpHtml","signUpText","user","CREATE_USER_ON_LOGIN","warn","id","error","LOG_VERIFICATION_URL","SKIP_EMAIL","POSTMARK_API_TOKEN","POSTMARK_KEY","Error","textBody","htmlBody","res","fetch","method","headers","Accept","body","JSON","stringify","From","To","Subject","TextBody","HtmlBody","MessageStream","ok","errorBody","json","status","render","PostPurchaseLoginEmail","siteName","invoiceUrl","COURSEBUILDER_URL","previewText","plainText","NewMemberEmail"]}