effect-cf 0.0.2 → 0.0.4
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/README.md +7 -0
- package/dist/index.d.mts +22 -4
- package/dist/index.mjs +17 -5
- package/package.json +1 -1
- package/src/Environment.ts +15 -1
- package/src/Worker.ts +81 -15
package/README.md
CHANGED
|
@@ -8,6 +8,12 @@ Cloudflare services should be described as `Context`, `Layer`, and `Effect` valu
|
|
|
8
8
|
|
|
9
9
|
The low-level Worker entrypoint factory is exported as `Worker.make`. It returns a `WorkerEntrypoint` class with a `fetch` handler and optional typed RPC methods. Durable Object support starts with `DurableObject.make`, which routes Durable Object lifecycle methods and RPC handlers through one managed runtime for each Durable Object instance.
|
|
10
10
|
|
|
11
|
+
Worker fetch handlers can return either web `Response` values or Effect `HttpServerResponse` values. `Worker.make` renders `HttpServerResponse` back to a web `Response` at the Cloudflare boundary, so application handlers can stay in Effect HTTP primitives.
|
|
12
|
+
|
|
13
|
+
Request-scoped app services belong in the implementation layer that owns request semantics, such as `HttpRouter` middleware, RPC middleware, or explicit `Effect.provide(...)` inside a custom fetch effect. `Worker.make` stays focused on Cloudflare boundary services: `NativeRequest`, `HttpServerRequest`, `WorkerEnvironment`, `ExecutionContext`, and `WorkerContext`.
|
|
14
|
+
|
|
15
|
+
For modules that need an `ExportedHandler` object instead of a `WorkerEntrypoint` class, use `Worker.makeFetchHandler`. This helper is fetch-only and intentionally does not accept Worker RPC methods.
|
|
16
|
+
|
|
11
17
|
RPC contracts can be described as classes with `Worker.Tag` and `DurableObject.Tag`. Contract classes expose `.make(...)` for runtime entrypoint creation and `.Binding(...)` / `.Namespace(...)` for typed bindings. Bindings infer call types from the same code-owned contract classes. Definition-backed calls encode/decode arguments and success values with their Effect schemas at Worker and Durable Object boundaries.
|
|
12
18
|
|
|
13
19
|
Binding helpers expose two RPC paths:
|
|
@@ -31,6 +37,7 @@ Client APIs use Cloudflare-style provider types, so object results expose pipeli
|
|
|
31
37
|
- `Rpc` - Cloudflare RPC type helpers, `RpcTarget` / `RpcStub` re-exports, and scoped disposal utilities
|
|
32
38
|
- `ServiceBinding` - typed Worker-to-Worker service binding helper
|
|
33
39
|
- `WorkerEnvironment` - request environment service
|
|
40
|
+
- `WorkerConfig` - Effect `Config` helpers backed by Cloudflare worker `env`, including `layerWith` for custom env-to-config mapping
|
|
34
41
|
|
|
35
42
|
## RPC Values
|
|
36
43
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Cause, Config, ConfigProvider, Context, Effect, Layer, Option, Schema, Scope } from "effect";
|
|
2
2
|
import { DurableObject, RpcStub, RpcTarget, WorkerEntrypoint } from "cloudflare:workers";
|
|
3
|
-
import { HttpServerRequest } from "effect/unstable/http";
|
|
3
|
+
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
4
4
|
import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
|
|
5
5
|
import * as RpcServer from "effect/unstable/rpc/RpcServer";
|
|
6
6
|
import * as _$effect_Types0 from "effect/Types";
|
|
@@ -63,6 +63,13 @@ declare namespace WorkerConfig {
|
|
|
63
63
|
const integer: <const Name extends Key>(name: Name) => Config.Config<number>;
|
|
64
64
|
/** Read a scalar Cloudflare var or secret as a boolean. */
|
|
65
65
|
const boolean: <const Name extends Key>(name: Name) => Config.Config<boolean>;
|
|
66
|
+
/** Build a `ConfigProvider` from a Cloudflare worker `env` object. */
|
|
67
|
+
const providerFromEnv: (env: WorkerEnv) => ConfigProvider.ConfigProvider;
|
|
68
|
+
/**
|
|
69
|
+
* Build a `ConfigProvider` from the current `WorkerEnvironment` with a custom
|
|
70
|
+
* conversion function.
|
|
71
|
+
*/
|
|
72
|
+
const providerWith: (makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider) => Effect.Effect<ConfigProvider.ConfigProvider, never, WorkerEnvironment>;
|
|
66
73
|
/** Build a `ConfigProvider` from the current `WorkerEnvironment`. */
|
|
67
74
|
const provider: Effect.Effect<ConfigProvider.ConfigProvider, never, WorkerEnvironment>;
|
|
68
75
|
/**
|
|
@@ -72,6 +79,8 @@ declare namespace WorkerConfig {
|
|
|
72
79
|
const providerLayer: _$effect_Layer0.Layer<never, never, WorkerEnvironment>;
|
|
73
80
|
/** Alias for `providerLayer` for concise use in worker layers. */
|
|
74
81
|
const layer: _$effect_Layer0.Layer<never, never, WorkerEnvironment>;
|
|
82
|
+
/** Build a `ConfigProvider` layer with a custom `env` conversion function. */
|
|
83
|
+
const layerWith: (makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider) => _$effect_Layer0.Layer<never, never, WorkerEnvironment>;
|
|
75
84
|
}
|
|
76
85
|
declare namespace Binding_d_exports {
|
|
77
86
|
export { BindingNotFoundError, BindingValidationError, Service$3 as Service, TypeId$2 as TypeId };
|
|
@@ -985,7 +994,7 @@ declare const Service$1: <Self, Api extends object = never>() => <Id extends str
|
|
|
985
994
|
readonly scopedCall: <Method extends ServiceMethodKey<ApiOrDefinition<Api, Definition>>>(method: Method, ...args: ServiceMethodArgs<ApiOrDefinition<Api, Definition>, Method>) => Effect.Effect<Awaited<Result<AsyncMethodSuccess<ApiOrDefinition<Api, Definition>, Method>>>, unknown, Self | _$effect_Scope0.Scope>;
|
|
986
995
|
};
|
|
987
996
|
declare namespace Worker_d_exports {
|
|
988
|
-
export { Api$1 as Api, Definition$1 as Definition, ExecutionContext, HandlerEffect$1 as HandlerEffect, Handlers$1 as Handlers, NativeRequest, Options$1 as Options, ReservedMethodName, RpcHandlers$1 as RpcHandlers, ServerApi$2 as ServerApi, Tag$1 as Tag, WorkerClass, WorkerContext, WorkerContextService, WorkerContextWaitUntilOptions, WorkerHandler, WorkerOptions, WorkerRpc, WorkerRpcHandler, WorkerRpcShape, implement$1 as implement, isWebSocketUpgrade, make$2 as make, method$1 as method };
|
|
997
|
+
export { Api$1 as Api, Definition$1 as Definition, ExecutionContext, FetchHandler, FetchWorkerOptions, HandlerEffect$1 as HandlerEffect, Handlers$1 as Handlers, NativeRequest, Options$1 as Options, ReservedMethodName, RpcHandlers$1 as RpcHandlers, ServerApi$2 as ServerApi, Tag$1 as Tag, WorkerClass, WorkerContext, WorkerContextService, WorkerContextWaitUntilOptions, WorkerFetchSuccess, WorkerHandler, WorkerOptions, WorkerRpc, WorkerRpcHandler, WorkerRpcShape, implement$1 as implement, isWebSocketUpgrade, make$2 as make, makeFetchHandler, method$1 as method, renderHttpResponse };
|
|
989
998
|
}
|
|
990
999
|
declare const ExecutionContext_base: Context.ServiceClass<ExecutionContext, "effect-cf/ExecutionContext", globalThis.ExecutionContext<unknown>>;
|
|
991
1000
|
declare class ExecutionContext extends ExecutionContext_base {}
|
|
@@ -1006,19 +1015,28 @@ type ReservedMethodName = ReservedMethodName$5 | "fetch" | "connect" | "alarm" |
|
|
|
1006
1015
|
type WorkerBaseContext<ROut> = ExecutionContext | WorkerContext | WorkerEnvironment | ROut;
|
|
1007
1016
|
type WorkerFetchContext<ROut> = WorkerBaseContext<ROut> | NativeRequest | HttpServerRequest.HttpServerRequest | Scope.Scope;
|
|
1008
1017
|
type WorkerRpcContext<ROut> = WorkerBaseContext<ROut> | Scope.Scope;
|
|
1009
|
-
type
|
|
1018
|
+
type WorkerFetchSuccess = Response | HttpServerResponse.HttpServerResponse;
|
|
1019
|
+
type WorkerHandler<ROut, A = WorkerFetchSuccess> = Effect.Effect<A, unknown, WorkerFetchContext<ROut>>;
|
|
1010
1020
|
type WorkerRpcHandler<ROut, A = unknown> = Effect.Effect<A, unknown, WorkerRpcContext<ROut>>;
|
|
1011
1021
|
type WorkerRpc<ROut> = Record<string, (...args: Array<any>) => WorkerRpcHandler<ROut>>;
|
|
1012
1022
|
type WorkerRpcShape<Rpc extends WorkerRpc<ROut>, ROut> = { readonly [Key in keyof Rpc]: Rpc[Key] extends ((...args: infer Args) => Effect.Effect<infer A, unknown, WorkerRpcContext<ROut>>) ? (...args: Args) => Promise<A> : never };
|
|
1013
1023
|
type RpcHandlers$1<ROut, Api> = { readonly [Key in keyof Api as Key extends keyof WorkerEntrypoint ? never : Key extends string ? Key extends ReservedMethodName ? never : [Api[Key]] extends [never] ? never : Api[Key] extends ((...args: Array<any>) => Promise<unknown>) ? Key : never : never]: Api[Key] extends ((...args: infer Args) => Promise<infer A>) ? (...args: Args) => WorkerRpcHandler<ROut, A> : never };
|
|
1014
1024
|
interface WorkerOptions<ROut, Rpc extends WorkerRpc<ROut>> {
|
|
1015
|
-
readonly fetch?: Effect.Effect<
|
|
1025
|
+
readonly fetch?: Effect.Effect<WorkerFetchSuccess, unknown, WorkerFetchContext<ROut>>;
|
|
1016
1026
|
readonly rpc?: Rpc;
|
|
1017
1027
|
}
|
|
1028
|
+
type FetchWorkerOptions<ROut> = Omit<WorkerOptions<ROut, Record<never, never>>, "rpc"> & {
|
|
1029
|
+
readonly rpc?: never;
|
|
1030
|
+
};
|
|
1018
1031
|
type WorkerClass<Rpc extends WorkerRpc<ROut>, ROut> = new (ctx: globalThis.ExecutionContext, env: WorkerEnv) => WorkerEntrypoint<WorkerEnv> & {
|
|
1019
1032
|
fetch(request: Request): Promise<Response>;
|
|
1020
1033
|
} & WorkerRpcShape<Rpc, ROut>;
|
|
1034
|
+
interface FetchHandler<Env extends WorkerEnv = WorkerEnv> {
|
|
1035
|
+
readonly fetch: (request: Request, env: Env, ctx: globalThis.ExecutionContext) => Promise<Response>;
|
|
1036
|
+
}
|
|
1037
|
+
declare const renderHttpResponse: <A extends HttpServerResponse.HttpServerResponse, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<Response, E, R>;
|
|
1021
1038
|
declare const make$2: <ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Record<never, never>>(layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>, options: WorkerOptions<ROut, Rpc>) => WorkerClass<Rpc, ROut>;
|
|
1039
|
+
declare const makeFetchHandler: <ROut, LayerError, Env extends WorkerEnv = WorkerEnv>(layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>, options: FetchWorkerOptions<ROut>) => FetchHandler<Env>;
|
|
1022
1040
|
declare const Tag$1: <_Self>() => <Id extends string, const MethodsShape extends Methods>(id: Id, methods: MethodsShape & NoReservedMethods<MethodsShape, ReservedMethodName$2>) => (abstract new () => object) & (Definition$2<Id, MethodsShape> & {
|
|
1023
1041
|
make: <ROut, LayerError>(layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>, options: Options$2<ROut, Definition$2<Id, MethodsShape>>) => WorkerClass<{ readonly [Key in keyof MethodsShape]: (...args: Array<unknown>) => WorkerRpcHandler<ROut, _$effect_Schema0.Codec.Encoded<MethodsShape[Key]["success"]>> }, ROut>;
|
|
1024
1042
|
Binding: <Self>() => <BindingId extends string>(bindingId: BindingId, binding: Omit<ServiceBindingDefinition<Definition$2<Id, MethodsShape>>, "definition">) => Context.ServiceClass<Self, BindingId, ServiceBindingClient<[Api$2<Definition$2<Id, MethodsShape>>] extends [never] ? Definition$2<Id, MethodsShape> extends infer T ? T extends Definition$2<Id, MethodsShape> ? T extends Definition$4.Any ? ServerApi$3<T> : never : never : never : Api$2<Definition$2<Id, MethodsShape>>>> & {
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
|
|
2
2
|
import { Cause, Config, ConfigProvider, Context, Data, Effect, Exit, Layer, ManagedRuntime, Option, Queue, Schema } from "effect";
|
|
3
3
|
import { DurableObject, RpcStub, RpcTarget, WorkerEntrypoint } from "cloudflare:workers";
|
|
4
|
-
import { HttpServerRequest } from "effect/unstable/http";
|
|
4
|
+
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
5
5
|
import * as RpcMessage from "effect/unstable/rpc/RpcMessage";
|
|
6
6
|
import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
|
|
7
7
|
import * as RpcServer from "effect/unstable/rpc/RpcServer";
|
|
@@ -17,8 +17,11 @@ let WorkerConfig;
|
|
|
17
17
|
_WorkerConfig.number = (name) => Config.number(name);
|
|
18
18
|
_WorkerConfig.integer = (name) => Config.int(name);
|
|
19
19
|
_WorkerConfig.boolean = (name) => Config.boolean(name);
|
|
20
|
-
const
|
|
20
|
+
const providerFromEnv = _WorkerConfig.providerFromEnv = (env) => ConfigProvider.fromUnknown(env);
|
|
21
|
+
const providerWith = _WorkerConfig.providerWith = (makeProvider) => Effect.map(WorkerEnvironment.asEffect(), makeProvider);
|
|
22
|
+
const provider = _WorkerConfig.provider = providerWith(providerFromEnv);
|
|
21
23
|
_WorkerConfig.layer = _WorkerConfig.providerLayer = ConfigProvider.layer(provider);
|
|
24
|
+
_WorkerConfig.layerWith = (makeProvider) => ConfigProvider.layer(providerWith(makeProvider));
|
|
22
25
|
})(WorkerConfig || (WorkerConfig = {}));
|
|
23
26
|
//#endregion
|
|
24
27
|
//#region src/Binding.ts
|
|
@@ -430,7 +433,9 @@ var Worker_exports = /* @__PURE__ */ __exportAll({
|
|
|
430
433
|
implement: () => implement$2,
|
|
431
434
|
isWebSocketUpgrade: () => isWebSocketUpgrade,
|
|
432
435
|
make: () => make$3,
|
|
433
|
-
|
|
436
|
+
makeFetchHandler: () => makeFetchHandler,
|
|
437
|
+
method: () => method$2,
|
|
438
|
+
renderHttpResponse: () => renderHttpResponse
|
|
434
439
|
});
|
|
435
440
|
var ExecutionContext = class extends Context.Service()("effect-cf/ExecutionContext") {};
|
|
436
441
|
var WorkerContext = class extends Context.Service()("effect-cf/WorkerContext") {};
|
|
@@ -460,13 +465,15 @@ const reservedMethodNames$2 = new Set([
|
|
|
460
465
|
"webSocketError"
|
|
461
466
|
]);
|
|
462
467
|
const RunSymbol$1 = Symbol.for("effect-cf/Worker/run");
|
|
468
|
+
const renderHttpResponse = (effect) => Effect.flatMap(effect, (response) => Effect.map(Effect.context(), (context) => HttpServerResponse.toWeb(response, { context })));
|
|
469
|
+
const renderFetchSuccess = (effect) => Effect.flatMap(effect, (response) => response instanceof Response ? Effect.succeed(response) : Effect.map(Effect.context(), (context) => HttpServerResponse.toWeb(response, { context })));
|
|
463
470
|
const make$3 = (layer, options) => {
|
|
464
471
|
class EffectWorker extends WorkerEntrypoint {
|
|
465
472
|
runtime;
|
|
466
473
|
constructor(ctx, env) {
|
|
467
474
|
super(ctx, env);
|
|
468
475
|
let runWaitUntilEffect = () => Promise.resolve(Exit.die(/* @__PURE__ */ new Error("WorkerContext runtime is not initialized")));
|
|
469
|
-
const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(Layer.succeed(ExecutionContext, ctx), Layer.succeed(WorkerContext, fromExecutionContext(ctx, (effect) => runWaitUntilEffect(effect))), Layer.succeed(WorkerEnvironment, env)));
|
|
476
|
+
const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(Layer.succeed(ExecutionContext, ctx), ConfigProvider.layer(Effect.succeed(WorkerConfig.providerFromEnv(env))), Layer.succeed(WorkerContext, fromExecutionContext(ctx, (effect) => runWaitUntilEffect(effect))), Layer.succeed(WorkerEnvironment, env)));
|
|
470
477
|
this.runtime = ManagedRuntime.make(runtimeLayer);
|
|
471
478
|
runWaitUntilEffect = (effect) => this.runtime.runPromiseExit(effect);
|
|
472
479
|
}
|
|
@@ -476,12 +483,17 @@ const make$3 = (layer, options) => {
|
|
|
476
483
|
fetch(request) {
|
|
477
484
|
const fetchHandler = options.fetch;
|
|
478
485
|
if (fetchHandler === void 0) return Promise.resolve(new Response("Not Found", { status: 404 }));
|
|
479
|
-
|
|
486
|
+
const requestServices = Layer.mergeAll(Layer.succeed(NativeRequest, request), Layer.succeed(HttpServerRequest.HttpServerRequest, HttpServerRequest.fromWeb(request)));
|
|
487
|
+
return this[RunSymbol$1](renderFetchSuccess(fetchHandler).pipe(Effect.provide(requestServices)));
|
|
480
488
|
}
|
|
481
489
|
}
|
|
482
490
|
defineEntrypointRpcMethods("Worker", EffectWorker.prototype, options.rpc, reservedMethodNames$2, (self, effect) => self[RunSymbol$1](effect));
|
|
483
491
|
return assumeEntrypointClass(EffectWorker);
|
|
484
492
|
};
|
|
493
|
+
const makeFetchHandler = (layer, options) => {
|
|
494
|
+
const WorkerClass = make$3(layer, options);
|
|
495
|
+
return { fetch: (request, env, ctx) => Promise.resolve(new WorkerClass(ctx, env).fetch(request)) };
|
|
496
|
+
};
|
|
485
497
|
const Tag$2 = Tag$3;
|
|
486
498
|
const method$2 = method$3;
|
|
487
499
|
const implement$2 = implement$3;
|
package/package.json
CHANGED
package/src/Environment.ts
CHANGED
|
@@ -72,8 +72,18 @@ export namespace WorkerConfig {
|
|
|
72
72
|
/** Read a scalar Cloudflare var or secret as a boolean. */
|
|
73
73
|
export const boolean = <const Name extends Key>(name: Name) => Config.boolean(name);
|
|
74
74
|
|
|
75
|
+
/** Build a `ConfigProvider` from a Cloudflare worker `env` object. */
|
|
76
|
+
export const providerFromEnv = (env: WorkerEnv) => ConfigProvider.fromUnknown(env);
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Build a `ConfigProvider` from the current `WorkerEnvironment` with a custom
|
|
80
|
+
* conversion function.
|
|
81
|
+
*/
|
|
82
|
+
export const providerWith = (makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider) =>
|
|
83
|
+
Effect.map(WorkerEnvironment.asEffect(), makeProvider);
|
|
84
|
+
|
|
75
85
|
/** Build a `ConfigProvider` from the current `WorkerEnvironment`. */
|
|
76
|
-
export const provider =
|
|
86
|
+
export const provider = providerWith(providerFromEnv);
|
|
77
87
|
|
|
78
88
|
/**
|
|
79
89
|
* Replace the active Effect `ConfigProvider` with one backed by the current
|
|
@@ -83,4 +93,8 @@ export namespace WorkerConfig {
|
|
|
83
93
|
|
|
84
94
|
/** Alias for `providerLayer` for concise use in worker layers. */
|
|
85
95
|
export const layer = providerLayer;
|
|
96
|
+
|
|
97
|
+
/** Build a `ConfigProvider` layer with a custom `env` conversion function. */
|
|
98
|
+
export const layerWith = (makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider) =>
|
|
99
|
+
ConfigProvider.layer(providerWith(makeProvider));
|
|
86
100
|
}
|
package/src/Worker.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { WorkerEntrypoint as CloudflareWorkerEntrypoint } from "cloudflare:workers";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import {
|
|
3
|
+
Cause,
|
|
4
|
+
ConfigProvider,
|
|
5
|
+
Context,
|
|
6
|
+
Effect,
|
|
7
|
+
Exit,
|
|
8
|
+
Layer,
|
|
9
|
+
ManagedRuntime,
|
|
10
|
+
type Scope,
|
|
11
|
+
} from "effect";
|
|
12
|
+
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
13
|
+
|
|
14
|
+
import { WorkerConfig, WorkerEnvironment, type WorkerEnv } from "./Environment";
|
|
6
15
|
import type * as RpcDefinition from "./RpcDefinition";
|
|
7
16
|
import * as WorkerDefinition from "./WorkerDefinition";
|
|
8
17
|
import * as Entrypoint from "./internal/Entrypoint";
|
|
@@ -122,7 +131,13 @@ type RuntimeContext<ROut> = WorkerBaseContext<ROut>;
|
|
|
122
131
|
|
|
123
132
|
const RunSymbol = Symbol.for("effect-cf/Worker/run");
|
|
124
133
|
|
|
125
|
-
export type
|
|
134
|
+
export type WorkerFetchSuccess = Response | HttpServerResponse.HttpServerResponse;
|
|
135
|
+
|
|
136
|
+
export type WorkerHandler<ROut, A = WorkerFetchSuccess> = Effect.Effect<
|
|
137
|
+
A,
|
|
138
|
+
unknown,
|
|
139
|
+
WorkerFetchContext<ROut>
|
|
140
|
+
>;
|
|
126
141
|
|
|
127
142
|
export type WorkerRpcHandler<ROut, A = unknown> = Effect.Effect<A, unknown, WorkerRpcContext<ROut>>;
|
|
128
143
|
|
|
@@ -153,10 +168,14 @@ export type RpcHandlers<ROut, Api> = {
|
|
|
153
168
|
};
|
|
154
169
|
|
|
155
170
|
export interface WorkerOptions<ROut, Rpc extends WorkerRpc<ROut>> {
|
|
156
|
-
readonly fetch?: Effect.Effect<
|
|
171
|
+
readonly fetch?: Effect.Effect<WorkerFetchSuccess, unknown, WorkerFetchContext<ROut>>;
|
|
157
172
|
readonly rpc?: Rpc;
|
|
158
173
|
}
|
|
159
174
|
|
|
175
|
+
export type FetchWorkerOptions<ROut> = Omit<WorkerOptions<ROut, Record<never, never>>, "rpc"> & {
|
|
176
|
+
readonly rpc?: never;
|
|
177
|
+
};
|
|
178
|
+
|
|
160
179
|
export type WorkerClass<Rpc extends WorkerRpc<ROut>, ROut> = new (
|
|
161
180
|
ctx: globalThis.ExecutionContext,
|
|
162
181
|
env: WorkerEnv,
|
|
@@ -164,6 +183,34 @@ export type WorkerClass<Rpc extends WorkerRpc<ROut>, ROut> = new (
|
|
|
164
183
|
fetch(request: Request): Promise<Response>;
|
|
165
184
|
} & WorkerRpcShape<Rpc, ROut>;
|
|
166
185
|
|
|
186
|
+
export interface FetchHandler<Env extends WorkerEnv = WorkerEnv> {
|
|
187
|
+
readonly fetch: (
|
|
188
|
+
request: Request,
|
|
189
|
+
env: Env,
|
|
190
|
+
ctx: globalThis.ExecutionContext,
|
|
191
|
+
) => Promise<Response>;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export const renderHttpResponse = <A extends HttpServerResponse.HttpServerResponse, E, R>(
|
|
195
|
+
effect: Effect.Effect<A, E, R>,
|
|
196
|
+
): Effect.Effect<Response, E, R> =>
|
|
197
|
+
Effect.flatMap(effect, (response) =>
|
|
198
|
+
Effect.map(Effect.context<never>(), (context) =>
|
|
199
|
+
HttpServerResponse.toWeb(response, { context }),
|
|
200
|
+
),
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const renderFetchSuccess = <E, R>(
|
|
204
|
+
effect: Effect.Effect<WorkerFetchSuccess, E, R>,
|
|
205
|
+
): Effect.Effect<Response, E, R> =>
|
|
206
|
+
Effect.flatMap(effect, (response) =>
|
|
207
|
+
response instanceof Response
|
|
208
|
+
? Effect.succeed(response)
|
|
209
|
+
: Effect.map(Effect.context<never>(), (context) =>
|
|
210
|
+
HttpServerResponse.toWeb(response, { context }),
|
|
211
|
+
),
|
|
212
|
+
);
|
|
213
|
+
|
|
167
214
|
export const make = <ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Record<never, never>>(
|
|
168
215
|
layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>,
|
|
169
216
|
options: WorkerOptions<ROut, Rpc>,
|
|
@@ -179,14 +226,19 @@ export const make = <ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Recor
|
|
|
179
226
|
|
|
180
227
|
const services = Layer.mergeAll(
|
|
181
228
|
Layer.succeed(ExecutionContext, ctx),
|
|
229
|
+
ConfigProvider.layer(Effect.succeed(WorkerConfig.providerFromEnv(env))),
|
|
182
230
|
Layer.succeed(
|
|
183
231
|
WorkerContext,
|
|
184
232
|
fromExecutionContext(ctx, (effect) => runWaitUntilEffect(effect)),
|
|
185
233
|
),
|
|
186
234
|
Layer.succeed(WorkerEnvironment, env),
|
|
187
|
-
)
|
|
235
|
+
) as Layer.Layer<ExecutionContext | WorkerContext | WorkerEnvironment, never, never>;
|
|
188
236
|
|
|
189
|
-
const runtimeLayer = Entrypoint.provideEntrypointServices
|
|
237
|
+
const runtimeLayer = Entrypoint.provideEntrypointServices<
|
|
238
|
+
ROut,
|
|
239
|
+
LayerError,
|
|
240
|
+
ExecutionContext | WorkerContext | WorkerEnvironment
|
|
241
|
+
>(layer, services);
|
|
190
242
|
|
|
191
243
|
this.runtime = ManagedRuntime.make(runtimeLayer);
|
|
192
244
|
runWaitUntilEffect = <A, E>(effect: Effect.Effect<A, E, never>) =>
|
|
@@ -204,14 +256,17 @@ export const make = <ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Recor
|
|
|
204
256
|
return Promise.resolve(new Response("Not Found", { status: 404 }));
|
|
205
257
|
}
|
|
206
258
|
|
|
259
|
+
const requestServices = Layer.mergeAll(
|
|
260
|
+
Layer.succeed(NativeRequest, request),
|
|
261
|
+
Layer.succeed(HttpServerRequest.HttpServerRequest, HttpServerRequest.fromWeb(request)),
|
|
262
|
+
);
|
|
263
|
+
|
|
207
264
|
return this[RunSymbol](
|
|
208
|
-
fetchHandler.pipe(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
),
|
|
214
|
-
),
|
|
265
|
+
renderFetchSuccess(fetchHandler).pipe(Effect.provide(requestServices)) as Effect.Effect<
|
|
266
|
+
Response,
|
|
267
|
+
unknown,
|
|
268
|
+
RuntimeContext<ROut> | Scope.Scope
|
|
269
|
+
>,
|
|
215
270
|
);
|
|
216
271
|
}
|
|
217
272
|
}
|
|
@@ -227,6 +282,17 @@ export const make = <ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Recor
|
|
|
227
282
|
return Entrypoint.assumeEntrypointClass<WorkerClass<Rpc, ROut>>(EffectWorker);
|
|
228
283
|
};
|
|
229
284
|
|
|
285
|
+
export const makeFetchHandler = <ROut, LayerError, Env extends WorkerEnv = WorkerEnv>(
|
|
286
|
+
layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>,
|
|
287
|
+
options: FetchWorkerOptions<ROut>,
|
|
288
|
+
): FetchHandler<Env> => {
|
|
289
|
+
const WorkerClass = make(layer, options);
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
fetch: (request, env, ctx) => Promise.resolve(new WorkerClass(ctx, env).fetch(request)),
|
|
293
|
+
};
|
|
294
|
+
};
|
|
295
|
+
|
|
230
296
|
export const Tag = WorkerDefinition.Tag;
|
|
231
297
|
|
|
232
298
|
export const method = WorkerDefinition.method;
|