1import type { PresignError } from "@distilled.cloud/aws/Presign";
2import type * as Effect from "effect/Effect";
3import * as Binding from "../../Binding.ts";
4import type { Bucket } from "./Bucket.ts";
5
6export interface PresignPutObjectRequest {
7 /**
8 * Key of the object to mint a presigned upload URL for.
9 */
10 key: string;
11 /**
12 * Number of seconds the URL remains valid.
13 * @default 900
14 */
15 expiresIn?: number;
16 /**
17 * Content-Type signed into the URL. The uploader must send exactly this
18 * `Content-Type` header or S3 rejects the upload with a signature
19 * mismatch. Omit to leave the Content-Type unconstrained.
20 */
21 contentType?: string;
22}
23
24/**
25 * Mint presigned upload (PUT) URLs for objects in a {@link Bucket}.
26 *
27 * Presigning is a pure SigV4 computation performed client-side with the
28 * Function's own credentials — no S3 API call is made. Because the URL
29 * inherits the signer's IAM permissions, the binding grants `s3:PutObject`
30 * on the bucket's objects to the host Function.
31 *
32 * ### Presigning Upload URLs
33 * **Example:** Mint a presigned PUT URL
34 * ```typescript
35 * const presignPutObject = yield* S3.PresignPutObject(bucket);
36 * const url = yield* presignPutObject({ key: "uploads/avatar.png" });
37 * // hand `url` to a browser — it can PUT the object without AWS credentials
38 * ```
39 *
40 * **Example:** Pin the uploaded Content-Type
41 * ```typescript
42 * const url = yield* presignPutObject({
43 * key: "uploads/avatar.png",
44 * expiresIn: 300, // valid for 5 minutes
45 * contentType: "image/png", // uploader must send Content-Type: image/png
46 * });
47 * ```
48 *
49 * @binding
50 */
51export interface PresignPutObject extends Binding.Service<
52 PresignPutObject,
53 "AWS.S3.PresignPutObject",
54 (
55 bucket: Bucket,
56 ) => Effect.Effect<
57 (request: PresignPutObjectRequest) => Effect.Effect<string, PresignError>
58 >
59> {}
60
61export const PresignPutObject = Binding.Service<PresignPutObject>(
62 "AWS.S3.PresignPutObject",
63);