1import type * as Effect from "effect/Effect";
2import * as Layer from "effect/Layer";
3import * as Binding from "../Binding.ts";
4import type { Bucket } from "./Bucket.ts";
5import { makeBucketBinding } from "./BucketBinding.ts";
6import type { BucketCredentials } from "./BucketTypes.ts";
7import { makeBucketAccess } from "./Internal/BucketClient.ts";
8import { readBucketOperations, type ReadBucketClient } from "./ReadBucket.ts";
9import {
10 writeBucketOperations,
11 type WriteBucketClient,
12} from "./WriteBucket.ts";
13
14export interface ReadWriteBucket extends Binding.Service<
15 ReadWriteBucket,
16 "Prisma.ReadWriteBucket",
17 (bucket: Bucket) => Effect.Effect<ReadWriteBucketClient>
18> {}
19
20/**
21 * Full-access client for a Prisma Object Store bucket: every operation of
22 * {@link ReadBucketClient} and {@link WriteBucketClient}.
23 */
24export interface ReadWriteBucketClient
25 extends ReadBucketClient, WriteBucketClient {}
26
27/**
28 * Bind a Prisma Object Store {@link Bucket} to a Prisma Compute app, AWS
29 * Lambda Function, or Cloudflare Worker with read and write access, and obtain
30 * the typed runtime client.
31 *
32 * Binding creates a read-write `Prisma.BucketAccessKey` for the bucket and carries
33 * its S3 credentials into the host environment, so the caller never handles a
34 * credential themselves.
35 *
36 * Provide {@link ReadWriteBucketBinding} on the host implementation.
37 *
38 * Use {@link ReadBucket} instead where read-only access is enough: Prisma
39 * bucket keys have a `read` role, so that binding's credential genuinely
40 * cannot write.
41 *
42 * ### Binding a Bucket
43 * **Example:** Read and write objects from Prisma Compute
44 * ```typescript
45 * export default Prisma.Compute(
46 * "api",
47 * { project, main: import.meta.filename },
48 * Effect.gen(function* () {
49 * const uploads = yield* Prisma.ReadWriteBucket(bucket);
50 *
51 * return {
52 * fetch: Effect.gen(function* () {
53 * yield* uploads.put("hits", "1");
54 * const object = yield* uploads.get("hits");
55 * return yield* HttpServerResponse.text(
56 * object === null ? "" : yield* object.text(),
57 * );
58 * }),
59 * };
60 * }).pipe(Effect.provide(Prisma.ReadWriteBucketBinding)),
61 * );
62 * ```
63 *
64 * @binding
65 * @product Bucket
66 */
67export const ReadWriteBucket = Binding.Service<ReadWriteBucket>(
68 "Prisma.ReadWriteBucket",
69);
70
71/**
72 * Build a read-write bucket client from a bound bucket key's credentials.
73 */
74export const makeReadWriteBucketClient = (
75 credentials: BucketCredentials,
76): ReadWriteBucketClient => {
77 const access = makeBucketAccess(credentials);
78 return {
79 ...readBucketOperations(access),
80 ...writeBucketOperations(access),
81 };
82};
83
84/**
85 * Implementation layer for {@link ReadWriteBucket}. Provide it on the host
86 * Function/Worker Effect:
87 *
88 * ```typescript
89 * Effect.gen(function* () {
90 * const uploads = yield* Prisma.ReadWriteBucket(bucket);
91 * // ...
92 * }).pipe(Effect.provide(Prisma.ReadWriteBucketBinding))
93 * ```
94 */
95export const ReadWriteBucketBinding = Layer.effect(
96 ReadWriteBucket,
97 makeBucketBinding({
98 capability: "ReadWrite",
99 role: "read_write",
100 makeClient: makeReadWriteBucketClient,
101 }),
102);