Skip to content

Instantly share code, notes, and snippets.

@58bits
Last active March 11, 2026 00:01
Show Gist options
  • Select an option

  • Save 58bits/8c4de23d10181f403d1c638fad41ce29 to your computer and use it in GitHub Desktop.

Select an option

Save 58bits/8c4de23d10181f403d1c638fad41ce29 to your computer and use it in GitHub Desktop.
Polyfill DOMParser for Cloudflare Workers
// Place this in the root of your project under functions/api/contact.ts
import { getWorkerLogger } from "@/lib/logger-worker";
import { DOMParser } from "@xmldom/xmldom";
import { reCaptchaAssess } from "@/lib/recaptcha/recaptcha-enterprise-assess-worker";
const log = getWorkerLogger();
export async function onRequestPost(context: any): Promise<Response> {
// Polyfill DOMParser for Cloudflare Workers
// We must do this before importing the AWS SDK because the SDK captures the global DOMParser at load time.
// Using dynamic import ensures this polyfill runs first.
if (!globalThis.DOMParser) {
(globalThis as any).DOMParser = DOMParser;
}
if (!globalThis.Node) {
(globalThis as any).Node = {
ELEMENT_NODE: 1,
ATTRIBUTE_NODE: 2,
TEXT_NODE: 3,
CDATA_SECTION_NODE: 4,
ENTITY_REFERENCE_NODE: 5,
ENTITY_NODE: 6,
PROCESSING_INSTRUCTION_NODE: 7,
COMMENT_NODE: 8,
DOCUMENT_NODE: 9,
DOCUMENT_TYPE_NODE: 10,
DOCUMENT_FRAGMENT_NODE: 11,
NOTATION_NODE: 12,
};
}
try {
// Dynamically import AWS SDK to ensure polyfill is active
const { SESClient, SendEmailCommand } = await import("@aws-sdk/client-ses");
const { request, env } = context;
const formData = await request.json();
const { name, email, message, recaptchaToken, recaptchaAction } = formData;
if (!name || !email || !message) {
log.error({
contact: {
message: "Missing required fields",
name,
email,
},
});
return new Response(JSON.stringify({ message: "Missing required fields" }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
// Optionally verify reCAPTCHA Enterprise token before sending email
const recaptchaEnabled = env.RECAPTCHA_ENABLED === "true";
if (recaptchaEnabled) {
if (!recaptchaToken) {
log.error({
contact: {
message: "Missing reCAPTCHA token",
name,
email,
},
});
return new Response(JSON.stringify({ message: "Missing reCAPTCHA token" }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
const ip = request.headers.get("cf-connecting-ip") ?? "0.0.0.0";
const headers = Object.fromEntries(request.headers.entries());
// log.debug({
// contact: {
// message: "Starting reCAPTCHA assessment for contact form",
// action: recaptchaAction || "CONTACT_FORM",
// ip,
// headers,
// },
// });
// const result = await reCaptchaAssess(
await reCaptchaAssess(
recaptchaToken,
recaptchaAction || "CONTACT_FORM",
{
RECAPTCHA_SA_JSON: env.RECAPTCHA_SA_JSON,
RECAPTCHA_PROJECT_ID: env.RECAPTCHA_PROJECT_ID,
RECAPTCHA_SITE_KEY: env.RECAPTCHA_SITE_KEY,
RECAPTCHA_ENABLED: env.RECAPTCHA_ENABLED,
},
env.RECAPTCHA_THRESHOLD ? Number(env.RECAPTCHA_THRESHOLD) : 0.5,
ip,
headers,
);
// log.debug({
// contact: {
// message: `reCAPTCHA assessment result: ${result}`,
// action: recaptchaAction || "CONTACT_FORM",
// ip,
// headers,
// },
// });
}
// Initialize SES Client
const sesClient = new SESClient({
region: env.AWS_REGION,
credentials: {
accessKeyId: env.AWS_ACCESS_KEY_ID,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
},
});
const command = new SendEmailCommand({
Source: env.SES_SOURCE_EMAIL, // Must be verified in SES
Destination: {
ToAddresses: [env.SES_DESTINATION_EMAIL], // Where you want to receive the contact form
},
Message: {
Subject: {
Data: 'Website Contact Form Submission',
},
Body: {
Text: {
Data: `Name: ${name}\nEmail: ${email}\nMessage:\n${message}`,
},
Html: {
Data: `<p><strong>Name:</strong> ${name}</p>
<p><strong>Email:</strong> ${email}</p>
<p><strong>Message:</strong><br/>${message.replace(/\n/g, "<br/>")}</p>`,
},
},
},
ReplyToAddresses: [email],
});
const awsResponse = await sesClient.send(command);
log.info({
contact: {
message: "Message sent successfully via SES",
name,
email,
requestId: awsResponse?.$metadata?.requestId,
},
});
return new Response(
JSON.stringify({
message: "Message sent successfully!",
requestId: awsResponse?.$metadata?.requestId,
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
},
);
} catch (error: any) {
log.error({
contact: {
message: "Error sending email",
errorMessage: error?.message,
code: error?.Code || error?.code,
httpStatusCode: error?.$metadata?.httpStatusCode,
requestId: error?.$metadata?.requestId,
},
});
// Handle AWS SDK / SES errors with structured responses
if (error?.$metadata?.httpStatusCode) {
const status = error.$metadata.httpStatusCode;
const code = error.Code || error.code;
const awsMessage =
code === "InvalidClientTokenId"
? "Email configuration is invalid. Please contact support."
: error.message || "Email service error.";
return new Response(
JSON.stringify({
message: awsMessage,
code,
status,
}),
{
status: status >= 400 && status < 600 ? status : 500,
headers: { "Content-Type": "application/json" },
},
);
}
// Fallback for non-AWS or unexpected errors
log.error({
contact: {
message: "Unexpected error while sending email",
error: String(error),
},
});
return new Response(JSON.stringify({ message: "Failed to send message." }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment