effect-cf 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +91 -0
- package/dist/Hyperdrive-By6DrSS_.d.mts +140 -0
- package/dist/Hyperdrive-LuQaVhXU.mjs +86 -0
- package/dist/HyperdrivePg.d.mts +14 -0
- package/dist/HyperdrivePg.mjs +13 -0
- package/dist/index.d.mts +257 -200
- package/dist/index.mjs +251 -190
- package/package.json +13 -1
- package/src/D1.ts +3 -59
- package/src/Hyperdrive.ts +82 -0
- package/src/HyperdrivePg.ts +27 -0
- package/src/Images.ts +332 -0
- package/src/Kv.ts +0 -62
- package/src/R2.ts +230 -0
- package/src/index.ts +3 -0
package/src/R2.ts
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { Context, Data, Effect, Option, type Layer } from "effect";
|
|
2
|
+
|
|
3
|
+
import * as Binding from "./Binding";
|
|
4
|
+
import type { WorkerEnvironment } from "./Environment";
|
|
5
|
+
|
|
6
|
+
/** Error raised when an R2 operation fails. */
|
|
7
|
+
export class R2OperationError extends Data.TaggedError("R2OperationError")<{
|
|
8
|
+
readonly binding: string;
|
|
9
|
+
readonly operation: string;
|
|
10
|
+
readonly cause: unknown;
|
|
11
|
+
}> {}
|
|
12
|
+
|
|
13
|
+
/** Typed R2 bucket binding definition. */
|
|
14
|
+
export interface R2Definition {
|
|
15
|
+
/** Binding name as configured in `wrangler.jsonc`. */
|
|
16
|
+
readonly binding: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type R2GetOptions = globalThis.R2GetOptions;
|
|
20
|
+
export type R2PutOptions = globalThis.R2PutOptions;
|
|
21
|
+
export type R2ListOptions = globalThis.R2ListOptions;
|
|
22
|
+
export type R2MultipartOptions = globalThis.R2MultipartOptions;
|
|
23
|
+
export type R2UploadPartOptions = globalThis.R2UploadPartOptions;
|
|
24
|
+
export type R2PutValue = ReadableStream | ArrayBuffer | ArrayBufferView | string | null | Blob;
|
|
25
|
+
export type R2UploadPartValue = ReadableStream | ArrayBuffer | ArrayBufferView | string | Blob;
|
|
26
|
+
|
|
27
|
+
export interface R2MultipartUploadClient {
|
|
28
|
+
readonly raw: globalThis.R2MultipartUpload;
|
|
29
|
+
readonly key: string;
|
|
30
|
+
readonly uploadId: string;
|
|
31
|
+
readonly uploadPart: (
|
|
32
|
+
partNumber: number,
|
|
33
|
+
value: R2UploadPartValue,
|
|
34
|
+
options?: R2UploadPartOptions,
|
|
35
|
+
) => Effect.Effect<globalThis.R2UploadedPart, R2OperationError>;
|
|
36
|
+
readonly abort: Effect.Effect<void, R2OperationError>;
|
|
37
|
+
readonly complete: (
|
|
38
|
+
uploadedParts: ReadonlyArray<globalThis.R2UploadedPart>,
|
|
39
|
+
) => Effect.Effect<globalThis.R2Object, R2OperationError>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface R2Client {
|
|
43
|
+
readonly head: (
|
|
44
|
+
key: string,
|
|
45
|
+
) => Effect.Effect<Option.Option<globalThis.R2Object>, R2OperationError>;
|
|
46
|
+
readonly get: {
|
|
47
|
+
(
|
|
48
|
+
key: string,
|
|
49
|
+
options: R2GetOptions & { readonly onlyIf: globalThis.R2Conditional | Headers },
|
|
50
|
+
): Effect.Effect<
|
|
51
|
+
Option.Option<globalThis.R2ObjectBody | globalThis.R2Object>,
|
|
52
|
+
R2OperationError
|
|
53
|
+
>;
|
|
54
|
+
(
|
|
55
|
+
key: string,
|
|
56
|
+
options?: R2GetOptions,
|
|
57
|
+
): Effect.Effect<Option.Option<globalThis.R2ObjectBody>, R2OperationError>;
|
|
58
|
+
};
|
|
59
|
+
readonly put: {
|
|
60
|
+
(
|
|
61
|
+
key: string,
|
|
62
|
+
value: R2PutValue,
|
|
63
|
+
options: R2PutOptions & { readonly onlyIf: globalThis.R2Conditional | Headers },
|
|
64
|
+
): Effect.Effect<Option.Option<globalThis.R2Object>, R2OperationError>;
|
|
65
|
+
(
|
|
66
|
+
key: string,
|
|
67
|
+
value: R2PutValue,
|
|
68
|
+
options?: R2PutOptions,
|
|
69
|
+
): Effect.Effect<globalThis.R2Object, R2OperationError>;
|
|
70
|
+
};
|
|
71
|
+
readonly createMultipartUpload: (
|
|
72
|
+
key: string,
|
|
73
|
+
options?: R2MultipartOptions,
|
|
74
|
+
) => Effect.Effect<R2MultipartUploadClient, R2OperationError>;
|
|
75
|
+
readonly resumeMultipartUpload: (
|
|
76
|
+
key: string,
|
|
77
|
+
uploadId: string,
|
|
78
|
+
) => Effect.Effect<R2MultipartUploadClient, R2OperationError>;
|
|
79
|
+
readonly delete: (keys: string | ReadonlyArray<string>) => Effect.Effect<void, R2OperationError>;
|
|
80
|
+
readonly list: (options?: R2ListOptions) => Effect.Effect<globalThis.R2Objects, R2OperationError>;
|
|
81
|
+
readonly unsafeRaw: Effect.Effect<globalThis.R2Bucket>;
|
|
82
|
+
readonly definition: R2Definition;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
declare const R2ServiceTypeId: unique symbol;
|
|
86
|
+
|
|
87
|
+
/** Nominal service marker for R2 services created with {@link make}. */
|
|
88
|
+
export interface R2Service<Id extends string> {
|
|
89
|
+
readonly [R2ServiceTypeId]: {
|
|
90
|
+
readonly id: Id;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type LayerOptions = {
|
|
95
|
+
readonly binding: string;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export interface TagClass<Self, Id extends string> extends Context.ServiceClass<
|
|
99
|
+
Self,
|
|
100
|
+
Id,
|
|
101
|
+
R2Client
|
|
102
|
+
> {
|
|
103
|
+
readonly id: Id;
|
|
104
|
+
readonly layer: (
|
|
105
|
+
options: LayerOptions,
|
|
106
|
+
) => Layer.Layer<
|
|
107
|
+
Self,
|
|
108
|
+
Binding.BindingNotFoundError | Binding.BindingValidationError,
|
|
109
|
+
WorkerEnvironment
|
|
110
|
+
>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const r2Error = (binding: string, operation: string, cause: unknown) =>
|
|
114
|
+
new R2OperationError({ binding, operation, cause });
|
|
115
|
+
|
|
116
|
+
const tryR2Promise = <A>(
|
|
117
|
+
binding: string,
|
|
118
|
+
operation: string,
|
|
119
|
+
evaluate: () => Promise<A>,
|
|
120
|
+
): Effect.Effect<A, R2OperationError> =>
|
|
121
|
+
Effect.tryPromise({
|
|
122
|
+
try: evaluate,
|
|
123
|
+
catch: (cause) => r2Error(binding, operation, cause),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const tryR2Sync = <A>(
|
|
127
|
+
binding: string,
|
|
128
|
+
operation: string,
|
|
129
|
+
evaluate: () => A,
|
|
130
|
+
): Effect.Effect<A, R2OperationError> =>
|
|
131
|
+
Effect.try({
|
|
132
|
+
try: evaluate,
|
|
133
|
+
catch: (cause) => r2Error(binding, operation, cause),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const maybe = <A>(value: A | null): Option.Option<A> =>
|
|
137
|
+
value === null ? Option.none() : Option.some(value);
|
|
138
|
+
|
|
139
|
+
export const isR2Bucket = (value: unknown): value is globalThis.R2Bucket => {
|
|
140
|
+
if (typeof value !== "object" || value === null) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const resource = value as Record<string, unknown>;
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
typeof resource.head === "function" &&
|
|
148
|
+
typeof resource.get === "function" &&
|
|
149
|
+
typeof resource.put === "function" &&
|
|
150
|
+
typeof resource.createMultipartUpload === "function" &&
|
|
151
|
+
typeof resource.resumeMultipartUpload === "function" &&
|
|
152
|
+
typeof resource.delete === "function" &&
|
|
153
|
+
typeof resource.list === "function"
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const makeClient = (
|
|
158
|
+
definition: R2Definition,
|
|
159
|
+
): ((bucket: globalThis.R2Bucket) => R2Client) => {
|
|
160
|
+
const wrapUpload = (upload: globalThis.R2MultipartUpload): R2MultipartUploadClient => ({
|
|
161
|
+
raw: upload,
|
|
162
|
+
key: upload.key,
|
|
163
|
+
uploadId: upload.uploadId,
|
|
164
|
+
uploadPart: (partNumber, value, options) =>
|
|
165
|
+
tryR2Promise(definition.binding, "uploadPart", () =>
|
|
166
|
+
upload.uploadPart(partNumber, value, options),
|
|
167
|
+
),
|
|
168
|
+
abort: tryR2Promise(definition.binding, "abortMultipartUpload", () => upload.abort()),
|
|
169
|
+
complete: (uploadedParts) =>
|
|
170
|
+
tryR2Promise(definition.binding, "completeMultipartUpload", () =>
|
|
171
|
+
upload.complete([...uploadedParts]),
|
|
172
|
+
),
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
return (bucket) => ({
|
|
176
|
+
definition,
|
|
177
|
+
head: (key) =>
|
|
178
|
+
tryR2Promise(definition.binding, "head", () => bucket.head(key)).pipe(Effect.map(maybe)),
|
|
179
|
+
get: ((key: string, options?: R2GetOptions) =>
|
|
180
|
+
tryR2Promise(definition.binding, "get", () => bucket.get(key, options)).pipe(
|
|
181
|
+
Effect.map(maybe),
|
|
182
|
+
)) as R2Client["get"],
|
|
183
|
+
put: ((key: string, value: R2PutValue, options?: R2PutOptions) =>
|
|
184
|
+
tryR2Promise(definition.binding, "put", () => bucket.put(key, value, options)).pipe(
|
|
185
|
+
Effect.map((object) => {
|
|
186
|
+
if (object === null) {
|
|
187
|
+
return Option.none<globalThis.R2Object>();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (options !== undefined && "onlyIf" in options) {
|
|
191
|
+
return Option.some(object);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return object;
|
|
195
|
+
}),
|
|
196
|
+
)) as R2Client["put"],
|
|
197
|
+
createMultipartUpload: (key, options) =>
|
|
198
|
+
tryR2Promise(definition.binding, "createMultipartUpload", () =>
|
|
199
|
+
bucket.createMultipartUpload(key, options),
|
|
200
|
+
).pipe(Effect.map(wrapUpload)),
|
|
201
|
+
resumeMultipartUpload: (key, uploadId) =>
|
|
202
|
+
tryR2Sync(definition.binding, "resumeMultipartUpload", () =>
|
|
203
|
+
wrapUpload(bucket.resumeMultipartUpload(key, uploadId)),
|
|
204
|
+
),
|
|
205
|
+
delete: (keys) => {
|
|
206
|
+
const nativeKeys = typeof keys === "string" ? keys : [...keys];
|
|
207
|
+
return tryR2Promise(definition.binding, "delete", () => bucket.delete(nativeKeys));
|
|
208
|
+
},
|
|
209
|
+
list: (options) => tryR2Promise(definition.binding, "list", () => bucket.list(options)),
|
|
210
|
+
unsafeRaw: Effect.succeed(bucket),
|
|
211
|
+
});
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
export const layer = <Self>(tag: Context.Service<Self, R2Client>, definition: R2Definition) =>
|
|
215
|
+
Binding.layer(tag, definition.binding, isR2Bucket, makeClient(definition));
|
|
216
|
+
|
|
217
|
+
export const make = <Id extends string>(id: Id) => Tag<R2Service<Id>>()<Id>(id);
|
|
218
|
+
|
|
219
|
+
export const Tag =
|
|
220
|
+
<Self>() =>
|
|
221
|
+
<Id extends string>(id: Id) => {
|
|
222
|
+
const tag = Context.Service<Self, R2Client>()(id);
|
|
223
|
+
|
|
224
|
+
const makeLayer = (definition: LayerOptions) => layer(tag, definition);
|
|
225
|
+
|
|
226
|
+
return Object.assign(tag, {
|
|
227
|
+
id,
|
|
228
|
+
layer: makeLayer,
|
|
229
|
+
}) as TagClass<Self, Id>;
|
|
230
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -8,10 +8,13 @@ export * as DurableObjectRpcWebSocket from "./DurableObjectRpcWebSocket";
|
|
|
8
8
|
export * as DurableObjectState from "./DurableObjectState";
|
|
9
9
|
export * as DurableObjectWebSocket from "./DurableObjectWebSocket";
|
|
10
10
|
export * as DurableObjectStorage from "./DurableObjectStorage";
|
|
11
|
+
export * as Hyperdrive from "./Hyperdrive";
|
|
12
|
+
export * as Images from "./Images";
|
|
11
13
|
export * as Kv from "./Kv";
|
|
12
14
|
export * as Queue from "./Queue";
|
|
13
15
|
export * as QueueBinding from "./QueueBinding";
|
|
14
16
|
export * as QueueDefinition from "./QueueDefinition";
|
|
17
|
+
export * as R2 from "./R2";
|
|
15
18
|
export * as Rpc from "./Rpc";
|
|
16
19
|
export * as RpcDefinition from "./RpcDefinition";
|
|
17
20
|
export * as ServiceBinding from "./ServiceBinding";
|