Skip to content

Instantly share code, notes, and snippets.

View Nooshu's full-sized avatar

Matt Hobbs Nooshu

View GitHub Profile
@Nooshu
Nooshu / cloudflare-node-compatibility.mdc
Created October 8, 2026 17:53
An example of an mdc file used in cursor to control how node dependencies are updated by the AI Adent when I tell it to do that.
---
description: Validate dependency upgrades against the Node.js version used by Cloudflare Pages before making changes.
alwaysApply: true
---
# Cloudflare Pages Node.js Compatibility
Before upgrading, installing, or modifying any npm dependency, verify that the proposed version is compatible with the Node.js version used by this project's Cloudflare Pages build environment.
## 1. Determine the Node.js version
@Nooshu
Nooshu / AGENTS.md
Created October 7, 2026 22:17
How I generated the AGENTS.md file using Cursor AI for my GDS complient frontends blog post.

AGENTS.md — Building UK government services

Practical decision guide for AI coding agents designing, implementing, reviewing, refactoring, and testing UK government digital services.

This file synthesises official guidance into rules an agent can apply. Prefer the linked authoritative sources when this file and upstream guidance diverge.


How to use this file

@Nooshu
Nooshu / contact.js
Created March 13, 2026 19:55
This is the Cloudflare Turnstile version of the contact.js file that sits in the functions/api directory.
import { escapeHtml } from '../../_helpers/escape-html.js';
export const onRequestPost = async ({ request, env }) => {
try {
// Accept standard form submissions
const contentType = request.headers.get('content-type') || '';
if (!contentType.includes('application/x-www-form-urlencoded') && !contentType.includes('multipart/form-data')) {
return new Response(JSON.stringify({ error: 'Unsupported content type' }), {
status: 415,
headers: { 'content-type': 'application/json' },
@Nooshu
Nooshu / turnstile.js
Created March 13, 2026 19:17
This is the client-side script for adding Cloudflare Turnstile to my blog.
(function () {
const SITE_KEY = "0x4AAAAAACpYvR2v9J0i1tr_";
const form = document.getElementById("fs-frm");
if (!form) return;
const tokenInputName = "cf-turnstile-response";
let tokenInput = form.querySelector(`input[name="${tokenInputName}"]`);
if (!tokenInput) {
tokenInput = document.createElement("input");
tokenInput.type = "hidden";
@Nooshu
Nooshu / accessible-form.html
Created March 10, 2026 00:14
The accessible form I use on my blog for the contact page.
<form id="fs-frm" action="/api/contact" method="POST" aria-labelledby="page-title" novalidate>
<div id="form-error-summary" class="form-error-summary" role="alert" tabindex="-1" hidden></div>
<div id="form-status" class="form-status" role="status"></div>
<div class="abc" aria-hidden="true">
<input type="checkbox" name="_its-a-trap!" tabindex="-1" autocomplete="off" />
</div>
<input type="hidden" name="_redirect" value="/contact/thanks/" />
<input type="hidden" name="_append" value="false" />
<input type="hidden" name="_email.subject" value="New Message from Nooshu.com" />
<fieldset>
@Nooshu
Nooshu / contact.js
Created March 9, 2026 19:49
This is the code that runs on my Cloudflare worker to allow sending of emails from my website contact form to my choosen email address.
import { escapeHtml } from '../../_helpers/escape-html.js';
export const onRequestPost = async ({ request, env }) => {
try {
// Accept standard form submissions
const contentType = request.headers.get('content-type') || '';
if (!contentType.includes('application/x-www-form-urlencoded') && !contentType.includes('multipart/form-data')) {
return new Response(JSON.stringify({ error: 'Unsupported content type' }), {
status: 415,
headers: { 'content-type': 'application/json' },
@Nooshu
Nooshu / webperf.js
Created March 4, 2026 23:12
The Web performance snippet I use to populate how quick a page loads on my blog, now fixed the iOS 0 milliseconds issue.
(function() {
/* check to see if the browser is modern enough to support the
PerformanceNavigationTiming API */
if (!window.performance?.getEntriesByType) {
console.warn('Performance API not supported');
return;
}
function showLoadTime() {
const entries = performance.getEntriesByType('navigation');
@Nooshu
Nooshu / build-events.js
Created February 20, 2026 13:29
The build events file that I use with my 11ty build. It contains extensive logging that output to the Cloudflare pages build log.
import env from '../_data/env.js';
import { clearCssBuildCache } from '../_helpers/css-manipulation.js';
import { generatePreloadHeaders } from '../_helpers/header-generator.js';
import { compressHtmlFiles } from '../_helpers/html-compression.js';
import { compressJavaScriptFiles } from '../_helpers/js-compression.js';
import { minifyJavaScriptFiles } from '../_helpers/js-minify.js';
/**
* Register eleventy.before and eleventy.after handlers.
* Only registered when !env.isLocal (production/preview)
@Nooshu
Nooshu / [[path]].js
Created February 20, 2026 13:01
The Cloudflare function that does the content negotiation for the HTML that has been compressed to Brotli 11.
/**
* Catch-all Pages Function for HTML document content negotiation.
* Serves pre-compressed Brotli 11 .br files when client sends Accept-Encoding: br,
* otherwise passes through to static assets (uncompressed HTML).
* Only runs for GET and HEAD; POST /api/contact is handled by functions/api/contact.js.
*/
async function handleHtmlWithBrotli(request, env) {
const url = new URL(request.url);
const pathname = url.pathname;
@Nooshu
Nooshu / html-compression.js
Created February 20, 2026 12:55
The HTML compression postbuild file for compressing the HTML to Brotli 11. (contains logging for Cloudflare pages builds)
import fs from 'fs';
import path from 'path';
import { brotliCompress, BROTLI_LEVEL } from './compression.js';
/**
* Recursively find all .html files in a directory.
* @param {string} dir - Directory to search
* @param {string[]} [acc=[]] - Accumulator for results
* @returns {string[]} Relative paths to .html files