effect-cf 0.29.0 → 0.31.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.
@@ -1,4 +1,4 @@
1
- import { Data, Effect, Exit, Option, Predicate, Schema as S } from "effect";
1
+ import { Clock, Data, Duration, Effect, Exit, Option, Predicate, Schema as S } from "effect";
2
2
 
3
3
  import * as ErrorMessage from "./internal/ErrorMessage";
4
4
 
@@ -99,6 +99,11 @@ export interface DurableObjectTransaction {
99
99
  scheduledTime: number | Date,
100
100
  options?: globalThis.DurableObjectSetAlarmOptions,
101
101
  ): StorageEffect<void>;
102
+ /** Schedules the alarm after a delay measured by the Effect clock. */
103
+ setAlarmAfter(
104
+ delay: Duration.Input,
105
+ options?: globalThis.DurableObjectSetAlarmOptions,
106
+ ): StorageEffect<void>;
102
107
  deleteAlarm(options?: globalThis.DurableObjectSetAlarmOptions): StorageEffect<void>;
103
108
  }
104
109
 
@@ -132,6 +137,11 @@ export interface DurableObjectStorage {
132
137
  scheduledTime: number | Date,
133
138
  options?: globalThis.DurableObjectSetAlarmOptions,
134
139
  ): StorageEffect<void>;
140
+ /** Schedules the alarm after a delay measured by the Effect clock. */
141
+ setAlarmAfter(
142
+ delay: Duration.Input,
143
+ options?: globalThis.DurableObjectSetAlarmOptions,
144
+ ): StorageEffect<void>;
135
145
  deleteAlarm(options?: globalThis.DurableObjectSetAlarmOptions): StorageEffect<void>;
136
146
  /**
137
147
  * SQLite-backed Durable Object storage only.
@@ -174,6 +184,21 @@ const tryStoragePromise = <A>(operation: string, evaluate: () => Promise<A>): St
174
184
  catch: (cause) => storageError(operation, cause),
175
185
  });
176
186
 
187
+ const setAlarmAfter = Effect.fn("DurableObjectStorage.setAlarmAfter")(function* (
188
+ operation: string,
189
+ setAlarm: (
190
+ scheduledTime: number,
191
+ options?: globalThis.DurableObjectSetAlarmOptions,
192
+ ) => Promise<void>,
193
+ delay: Duration.Input,
194
+ options?: globalThis.DurableObjectSetAlarmOptions,
195
+ ) {
196
+ const now = yield* Clock.currentTimeMillis;
197
+ const delayMillis = Math.ceil(Duration.toMillis(delay));
198
+
199
+ yield* tryStoragePromise(operation, () => setAlarm(now + delayMillis, options));
200
+ });
201
+
177
202
  const fromSqlCursor = <T extends Record<string, SqlStorageValue>>(
178
203
  cursor: globalThis.SqlStorageCursor<T>,
179
204
  ): SqlCursor<T> => ({
@@ -293,6 +318,13 @@ const fromDurableObjectTransaction = (
293
318
  tryStoragePromise("transaction.getAlarm", () => txn.getAlarm(options)),
294
319
  setAlarm: (scheduledTime: number | Date, options?: globalThis.DurableObjectSetAlarmOptions) =>
295
320
  tryStoragePromise("transaction.setAlarm", () => txn.setAlarm(scheduledTime, options)),
321
+ setAlarmAfter: (delay: Duration.Input, options?: globalThis.DurableObjectSetAlarmOptions) =>
322
+ setAlarmAfter(
323
+ "transaction.setAlarm",
324
+ (scheduledTime, options) => txn.setAlarm(scheduledTime, options),
325
+ delay,
326
+ options,
327
+ ),
296
328
  deleteAlarm: (options?: globalThis.DurableObjectSetAlarmOptions) =>
297
329
  tryStoragePromise("transaction.deleteAlarm", () => txn.deleteAlarm(options)),
298
330
  }) as DurableObjectTransaction;
@@ -315,6 +347,13 @@ export const fromDurableObjectStorage = (
315
347
  tryStoragePromise("getAlarm", () => storage.getAlarm(options)),
316
348
  setAlarm: (scheduledTime: number | Date, options?: globalThis.DurableObjectSetAlarmOptions) =>
317
349
  tryStoragePromise("setAlarm", () => storage.setAlarm(scheduledTime, options)),
350
+ setAlarmAfter: (delay: Duration.Input, options?: globalThis.DurableObjectSetAlarmOptions) =>
351
+ setAlarmAfter(
352
+ "setAlarm",
353
+ (scheduledTime, options) => storage.setAlarm(scheduledTime, options),
354
+ delay,
355
+ options,
356
+ ),
318
357
  deleteAlarm: (options?: globalThis.DurableObjectSetAlarmOptions) =>
319
358
  tryStoragePromise("deleteAlarm", () => storage.deleteAlarm(options)),
320
359
  transactionSync: <A, E, R>(closure: () => Effect.Effect<A, E, R>) =>
package/src/Images.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import type {
2
2
  HostedImagesBinding as CloudflareHostedImagesBinding,
3
+ ImageDirectUploadOptions as CloudflareImageDirectUploadOptions,
4
+ ImageDirectUploadResult as CloudflareImageDirectUploadResult,
3
5
  ImageDrawOptions as CloudflareImageDrawOptions,
4
6
  ImageHandle as CloudflareImageHandle,
5
7
  ImageInfoResponse as CloudflareImageInfoResponse,
@@ -8,13 +10,16 @@ import type {
8
10
  ImageListOptions as CloudflareImageListOptions,
9
11
  ImageMetadata as CloudflareImageMetadata,
10
12
  ImageOutputOptions as CloudflareImageOutputOptions,
13
+ ImageSignedUrlOptions as CloudflareImageSignedUrlOptions,
11
14
  ImageTransform as CloudflareImageTransform,
12
15
  ImageTransformationOutputOptions as CloudflareImageTransformationOutputOptions,
16
+ ImageTransformationResponseOptions as CloudflareImageTransformationResponseOptions,
13
17
  ImageTransformationResult as CloudflareImageTransformationResult,
14
18
  ImageTransformer as CloudflareImageTransformer,
15
19
  ImageUpdateOptions as CloudflareImageUpdateOptions,
16
20
  ImageUploadOptions as CloudflareImageUploadOptions,
17
21
  Response as CloudflareResponse,
22
+ TextOptions as CloudflareTextOptions,
18
23
  } from "@cloudflare/workers-types";
19
24
  import { Context, Data, Effect, Function, Option, Predicate, type Layer } from "effect";
20
25
 
@@ -51,12 +56,17 @@ export type ImageDrawOptions = CloudflareImageDrawOptions;
51
56
  export type ImageInputOptions = CloudflareImageInputOptions;
52
57
  export type ImageOutputOptions = CloudflareImageOutputOptions;
53
58
  export type ImageTransformationOutputOptions = CloudflareImageTransformationOutputOptions;
59
+ export type ImageTransformationResponseOptions = CloudflareImageTransformationResponseOptions;
54
60
  export type ImageTransformationResult = CloudflareImageTransformationResult;
55
61
  export type ImageUploadOptions = CloudflareImageUploadOptions;
56
62
  export type ImageUpdateOptions = CloudflareImageUpdateOptions;
57
63
  export type ImageListOptions = CloudflareImageListOptions;
58
64
  export type ImageList = CloudflareImageList;
59
65
  export type ImageMetadata = CloudflareImageMetadata;
66
+ export type ImageSignedUrlOptions = CloudflareImageSignedUrlOptions;
67
+ export type ImageDirectUploadOptions = CloudflareImageDirectUploadOptions;
68
+ export type ImageDirectUploadResult = CloudflareImageDirectUploadResult;
69
+ export type TextOptions = CloudflareTextOptions;
60
70
  export type ImageInputValue = ReadableStream<Uint8Array> | ArrayBuffer;
61
71
  export type ImageUploadValue = ReadableStream<Uint8Array> | ArrayBuffer;
62
72
 
@@ -79,15 +89,23 @@ export interface Steps {
79
89
  readonly steps: ReadonlyArray<Step>;
80
90
  }
81
91
 
82
- export interface ProcessOptions {
83
- readonly stream: ImageInputValue;
84
- readonly inputOptions?: ImageInputOptions;
85
- readonly outputOptions: ImageOutputOptions;
86
- }
92
+ export type ProcessOptions =
93
+ | {
94
+ readonly stream: ImageInputValue;
95
+ readonly inputOptions?: ImageInputOptions;
96
+ readonly outputOptions: ImageOutputOptions;
97
+ }
98
+ | {
99
+ readonly text: string;
100
+ readonly textOptions: TextOptions;
101
+ readonly outputOptions: ImageOutputOptions;
102
+ };
87
103
 
88
104
  export interface ImagesTransformationResultClient {
89
105
  readonly raw: CloudflareImageTransformationResult;
90
- readonly response: Effect.Effect<CloudflareResponse, ImagesOperationError>;
106
+ readonly response: (
107
+ options?: ImageTransformationResponseOptions,
108
+ ) => Effect.Effect<CloudflareResponse, ImagesOperationError>;
91
109
  readonly contentType: Effect.Effect<string, ImagesOperationError>;
92
110
  readonly image: (
93
111
  options?: ImageTransformationOutputOptions,
@@ -98,6 +116,9 @@ export interface ImageHandleClient {
98
116
  readonly raw: CloudflareImageHandle;
99
117
  readonly details: Effect.Effect<Option.Option<ImageMetadata>, ImagesOperationError>;
100
118
  readonly bytes: Effect.Effect<Option.Option<ReadableStream<Uint8Array>>, ImagesOperationError>;
119
+ readonly signedUrl: (
120
+ options: ImageSignedUrlOptions,
121
+ ) => Effect.Effect<string, ImagesOperationError>;
101
122
  readonly update: (
102
123
  options: ImageUpdateOptions,
103
124
  ) => Effect.Effect<ImageMetadata, ImagesOperationError>;
@@ -111,6 +132,9 @@ export interface HostedImagesClient {
111
132
  options?: ImageUploadOptions,
112
133
  ) => Effect.Effect<ImageMetadata, ImagesOperationError>;
113
134
  readonly list: (options?: ImageListOptions) => Effect.Effect<ImageList, ImagesOperationError>;
135
+ readonly createDirectUpload: (
136
+ options?: ImageDirectUploadOptions,
137
+ ) => Effect.Effect<ImageDirectUploadResult, ImagesOperationError>;
114
138
  readonly rawUnsafe: Effect.Effect<CloudflareHostedImagesBinding>;
115
139
  }
116
140
 
@@ -123,6 +147,7 @@ export interface ImagesRuntimeBinding {
123
147
  image: ImageInputValue,
124
148
  options?: ImageInputOptions,
125
149
  ) => CloudflareImageTransformer;
150
+ readonly text?: (content: string, options: TextOptions) => CloudflareImageTransformer;
126
151
  readonly hosted?: CloudflareHostedImagesBinding;
127
152
  }
128
153
 
@@ -135,6 +160,10 @@ export interface ImagesClient {
135
160
  image: ImageInputValue,
136
161
  options?: ImageInputOptions,
137
162
  ) => Effect.Effect<CloudflareImageTransformer, ImagesOperationError>;
163
+ readonly text: (
164
+ content: string,
165
+ options: TextOptions,
166
+ ) => Effect.Effect<CloudflareImageTransformer, ImagesOperationError>;
138
167
  readonly process: (
139
168
  steps: Steps,
140
169
  options: ProcessOptions,
@@ -230,7 +259,10 @@ const hasFunction = <Candidate>(value: Candidate, key: string): boolean =>
230
259
  const isHostedImagesBinding = <Candidate>(
231
260
  value: Candidate,
232
261
  ): value is Candidate & CloudflareHostedImagesBinding =>
233
- hasFunction(value, "image") && hasFunction(value, "upload") && hasFunction(value, "list");
262
+ hasFunction(value, "image") &&
263
+ hasFunction(value, "upload") &&
264
+ hasFunction(value, "list") &&
265
+ hasFunction(value, "createDirectUpload");
234
266
 
235
267
  export const isImagesBinding = <Candidate>(
236
268
  value: Candidate,
@@ -242,7 +274,7 @@ const wrapResult = (
242
274
  result: CloudflareImageTransformationResult,
243
275
  ): ImagesTransformationResultClient => ({
244
276
  raw: result,
245
- response: tryImagesSync(binding, "response", () => result.response()),
277
+ response: (options) => tryImagesSync(binding, "response", () => result.response(options)),
246
278
  contentType: tryImagesSync(binding, "contentType", () => result.contentType()),
247
279
  image: (options) => tryImagesSync(binding, "image", () => result.image(options)),
248
280
  });
@@ -257,6 +289,9 @@ const wrapHandle = (binding: string, handle: CloudflareImageHandle): ImageHandle
257
289
  Effect.map(maybe),
258
290
  Effect.withSpan("Images.bytes"),
259
291
  ),
292
+ signedUrl: Effect.fn("Images.signedUrl")((options: ImageSignedUrlOptions) =>
293
+ tryImagesPromise(binding, "signedUrl", () => handle.signedUrl(options)),
294
+ ),
260
295
  update: Effect.fn("Images.update")((options: ImageUpdateOptions) =>
261
296
  tryImagesPromise(binding, "update", () => handle.update(options)),
262
297
  ),
@@ -276,6 +311,9 @@ const wrapHosted = (
276
311
  list: Effect.fn("Images.list")((options?: ImageListOptions) =>
277
312
  tryImagesPromise(binding, "list", () => hosted.list(options)),
278
313
  ),
314
+ createDirectUpload: Effect.fn("Images.createDirectUpload")((options?: ImageDirectUploadOptions) =>
315
+ tryImagesPromise(binding, "createDirectUpload", () => hosted.createDirectUpload(options)),
316
+ ),
279
317
  rawUnsafe: Effect.succeed(hosted),
280
318
  });
281
319
 
@@ -285,8 +323,20 @@ export const makeClient =
285
323
  const input = (image: ImageInputValue, options?: ImageInputOptions) =>
286
324
  tryImagesSync(definition.binding, "input", () => images.input(image, options));
287
325
 
326
+ const text = (content: string, options: TextOptions) =>
327
+ tryImagesSync(definition.binding, "text", () => {
328
+ if (!hasFunction(images, "text")) {
329
+ throw new Error("Images binding is missing text()");
330
+ }
331
+
332
+ return images.text!(content, options);
333
+ });
334
+
288
335
  const process = Effect.fn("Images.process")(function* (steps: Steps, options: ProcessOptions) {
289
- let transformer = yield* input(options.stream, options.inputOptions);
336
+ let transformer =
337
+ "text" in options
338
+ ? yield* text(options.text, options.textOptions)
339
+ : yield* input(options.stream, options.inputOptions);
290
340
 
291
341
  for (const step of steps.steps) {
292
342
  transformer = yield* Step.$match(step, {
@@ -314,6 +364,7 @@ export const makeClient =
314
364
  tryImagesPromise(definition.binding, "info", () => images.info(image, options)),
315
365
  ),
316
366
  input,
367
+ text,
317
368
  process,
318
369
  hosted: isHostedImagesBinding(images.hosted)
319
370
  ? Option.some(wrapHosted(definition.binding, images.hosted))