effect-cf 0.33.0 → 0.35.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 +22 -0
- package/README.md +31 -1079
- package/dist/{Artifacts-DnHQA-Ax.d.mts → Artifacts-B3r3RuTB.d.mts} +1 -48
- package/dist/{Artifacts-CSIk1Oml.mjs → Artifacts-CBxWGeZB.mjs} +2 -7
- package/dist/{Binding-pfilNJmP.mjs → Binding-C82jRhdr.mjs} +1 -2
- package/dist/{Binding-xJJJPmiD.d.mts → Binding-DKcLrQCM.d.mts} +0 -45
- package/dist/ComputerArtifacts.d.mts +1 -3
- package/dist/ComputerArtifacts.mjs +1 -2
- package/dist/ComputerWorkspace.d.mts +11 -12
- package/dist/ComputerWorkspace.mjs +31 -10
- package/dist/ComputerWorkspaceHost.d.mts +1 -9
- package/dist/{ContainerNamespace-CFjiLw8b.d.mts → ContainerNamespace-DbLaeFhN.d.mts} +1 -14
- package/dist/{DurableObjectState-CVLLse69.mjs → DurableObjectState-DcqElJ4e.mjs} +82 -89
- package/dist/{DurableObjectState-BpRjz6-q.d.mts → DurableObjectState-DpYdNZgT.d.mts} +102 -266
- package/dist/{ErrorMessage-BM0K-Nik.mjs → ErrorMessage-Byx2OgNd.mjs} +0 -1
- package/dist/{Hyperdrive-z-9fFz15.d.mts → Hyperdrive-HrwFlZ6x.d.mts} +1 -4
- package/dist/HyperdrivePg.d.mts +2 -11
- package/dist/HyperdrivePg.mjs +0 -8
- package/dist/Sandbox.d.mts +2 -32
- package/dist/Sandbox.mjs +2 -11
- package/dist/Vitest.d.mts +3 -31
- package/dist/Vitest.mjs +8 -26
- package/dist/{WorkflowBinding-lBR4_-op.d.mts → WorkflowBinding-Cn3AuUyP.d.mts} +2 -5
- package/dist/index.d.mts +42 -480
- package/dist/index.mjs +267 -380
- package/package.json +1 -1
- package/src/AiGateway.ts +0 -6
- package/src/AnalyticsEngine.ts +8 -10
- package/src/Artifacts.ts +0 -47
- package/src/Binding.ts +0 -8
- package/src/BrowserRendering.ts +0 -4
- package/src/Cache.ts +0 -19
- package/src/CloudflareOtlp.ts +6 -39
- package/src/ComputerArtifacts.ts +0 -2
- package/src/ComputerWorkspace.ts +53 -35
- package/src/ComputerWorkspaceHost.ts +0 -8
- package/src/ContainerNamespace.ts +0 -13
- package/src/D1.ts +0 -22
- package/src/DurableObject.ts +51 -32
- package/src/DurableObjectAlarm.ts +6 -210
- package/src/DurableObjectDefinition.ts +8 -20
- package/src/DurableObjectNamespace.ts +88 -115
- package/src/DurableObjectRpcWebSocket.ts +5 -46
- package/src/DurableObjectSqlite.ts +0 -12
- package/src/DurableObjectState.ts +18 -38
- package/src/DurableObjectStorage.ts +55 -70
- package/src/DurableObjectWebSocket.ts +23 -72
- package/src/Email.ts +0 -12
- package/src/Environment.ts +0 -37
- package/src/Hyperdrive.ts +0 -3
- package/src/HyperdrivePg.ts +0 -9
- package/src/Images.ts +0 -5
- package/src/Kv.ts +0 -15
- package/src/QueueBinding.ts +0 -2
- package/src/R2.ts +0 -5
- package/src/RpcDefinition.ts +5 -17
- package/src/RpcTracing.ts +133 -0
- package/src/Sandbox.ts +0 -30
- package/src/ServiceBinding.ts +83 -128
- package/src/Vectorize.ts +0 -5
- package/src/Vitest.ts +18 -43
- package/src/WebTransport.ts +0 -15
- package/src/Worker.ts +140 -108
- package/src/WorkerDefinition.ts +5 -14
- package/src/WorkersAi.ts +21 -18
- package/src/Workflow.ts +45 -54
- package/src/WorkflowBinding.ts +0 -3
- package/src/index.ts +1 -0
- package/src/internal/Entrypoint.ts +23 -4
- package/src/internal/ErrorMessage.ts +0 -1
- package/src/internal/NativeCallback.ts +55 -0
- package/src/internal/RpcInvocation.ts +18 -1
- package/src/internal/Runtime.ts +12 -7
- package/src/internal/WorkerContext.ts +5 -14
|
@@ -1,11 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Cause,
|
|
3
|
+
Clock,
|
|
4
|
+
Data,
|
|
5
|
+
Duration,
|
|
6
|
+
Effect,
|
|
7
|
+
Exit,
|
|
8
|
+
Fiber,
|
|
9
|
+
Option,
|
|
10
|
+
Predicate,
|
|
11
|
+
Result,
|
|
12
|
+
Schema as S,
|
|
13
|
+
} from "effect";
|
|
2
14
|
|
|
3
15
|
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
16
|
+
import { runNativeCallback } from "./internal/NativeCallback";
|
|
4
17
|
|
|
5
|
-
/** Supported primitive value types for Durable Object SQL APIs. */
|
|
6
18
|
export type SqlStorageValue = globalThis.SqlStorageValue;
|
|
7
19
|
|
|
8
|
-
/** Error type used when a storage operation throws or rejects. */
|
|
9
20
|
export class StorageOperationError extends Data.TaggedError("StorageOperationError")<{
|
|
10
21
|
readonly operation: string;
|
|
11
22
|
readonly cause: unknown;
|
|
@@ -17,9 +28,6 @@ export class StorageOperationError extends Data.TaggedError("StorageOperationErr
|
|
|
17
28
|
|
|
18
29
|
type StorageEffect<A> = Effect.Effect<A, StorageOperationError>;
|
|
19
30
|
|
|
20
|
-
/**
|
|
21
|
-
* Effect wrapper for Cloudflare SQL cursor operations.
|
|
22
|
-
*/
|
|
23
31
|
export interface SqlCursor<T extends Record<string, SqlStorageValue>> {
|
|
24
32
|
next(): StorageEffect<{ done?: false; value: T } | { done: true; value?: never }>;
|
|
25
33
|
toArray(): StorageEffect<Array<T>>;
|
|
@@ -30,11 +38,7 @@ export interface SqlCursor<T extends Record<string, SqlStorageValue>> {
|
|
|
30
38
|
readonly rowsWritten: StorageEffect<number>;
|
|
31
39
|
}
|
|
32
40
|
|
|
33
|
-
/**
|
|
34
|
-
* Effect wrapper for Durable Object SQLite APIs.
|
|
35
|
-
*/
|
|
36
41
|
export interface SqlStorage {
|
|
37
|
-
/** Executes a SQL statement and returns a typed cursor. */
|
|
38
42
|
exec<T extends Record<string, SqlStorageValue>>(
|
|
39
43
|
query: string,
|
|
40
44
|
...bindings: Array<SqlStorageValue>
|
|
@@ -42,9 +46,6 @@ export interface SqlStorage {
|
|
|
42
46
|
readonly databaseSize: number;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
/**
|
|
46
|
-
* Schema pair used by `SyncKvStorage.schema(...)`.
|
|
47
|
-
*/
|
|
48
49
|
export interface SyncKvDefinition<Key, Value, EncodedValue> {
|
|
49
50
|
readonly key: S.Codec<Key, string>;
|
|
50
51
|
readonly value: S.Codec<Value, EncodedValue>;
|
|
@@ -60,9 +61,6 @@ export interface SchemaBackedSyncKvStorage<Key, Value> {
|
|
|
60
61
|
list(options?: globalThis.SyncKvListOptions): Effect.Effect<Array<[Key, Value]>, unknown>;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
/**
|
|
64
|
-
* Effect wrapper for synchronous KV attached to Durable Object SQLite storage.
|
|
65
|
-
*/
|
|
66
64
|
export interface SyncKvStorage {
|
|
67
65
|
get<T = unknown>(key: string): StorageEffect<T | undefined>;
|
|
68
66
|
put<T>(key: string, value: T): StorageEffect<void>;
|
|
@@ -99,7 +97,6 @@ export interface DurableObjectTransaction {
|
|
|
99
97
|
scheduledTime: number | Date,
|
|
100
98
|
options?: globalThis.DurableObjectSetAlarmOptions,
|
|
101
99
|
): StorageEffect<void>;
|
|
102
|
-
/** Schedules the alarm after a delay measured by the Effect clock. */
|
|
103
100
|
setAlarmAfter(
|
|
104
101
|
delay: Duration.Input,
|
|
105
102
|
options?: globalThis.DurableObjectSetAlarmOptions,
|
|
@@ -107,19 +104,6 @@ export interface DurableObjectTransaction {
|
|
|
107
104
|
deleteAlarm(options?: globalThis.DurableObjectSetAlarmOptions): StorageEffect<void>;
|
|
108
105
|
}
|
|
109
106
|
|
|
110
|
-
/**
|
|
111
|
-
* Effect wrapper around Cloudflare Durable Object storage.
|
|
112
|
-
*
|
|
113
|
-
* @example
|
|
114
|
-
* ```ts
|
|
115
|
-
* const program = Effect.gen(function* () {
|
|
116
|
-
* const state = yield* DurableObjectState;
|
|
117
|
-
* yield* state.storage.put("counter", 1);
|
|
118
|
-
* const value = yield* state.storage.get<number>("counter");
|
|
119
|
-
* return value;
|
|
120
|
-
* });
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
107
|
export interface DurableObjectStorage {
|
|
124
108
|
get<T = unknown>(
|
|
125
109
|
key: string,
|
|
@@ -137,7 +121,6 @@ export interface DurableObjectStorage {
|
|
|
137
121
|
scheduledTime: number | Date,
|
|
138
122
|
options?: globalThis.DurableObjectSetAlarmOptions,
|
|
139
123
|
): StorageEffect<void>;
|
|
140
|
-
/** Schedules the alarm after a delay measured by the Effect clock. */
|
|
141
124
|
setAlarmAfter(
|
|
142
125
|
delay: Duration.Input,
|
|
143
126
|
options?: globalThis.DurableObjectSetAlarmOptions,
|
|
@@ -161,9 +144,9 @@ export interface DurableObjectStorage {
|
|
|
161
144
|
): Effect.Effect<A, E | StorageOperationError, R>;
|
|
162
145
|
/** Flushes pending writes to disk. */
|
|
163
146
|
sync(): StorageEffect<void>;
|
|
164
|
-
/** SQLite-backed Durable Object storage
|
|
147
|
+
/** Requires SQLite-backed Durable Object storage. */
|
|
165
148
|
getCurrentBookmark(): StorageEffect<string>;
|
|
166
|
-
/** SQLite-backed Durable Object storage
|
|
149
|
+
/** Requires SQLite-backed Durable Object storage. */
|
|
167
150
|
onNextSessionRestoreBookmark(bookmark: string): StorageEffect<string>;
|
|
168
151
|
readonly sql: SqlStorage;
|
|
169
152
|
readonly kv: SyncKvStorage;
|
|
@@ -329,9 +312,6 @@ const fromDurableObjectTransaction = (
|
|
|
329
312
|
tryStoragePromise("transaction.deleteAlarm", () => txn.deleteAlarm(options)),
|
|
330
313
|
}) as DurableObjectTransaction;
|
|
331
314
|
|
|
332
|
-
/**
|
|
333
|
-
* Wraps native Cloudflare storage APIs as Effect-returning helpers.
|
|
334
|
-
*/
|
|
335
315
|
export const fromDurableObjectStorage = (
|
|
336
316
|
storage: globalThis.DurableObjectStorage,
|
|
337
317
|
): DurableObjectStorage => ({
|
|
@@ -364,6 +344,7 @@ export const fromDurableObjectStorage = (
|
|
|
364
344
|
// failed Exit is thrown to abort it. Keep a typed reference to that
|
|
365
345
|
// Exit rather than recovering its type from the untyped catch binding.
|
|
366
346
|
let aborted: Exit.Exit<A, E> | undefined;
|
|
347
|
+
let escapedFiber: Fiber.Fiber<unknown, unknown> | undefined;
|
|
367
348
|
|
|
368
349
|
try {
|
|
369
350
|
return Effect.succeed(
|
|
@@ -373,55 +354,59 @@ export const fromDurableObjectStorage = (
|
|
|
373
354
|
if (Exit.isSuccess(exit)) {
|
|
374
355
|
return exit.value;
|
|
375
356
|
}
|
|
357
|
+
const defect = Cause.findDefect(exit.cause);
|
|
358
|
+
|
|
359
|
+
if (Result.isSuccess(defect) && Cause.isAsyncFiberError(defect.success)) {
|
|
360
|
+
escapedFiber = defect.success.fiber;
|
|
361
|
+
escapedFiber.interruptUnsafe();
|
|
362
|
+
}
|
|
376
363
|
aborted = exit;
|
|
377
364
|
|
|
378
365
|
throw exit;
|
|
379
366
|
}),
|
|
380
367
|
);
|
|
381
368
|
} catch (cause) {
|
|
382
|
-
|
|
383
|
-
|
|
369
|
+
const failure: Effect.Effect<never, E | StorageOperationError> =
|
|
370
|
+
aborted !== undefined && cause === aborted && Exit.isFailure(aborted)
|
|
371
|
+
? Effect.failCause(aborted.cause)
|
|
372
|
+
: Effect.fail(storageError("transactionSync", cause));
|
|
373
|
+
const fiber = escapedFiber;
|
|
374
|
+
|
|
375
|
+
if (fiber !== undefined) {
|
|
376
|
+
return Fiber.interrupt(fiber).pipe(Effect.andThen(failure));
|
|
384
377
|
}
|
|
385
378
|
|
|
386
|
-
return
|
|
379
|
+
return failure;
|
|
387
380
|
}
|
|
388
381
|
}),
|
|
389
382
|
),
|
|
390
383
|
),
|
|
391
384
|
transaction: <A, E, R>(closure: (txn: DurableObjectTransaction) => Effect.Effect<A, E, R>) =>
|
|
392
|
-
Effect.
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
// transaction, and holding it here keeps its error type.
|
|
397
|
-
let aborted: Exit.Exit<A, E> | undefined;
|
|
385
|
+
Effect.suspend(() => {
|
|
386
|
+
// See `transactionSync`: the thrown Exit aborts Cloudflare's
|
|
387
|
+
// transaction, and holding it here keeps its error type.
|
|
388
|
+
let aborted: Exit.Exit<A, E> | undefined;
|
|
398
389
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
throw exit;
|
|
411
|
-
})
|
|
412
|
-
.then(
|
|
413
|
-
(value) => resume(Effect.succeed(value)),
|
|
414
|
-
(cause) => {
|
|
415
|
-
if (aborted !== undefined && cause === aborted && Exit.isFailure(aborted)) {
|
|
416
|
-
resume(Effect.failCause(aborted.cause));
|
|
417
|
-
} else {
|
|
418
|
-
resume(Effect.fail(storageError("transaction", cause)));
|
|
419
|
-
}
|
|
420
|
-
},
|
|
421
|
-
);
|
|
390
|
+
return runNativeCallback<A, E, R, A>((run) =>
|
|
391
|
+
storage.transaction(async (txn) => {
|
|
392
|
+
const exit = await run(Effect.suspend(() => closure(fromDurableObjectTransaction(txn))));
|
|
393
|
+
|
|
394
|
+
if (Exit.isSuccess(exit)) {
|
|
395
|
+
return exit.value;
|
|
396
|
+
}
|
|
397
|
+
aborted = exit;
|
|
398
|
+
|
|
399
|
+
throw exit;
|
|
422
400
|
}),
|
|
423
|
-
)
|
|
424
|
-
|
|
401
|
+
).pipe(
|
|
402
|
+
Effect.catch(
|
|
403
|
+
(cause): Effect.Effect<never, E | StorageOperationError> =>
|
|
404
|
+
aborted !== undefined && cause === aborted && Exit.isFailure(aborted)
|
|
405
|
+
? Effect.failCause(aborted.cause)
|
|
406
|
+
: Effect.fail(storageError("transaction", cause)),
|
|
407
|
+
),
|
|
408
|
+
);
|
|
409
|
+
}),
|
|
425
410
|
sync: () => tryStoragePromise("sync", () => storage.sync()),
|
|
426
411
|
getCurrentBookmark: () =>
|
|
427
412
|
tryStoragePromise("getCurrentBookmark", () => storage.getCurrentBookmark()),
|
|
@@ -3,10 +3,8 @@ import { Data, Effect, Option, Result, Schema as S } from "effect";
|
|
|
3
3
|
import { DurableObjectState } from "./DurableObjectState";
|
|
4
4
|
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
5
5
|
|
|
6
|
-
/** Data supported by Cloudflare websocket `send`. */
|
|
7
6
|
export type DurableWebSocketSendData = string | ArrayBuffer | ArrayBufferView;
|
|
8
7
|
|
|
9
|
-
/** Error raised when sending on a Durable Object websocket fails. */
|
|
10
8
|
export class DurableWebSocketSendError extends Data.TaggedError("DurableWebSocketSendError")<{
|
|
11
9
|
readonly cause: unknown;
|
|
12
10
|
}> {
|
|
@@ -15,7 +13,6 @@ export class DurableWebSocketSendError extends Data.TaggedError("DurableWebSocke
|
|
|
15
13
|
}
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
/** Error raised when closing a Durable Object websocket fails. */
|
|
19
16
|
export class DurableWebSocketCloseError extends Data.TaggedError("DurableWebSocketCloseError")<{
|
|
20
17
|
readonly cause: unknown;
|
|
21
18
|
}> {
|
|
@@ -36,95 +33,55 @@ export class DurableWebSocketAttachmentError extends Data.TaggedError(
|
|
|
36
33
|
}
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
/** Effect-native wrapper around a hibernatable Durable Object websocket. */
|
|
40
36
|
export interface DurableWebSocket<Attachment = unknown> {
|
|
41
|
-
/** Underlying Cloudflare websocket. */
|
|
42
37
|
readonly raw: WebSocket;
|
|
43
|
-
/** Sends a message through the socket. */
|
|
44
38
|
send(data: DurableWebSocketSendData): Effect.Effect<void, DurableWebSocketSendError>;
|
|
45
|
-
/** Closes the socket. */
|
|
46
39
|
close(code?: number, reason?: string): Effect.Effect<void, DurableWebSocketCloseError>;
|
|
47
40
|
/** Serializes hibernation attachment metadata onto the socket. */
|
|
48
|
-
serializeAttachment<A = Attachment>(
|
|
41
|
+
serializeAttachment<A extends Attachment = Attachment>(
|
|
49
42
|
value: A,
|
|
50
43
|
): Effect.Effect<void, DurableWebSocketAttachmentError>;
|
|
51
44
|
/** Deserializes hibernation attachment metadata from the socket. */
|
|
52
45
|
readonly deserializeAttachment: Effect.Effect<unknown, DurableWebSocketAttachmentError>;
|
|
53
46
|
}
|
|
54
47
|
|
|
55
|
-
const wrappers = new WeakMap<WebSocket, DurableWebSocket<unknown>>();
|
|
56
|
-
|
|
57
|
-
/** Wraps a native Cloudflare websocket in the Effect-native Durable Object API. */
|
|
58
48
|
export const fromWebSocket = <Attachment = unknown>(
|
|
59
49
|
raw: WebSocket,
|
|
60
|
-
): DurableWebSocket<Attachment> => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const socket: DurableWebSocket<unknown> = {
|
|
69
|
-
raw,
|
|
70
|
-
send: (data) =>
|
|
71
|
-
Effect.try({
|
|
72
|
-
try: () => raw.send(data),
|
|
73
|
-
catch: (cause) => new DurableWebSocketSendError({ cause }),
|
|
74
|
-
}),
|
|
75
|
-
close: (code, reason) =>
|
|
76
|
-
Effect.try({
|
|
77
|
-
try: () => raw.close(code, reason),
|
|
78
|
-
catch: (cause) => new DurableWebSocketCloseError({ cause }),
|
|
79
|
-
}),
|
|
80
|
-
serializeAttachment: (value) =>
|
|
81
|
-
Effect.try({
|
|
82
|
-
try: () => raw.serializeAttachment(value),
|
|
83
|
-
catch: (cause) => new DurableWebSocketAttachmentError({ operation: "serialize", cause }),
|
|
84
|
-
}),
|
|
85
|
-
deserializeAttachment: Effect.try({
|
|
86
|
-
try: () => raw.deserializeAttachment(),
|
|
87
|
-
catch: (cause) => new DurableWebSocketAttachmentError({ operation: "deserialize", cause }),
|
|
50
|
+
): DurableWebSocket<Attachment> => ({
|
|
51
|
+
raw,
|
|
52
|
+
send: (data) =>
|
|
53
|
+
Effect.try({
|
|
54
|
+
try: () => raw.send(data),
|
|
55
|
+
catch: (cause) => new DurableWebSocketSendError({ cause }),
|
|
88
56
|
}),
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
57
|
+
close: (code, reason) =>
|
|
58
|
+
Effect.try({
|
|
59
|
+
try: () => raw.close(code, reason),
|
|
60
|
+
catch: (cause) => new DurableWebSocketCloseError({ cause }),
|
|
61
|
+
}),
|
|
62
|
+
serializeAttachment: <A extends Attachment = Attachment>(value: A) =>
|
|
63
|
+
Effect.try({
|
|
64
|
+
try: () => raw.serializeAttachment(value),
|
|
65
|
+
catch: (cause) => new DurableWebSocketAttachmentError({ operation: "serialize", cause }),
|
|
66
|
+
}),
|
|
67
|
+
deserializeAttachment: Effect.try({
|
|
68
|
+
try: () => raw.deserializeAttachment(),
|
|
69
|
+
catch: (cause) => new DurableWebSocketAttachmentError({ operation: "deserialize", cause }),
|
|
70
|
+
}),
|
|
71
|
+
});
|
|
96
72
|
|
|
97
|
-
/**
|
|
98
|
-
* Options for accepting an incoming websocket request in a Durable Object.
|
|
99
|
-
*/
|
|
100
73
|
export interface AcceptUpgradeOptions<Attachment = unknown> {
|
|
101
|
-
/** Optional websocket tags for Durable Object hibernation filtering. */
|
|
102
74
|
readonly tags?: ReadonlyArray<string> | undefined;
|
|
103
75
|
/** Optional attachment serialized onto the server socket. */
|
|
104
76
|
readonly attachment?: Attachment | undefined;
|
|
105
77
|
}
|
|
106
78
|
|
|
107
|
-
/**
|
|
108
|
-
* Result of a websocket upgrade accepted by {@link acceptUpgrade}.
|
|
109
|
-
*/
|
|
110
79
|
export interface AcceptedUpgrade<Attachment = unknown> {
|
|
111
80
|
readonly client: WebSocket;
|
|
112
81
|
readonly server: DurableWebSocket<Attachment>;
|
|
113
82
|
readonly response: Response;
|
|
114
83
|
}
|
|
115
84
|
|
|
116
|
-
/**
|
|
117
|
-
* Accepts a websocket upgrade and registers the server socket on `DurableObjectState`.
|
|
118
|
-
*
|
|
119
|
-
* @example
|
|
120
|
-
* ```ts
|
|
121
|
-
* const response = yield* DurableObjectWebSocket.acceptUpgrade({
|
|
122
|
-
* tags: ["room:general"],
|
|
123
|
-
* });
|
|
124
|
-
*
|
|
125
|
-
* return response.response;
|
|
126
|
-
* ```
|
|
127
|
-
*/
|
|
128
85
|
export const acceptUpgrade = Effect.fn("DurableObjectWebSocket.acceptUpgrade")(function* <
|
|
129
86
|
Attachment = unknown,
|
|
130
87
|
>(
|
|
@@ -158,9 +115,7 @@ export const acceptUpgrade = Effect.fn("DurableObjectWebSocket.acceptUpgrade")(f
|
|
|
158
115
|
export type AttachmentInvalidPolicy = "ignore" | "ignore-and-close" | "fail";
|
|
159
116
|
|
|
160
117
|
export interface AttachmentRehydrateOptions {
|
|
161
|
-
/** Optional Durable Object websocket tag filter. */
|
|
162
118
|
readonly tag?: string | undefined;
|
|
163
|
-
/** Invalid attachment behavior. Defaults to skipping invalid sockets. */
|
|
164
119
|
readonly onInvalid?: AttachmentInvalidPolicy | undefined;
|
|
165
120
|
}
|
|
166
121
|
|
|
@@ -187,7 +142,6 @@ export interface DurableWebSocketAttachment<Attachment, Encoded> {
|
|
|
187
142
|
readonly schema: S.Codec<Attachment, Encoded, never, never>;
|
|
188
143
|
}
|
|
189
144
|
|
|
190
|
-
/** Creates typed attachment helpers for accepted and rehydrated sockets. */
|
|
191
145
|
export const attachment = <const AttachmentSchema extends S.Codec<any, any, never, never>>(
|
|
192
146
|
schema: AttachmentSchema,
|
|
193
147
|
): DurableWebSocketAttachment<
|
|
@@ -195,15 +149,13 @@ export const attachment = <const AttachmentSchema extends S.Codec<any, any, neve
|
|
|
195
149
|
S.Codec.Encoded<AttachmentSchema>
|
|
196
150
|
> => {
|
|
197
151
|
type Attachment = S.Schema.Type<AttachmentSchema>;
|
|
198
|
-
type Encoded = S.Codec.Encoded<AttachmentSchema>;
|
|
199
152
|
|
|
200
153
|
const serialize = (socket: DurableWebSocket<unknown>, value: Attachment) =>
|
|
201
154
|
S.encodeEffect(schema)(value).pipe(
|
|
202
155
|
Effect.mapError(
|
|
203
156
|
(cause) => new DurableWebSocketAttachmentError({ operation: "serialize", cause }),
|
|
204
157
|
),
|
|
205
|
-
|
|
206
|
-
Effect.flatMap((encoded) => socket.serializeAttachment(encoded as Encoded)),
|
|
158
|
+
Effect.flatMap((encoded) => socket.serializeAttachment(encoded)),
|
|
207
159
|
);
|
|
208
160
|
|
|
209
161
|
const deserialize = (socket: DurableWebSocket<unknown>) =>
|
|
@@ -267,7 +219,6 @@ export interface DurableWebSocketHandlers<R = never, E = unknown> {
|
|
|
267
219
|
readonly error?: (socket: DurableWebSocket, cause: unknown) => Effect.Effect<void, E, R>;
|
|
268
220
|
}
|
|
269
221
|
|
|
270
|
-
/** Maps compact websocket lifecycle handler names to `DurableObject.make` options. */
|
|
271
222
|
export const handlers = <R = never, E = unknown>(options: DurableWebSocketHandlers<R, E>) => ({
|
|
272
223
|
webSocketMessage: options.message,
|
|
273
224
|
webSocketClose: options.close,
|
package/src/Email.ts
CHANGED
|
@@ -13,17 +13,13 @@ import * as ErrorMessage from "./internal/ErrorMessage";
|
|
|
13
13
|
const expectedSendEmailBinding = "Send Email binding with send()";
|
|
14
14
|
const textEncoder = new TextEncoder();
|
|
15
15
|
|
|
16
|
-
/** Documented Cloudflare Email Sending limits. */
|
|
17
16
|
export const sendLimits = {
|
|
18
|
-
/** Combined `to`, `cc`, and `bcc` addresses per message. */
|
|
19
17
|
maxRecipients: 50,
|
|
20
18
|
maxAttachments: 32,
|
|
21
|
-
/** Total message size, including attachments. Not enforced client side. */
|
|
22
19
|
maxMessageBytes: 5 * 1024 * 1024,
|
|
23
20
|
maxHeaderNameBytes: 100,
|
|
24
21
|
maxHeaderValueBytes: 2048,
|
|
25
22
|
maxHeadersBytes: 16 * 1024,
|
|
26
|
-
/** Allowlisted custom headers, excluding `X-` prefixed headers. */
|
|
27
23
|
maxAllowlistHeaders: 20,
|
|
28
24
|
} as const;
|
|
29
25
|
|
|
@@ -58,10 +54,8 @@ export const emailErrorCodes = [
|
|
|
58
54
|
"E_HEADERS_TOO_MANY",
|
|
59
55
|
] as const;
|
|
60
56
|
|
|
61
|
-
/** A documented Cloudflare Email Sending error code. */
|
|
62
57
|
export type EmailErrorCode = (typeof emailErrorCodes)[number];
|
|
63
58
|
|
|
64
|
-
/** Error raised when a Cloudflare Send Email operation fails. */
|
|
65
59
|
export class EmailOperationError extends Data.TaggedError("EmailOperationError")<{
|
|
66
60
|
readonly binding: string;
|
|
67
61
|
readonly operation: string;
|
|
@@ -82,7 +76,6 @@ export class EmailOperationError extends Data.TaggedError("EmailOperationError")
|
|
|
82
76
|
}
|
|
83
77
|
}
|
|
84
78
|
|
|
85
|
-
/** A single message field that violates a documented Email Sending limit. */
|
|
86
79
|
export interface EmailViolation {
|
|
87
80
|
readonly path: string;
|
|
88
81
|
readonly message: string;
|
|
@@ -90,7 +83,6 @@ export interface EmailViolation {
|
|
|
90
83
|
readonly actual?: number;
|
|
91
84
|
}
|
|
92
85
|
|
|
93
|
-
/** Error raised when a message violates documented Cloudflare Email Sending limits. */
|
|
94
86
|
export class EmailValidationError extends Data.TaggedError("EmailValidationError")<{
|
|
95
87
|
readonly binding: string;
|
|
96
88
|
readonly operation: string;
|
|
@@ -101,9 +93,7 @@ export class EmailValidationError extends Data.TaggedError("EmailValidationError
|
|
|
101
93
|
}
|
|
102
94
|
}
|
|
103
95
|
|
|
104
|
-
/** Typed Cloudflare Send Email binding definition. */
|
|
105
96
|
export interface EmailDefinition {
|
|
106
|
-
/** Binding name as configured in `wrangler.jsonc`. */
|
|
107
97
|
readonly binding: string;
|
|
108
98
|
}
|
|
109
99
|
|
|
@@ -117,7 +107,6 @@ export type EmailSendError = EmailOperationError | EmailValidationError;
|
|
|
117
107
|
type EmailFieldCandidate = Parameters<typeof Predicate.isUnknown>[0];
|
|
118
108
|
|
|
119
109
|
export interface EmailSendOptions {
|
|
120
|
-
/** Validates builder messages against documented limits. Defaults to `true`. */
|
|
121
110
|
readonly validate?: boolean;
|
|
122
111
|
}
|
|
123
112
|
|
|
@@ -133,7 +122,6 @@ export interface EmailClient {
|
|
|
133
122
|
|
|
134
123
|
declare const EmailServiceTypeId: unique symbol;
|
|
135
124
|
|
|
136
|
-
/** Nominal service marker for Send Email services created with {@link make}. */
|
|
137
125
|
export interface EmailService<Id extends string> {
|
|
138
126
|
readonly [EmailServiceTypeId]: {
|
|
139
127
|
readonly id: Id;
|
package/src/Environment.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Config, ConfigProvider, Context, Effect, type Layer, Predicate } from "effect";
|
|
2
2
|
|
|
3
|
-
/** Cloudflare worker environment object (`env`). */
|
|
4
3
|
export type WorkerEnv = Cloudflare.Env;
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -23,38 +22,9 @@ type ScalarConfigKey = Extract<
|
|
|
23
22
|
string
|
|
24
23
|
>;
|
|
25
24
|
|
|
26
|
-
/**
|
|
27
|
-
* Effect `Config` helpers for scalar Cloudflare vars and secrets declared on
|
|
28
|
-
* `Cloudflare.Env`.
|
|
29
|
-
*
|
|
30
|
-
* Users still author their app config explicitly with Effect `Config`:
|
|
31
|
-
*
|
|
32
|
-
* ```ts
|
|
33
|
-
* import { Config, Effect } from "effect";
|
|
34
|
-
* import { WorkerConfig } from "effect-cf";
|
|
35
|
-
*
|
|
36
|
-
* const AppConfig = Config.all({
|
|
37
|
-
* databaseUrl: WorkerConfig.redacted("DATABASE_URL"),
|
|
38
|
-
* port: WorkerConfig.integer("PORT").pipe(Config.withDefault(8787)),
|
|
39
|
-
* });
|
|
40
|
-
*
|
|
41
|
-
* const program = Effect.gen(function* () {
|
|
42
|
-
* const config = yield* AppConfig;
|
|
43
|
-
* // ...
|
|
44
|
-
* }).pipe(Effect.provide(WorkerConfig.providerLayer));
|
|
45
|
-
* ```
|
|
46
|
-
*
|
|
47
|
-
* Keys are constrained to scalar `Cloudflare.Env` properties (`string`,
|
|
48
|
-
* `number`, or `boolean`, including optional scalar properties). Binding
|
|
49
|
-
* objects such as `KVNamespace`, `DurableObjectNamespace`, and service
|
|
50
|
-
* bindings are intentionally excluded; keep using the package binding helpers
|
|
51
|
-
* for those live resources.
|
|
52
|
-
*/
|
|
53
25
|
export namespace WorkerConfig {
|
|
54
|
-
/** Scalar env value types supported by the typed config key helpers. */
|
|
55
26
|
export type Scalar = ScalarConfigValue;
|
|
56
27
|
|
|
57
|
-
/** Scalar keys available on the current consumer's `Cloudflare.Env`. */
|
|
58
28
|
export type Key = ScalarConfigKey;
|
|
59
29
|
|
|
60
30
|
/** Read a scalar Cloudflare var or secret as a string. */
|
|
@@ -72,7 +42,6 @@ export namespace WorkerConfig {
|
|
|
72
42
|
/** Read a scalar Cloudflare var or secret as a boolean. */
|
|
73
43
|
export const boolean = <const Name extends Key>(name: Name) => Config.boolean(name);
|
|
74
44
|
|
|
75
|
-
/** Options for building a `ConfigProvider` from a Cloudflare worker `env` object. */
|
|
76
45
|
export interface ProviderOptions {
|
|
77
46
|
/**
|
|
78
47
|
* Keep empty-string env values as explicit `""` config values.
|
|
@@ -104,14 +73,9 @@ export namespace WorkerConfig {
|
|
|
104
73
|
return ConfigProvider.fromEnvRecord(record, options);
|
|
105
74
|
};
|
|
106
75
|
|
|
107
|
-
/**
|
|
108
|
-
* Build a `ConfigProvider` from the current `WorkerEnvironment` with a custom
|
|
109
|
-
* conversion function.
|
|
110
|
-
*/
|
|
111
76
|
export const providerWith = (makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider) =>
|
|
112
77
|
Effect.map(WorkerEnvironment, makeProvider);
|
|
113
78
|
|
|
114
|
-
/** Build a `ConfigProvider` from the current `WorkerEnvironment`. */
|
|
115
79
|
export const provider = providerWith(providerFromEnv);
|
|
116
80
|
|
|
117
81
|
/**
|
|
@@ -121,7 +85,6 @@ export namespace WorkerConfig {
|
|
|
121
85
|
export const providerLayer: Layer.Layer<never, never, WorkerEnvironment> =
|
|
122
86
|
ConfigProvider.layer(provider);
|
|
123
87
|
|
|
124
|
-
/** Build a `ConfigProvider` layer with a custom `env` conversion function. */
|
|
125
88
|
export const layerWith = (
|
|
126
89
|
makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider,
|
|
127
90
|
): Layer.Layer<never, never, WorkerEnvironment> =>
|
package/src/Hyperdrive.ts
CHANGED
|
@@ -5,9 +5,7 @@ import type { WorkerEnvironment } from "./Environment";
|
|
|
5
5
|
|
|
6
6
|
const expectedHyperdrive = "Hyperdrive binding with connectionString";
|
|
7
7
|
|
|
8
|
-
/** Typed Hyperdrive binding definition. */
|
|
9
8
|
export interface HyperdriveDefinition {
|
|
10
|
-
/** Binding name as configured in `wrangler.jsonc`. */
|
|
11
9
|
readonly binding: string;
|
|
12
10
|
}
|
|
13
11
|
|
|
@@ -19,7 +17,6 @@ export interface HyperdriveClient {
|
|
|
19
17
|
|
|
20
18
|
declare const HyperdriveServiceTypeId: unique symbol;
|
|
21
19
|
|
|
22
|
-
/** Nominal service marker for Hyperdrive services created with {@link make}. */
|
|
23
20
|
export interface HyperdriveService<Id extends string> {
|
|
24
21
|
readonly [HyperdriveServiceTypeId]: {
|
|
25
22
|
readonly id: Id;
|
package/src/HyperdrivePg.ts
CHANGED
|
@@ -6,20 +6,11 @@ import type * as Binding from "./Binding";
|
|
|
6
6
|
import type { WorkerEnvironment } from "./Environment";
|
|
7
7
|
import type * as Hyperdrive from "./Hyperdrive";
|
|
8
8
|
|
|
9
|
-
/** Hyperdrive owns database pooling, so app-side pool and connection options are not exposed. */
|
|
10
9
|
export type PgLayerOptions = Omit<
|
|
11
10
|
Parameters<typeof PgClient.makeClient>[0],
|
|
12
11
|
"url" | "host" | "port" | "path" | "ssl" | "database" | "username" | "password" | "stream"
|
|
13
12
|
>;
|
|
14
13
|
|
|
15
|
-
/**
|
|
16
|
-
* Provides `PgClient` and `SqlClient` backed by a Hyperdrive binding.
|
|
17
|
-
*
|
|
18
|
-
* Note: since Effect `4.0.0-beta.99`, `PgClient.makeClient` connects eagerly,
|
|
19
|
-
* so the TCP connection to Hyperdrive is opened when this layer is built.
|
|
20
|
-
* In per-request Workers runtimes, build the layer within the request
|
|
21
|
-
* lifecycle rather than sharing it across requests.
|
|
22
|
-
*/
|
|
23
14
|
export const layer = <Self, Id extends string>(
|
|
24
15
|
tag: Hyperdrive.TagClass<Self, Id>,
|
|
25
16
|
binding: Hyperdrive.LayerOptions,
|
package/src/Images.ts
CHANGED
|
@@ -33,7 +33,6 @@ export type TypeId = typeof TypeId;
|
|
|
33
33
|
|
|
34
34
|
const expectedImagesBinding = "Images binding with info() and input()";
|
|
35
35
|
|
|
36
|
-
/** Error raised when a Cloudflare Images operation fails. */
|
|
37
36
|
export class ImagesOperationError extends Data.TaggedError("ImagesOperationError")<{
|
|
38
37
|
readonly binding: string;
|
|
39
38
|
readonly operation: string;
|
|
@@ -44,9 +43,7 @@ export class ImagesOperationError extends Data.TaggedError("ImagesOperationError
|
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
/** Typed Cloudflare Images binding definition. */
|
|
48
46
|
export interface ImagesDefinition {
|
|
49
|
-
/** Binding name as configured in `wrangler.jsonc`. */
|
|
50
47
|
readonly binding: string;
|
|
51
48
|
}
|
|
52
49
|
|
|
@@ -175,7 +172,6 @@ export interface ImagesClient {
|
|
|
175
172
|
|
|
176
173
|
declare const ImagesServiceTypeId: unique symbol;
|
|
177
174
|
|
|
178
|
-
/** Nominal service marker for Images services created with {@link make}. */
|
|
179
175
|
export interface ImagesService<Id extends string> {
|
|
180
176
|
readonly [ImagesServiceTypeId]: {
|
|
181
177
|
readonly id: Id;
|
|
@@ -206,7 +202,6 @@ const makeSteps = (steps: ReadonlyArray<Step>): Steps => ({
|
|
|
206
202
|
steps,
|
|
207
203
|
});
|
|
208
204
|
|
|
209
|
-
/** Empty Images transformation pipeline. */
|
|
210
205
|
export const empty: Steps = makeSteps([]);
|
|
211
206
|
|
|
212
207
|
export const transform: {
|