Bootstraps the Go module and the Go -> Cloudflare Workers build tooling — the foundation the rest of the ingest Worker builds on. Everything is structured so go test and a local dev server run on plain Go (no TinyGo), while the real Wasm Worker entrypoint is isolated behind build tags.
Approach
Go module: github.com/JMR-dev/LibreMail-Bug-Report-Ingest (Go 1.26).
Go -> Workers path: TinyGo -> Wasm via github.com/syumai/workers. Cloudflare Workers execute WebAssembly, and TinyGo produces far smaller modules than the stdlib GOOS=js GOARCH=wasm compiler — comfortably within the Worker size limit — which is why it is the standard path for Go on Workers. syumai/workers adapts Go's net/http handler model to the Workers fetch event, so a single http.Handler runs unchanged on the dev server and in the Worker.
Structure (works without TinyGo):
internal/handler/ — build-tag-free core http.Handler (GET /, GET /healthz, JSON, 404/405) plus net/http/httptest unit tests.
cmd/devserver/ — plain net/http server mounting the same handler for local dev.
worker/main.go — Workers (Wasm) entrypoint behind //go:build js && wasm, wiring the same handler; excluded from host builds/tests.
Node tooling: pnpm only. wrangler is a dev dependency; pnpm-workspace.yaml approves the wrangler toolchain build scripts (esbuild/sharp/workerd).
wrangler.jsonc: name = libremail-bug-report-ingest, main = ./build/worker.mjs, recent compatibility_date, build via pnpm run build.
Verification
go vet ./... is clean; go test ./...:
=== RUN TestRoot
--- PASS: TestRoot (0.00s)
=== RUN TestHealthz
--- PASS: TestHealthz (0.00s)
=== RUN TestUnknownPathReturns404
--- PASS: TestUnknownPathReturns404 (0.00s)
=== RUN TestNonGetReturns405
--- PASS: TestNonGetReturns405 (0.00s)
PASS
ok github.com/JMR-dev/LibreMail-Bug-Report-Ingest/internal/handler
Hello-world runs locally via go run ./cmd/devserver:
$ curl -s localhost:8787/
{"service":"libremail-bug-report-ingest","status":"ok","message":"hello from the LibreMail bug-report ingest Worker"}
$ curl -s localhost:8787/healthz
{"status":"ok"}
As an extra signal the Wasm wiring is correct, the worker entrypoint compiles for the target — GOOS=js GOARCH=wasm go build ./worker succeeds — even though the real artifact is produced by TinyGo in CI.
TinyGo / Wasm build (documented; not run here — TinyGo intentionally absent)
pnpm run build runs, verbatim:
go run github.com/syumai/workers/cmd/workers-assets-gen && tinygo build -o ./build/app.wasm -target wasm -no-debug ./worker
TinyGo (0.35.0+) is required only for the Wasm build and is installed in CI. Local dev and tests need only plain Go. The pnpm exec wrangler dev/deploy path is documented in the README.
Out of scope / possible follow-ups
CI workflow (install TinyGo + pnpm, run go test, build Wasm, wrangler deploy).
Actual wrangler dev against a real Wasm build is not exercised locally because TinyGo is intentionally not installed on this machine.
Bootstraps the Go module and the Go -> Cloudflare Workers build tooling — the foundation the rest of the ingest Worker builds on. Everything is structured so `go test` and a local dev server run on **plain Go** (no TinyGo), while the real Wasm Worker entrypoint is isolated behind build tags.
## Approach
- **Go module**: `github.com/JMR-dev/LibreMail-Bug-Report-Ingest` (Go 1.26).
- **Go -> Workers path: TinyGo -> Wasm via [`github.com/syumai/workers`](https://github.com/syumai/workers).** Cloudflare Workers execute WebAssembly, and TinyGo produces far smaller modules than the stdlib `GOOS=js GOARCH=wasm` compiler — comfortably within the Worker size limit — which is why it is the standard path for Go on Workers. `syumai/workers` adapts Go's `net/http` handler model to the Workers `fetch` event, so a single `http.Handler` runs unchanged on the dev server and in the Worker.
- **Structure (works without TinyGo)**:
- `internal/handler/` — build-tag-free core `http.Handler` (`GET /`, `GET /healthz`, JSON, 404/405) plus `net/http/httptest` unit tests.
- `cmd/devserver/` — plain `net/http` server mounting the same handler for local dev.
- `worker/main.go` — Workers (Wasm) entrypoint behind `//go:build js && wasm`, wiring the same handler; excluded from host builds/tests.
- **Node tooling**: pnpm only. `wrangler` is a dev dependency; `pnpm-workspace.yaml` approves the wrangler toolchain build scripts (esbuild/sharp/workerd).
- **wrangler.jsonc**: `name = libremail-bug-report-ingest`, `main = ./build/worker.mjs`, recent `compatibility_date`, build via `pnpm run build`.
## Verification
`go vet ./...` is clean; `go test ./...`:
```
=== RUN TestRoot
--- PASS: TestRoot (0.00s)
=== RUN TestHealthz
--- PASS: TestHealthz (0.00s)
=== RUN TestUnknownPathReturns404
--- PASS: TestUnknownPathReturns404 (0.00s)
=== RUN TestNonGetReturns405
--- PASS: TestNonGetReturns405 (0.00s)
PASS
ok github.com/JMR-dev/LibreMail-Bug-Report-Ingest/internal/handler
```
Hello-world runs locally via `go run ./cmd/devserver`:
```
$ curl -s localhost:8787/
{"service":"libremail-bug-report-ingest","status":"ok","message":"hello from the LibreMail bug-report ingest Worker"}
$ curl -s localhost:8787/healthz
{"status":"ok"}
```
As an extra signal the Wasm wiring is correct, the worker entrypoint compiles for the target — `GOOS=js GOARCH=wasm go build ./worker` succeeds — even though the real artifact is produced by TinyGo in CI.
## TinyGo / Wasm build (documented; not run here — TinyGo intentionally absent)
`pnpm run build` runs, verbatim:
```
go run github.com/syumai/workers/cmd/workers-assets-gen && tinygo build -o ./build/app.wasm -target wasm -no-debug ./worker
```
TinyGo (0.35.0+) is required only for the Wasm build and is installed in CI. Local dev and tests need only plain Go. The `pnpm exec wrangler dev`/`deploy` path is documented in the README.
## Out of scope / possible follow-ups
- CI workflow (install TinyGo + pnpm, run `go test`, build Wasm, `wrangler deploy`).
- Actual `wrangler dev` against a real Wasm build is not exercised locally because TinyGo is intentionally not installed on this machine.
Closes #1
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Bootstraps the Go module and the Go -> Cloudflare Workers build tooling — the foundation the rest of the ingest Worker builds on. Everything is structured so
go testand a local dev server run on plain Go (no TinyGo), while the real Wasm Worker entrypoint is isolated behind build tags.Approach
github.com/JMR-dev/LibreMail-Bug-Report-Ingest(Go 1.26).github.com/syumai/workers. Cloudflare Workers execute WebAssembly, and TinyGo produces far smaller modules than the stdlibGOOS=js GOARCH=wasmcompiler — comfortably within the Worker size limit — which is why it is the standard path for Go on Workers.syumai/workersadapts Go'snet/httphandler model to the Workersfetchevent, so a singlehttp.Handlerruns unchanged on the dev server and in the Worker.internal/handler/— build-tag-free corehttp.Handler(GET /,GET /healthz, JSON, 404/405) plusnet/http/httptestunit tests.cmd/devserver/— plainnet/httpserver mounting the same handler for local dev.worker/main.go— Workers (Wasm) entrypoint behind//go:build js && wasm, wiring the same handler; excluded from host builds/tests.wrangleris a dev dependency;pnpm-workspace.yamlapproves the wrangler toolchain build scripts (esbuild/sharp/workerd).name = libremail-bug-report-ingest,main = ./build/worker.mjs, recentcompatibility_date, build viapnpm run build.Verification
go vet ./...is clean;go test ./...:Hello-world runs locally via
go run ./cmd/devserver:As an extra signal the Wasm wiring is correct, the worker entrypoint compiles for the target —
GOOS=js GOARCH=wasm go build ./workersucceeds — even though the real artifact is produced by TinyGo in CI.TinyGo / Wasm build (documented; not run here — TinyGo intentionally absent)
pnpm run buildruns, verbatim:TinyGo (0.35.0+) is required only for the Wasm build and is installed in CI. Local dev and tests need only plain Go. The
pnpm exec wrangler dev/deploypath is documented in the README.Out of scope / possible follow-ups
go test, build Wasm,wrangler deploy).wrangler devagainst a real Wasm build is not exercised locally because TinyGo is intentionally not installed on this machine.Closes #1