Last active
January 7, 2024 05:36
-
-
Save johnmaguire/5a551fcdd42fb60e69907aa11033d57b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
00:18:51.513 Cloning repository... | |
00:18:52.660 From https://github.com/johnmaguire/helical-piers | |
00:18:52.660 * branch 09e1545825ca73d66f47bf32855c606e091a0c65 -> FETCH_HEAD | |
00:18:52.661 | |
00:18:52.738 HEAD is now at 09e1545 Try logging values for contact form | |
00:18:52.739 | |
00:18:52.849 | |
00:18:52.883 Success: Finished cloning repository files | |
00:18:53.723 Detected the following tools from environment: [email protected], [email protected] | |
00:18:53.724 Installing project dependencies: npm install --progress=false | |
00:19:23.714 | |
00:19:23.714 added 883 packages, and audited 884 packages in 29s | |
00:19:23.715 | |
00:19:23.715 347 packages are looking for funding | |
00:19:23.715 run `npm fund` for details | |
00:19:23.716 | |
00:19:23.717 found 0 vulnerabilities | |
00:19:23.749 Executing user command: npm run build | |
00:19:24.671 | |
00:19:24.672 > @onwidget/[email protected] build | |
00:19:24.672 > astro build | |
00:19:24.672 | |
00:19:27.843 05:19:27 [WARN] [@astrojs/cloudflare] The current configuration does not support image optimization. To allow your project to build with the original, unoptimized images, the image service has been automatically switched to the 'noop' option. See https://docs.astro.build/en/reference/configuration-reference/#imageservice | |
00:19:28.265 05:19:28 [WARN] [content] The post collection is defined but no content/post folder exists in the content directory. Create a new folder for the collection, or check your content configuration file for typos. | |
00:19:28.266 05:19:28 Types generated 370ms | |
00:19:28.267 05:19:28 [build] output: "hybrid" | |
00:19:28.267 05:19:28 [build] directory: /opt/buildhome/repo/dist/ | |
00:19:28.268 05:19:28 [build] adapter: @astrojs/cloudflare | |
00:19:28.268 05:19:28 [build] Collecting build info... | |
00:19:28.269 05:19:28 [build] ✓ Completed in 489ms. | |
00:19:28.272 05:19:28 [build] Building hybrid entrypoints... | |
00:19:30.612 05:19:30 [astro-icon] Loaded icons from flat-color-icons, tabler | |
00:19:31.394 05:19:31 [build] ✓ Completed in 3.12s. | |
00:19:31.415 | |
00:19:31.415 prerendering static routes | |
00:19:31.555 05:19:31 ▶ src/pages/index.astro | |
00:19:31.600 05:19:31 └─ /index.html (+44ms) | |
00:19:31.601 05:19:31 ▶ src/pages/contact.astro | |
00:19:31.612 05:19:31 └─ /contact/index.html (+10ms) | |
00:19:31.614 05:19:31 ▶ src/pages/about.astro | |
00:19:31.636 05:19:31 └─ /about/index.html (+22ms) | |
00:19:31.641 05:19:31 ▶ src/pages/404.astro | |
00:19:31.642 05:19:31 └─ /404.html (+4ms) | |
00:19:31.643 05:19:31 ✓ Completed in 238ms. | |
00:19:31.643 | |
00:19:31.643 generating optimized images | |
00:19:31.650 05:19:31 ▶ /_astro/default.Th1dKr9c_ZJGkcR.webp (before: 285kB, after: 285kB) (+4ms) (1/1) | |
00:19:31.650 05:19:31 ✓ Completed in 5ms. | |
00:19:31.651 | |
00:19:31.676 05:19:31 | |
00:19:31.677 finalizing server assets | |
00:19:31.677 | |
00:19:31.677 05:19:31 [build] Rearranging server assets... | |
00:19:31.689 05:19:31 [@astrojs/sitemap] `sitemap-index.xml` created at `dist` | |
00:19:31.691 | |
00:19:31.691 AstroCompress processing | |
00:19:31.915 ✓ Successfully compressed a total of 1 CSS file for 530 Bytes. | |
00:19:32.466 ✓ Successfully compressed a total of 4 HTML files for 10.56 KB. | |
00:19:33.127 ✓ Successfully compressed a total of 17 JavaScript files for 69.5 KB. | |
00:19:33.306 ✓ Successfully compressed a total of 1 SVG file for 105 Bytes. | |
00:19:33.355 05:19:33 [build] Server built in 5.58s | |
00:19:33.356 05:19:33 [build] Complete! | |
00:19:33.405 Finished | |
00:19:33.405 Found Functions directory at /functions. Uploading. | |
00:19:34.801 ✨ Compiled Worker successfully | |
00:19:34.868 Found _routes.json in output directory. Uploading. | |
00:19:34.887 Validating asset output directory | |
00:19:35.644 Deploying your site to Cloudflare's global network... | |
00:19:38.100 Parsed 1 valid header rule. | |
00:19:39.722 Uploading... (23/23) | |
00:19:39.722 ✨ Success! Uploaded 0 files (23 already uploaded) (0.54 sec) | |
00:19:39.723 | |
00:19:39.988 ✨ Upload complete! | |
00:19:42.285 Success: Assets published! | |
00:19:44.563 Success: Your site was deployed! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Routing configuration | |
Configuration of routing for this deployment. This file is generated based on the files present in the /functions directory. | |
Using routing | |
{ | |
"routes": [ | |
{ | |
"routePath": "/do/contact", | |
"mountPath": "/do", | |
"method": "POST", | |
"module": [ | |
"do/contact.ts:onRequestPost" | |
] | |
}, | |
{ | |
"routePath": "/:path*", | |
"mountPath": "/", | |
"method": "", | |
"module": [ | |
"[[path]].js:onRequest" | |
] | |
} | |
], | |
"baseURL": "/" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Invocation routes | |
Invocation routes determine when your Functions script is executed. This file is generated based on the files present in the /functions directory. | |
Using billable routes | |
{ | |
"version": 1, | |
"include": [ | |
"/_image" | |
], | |
"exclude": [] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
❯ tree functions | |
functions | |
├── [[path]].js | |
└── do | |
└── contact.ts | |
2 directories, 2 files | |
❯ cat functions/do/contact.ts | |
interface Env {} | |
// ========= API ========== | |
interface EmailAddress { | |
email: string; | |
name?: string; | |
} | |
export interface Personalization { | |
to: [EmailAddress, ...EmailAddress[]]; | |
from?: EmailAddress; | |
dkim_domain?: string; | |
dkim_private_key?: string; | |
dkim_selector?: string; | |
reply_to?: EmailAddress; | |
cc?: EmailAddress[]; | |
bcc?: EmailAddress[]; | |
subject?: string; | |
headers?: Record<string, string>; | |
} | |
export interface ContentItem { | |
type: string; | |
value: string; | |
} | |
export interface MailSendBody { | |
personalizations: [Personalization, ...Personalization[]]; | |
from: EmailAddress; | |
reply_to?: EmailAddress; | |
subject: string; | |
content: [ContentItem, ...ContentItem[]]; | |
headers?: Record<string, string>; | |
} | |
interface Success { | |
success: true; | |
} | |
interface Failure { | |
success: false; | |
errors: string[]; | |
} | |
export const sendEmail = async ( | |
payload: MailSendBody | |
): Promise<Success | Failure> => { | |
const response = await fetch("https://api.mailchannels.net/tx/v1/send", { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify(payload), | |
}); | |
if (response.status === 202) return { success: true }; | |
try { | |
const { errors } = await response.clone().json(); | |
return { success: false, errors }; | |
} catch { | |
return { success: false, errors: [response.statusText] }; | |
} | |
}; | |
// ========== Types ========== | |
interface Submission { | |
request: Request; | |
formData: FormData; | |
} | |
// ========== Email Customization ========== | |
const textPlainContent = ({ request, formData }: Submission) => { | |
return `At ${new Date().toISOString()}, you received a new form submission from ${request.headers.get( | |
"CF-Connecting-IP" | |
)}: | |
${[...formData.entries()] | |
.map( | |
([field, value]) => `${field} | |
${value} | |
` | |
) | |
.join("\n")}`; | |
}; | |
const textHTMLContent = ({ request, formData }: Submission) => { | |
return `<!DOCTYPE html> | |
<html> | |
<body> | |
<h1>New contact form submission</h1> | |
<div>At ${new Date().toISOString()}, you received a new form submission from ${request.headers.get( | |
"CF-Connecting-IP" | |
)}:</div> | |
<table> | |
<tbody> | |
${[...formData.entries()] | |
.map( | |
([field, value]) => | |
`<tr><td><strong>${field}</strong></td><td>${value}</td></tr>` | |
) | |
.join("\n")} | |
</tbody> | |
</table> | |
</body> | |
</html>`; | |
}; | |
// ========== Handler ========== | |
export const onRequestPost: PagesFunction<Env> = async(context) => { | |
console.log("Received contact form request"); | |
const formData = await context.request.formData(); | |
const request = context.request; | |
const submission: Submission = { formData,request }; | |
const personalizations: MailSendBody["personalizations"] = [ | |
{ | |
to: [{ email: "[email protected]", name: "John Maguire" }], | |
}, | |
]; | |
// This should be set via the form body | |
const from: MailSendBody["from"] = { email: "[email protected]", name: "MI Pier Support" }; | |
const subject: MailSendBody["subject"] = "New contact form submission" | |
const content: MailSendBody["content"] = | |
[ | |
{ | |
type: "text/plain", | |
value: textPlainContent(submission), | |
}, | |
{ | |
type: "text/html", | |
value: textHTMLContent(submission), | |
}, | |
]; | |
const { success } = await sendEmail({ | |
personalizations, | |
from, | |
subject, | |
content, | |
}); | |
console.log("Finishing request"); | |
if (success) { | |
return Response.redirect('https://www.mipiersupport.com/contact?success=true'); | |
} | |
return new Response(`Could not send your email. Please try again.`, { | |
status: 512, | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment