| 1 | import * as Cloudflare from "@/Cloudflare/index.ts"; |
| 2 | import * as Effect from "effect/Effect"; |
| 3 | import { HttpServerRequest } from "effect/http/HttpServerRequest"; |
| 4 | import * as HttpServerResponse from "effect/http/HttpServerResponse"; |
| 5 | import { TestBucket } from "./bucket.ts"; |
| 6 | import { writeRoutes } from "./write-routes.ts"; |
| 7 | |
| 8 | /** Write-only access via the native Worker binding (`WriteBucketBinding`). */ |
| 9 | export default class R2WriteBindingWorker extends Cloudflare.Worker<R2WriteBindingWorker>()( |
| 10 | "R2WriteBindingWorker", |
| 11 | { main: import.meta.url }, |
| 12 | Effect.gen(function* () { |
| 13 | const bucket = yield* TestBucket; |
| 14 | const r2 = yield* Cloudflare.R2.WriteBucket(bucket); |
| 15 | return { |
| 16 | fetch: Effect.gen(function* () { |
| 17 | const request = yield* HttpServerRequest; |
| 18 | const url = new URL(request.url, "http://x"); |
| 19 | // `PUT /put-stream?key=&sha256=` — `put(key, stream, { contentLength, |
| 20 | // sha256 })`: the body reaches R2 as an Effect `Stream`, and R2 must |
| 21 | // verify it against the declared hash. Only the native binding can |
| 22 | // stream, so this route is not part of the shared write routes. |
| 23 | if (request.method === "PUT" && url.pathname === "/put-stream") { |
| 24 | const key = url.searchParams.get("key") ?? ""; |
| 25 | const sha256 = url.searchParams.get("sha256") ?? ""; |
| 26 | const contentLength = Number(request.headers["content-length"] ?? 0); |
| 27 | return yield* r2 |
| 28 | .put(key, request.stream, { contentLength, sha256 }) |
| 29 | .pipe( |
| 30 | Effect.flatMap((object) => |
| 31 | HttpServerResponse.json({ |
| 32 | stored: true, |
| 33 | size: object?.size ?? null, |
| 34 | }), |
| 35 | ), |
| 36 | Effect.catchTag("R2Error", (e) => |
| 37 | HttpServerResponse.json( |
| 38 | { stored: false, error: e.message }, |
| 39 | { status: 400 }, |
| 40 | ), |
| 41 | ), |
| 42 | ); |
| 43 | } |
| 44 | const handled = yield* writeRoutes(r2, request, url); |
| 45 | return handled ?? HttpServerResponse.text("Not Found", { status: 404 }); |
| 46 | }), |
| 47 | }; |
| 48 | }).pipe(Effect.provide(Cloudflare.R2.WriteBucketBinding)), |
| 49 | ) {} |