Created
November 14, 2025 01:25
-
-
Save TheKidCoder/3e6f4c1e0425663360cceeb0e2227eb0 to your computer and use it in GitHub Desktop.
Ascend Sitemap Root
This file contains hidden or 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
| /** | |
| * 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