Skip to content

Instantly share code, notes, and snippets.

@TheKidCoder
Created November 14, 2025 01:25
Show Gist options
  • Select an option

  • Save TheKidCoder/3e6f4c1e0425663360cceeb0e2227eb0 to your computer and use it in GitHub Desktop.

Select an option

Save TheKidCoder/3e6f4c1e0425663360cceeb0e2227eb0 to your computer and use it in GitHub Desktop.
Ascend Sitemap Root
/**
* Dutchie Cloudflare Store-Front Proxy
*
* This worker is intended to be installed on customer-managed Cloudflare accounts to proxy
* Dutchie Storefront traffic to the appropriate destination domain and optionally rewrite
* non-proxied requests based on configured domain mappings.
*
* Example install scope: https://northcannabisco.com/* -> dutchie-proxy-script
*
* Environment variables:
* - STOREFRONT_HOST_DOMAIN: The destination storefront domain to proxy to (commonly "dutchie.com").
* - REWRITE_DOMAINS: A semicolon-separated list of domain pairs used to rewrite requests when not
* proxying. This is useful when the worker sits at the customer's root domain and needs to forward
* non-storefront traffic to another origin (e.g., a CMS hosted elsewhere).
* Format: "source.com:destination.com;source2.com:destination2.com"
*
* Request headers:
* - X-DUTCHIE-PROXY-PASS: When present (any value), the worker bypasses both proxying and
* REWRITE_DOMAINS handling. The original request is forwarded untouched to the current origin.
*
* Behavior overview:
* - Never proxies the root path "/".
* - Proxies requests whose path starts with: /stores, /checkout, /oauth, /pay.
* - Proxies requests when the Referer header's path starts with any of: /stores, /checkout, /oauth, /pay
* (even if the current request path itself does not match these prefixes).
* - For non-proxied requests, optionally rewrites the hostname according to REWRITE_DOMAINS.
* - If X-DUTCHIE-PROXY-PASS is present, bypasses proxy and rewrite logic entirely.
*
* Changelog:
* - 2025-10-30: Added 404 retry logic. If a proxied request 404s, retry on the original origin.
* - 2025-08-08: Added X-DUTCHIE-PROXY-PASS header support to bypass proxying and rewriting.
* - 2025-07-27: Added support for REWRITE_DOMAINS environment variable to rewrite non-proxied requests.
*/
function renderSitemapIndex(request) {
const sitemapIndex = `<?xmlversion="1.0"encoding="UTF-8"?><sitemapindexxmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><sitemap><loc>https://www.letsascend.com/stores/battle-creek-michigan/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/michigan-supply-and-provisions-grand-river/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/carroll-ohio/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/ascend-nj-montclair/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/rochelle-park-new-jersey/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/whitehall-pennsylvania/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/fairview-heights-illinois/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/ascend-wellness-holdings/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/ascend-cincinnati-ohio/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/cranberry-pennsylvania/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/scranton-pennsylvania/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/wayne-pennsylvania/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/monaca-pennsylvania/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/new-bedford-massachusetts/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/boston-massachusetts/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/fort-lee-new-jersey/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/wharton-new-jersey/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/newton-massachusetts/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/northlake-illinois/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/grand-rapids-28th-street-michigan/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/grand-rapids-century-avenue-michigan/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/east-lansing-michigan/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/grand-rapids-scribner-avenue-michigan/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/morenci-michigan/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/piqua-ohio/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/sandusky-ohio/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/collinsville-illinois/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/springfield-adams-street-illinois/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/springfield-horizon-drive-illinois/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/chicago-midway-illinois/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/chicago-ridge-illinois/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/ann-arbor-michigan/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/detroit-michigan/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/aberdeen-maryland/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/crofton-maryland/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/ellicott-city-maryland/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/laurel-maryland/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/chicago-logan-square-illinois/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/river-north-illinois/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/chicago-tinley-park-illinois/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/ascend-cannabis-coshocton/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/englewood-ohio/sitemap.xml</loc></sitemap><sitemap><loc>https://www.letsascend.com/stores/hoboken-new-jersey/sitemap.xml</loc></sitemap></sitemapindex>`;
return new Response(sitemapIndex, {
headers: {
'Content-Type': 'application/xml; charset=utf-8'
}
});
}
export function shouldProxyRequest(request) {
// Bypass proxying entirely if the special header is present
if (request.headers.get('X-DUTCHIE-PROXY-PASS') !== null) {
return false;
}
const urlObject = new URL(request.url);
const refererHeader = request.headers.get('Referer');
const refererUrl = refererHeader ? refererHeader : urlObject.origin;
// Handle malformed referrer URLs gracefully
let refererObject;
try {
refererObject = new URL(refererUrl);
}
catch (error) {
// If referrer is malformed, fall back to request origin
refererObject = new URL(urlObject.origin);
}
const visitablePaths = /^\/stores|^\/checkout|^\/oauth|^\/pay/;
let pathName = urlObject.pathname;
// Check if the path starts with /stores
if (pathName.startsWith('/stores')) {
// Remove trailing slash if present
pathName = pathName.replace(/\/$/, '');
}
// NEVER proxy the root path
if (pathName === '/') {
return false;
}
// If direct path, always allow.
if (visitablePaths.test(pathName)) {
return true;
}
// If referrer path, always allow.
if (visitablePaths.test(refererObject.pathname)) {
return true;
}
// If Cloudflare CDN path AND a valid referrer allow.
if (/^\/cdn-cgi/.test(pathName) && visitablePaths.test(refererObject.pathname)) {
return true;
}
return false;
}
async function handleRequest(request, env) {
const STOREFRONT_HOST_DOMAIN = env.STOREFRONT_HOST_DOMAIN || "dutchie.com";
// The env var supports multiple domains.
// Format: "source.com:destination.com;source2.com:destination2.com"
const REWRITE_DOMAINS_CONFIG = env.REWRITE_DOMAINS;
try {
// If the request should be proxied to the storefront
if (shouldProxyRequest(request)) {
if (request.url.startsWith('/stores/sitemap.xml')) {
return renderSitemapIndex(request);
}
const ORIGIN_DOMAIN = request.headers.get('Host') || '';
const proxyUrl = new URL(request.url);
proxyUrl.hostname = STOREFRONT_HOST_DOMAIN;
const proxyRequest = new Request(proxyUrl.toString(), request);
// Set headers for the proxy request
proxyRequest.headers.set('Host', STOREFRONT_HOST_DOMAIN);
proxyRequest.headers.set('X-Forwarded-Host', ORIGIN_DOMAIN);
proxyRequest.headers.set('X-Forwarded-Proto', 'https');
proxyRequest.headers.set('X-Forwarded-For', request.headers.get('CF-Connecting-IP') || '');
proxyRequest.headers.set('X-Forwarding-Proxy', 'dutchie-hosted-proxy');
// --- MODIFICATION START ---
// Fetch the proxy request
const proxyResponse = await fetch(proxyRequest);
// If the proxied request returns a 404, retry on the original origin.
// This handles assets that might exist on the customer's origin but not on the proxy.
if (proxyResponse.status === 404) {
// We must create a new Request object based on the original `request`
// and add the 'X-DUTCHIE-PROXY-PASS' header. This tells
// `shouldProxyRequest` to return `false` on the *next* invocation,
// preventing an infinite proxy loop.
const originRequest = new Request(request.url, request);
originRequest.headers.set('X-DUTCHIE-PROXY-PASS', 'true');
// This fetch will be caught by this worker's 'fetch' handler again.
// `shouldProxyRequest` will return `false` due to the header.
// The request will then fall through to the rewrite logic
// or the final origin fetch.
return await fetch(originRequest);
}
// Otherwise, return the proxy response as-is
return proxyResponse;
// --- MODIFICATION END ---
}
// If not proxying, check for a rewrite rule based on the request's host.
if (REWRITE_DOMAINS_CONFIG) {
// Create a lookup map from the environment variable string.
const rewriteMap = new Map(REWRITE_DOMAINS_CONFIG.split(';')
.map((pair) => {
const parts = pair.split(':');
return (parts.length === 2 && parts[0] && parts[1]) ? [parts[0].trim(), parts[1].trim()] : null;
})
.filter((p) => p !== null) // Type guard to filter out null values
);
const requestHost = new URL(request.url).hostname;
const destinationHost = rewriteMap.get(requestHost);
if (destinationHost) {
const url = new URL(request.url);
url.hostname = destinationHost;
const newOriginRequest = new Request(url.toString(), request);
newOriginRequest.headers.set('Host', destinationHost);
// --- MODIFICATION START ---
// Forward the end-user's IP address to the destination host.
const clientIp = request.headers.get('CF-Connecting-IP');
if (clientIp) {
newOriginRequest.headers.set('X-Forwarded-For', clientIp);
newOriginRequest.headers.set('X-Real-IP', clientIp);
}
// --- MODIFICATION END ---
return await fetch(newOriginRequest);
}
}
// Fallback: If no rewrite rule matches, forward the original request.
// This is also the eventual target for 404-retry requests.
return await fetch(request);
}
catch (error) {
console.error('Error handling request:', error);
return await fetch(request); // Fallback on error
}
}
export default {
async fetch(request, env, ctx) {
return handleRequest(request, env);
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment