Skip to content

feat: CORS proxy fallback for URL-loaded media (?disk= / ?hd=) - #59

Open
anomixer wants to merge 11 commits into
mikedaley:masterfrom
anomixer:feat/corsproxy
Open

feat: CORS proxy fallback for URL-loaded media (?disk= / ?hd=)#59
anomixer wants to merge 11 commits into
mikedaley:masterfrom
anomixer:feat/corsproxy

Conversation

@anomixer

@anomixer anomixer commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Hi Mike,

I've created a CORS proxy for you to integrate with your web-a2e. Check this out.

Overview

This PR lets ?disk= / ?hd= links load disk and hard-drive images from hosts that send no Access-Control-Allow-Origin header — the common case for archive mirrors and plain web servers like Asimov — while keeping everything working for hosts that already allow cross-origin reads.

The browser first tries a direct fetch. When it fails with the opaque TypeError that signals a CORS refusal, the request is automatically retried through a same-origin /proxy/url/… endpoint, which fetches the file server-side and returns it with permissive CORS headers. Hosts that already send CORS headers are never routed through the proxy.

The server-side proxy is provided two ways

  1. Cloudflare Pages Functionfunctions/proxy/[[path]].js, deployed by the optional .github/workflows/cloudflare-pages-deploy.yml.
  2. Vite dev pluginplugins/dev-proxy-plugin.js serves the same /proxy/url route during npm run dev, so development behaves like production.

Important: the Cloudflare deployment is opt-in

This PR does not change the existing deployment. The Cloudflare Pages workflow is skipped unless the repository sets CLOUDFLARE_PAGES_ENABLED=true. If you keep your current VPS/static deployment, nothing here changes — you just need to provide the /proxy/url/<encoded> endpoint another way (e.g. an nginx reverse-proxy location block) for the fallback to work on your host.

To enable Cloudflare Pages on a repo:

  • Variable: CLOUDFLARE_PAGES_ENABLED=true
  • Variable (optional): CLOUDFLARE_PAGES_PROJECT (defaults to web-a2e)
  • Secrets: CLOUDFLARE_API_TOKEN (Account · Cloudflare Pages:Edit), CLOUDFLARE_ACCOUNT_ID

Formats

Parameter Device Formats
?disk= Disk II (floppy) .dsk .do .po .woz
?hd= SmartPort (hard drive) .2mg .hdv

Testing

Verified locally (npm run dev) and on a live Cloudflare Pages deployment. URLs that previously failed due to CORS — including Internet Archive (archive.org) and Asimov (asimov.applefritter.com) — now load fine. For example, ?disk=https://archive.org/download/pouet_82820/IBZII.dsk loads the full 143360-byte image via the proxy. All 91 existing Vitest tests pass.

You are welcome to try it on my fork's live deployment: https://web-a2e.pages.dev — append any ?disk=… / ?hd=… URL (including an Asimov or Internet Archive image) and it should load.

Files changed

  • src/js/disk-manager/url-media-loader.js — CORS fallback through /proxy/url
  • functions/proxy/[[path]].js — Cloudflare Pages Function proxy
  • plugins/dev-proxy-plugin.js — Vite dev-server proxy middleware
  • .github/workflows/cloudflare-pages-deploy.yml — opt-in CF Pages deploy
  • vite.config.js, .gitignore, README.md, CLAUDE.md

A same-origin /proxy/url proxy lets ?disk= and ?hd= links load from hosts
that send no Access-Control-Allow-Origin. Deployed as a Cloudflare Pages
Function (functions/proxy/[[path]].js); the local Vite dev server serves the
same route via plugins/dev-proxy-plugin.js so dev matches production.

url-media-loader first tries a direct fetch, then retries through the proxy
on the opaque TypeError that signals a CORS refusal. Add format tables and
CORS behavior to README/CLAUDE docs.
A same-origin /proxy/url proxy lets ?disk= and ?hd= links load from hosts
that send no Access-Control-Allow-Origin. The browser first tries a direct
fetch, then retries through the proxy on the opaque TypeError that signals a
CORS refusal; hosts that already send CORS headers are never routed through it.

Server-side, the proxy is provided two ways:
- Cloudflare Pages Function (functions/proxy/[[path]].js), deployed by an
  opt-in .github/workflows/cloudflare-pages-deploy.yml that is skipped unless
  vars.CLOUDFLARE_PAGES_ENABLED == 'true', so an existing VPS/static
  deployment is untouched.
- A Vite plugin (plugins/dev-proxy-plugin.js) serves the same /proxy/url route
  during npm run dev (and must call next() on non-proxy paths).

Document formats and the CORS/opt-in behavior in README and CLAUDE docs.
@mikedaley

Copy link
Copy Markdown
Owner

Thanks for this PR. I'll need to review in more detail and come back to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants