1import * as Effect from "effect/Effect";
2import * as Layer from "effect/Layer";
3import { makePresignBinding, presignR2Url } from "./PresignToken.ts";
4import {
5 PresignPutObject,
6 type PresignPutObjectRequest,
7} from "./PresignPutObject.ts";
8
9/**
10 * Implementation of {@link PresignPutObject} that signs URLs with S3
11 * credentials derived from an API token. Signing is local SigV4 — no request
12 * is made to R2.
13 *
14 * Deployed, it mints a scoped account API token with
15 * `Workers R2 Storage Write` (access key id = token id, secret = SHA-256 of
16 * the token value) and signs URLs for `{accountId}.r2.cloudflarestorage.com`.
17 * Under `alchemy dev`, a locally-emulated bucket is signed with fixed local
18 * credentials for the Worker's local S3 endpoint, and no token is created.
19 *
20 * @layer
21 * @provides Cloudflare.R2.PresignPutObject
22 * @product R2
23 */
24export const PresignPutObjectToken = Layer.effect(
25 PresignPutObject,
26 Effect.suspend(() =>
27 makePresignBinding<PresignPutObjectRequest>({
28 name: "Cloudflare.R2.PresignPutObject",
29 access: "write",
30 presign: (credentials, request) =>
31 presignR2Url(credentials, {
32 method: "PUT",
33 key: request.key,
34 expiresIn: request.expiresIn,
35 headers:
36 request.contentType !== undefined
37 ? { "content-type": request.contentType }
38 : undefined,
39 }),
40 }),
41 ),
42);