effect-cf 0.52.0 → 0.54.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 +16 -0
- package/README.md +7 -1
- package/dist/AnalyticsEngine.d.mts +2 -2
- package/dist/AnalyticsEngine.mjs +3 -3
- package/dist/CloudflareOtlp.d.mts +3 -3
- package/dist/CloudflareOtlp.mjs +7 -7
- package/dist/D1.d.mts +1 -1
- package/dist/DurableObject.d.mts +1 -0
- package/dist/DurableObject.mjs +33 -11
- package/dist/DurableObjectAlarm.d.mts +74 -9
- package/dist/DurableObjectAlarm.mjs +245 -35
- package/dist/DurableObjectRpcWebSocket.d.mts +3 -3
- package/dist/DurableObjectRpcWebSocket.mjs +3 -3
- package/dist/DurableObjectSqlite.d.mts +1 -1
- package/dist/DurableObjectSqlite.mjs +2 -2
- package/dist/HyperdrivePg.d.mts +1 -1
- package/dist/Mcp.d.mts +3 -3
- package/dist/Mcp.mjs +3 -3
- package/dist/RateLimit.d.mts +50 -0
- package/dist/RateLimit.mjs +46 -0
- package/dist/RpcWebSocketClient.d.mts +6 -6
- package/dist/RpcWebSocketClient.mjs +3 -3
- package/dist/Worker.d.mts +2 -2
- package/dist/Worker.mjs +4 -4
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/internal/Runtime.mjs +5 -3
- package/dist/internal/Telemetry.mjs +1 -1
- package/package.json +5 -5
- package/src/AnalyticsEngine.ts +4 -4
- package/src/CloudflareOtlp.ts +8 -8
- package/src/D1.ts +1 -1
- package/src/DurableObject.ts +93 -30
- package/src/DurableObjectAlarm.ts +601 -59
- package/src/DurableObjectRpcWebSocket.ts +3 -3
- package/src/DurableObjectSqlite.ts +2 -2
- package/src/HyperdrivePg.ts +1 -1
- package/src/Mcp.ts +4 -4
- package/src/RateLimit.ts +110 -0
- package/src/RpcWebSocketClient.ts +6 -6
- package/src/Worker.ts +4 -4
- package/src/index.ts +1 -0
- package/src/internal/Entrypoint.ts +8 -4
- package/src/internal/Runtime.ts +12 -7
- package/src/internal/Telemetry.ts +1 -1
|
@@ -5,9 +5,9 @@ import * as Option from "effect/Option";
|
|
|
5
5
|
import * as Predicate from "effect/Predicate";
|
|
6
6
|
import * as Queue from "effect/Queue";
|
|
7
7
|
import * as Schema from "effect/Schema";
|
|
8
|
-
import * as RpcMessage from "effect/
|
|
9
|
-
import * as RpcSerialization from "effect/
|
|
10
|
-
import * as RpcServer from "effect/
|
|
8
|
+
import * as RpcMessage from "effect/rpc/RpcMessage";
|
|
9
|
+
import * as RpcSerialization from "effect/rpc/RpcSerialization";
|
|
10
|
+
import * as RpcServer from "effect/rpc/RpcServer";
|
|
11
11
|
|
|
12
12
|
import { DurableObjectState } from "./DurableObjectState";
|
|
13
13
|
import {
|
|
@@ -3,8 +3,8 @@ import * as Context from "effect/Context";
|
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
4
|
import * as Layer from "effect/Layer";
|
|
5
5
|
import * as Scheduler from "effect/Scheduler";
|
|
6
|
-
import * as Reactivity from "effect/
|
|
7
|
-
import { SqlClient } from "effect/
|
|
6
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
7
|
+
import { SqlClient } from "effect/sql";
|
|
8
8
|
|
|
9
9
|
import { DurableObjectState } from "./DurableObjectState";
|
|
10
10
|
|
package/src/HyperdrivePg.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { PgClient } from "@effect/sql-pg";
|
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Layer from "effect/Layer";
|
|
4
4
|
import * as Redacted from "effect/Redacted";
|
|
5
|
-
import type { SqlClient, SqlError } from "effect/
|
|
5
|
+
import type { SqlClient, SqlError } from "effect/sql";
|
|
6
6
|
|
|
7
7
|
import type * as Binding from "./Binding";
|
|
8
8
|
import type { WorkerEnvironment } from "./Environment";
|
package/src/Mcp.ts
CHANGED
|
@@ -21,9 +21,9 @@ import * as Schema from "effect/Schema";
|
|
|
21
21
|
import * as Sink from "effect/Sink";
|
|
22
22
|
import * as Stream from "effect/Stream";
|
|
23
23
|
import type { JsonSchema } from "effect";
|
|
24
|
-
import * as AiError from "effect/
|
|
25
|
-
import * as Tool from "effect/
|
|
26
|
-
import type { Toolkit } from "effect/
|
|
24
|
+
import * as AiError from "effect/ai/AiError";
|
|
25
|
+
import * as Tool from "effect/ai/Tool";
|
|
26
|
+
import type { Toolkit } from "effect/ai";
|
|
27
27
|
|
|
28
28
|
import { NativeRequest } from "./Worker";
|
|
29
29
|
import { runNativeCallback } from "./internal/NativeCallback";
|
|
@@ -424,7 +424,7 @@ const registerToolkitTool = <Tools extends Record<string, Tool.Any>>(
|
|
|
424
424
|
*
|
|
425
425
|
* ```ts
|
|
426
426
|
* import { Effect, Layer, Option } from "effect"
|
|
427
|
-
* import { HttpRouter } from "effect/
|
|
427
|
+
* import { HttpRouter } from "effect/http"
|
|
428
428
|
* import { Worker } from "effect-cf"
|
|
429
429
|
* import * as Mcp from "effect-cf/mcp"
|
|
430
430
|
*
|
package/src/RateLimit.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as Context from "effect/Context";
|
|
2
|
+
import * as Data from "effect/Data";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Predicate from "effect/Predicate";
|
|
5
|
+
import type { Layer } from "effect";
|
|
6
|
+
|
|
7
|
+
import * as Binding from "./Binding";
|
|
8
|
+
import type { WorkerEnvironment } from "./Environment";
|
|
9
|
+
|
|
10
|
+
export type { BindingNotFoundError, BindingValidationError } from "./Binding";
|
|
11
|
+
|
|
12
|
+
const expectedRateLimit = "Rate Limiting binding with limit()";
|
|
13
|
+
|
|
14
|
+
export type RateLimitBinding = globalThis.RateLimit;
|
|
15
|
+
export type RateLimitOptions = globalThis.RateLimitOptions;
|
|
16
|
+
export type RateLimitOutcome = globalThis.RateLimitOutcome;
|
|
17
|
+
|
|
18
|
+
export class RateLimitOperationError extends Data.TaggedError("RateLimitOperationError")<{
|
|
19
|
+
readonly binding: string;
|
|
20
|
+
readonly operation: "limit";
|
|
21
|
+
readonly cause: unknown;
|
|
22
|
+
}> {
|
|
23
|
+
override get message(): string {
|
|
24
|
+
return `Cloudflare rate limit binding "${this.binding}" operation "limit" failed`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface RateLimitDefinition {
|
|
29
|
+
readonly binding: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface RateLimitClient {
|
|
33
|
+
/** Denial is a successful result with success: false. Calls are never retried. */
|
|
34
|
+
readonly limit: (
|
|
35
|
+
options: RateLimitOptions,
|
|
36
|
+
) => Effect.Effect<RateLimitOutcome, RateLimitOperationError>;
|
|
37
|
+
readonly rawUnsafe: Effect.Effect<RateLimitBinding>;
|
|
38
|
+
readonly definition: RateLimitDefinition;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
declare const RateLimitServiceTypeId: unique symbol;
|
|
42
|
+
|
|
43
|
+
export interface RateLimitService<Id extends string> {
|
|
44
|
+
readonly [RateLimitServiceTypeId]: {
|
|
45
|
+
readonly id: Id;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type LayerOptions = {
|
|
50
|
+
readonly binding: string;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export interface TagClass<Self, Id extends string> extends Context.ServiceClass<
|
|
54
|
+
Self,
|
|
55
|
+
Id,
|
|
56
|
+
RateLimitClient
|
|
57
|
+
> {
|
|
58
|
+
readonly id: Id;
|
|
59
|
+
readonly layer: (
|
|
60
|
+
options: LayerOptions,
|
|
61
|
+
) => Layer.Layer<
|
|
62
|
+
Self,
|
|
63
|
+
Binding.BindingNotFoundError | Binding.BindingValidationError,
|
|
64
|
+
WorkerEnvironment
|
|
65
|
+
>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const isRateLimit = <Candidate>(value: Candidate): value is Candidate & RateLimitBinding =>
|
|
69
|
+
Predicate.hasProperty(value, "limit") && Predicate.isFunction(value.limit);
|
|
70
|
+
|
|
71
|
+
export const makeClient =
|
|
72
|
+
(definition: RateLimitDefinition) =>
|
|
73
|
+
(rateLimit: RateLimitBinding): RateLimitClient => ({
|
|
74
|
+
definition,
|
|
75
|
+
limit: (options) =>
|
|
76
|
+
Effect.tryPromise({
|
|
77
|
+
try: () => rateLimit.limit(options),
|
|
78
|
+
catch: (cause) =>
|
|
79
|
+
new RateLimitOperationError({
|
|
80
|
+
binding: definition.binding,
|
|
81
|
+
operation: "limit",
|
|
82
|
+
cause,
|
|
83
|
+
}),
|
|
84
|
+
}),
|
|
85
|
+
rawUnsafe: Effect.succeed(rateLimit),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
export const layer = <Self>(
|
|
89
|
+
tag: Context.Service<Self, RateLimitClient>,
|
|
90
|
+
definition: RateLimitDefinition,
|
|
91
|
+
) =>
|
|
92
|
+
Binding.layer(tag, definition.binding, isRateLimit, makeClient(definition), {
|
|
93
|
+
expected: expectedRateLimit,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
export const make = <Id extends string>(id: Id) => Tag<RateLimitService<Id>>()<Id>(id);
|
|
97
|
+
|
|
98
|
+
export const Tag =
|
|
99
|
+
<Self>() =>
|
|
100
|
+
<Id extends string>(id: Id) => {
|
|
101
|
+
const tag = Context.Service<Self, RateLimitClient>()(id);
|
|
102
|
+
|
|
103
|
+
const makeLayer = (definition: LayerOptions) => layer(tag, definition);
|
|
104
|
+
|
|
105
|
+
// SAFETY: these are exactly the members required by TagClass, attached to the matching service tag.
|
|
106
|
+
return Object.assign(tag, {
|
|
107
|
+
id,
|
|
108
|
+
layer: makeLayer,
|
|
109
|
+
}) as TagClass<Self, Id>;
|
|
110
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type * as Context from "effect/Context";
|
|
2
2
|
import * as Layer from "effect/Layer";
|
|
3
|
-
import type * as Rpc from "effect/
|
|
4
|
-
import * as RpcClient from "effect/
|
|
5
|
-
import type { RpcClientError } from "effect/
|
|
6
|
-
import type * as RpcGroup from "effect/
|
|
7
|
-
import * as RpcSerialization from "effect/
|
|
8
|
-
import * as Socket from "effect/
|
|
3
|
+
import type * as Rpc from "effect/rpc/Rpc";
|
|
4
|
+
import * as RpcClient from "effect/rpc/RpcClient";
|
|
5
|
+
import type { RpcClientError } from "effect/rpc/RpcClientError";
|
|
6
|
+
import type * as RpcGroup from "effect/rpc/RpcGroup";
|
|
7
|
+
import * as RpcSerialization from "effect/rpc/RpcSerialization";
|
|
8
|
+
import * as Socket from "effect/socket/Socket";
|
|
9
9
|
|
|
10
10
|
export interface LayerOptions {
|
|
11
11
|
readonly socket?: Parameters<typeof Socket.layerWebSocket>[1];
|
package/src/Worker.ts
CHANGED
|
@@ -5,10 +5,10 @@ import * as Layer from "effect/Layer";
|
|
|
5
5
|
import * as References from "effect/References";
|
|
6
6
|
import * as Tracer from "effect/Tracer";
|
|
7
7
|
import type { Cause, ManagedRuntime, Scope } from "effect";
|
|
8
|
-
import * as HttpEffect from "effect/
|
|
9
|
-
import * as HttpMiddleware from "effect/
|
|
10
|
-
import * as HttpServerRequest from "effect/
|
|
11
|
-
import * as HttpServerResponse from "effect/
|
|
8
|
+
import * as HttpEffect from "effect/http/HttpEffect";
|
|
9
|
+
import * as HttpMiddleware from "effect/http/HttpMiddleware";
|
|
10
|
+
import * as HttpServerRequest from "effect/http/HttpServerRequest";
|
|
11
|
+
import * as HttpServerResponse from "effect/http/HttpServerResponse";
|
|
12
12
|
|
|
13
13
|
import { WorkerEnvironment, type WorkerEnv } from "./Environment";
|
|
14
14
|
import { fromMessage, fromMessageBatch, type QueueHandler } from "./Queue";
|
package/src/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ export * as Kv from "./Kv";
|
|
|
27
27
|
export * as Queue from "./Queue";
|
|
28
28
|
export * as QueueBinding from "./QueueBinding";
|
|
29
29
|
export * as QueueDefinition from "./QueueDefinition";
|
|
30
|
+
export * as RateLimit from "./RateLimit";
|
|
30
31
|
export * as R2 from "./R2";
|
|
31
32
|
export * as Rpc from "./Rpc";
|
|
32
33
|
export * as RpcDefinition from "./RpcDefinition";
|
|
@@ -44,12 +44,16 @@ const invokeEntrypointRpcMethod = <Self>(
|
|
|
44
44
|
);
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
export const provideEntrypointServices = <ROut, LayerError, RIn>(
|
|
47
|
+
export const provideEntrypointServices = <ROut, LayerError, RIn, ServicesError = never>(
|
|
48
48
|
layer: Layer.Layer<ROut, LayerError, RIn>,
|
|
49
|
-
services: Layer.Layer<RIn,
|
|
50
|
-
): Layer.Layer<ROut | RIn, LayerError, never> =>
|
|
49
|
+
services: Layer.Layer<RIn, ServicesError, never>,
|
|
50
|
+
): Layer.Layer<ROut | RIn, LayerError | ServicesError, never> =>
|
|
51
51
|
// SAFETY: provideMerge supplies RIn while retaining it in the output context for entrypoint consumers.
|
|
52
|
-
layer.pipe(Layer.provideMerge(services)) as Layer.Layer<
|
|
52
|
+
layer.pipe(Layer.provideMerge(services)) as Layer.Layer<
|
|
53
|
+
ROut | RIn,
|
|
54
|
+
LayerError | ServicesError,
|
|
55
|
+
never
|
|
56
|
+
>;
|
|
53
57
|
|
|
54
58
|
export const defineEntrypointRpcMethods = <Self, Prototype extends object = object>(
|
|
55
59
|
target: string,
|
package/src/internal/Runtime.ts
CHANGED
|
@@ -56,11 +56,14 @@ const runPromise = <A, E, R, LayerError>(
|
|
|
56
56
|
* layer so the resulting runtime satisfies both the user services and the
|
|
57
57
|
* platform services.
|
|
58
58
|
*/
|
|
59
|
-
export const makeEntrypointRuntime = <ROut, LayerError, Services>(
|
|
59
|
+
export const makeEntrypointRuntime = <ROut, LayerError, Services, ServicesError = never>(
|
|
60
60
|
layer: Layer.Layer<ROut, LayerError, Services | WorkerEnvironment>,
|
|
61
61
|
env: WorkerEnv,
|
|
62
|
-
services: Layer.Layer<Services>,
|
|
63
|
-
): ManagedRuntime.ManagedRuntime<
|
|
62
|
+
services: Layer.Layer<Services, ServicesError>,
|
|
63
|
+
): ManagedRuntime.ManagedRuntime<
|
|
64
|
+
ROut | Services | WorkerEnvironment,
|
|
65
|
+
LayerError | ServicesError
|
|
66
|
+
> => {
|
|
64
67
|
const entrypointServices = Layer.mergeAll(
|
|
65
68
|
services,
|
|
66
69
|
ConfigProvider.layer(WorkerConfig.providerFromEnv(env)),
|
|
@@ -70,6 +73,10 @@ export const makeEntrypointRuntime = <ROut, LayerError, Services>(
|
|
|
70
73
|
return ManagedRuntime.make(provideEntrypointServices(layer, entrypointServices));
|
|
71
74
|
};
|
|
72
75
|
|
|
76
|
+
/** Close event resources before an outer lifecycle (such as alarm reconciliation) completes. */
|
|
77
|
+
export const scopeEvent = <A, E, R>(effect: Effect.Effect<A, E, R | Scope.Scope>) =>
|
|
78
|
+
Effect.scoped(RpcTargets.withScope(effect));
|
|
79
|
+
|
|
73
80
|
export function runEventPromise<A, E, R, LayerError>(
|
|
74
81
|
runtime: ManagedRuntime.ManagedRuntime<R, LayerError>,
|
|
75
82
|
effect: Effect.Effect<A, E, NoInfer<R> | Scope.Scope>,
|
|
@@ -105,7 +112,7 @@ export function runEventPromise<A, E, R, REvent, EventLayerError, LayerError>(
|
|
|
105
112
|
const [runtime, effect, eventLayer, parent, onFailure] = args;
|
|
106
113
|
|
|
107
114
|
if (eventLayer === undefined) {
|
|
108
|
-
const event =
|
|
115
|
+
const event = scopeEvent(effect);
|
|
109
116
|
|
|
110
117
|
return runPromise(
|
|
111
118
|
runtime,
|
|
@@ -114,9 +121,7 @@ export function runEventPromise<A, E, R, REvent, EventLayerError, LayerError>(
|
|
|
114
121
|
);
|
|
115
122
|
}
|
|
116
123
|
|
|
117
|
-
const event = Effect.
|
|
118
|
-
RpcTargets.withScope(effect.pipe(Effect.provide(eventLayer, { local: true }))),
|
|
119
|
-
);
|
|
124
|
+
const event = scopeEvent(effect.pipe(Effect.provide(eventLayer, { local: true })));
|
|
120
125
|
|
|
121
126
|
return runPromise(
|
|
122
127
|
runtime,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
2
|
import * as Option from "effect/Option";
|
|
3
|
-
import { Flusher } from "effect/
|
|
3
|
+
import { Flusher } from "effect/observability/OtlpExporter";
|
|
4
4
|
|
|
5
5
|
/** Maximum event lifetime spent on an internally scheduled telemetry flush. */
|
|
6
6
|
const scheduledFlushTimeout = "2 seconds";
|