Skip to content

Navigation Menu

Sign in
Sign up

fix(uploads): store images in R2 so the Worker can boot - #4

Open
pallaoro wants to merge 1 commit into
main from
fix/r2-uploads
Open

fix(uploads): store images in R2 so the Worker can boot #4
pallaoro wants to merge 1 commit into
main from
fix/r2-uploads

Conversation

@pallaoro

@pallaoro pallaoro commented Sep 3, 2026

Copy link
Copy Markdown
Member

The bug

src/server/uploads.ts stored uploads on the local filesystem with node:fs, and resolved its uploads directory at module scope:

const __dirname = dirname(fileURLToPath(import.meta.url));
const UPLOADS_DIR = join(__dirname, "..", "..", "uploads");
mkdirSync(UPLOADS_DIR, { recursive: true });

On Workers import.meta.url is undefined, so fileURLToPath throws while the module is still being imported. The failure happens before any handler is registered, so the Worker never starts and every route is dead, not just uploads.

Reproduced on a clean checkout with wrangler dev:

✘ [ERROR] service core:user:open-design: Uncaught TypeError:
 The "path" argument must be of type string or an instance of URL. Received undefined
 at fileURLToPath (node-internal:internal_url:155:15)
 MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start.

The fix

Use the R2-backed uploads.ts that the other templates in this family already ship (byte-identical to the one in OpenCMS and OpenFrame), bind the bucket once in middleware ahead of the routes, and declare the binding in wrangler.toml.

  • src/server/uploads.ts now talks to R2Bucket instead of fs
  • src/server/index.ts calls initUploads(c.env.UPLOADS) in an app.use("*") registered before the routes, so it runs first
  • wrangler.toml gains the UPLOADS R2 binding
  • README pointed at a stale port and at the old on-disk paths

Verification

Against a local wrangler dev:

Check Result
Worker boots Ready on http://localhost:8787
GET /api/templates 200, six seeded templates
Design create / get / list / delete 200 on each, first page auto-created
POST /api/uploads then GET /api/uploads/:filename 200 image/png, bytes identical to the file sent

vite build succeeds. tsc --noEmit is unchanged from before this branch (the repo has never carried Cloudflare worker types, so D1Database and R2Bucket do not resolve; adding @cloudflare/workers-types globally overrides the DOM fetch typings and breaks the client, so that is left for a separate change).

src/server/uploads.ts wrote to the local filesystem via node:fs and
resolved its uploads directory with fileURLToPath(import.meta.url) at
module scope. Neither works on Workers: import.meta.url is undefined
there, so the call threw while the module was still being imported and
the Worker never started. Every route was dead, not just uploads.
Swap the module for the R2 implementation the other templates already
use, bind the bucket once in middleware, and declare the binding in
wrangler.toml.
Verified against a local `wrangler dev`: the Worker boots, GET
/api/templates returns the seeded rows, design create/get/list/delete
round-trip, and an uploaded PNG comes back byte-identical from
GET /api/uploads/:filename.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

1 participant

AltStyle によって変換されたページ (->オリジナル) /