effect-cf 0.20.0 → 0.22.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 +56 -0
- package/README.md +2 -2
- package/dist/{Hyperdrive-RTjgirMV.d.mts → Hyperdrive-COyg7R26.d.mts} +40 -13
- package/dist/HyperdrivePg.d.mts +13 -5
- package/dist/HyperdrivePg.mjs +12 -7
- package/dist/index.d.mts +708 -549
- package/dist/index.mjs +946 -589
- package/package.json +10 -5
- package/src/AiGateway.ts +82 -47
- package/src/AnalyticsEngine.ts +74 -58
- package/src/Binding.ts +66 -13
- package/src/BrowserRendering.ts +30 -7
- package/src/Cache.ts +32 -8
- package/src/CloudflareOtlp.ts +32 -9
- package/src/ContainerNamespace.ts +87 -55
- package/src/D1.ts +13 -3
- package/src/DurableObject.ts +27 -164
- package/src/DurableObjectAlarm.ts +30 -9
- package/src/DurableObjectDefinition.ts +58 -54
- package/src/DurableObjectNamespace.ts +99 -96
- package/src/DurableObjectRpcWebSocket.ts +14 -6
- package/src/DurableObjectSqlite.ts +6 -3
- package/src/DurableObjectState.ts +6 -9
- package/src/DurableObjectStorage.ts +7 -1
- package/src/DurableObjectWebSocket.ts +51 -41
- package/src/Email.ts +40 -13
- package/src/Environment.ts +26 -6
- package/src/Hyperdrive.ts +2 -2
- package/src/HyperdrivePg.ts +25 -13
- package/src/Images.ts +77 -82
- package/src/Kv.ts +37 -27
- package/src/Queue.ts +6 -1
- package/src/QueueBinding.ts +18 -21
- package/src/QueueDefinition.ts +15 -14
- package/src/R2.ts +107 -29
- package/src/Rpc.ts +3 -1
- package/src/RpcDefinition.ts +177 -133
- package/src/ServiceBinding.ts +112 -108
- package/src/Vectorize.ts +59 -14
- package/src/Worker.ts +205 -198
- package/src/WorkerDefinition.ts +5 -10
- package/src/WorkersAi.ts +27 -17
- package/src/Workflow.ts +54 -49
- package/src/WorkflowBinding.ts +19 -11
- package/src/WorkflowDefinition.ts +24 -27
- package/src/index.ts +4 -3
- package/src/internal/Entrypoint.ts +3 -1
- package/src/internal/ErrorMessage.ts +24 -0
- package/src/internal/RpcInvocation.ts +11 -8
- package/src/internal/Runtime.ts +52 -0
- package/src/internal/WorkerContext.ts +14 -2
- package/src/Entry.ts +0 -259
- package/src/internal/Clock.ts +0 -37
package/src/Entry.ts
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import { WorkerEntrypoint as CloudflareWorkerEntrypoint } from "cloudflare:workers";
|
|
2
|
-
import { Cause, Context, Effect, Exit, Layer, ManagedRuntime, type Scope } from "effect";
|
|
3
|
-
import { HttpServerRequest } from "effect/unstable/http";
|
|
4
|
-
|
|
5
|
-
import { WorkerEnvironment, type WorkerEnv } from "./Environment";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Access to Cloudflare's native `ExecutionContext`.
|
|
9
|
-
*/
|
|
10
|
-
export class ExecutionContext extends Context.Service<
|
|
11
|
-
ExecutionContext,
|
|
12
|
-
globalThis.ExecutionContext
|
|
13
|
-
>()("effect-cf/ExecutionContext") {}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Options for {@link WorkerContextService.waitUntil}.
|
|
17
|
-
*/
|
|
18
|
-
export interface WorkerContextWaitUntilOptions<E, R> {
|
|
19
|
-
/** Custom failure handler for the background effect. */
|
|
20
|
-
readonly onFailure?: (cause: Cause.Cause<E>) => Effect.Effect<void, never, R>;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Effect wrapper around `ExecutionContext` background APIs.
|
|
25
|
-
*/
|
|
26
|
-
export interface WorkerContextService {
|
|
27
|
-
readonly raw: globalThis.ExecutionContext;
|
|
28
|
-
waitUntil<A, E, R, R2 = never>(
|
|
29
|
-
effect: Effect.Effect<A, E, R>,
|
|
30
|
-
options?: WorkerContextWaitUntilOptions<E, R2>,
|
|
31
|
-
): Effect.Effect<void, never, R | R2>;
|
|
32
|
-
readonly passThroughOnException: Effect.Effect<void>;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Service used inside handlers to schedule background work via `waitUntil`.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* const handler = Effect.gen(function* () {
|
|
41
|
-
* const ctx = yield* WorkerContext;
|
|
42
|
-
* yield* ctx.waitUntil(Effect.log("flush analytics"));
|
|
43
|
-
* return new Response("ok");
|
|
44
|
-
* });
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
export class WorkerContext extends Context.Service<WorkerContext, WorkerContextService>()(
|
|
48
|
-
"effect-cf/WorkerContext",
|
|
49
|
-
) {}
|
|
50
|
-
|
|
51
|
-
type RunWaitUntilEffect = <A, E>(
|
|
52
|
-
effect: Effect.Effect<A, E, never>,
|
|
53
|
-
) => Promise<Exit.Exit<A, unknown>>;
|
|
54
|
-
|
|
55
|
-
const fromExecutionContext = (
|
|
56
|
-
ctx: globalThis.ExecutionContext,
|
|
57
|
-
runPromiseExit: RunWaitUntilEffect,
|
|
58
|
-
): WorkerContextService => ({
|
|
59
|
-
raw: ctx,
|
|
60
|
-
waitUntil: <A, E, R, R2 = never>(
|
|
61
|
-
effect: Effect.Effect<A, E, R>,
|
|
62
|
-
options?: WorkerContextWaitUntilOptions<E, R2>,
|
|
63
|
-
) =>
|
|
64
|
-
Effect.context<R | R2>().pipe(
|
|
65
|
-
Effect.flatMap((context) =>
|
|
66
|
-
Effect.sync(() => {
|
|
67
|
-
const observed = Effect.exit(effect).pipe(
|
|
68
|
-
Effect.flatMap((exit) => {
|
|
69
|
-
if (Exit.isSuccess(exit)) {
|
|
70
|
-
return Effect.void;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const handleFailure =
|
|
74
|
-
options?.onFailure?.(exit.cause) ??
|
|
75
|
-
Effect.logError("WorkerContext.waitUntil failed", Cause.pretty(exit.cause));
|
|
76
|
-
|
|
77
|
-
return handleFailure.pipe(
|
|
78
|
-
Effect.catchCause((handlerCause) =>
|
|
79
|
-
Effect.logError(
|
|
80
|
-
"WorkerContext.waitUntil failure handler failed",
|
|
81
|
-
Cause.pretty(exit.cause),
|
|
82
|
-
Cause.pretty(handlerCause),
|
|
83
|
-
),
|
|
84
|
-
),
|
|
85
|
-
);
|
|
86
|
-
}),
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
ctx.waitUntil(
|
|
90
|
-
runPromiseExit(Effect.scoped(Effect.provideContext(observed, context))).then((exit) => {
|
|
91
|
-
if (Exit.isFailure(exit)) {
|
|
92
|
-
console.error(
|
|
93
|
-
"WorkerContext.waitUntil failure handler failed",
|
|
94
|
-
Cause.pretty(exit.cause),
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
}),
|
|
98
|
-
);
|
|
99
|
-
}),
|
|
100
|
-
),
|
|
101
|
-
),
|
|
102
|
-
passThroughOnException: Effect.sync(() => ctx.passThroughOnException()),
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Access to the incoming `Request` currently handled by a worker or Durable Object fetch.
|
|
107
|
-
*/
|
|
108
|
-
export class NativeRequest extends Context.Service<NativeRequest, Request>()(
|
|
109
|
-
"effect-cf/NativeRequest",
|
|
110
|
-
) {}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Returns `true` when the request is a websocket upgrade request.
|
|
114
|
-
*/
|
|
115
|
-
export const isWebSocketUpgrade = (request: Request): boolean =>
|
|
116
|
-
request.headers.get("Upgrade")?.toLowerCase() === "websocket";
|
|
117
|
-
|
|
118
|
-
type RequestServices = ExecutionContext | WorkerContext | WorkerEnvironment;
|
|
119
|
-
|
|
120
|
-
type HandlerContext<ROut> =
|
|
121
|
-
| ExecutionContext
|
|
122
|
-
| WorkerContext
|
|
123
|
-
| WorkerEnvironment
|
|
124
|
-
| NativeRequest
|
|
125
|
-
| HttpServerRequest.HttpServerRequest
|
|
126
|
-
| ROut
|
|
127
|
-
| Scope.Scope;
|
|
128
|
-
|
|
129
|
-
type RuntimeContext<ROut> = RequestServices | ROut;
|
|
130
|
-
type RpcContext<ROut> = RuntimeContext<ROut> | Scope.Scope;
|
|
131
|
-
|
|
132
|
-
const RunSymbol = Symbol.for("effect-cf/Worker/run");
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Effect type for `fetch` handlers executed by {@link make}.
|
|
136
|
-
*/
|
|
137
|
-
export type WorkerHandler<ROut, A = unknown> = Effect.Effect<A, unknown, HandlerContext<ROut>>;
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Effect type for worker RPC handlers.
|
|
141
|
-
*/
|
|
142
|
-
export type WorkerRpcHandler<ROut, A = unknown> = Effect.Effect<A, unknown, RpcContext<ROut>>;
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Shape of worker RPC handlers passed to {@link make}.
|
|
146
|
-
*/
|
|
147
|
-
export type WorkerRpc<ROut> = Record<string, (...args: Array<any>) => WorkerRpcHandler<ROut>>;
|
|
148
|
-
|
|
149
|
-
export type WorkerRpcShape<Rpc extends WorkerRpc<ROut>, ROut> = {
|
|
150
|
-
readonly [Key in keyof Rpc]: Rpc[Key] extends (
|
|
151
|
-
...args: infer Args
|
|
152
|
-
) => Effect.Effect<infer A, unknown, RpcContext<ROut>>
|
|
153
|
-
? (...args: Args) => Promise<A>
|
|
154
|
-
: never;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
export type RpcHandlers<ROut, Api> = {
|
|
158
|
-
readonly [Key in keyof Api as Key extends keyof CloudflareWorkerEntrypoint
|
|
159
|
-
? never
|
|
160
|
-
: Key extends string
|
|
161
|
-
? [Api[Key]] extends [never]
|
|
162
|
-
? never
|
|
163
|
-
: Api[Key] extends (...args: Array<any>) => Promise<unknown>
|
|
164
|
-
? Key
|
|
165
|
-
: never
|
|
166
|
-
: never]: Api[Key] extends (...args: infer Args) => Promise<infer A>
|
|
167
|
-
? (...args: Args) => WorkerRpcHandler<ROut, A>
|
|
168
|
-
: never;
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Options for creating a worker class with Effect handlers.
|
|
173
|
-
*/
|
|
174
|
-
export interface WorkerOptions<ROut, Rpc extends WorkerRpc<ROut>> {
|
|
175
|
-
/** Main request handler. */
|
|
176
|
-
readonly fetch: Effect.Effect<Response, unknown, HandlerContext<ROut>>;
|
|
177
|
-
/** Optional RPC methods exposed as class instance methods. */
|
|
178
|
-
readonly rpc?: Rpc;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Cloudflare `WorkerEntrypoint` constructor produced by {@link make}.
|
|
183
|
-
*/
|
|
184
|
-
export type WorkerClass<Rpc extends WorkerRpc<ROut>, ROut> = new (
|
|
185
|
-
ctx: globalThis.ExecutionContext,
|
|
186
|
-
env: WorkerEnv,
|
|
187
|
-
) => CloudflareWorkerEntrypoint<WorkerEnv> & WorkerRpcShape<Rpc, ROut>;
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Creates a Cloudflare worker class backed by a single managed Effect runtime.
|
|
191
|
-
*
|
|
192
|
-
* @example
|
|
193
|
-
* ```ts
|
|
194
|
-
* const Worker = Entry.make(Layer.empty, {
|
|
195
|
-
* fetch: Effect.succeed(new Response("ok")),
|
|
196
|
-
* });
|
|
197
|
-
* ```
|
|
198
|
-
*/
|
|
199
|
-
export const make = <ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Record<never, never>>(
|
|
200
|
-
layer: Layer.Layer<ROut, LayerError, RequestServices>,
|
|
201
|
-
options: WorkerOptions<ROut, Rpc>,
|
|
202
|
-
): WorkerClass<Rpc, ROut> => {
|
|
203
|
-
class EffectWorker extends CloudflareWorkerEntrypoint<WorkerEnv> {
|
|
204
|
-
readonly runtime: ManagedRuntime.ManagedRuntime<RuntimeContext<ROut>, LayerError>;
|
|
205
|
-
|
|
206
|
-
constructor(ctx: globalThis.ExecutionContext, env: WorkerEnv) {
|
|
207
|
-
super(ctx, env);
|
|
208
|
-
|
|
209
|
-
let runWaitUntilEffect: RunWaitUntilEffect = () =>
|
|
210
|
-
Promise.resolve(Exit.die(new Error("WorkerContext runtime is not initialized")));
|
|
211
|
-
|
|
212
|
-
const services = Layer.mergeAll(
|
|
213
|
-
Layer.succeed(ExecutionContext, ctx),
|
|
214
|
-
Layer.succeed(
|
|
215
|
-
WorkerContext,
|
|
216
|
-
fromExecutionContext(ctx, (effect) => runWaitUntilEffect(effect)),
|
|
217
|
-
),
|
|
218
|
-
Layer.succeed(WorkerEnvironment, env),
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
const runtimeLayer = layer.pipe(Layer.provideMerge(services)) as Layer.Layer<
|
|
222
|
-
RuntimeContext<ROut>,
|
|
223
|
-
LayerError,
|
|
224
|
-
never
|
|
225
|
-
>;
|
|
226
|
-
|
|
227
|
-
this.runtime = ManagedRuntime.make(runtimeLayer);
|
|
228
|
-
runWaitUntilEffect = <A, E>(effect: Effect.Effect<A, E, never>) =>
|
|
229
|
-
this.runtime.runPromiseExit(effect as Effect.Effect<A, E, RuntimeContext<ROut>>);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
[RunSymbol]<A, E>(effect: Effect.Effect<A, E, RuntimeContext<ROut> | Scope.Scope>): Promise<A> {
|
|
233
|
-
return this.runtime.runPromise(Effect.scoped(effect));
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
fetch(request: Request): Promise<Response> {
|
|
237
|
-
return this[RunSymbol](
|
|
238
|
-
options.fetch.pipe(
|
|
239
|
-
Effect.provideService(NativeRequest, request),
|
|
240
|
-
Effect.provideService(
|
|
241
|
-
HttpServerRequest.HttpServerRequest,
|
|
242
|
-
HttpServerRequest.fromWeb(request),
|
|
243
|
-
),
|
|
244
|
-
),
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
for (const [key, method] of Object.entries(options.rpc ?? {})) {
|
|
250
|
-
Object.defineProperty(EffectWorker.prototype, key, {
|
|
251
|
-
enumerable: true,
|
|
252
|
-
value(this: EffectWorker, ...args: Array<any>) {
|
|
253
|
-
return this[RunSymbol](Effect.suspend(() => method(...args)));
|
|
254
|
-
},
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return EffectWorker as WorkerClass<Rpc, ROut>;
|
|
259
|
-
};
|
package/src/internal/Clock.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { Clock, Duration, Effect, Layer } from "effect";
|
|
2
|
-
|
|
3
|
-
const maxTimerMillis = 2 ** 31 - 1;
|
|
4
|
-
const nanosPerMilli = BigInt(1_000_000);
|
|
5
|
-
|
|
6
|
-
export const clock: Clock.Clock = {
|
|
7
|
-
currentTimeMillisUnsafe: () => Date.now(),
|
|
8
|
-
currentTimeMillis: Effect.sync(() => clock.currentTimeMillisUnsafe()),
|
|
9
|
-
currentTimeNanosUnsafe: () => BigInt(Date.now()) * nanosPerMilli,
|
|
10
|
-
currentTimeNanos: Effect.sync(() => clock.currentTimeNanosUnsafe()),
|
|
11
|
-
// Workers expose `performance.now()` as time since worker start. It advances
|
|
12
|
-
// only across I/O, like `Date.now()`, but it never moves backward.
|
|
13
|
-
monotonicTimeNanosUnsafe: () =>
|
|
14
|
-
typeof performance === "undefined"
|
|
15
|
-
? BigInt(Date.now()) * nanosPerMilli
|
|
16
|
-
: BigInt(Math.round(performance.now() * 1_000_000)),
|
|
17
|
-
monotonicTimeNanos: Effect.sync(() => clock.monotonicTimeNanosUnsafe()),
|
|
18
|
-
sleep: (duration) => {
|
|
19
|
-
const millis = Duration.toMillis(duration);
|
|
20
|
-
|
|
21
|
-
if (millis <= 0) {
|
|
22
|
-
return Effect.yieldNow;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return Effect.callback<void>((resume) => {
|
|
26
|
-
if (millis > maxTimerMillis) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const handle = setTimeout(() => resume(Effect.void), millis);
|
|
31
|
-
|
|
32
|
-
return Effect.sync(() => clearTimeout(handle));
|
|
33
|
-
});
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const layer = Layer.effect(Clock.Clock, Effect.succeed(clock));
|