effect-cf 0.1.0 → 0.3.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 +27 -0
- package/README.md +139 -1
- package/dist/index.d.mts +904 -311
- package/dist/index.mjs +616 -127
- package/package.json +3 -2
- package/src/DurableObject.ts +9 -6
- package/src/DurableObjectRpcWebSocket.ts +21 -17
- package/src/DurableObjectState.ts +12 -10
- package/src/DurableObjectWebSocket.ts +203 -6
- package/src/Queue.ts +116 -0
- package/src/QueueBinding.ts +131 -0
- package/src/QueueDefinition.ts +129 -0
- package/src/Worker.ts +57 -68
- package/src/WorkerDefinition.ts +6 -0
- package/src/Workflow.ts +279 -0
- package/src/WorkflowBinding.ts +254 -0
- package/src/WorkflowDefinition.ts +167 -0
- package/src/index.ts +6 -0
- package/src/internal/WorkerContext.ts +83 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Data, Effect, Schema as S } from "effect";
|
|
2
|
+
|
|
3
|
+
import * as Binding from "./Binding";
|
|
4
|
+
import type * as RpcDefinition from "./RpcDefinition";
|
|
5
|
+
|
|
6
|
+
const TypeId = "effect-cf/QueueBinding" as const;
|
|
7
|
+
|
|
8
|
+
export type QueueSendOptions = globalThis.QueueSendOptions;
|
|
9
|
+
export type QueueSendResponse = globalThis.QueueSendResponse;
|
|
10
|
+
export type QueueSendBatchOptions = globalThis.QueueSendBatchOptions;
|
|
11
|
+
export type QueueSendBatchResponse = globalThis.QueueSendBatchResponse;
|
|
12
|
+
export type QueueMetrics = globalThis.QueueMetrics;
|
|
13
|
+
export type MessageSendRequest<Body> = globalThis.MessageSendRequest<Body>;
|
|
14
|
+
|
|
15
|
+
export interface QueueBindingDefinition<Message extends RpcDefinition.ServiceFreeSchema> {
|
|
16
|
+
/** Binding name as configured in `wrangler.jsonc`. */
|
|
17
|
+
readonly binding: string;
|
|
18
|
+
/** Codec used to encode messages before sending them to Cloudflare Queues. */
|
|
19
|
+
readonly message: Message;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare const QueueServiceTypeId: unique symbol;
|
|
23
|
+
|
|
24
|
+
/** Nominal service marker for Queue services created with {@link make}. */
|
|
25
|
+
export interface QueueService<Id extends string, Message extends RpcDefinition.ServiceFreeSchema> {
|
|
26
|
+
readonly [QueueServiceTypeId]: {
|
|
27
|
+
readonly id: Id;
|
|
28
|
+
readonly message: S.Schema.Type<Message>;
|
|
29
|
+
readonly encodedMessage: S.Codec.Encoded<Message>;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class QueueOperationError extends Data.TaggedError("QueueOperationError")<{
|
|
34
|
+
readonly binding: string;
|
|
35
|
+
readonly operation: string;
|
|
36
|
+
readonly cause: unknown;
|
|
37
|
+
}> {}
|
|
38
|
+
|
|
39
|
+
const queueError = (binding: string, operation: string, cause: unknown) =>
|
|
40
|
+
new QueueOperationError({ binding, operation, cause });
|
|
41
|
+
|
|
42
|
+
const tryQueuePromise = <A>(
|
|
43
|
+
binding: string,
|
|
44
|
+
operation: string,
|
|
45
|
+
evaluate: () => Promise<A>,
|
|
46
|
+
): Effect.Effect<A, QueueOperationError> =>
|
|
47
|
+
Effect.tryPromise({
|
|
48
|
+
try: evaluate,
|
|
49
|
+
catch: (cause) => queueError(binding, operation, cause),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const isQueue = <Body>(value: unknown): value is globalThis.Queue<Body> => {
|
|
53
|
+
if (typeof value !== "object" || value === null) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const resource = value as Record<string, unknown>;
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
typeof resource.send === "function" &&
|
|
61
|
+
typeof resource.sendBatch === "function" &&
|
|
62
|
+
typeof resource.metrics === "function"
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** Creates a typed Queue binding service tag plus Effect helpers. */
|
|
67
|
+
export const make = <Id extends string, Message extends RpcDefinition.ServiceFreeSchema>(
|
|
68
|
+
id: Id,
|
|
69
|
+
definition: QueueBindingDefinition<Message>,
|
|
70
|
+
) => Service<QueueService<Id, Message>>()<Id, Message>(id, definition);
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Builds an Effect service around a Cloudflare Queue producer binding.
|
|
74
|
+
*/
|
|
75
|
+
export const Service =
|
|
76
|
+
<Self>() =>
|
|
77
|
+
<Id extends string, Message extends RpcDefinition.ServiceFreeSchema>(
|
|
78
|
+
id: Id,
|
|
79
|
+
definition: QueueBindingDefinition<Message>,
|
|
80
|
+
) => {
|
|
81
|
+
type Body = S.Schema.Type<Message>;
|
|
82
|
+
type EncodedBody = S.Codec.Encoded<Message>;
|
|
83
|
+
|
|
84
|
+
const tag = Binding.Service<Self>()(
|
|
85
|
+
id,
|
|
86
|
+
definition.binding,
|
|
87
|
+
(value): value is globalThis.Queue<EncodedBody> => isQueue<EncodedBody>(value),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const encodeMessage = S.encodeEffect(definition.message);
|
|
91
|
+
|
|
92
|
+
const send = Effect.fnUntraced(function* (message: Body, options?: QueueSendOptions) {
|
|
93
|
+
const queue = yield* tag;
|
|
94
|
+
const encoded = yield* encodeMessage(message);
|
|
95
|
+
|
|
96
|
+
return yield* tryQueuePromise(definition.binding, "send", () => queue.send(encoded, options));
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const sendBatch = Effect.fnUntraced(function* (
|
|
100
|
+
messages: Iterable<MessageSendRequest<Body>>,
|
|
101
|
+
options?: QueueSendBatchOptions,
|
|
102
|
+
) {
|
|
103
|
+
const queue = yield* tag;
|
|
104
|
+
const encodedMessages: Array<MessageSendRequest<EncodedBody>> = [];
|
|
105
|
+
|
|
106
|
+
for (const message of messages) {
|
|
107
|
+
encodedMessages.push({
|
|
108
|
+
...message,
|
|
109
|
+
body: yield* encodeMessage(message.body),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return yield* tryQueuePromise(definition.binding, "sendBatch", () =>
|
|
114
|
+
queue.sendBatch(encodedMessages, options),
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const metrics = Effect.fnUntraced(function* () {
|
|
119
|
+
const queue = yield* tag;
|
|
120
|
+
|
|
121
|
+
return yield* tryQueuePromise(definition.binding, "metrics", () => queue.metrics());
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return Object.assign(tag, {
|
|
125
|
+
[TypeId]: TypeId,
|
|
126
|
+
binding: definition.binding,
|
|
127
|
+
send,
|
|
128
|
+
sendBatch,
|
|
129
|
+
metrics,
|
|
130
|
+
});
|
|
131
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Effect, Schema as S, type Layer, type Scope } from "effect";
|
|
2
|
+
|
|
3
|
+
import type { WorkerEnvironment } from "./Environment";
|
|
4
|
+
import * as QueueEntrypoint from "./Queue";
|
|
5
|
+
import * as QueueBinding from "./QueueBinding";
|
|
6
|
+
import type { ExecutionContext, WorkerContext } from "./Worker";
|
|
7
|
+
import * as WorkerEntrypoint from "./Worker";
|
|
8
|
+
import type * as RpcDefinition from "./RpcDefinition";
|
|
9
|
+
|
|
10
|
+
export interface Definition<
|
|
11
|
+
Id extends string = string,
|
|
12
|
+
Message extends RpcDefinition.ServiceFreeSchema = RpcDefinition.ServiceFreeSchema,
|
|
13
|
+
> {
|
|
14
|
+
readonly id: Id;
|
|
15
|
+
readonly message: Message;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export namespace Definition {
|
|
19
|
+
export type Any = Definition<string, RpcDefinition.ServiceFreeSchema>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare const BindingServiceTypeId: unique symbol;
|
|
23
|
+
|
|
24
|
+
export interface BindingService<Id extends string, Self extends Definition.Any> {
|
|
25
|
+
readonly [BindingServiceTypeId]: {
|
|
26
|
+
readonly id: Id;
|
|
27
|
+
readonly definition: Self;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type Handler<ROut, Self extends Definition.Any> = (
|
|
32
|
+
batch: QueueEntrypoint.QueueBatch<S.Schema.Type<Self["message"]>>,
|
|
33
|
+
) => Effect.Effect<
|
|
34
|
+
void,
|
|
35
|
+
unknown,
|
|
36
|
+
ExecutionContext | WorkerEntrypoint.WorkerContext | WorkerEnvironment | Scope.Scope | ROut
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
export interface Options<ROut, Self extends Definition.Any> extends Omit<
|
|
40
|
+
WorkerEntrypoint.WorkerOptions<ROut, Record<never, never>>,
|
|
41
|
+
"queue" | "rpc"
|
|
42
|
+
> {
|
|
43
|
+
readonly queue: Handler<ROut, Self>;
|
|
44
|
+
readonly rpc?: never;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const makeDefinition = <Id extends string, Message extends RpcDefinition.ServiceFreeSchema>(
|
|
48
|
+
id: Id,
|
|
49
|
+
definition: { readonly message: Message },
|
|
50
|
+
) => {
|
|
51
|
+
type SelfDefinition = Definition<Id, Message>;
|
|
52
|
+
const queueDefinition: SelfDefinition = {
|
|
53
|
+
id,
|
|
54
|
+
message: definition.message,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return Object.assign(queueDefinition, {
|
|
58
|
+
make: <ROut, LayerError>(
|
|
59
|
+
layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>,
|
|
60
|
+
options: Options<ROut, SelfDefinition>,
|
|
61
|
+
) =>
|
|
62
|
+
WorkerEntrypoint.make(layer, {
|
|
63
|
+
...options,
|
|
64
|
+
queue: wrapHandler(queueDefinition, options.queue),
|
|
65
|
+
}),
|
|
66
|
+
Binding:
|
|
67
|
+
<Self>() =>
|
|
68
|
+
<BindingId extends string>(
|
|
69
|
+
bindingId: BindingId,
|
|
70
|
+
binding: Omit<QueueBinding.QueueBindingDefinition<Message>, "message">,
|
|
71
|
+
) =>
|
|
72
|
+
QueueBinding.Service<Self>()<BindingId, Message>(bindingId, {
|
|
73
|
+
...binding,
|
|
74
|
+
message: definition.message,
|
|
75
|
+
}),
|
|
76
|
+
binding: <BindingId extends string>(
|
|
77
|
+
bindingId: BindingId,
|
|
78
|
+
binding: Omit<QueueBinding.QueueBindingDefinition<Message>, "message">,
|
|
79
|
+
) =>
|
|
80
|
+
QueueBinding.Service<BindingService<BindingId, SelfDefinition>>()<BindingId, Message>(
|
|
81
|
+
bindingId,
|
|
82
|
+
{
|
|
83
|
+
...binding,
|
|
84
|
+
message: definition.message,
|
|
85
|
+
},
|
|
86
|
+
),
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const make = makeDefinition;
|
|
91
|
+
|
|
92
|
+
export const Tag =
|
|
93
|
+
<_Self>() =>
|
|
94
|
+
<Id extends string, Message extends RpcDefinition.ServiceFreeSchema>(
|
|
95
|
+
id: Id,
|
|
96
|
+
definition: { readonly message: Message },
|
|
97
|
+
) => {
|
|
98
|
+
const queueDefinition = makeDefinition(id, definition);
|
|
99
|
+
|
|
100
|
+
abstract class QueueDefinitionClass {
|
|
101
|
+
static readonly id = queueDefinition.id;
|
|
102
|
+
static readonly message = queueDefinition.message;
|
|
103
|
+
static readonly make = queueDefinition.make;
|
|
104
|
+
static readonly Binding = queueDefinition.Binding;
|
|
105
|
+
static readonly binding = queueDefinition.binding;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return QueueDefinitionClass as (abstract new () => object) & typeof queueDefinition;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const Queue = Tag;
|
|
112
|
+
|
|
113
|
+
const wrapHandler = <ROut, const Self extends Definition.Any>(
|
|
114
|
+
definition: Self,
|
|
115
|
+
handler: Handler<ROut, Self>,
|
|
116
|
+
): QueueEntrypoint.QueueHandler<ROut> => {
|
|
117
|
+
const decodeBody = S.decodeUnknownEffect(definition.message);
|
|
118
|
+
|
|
119
|
+
return (batch) =>
|
|
120
|
+
Effect.gen(function* () {
|
|
121
|
+
const decoded = yield* QueueEntrypoint.decodeBatch(batch.raw, decodeBody);
|
|
122
|
+
yield* handler(decoded);
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const implement = <ROut, const Self extends Definition.Any>(
|
|
127
|
+
_definition: Self,
|
|
128
|
+
handler: Handler<ROut, Self>,
|
|
129
|
+
): Handler<ROut, Self> => handler;
|
package/src/Worker.ts
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
import { WorkerEntrypoint as CloudflareWorkerEntrypoint } from "cloudflare:workers";
|
|
2
|
-
import {
|
|
3
|
-
Cause,
|
|
4
|
-
ConfigProvider,
|
|
5
|
-
Context,
|
|
6
|
-
Effect,
|
|
7
|
-
Exit,
|
|
8
|
-
Layer,
|
|
9
|
-
ManagedRuntime,
|
|
10
|
-
type Scope,
|
|
11
|
-
} from "effect";
|
|
2
|
+
import { Cause, ConfigProvider, Context, Effect, Layer, ManagedRuntime, type Scope } from "effect";
|
|
12
3
|
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
13
4
|
|
|
14
5
|
import { WorkerConfig, WorkerEnvironment, type WorkerEnv } from "./Environment";
|
|
6
|
+
import { fromMessage, fromMessageBatch, type QueueHandler } from "./Queue";
|
|
15
7
|
import type * as RpcDefinition from "./RpcDefinition";
|
|
16
8
|
import * as WorkerDefinition from "./WorkerDefinition";
|
|
17
9
|
import * as Entrypoint from "./internal/Entrypoint";
|
|
10
|
+
import { fromExecutionContext, type RunWaitUntilEffect } from "./internal/WorkerContext";
|
|
18
11
|
|
|
19
12
|
export class ExecutionContext extends Context.Service<
|
|
20
13
|
ExecutionContext,
|
|
@@ -22,6 +15,7 @@ export class ExecutionContext extends Context.Service<
|
|
|
22
15
|
>()("effect-cf/ExecutionContext") {}
|
|
23
16
|
|
|
24
17
|
export interface WorkerContextWaitUntilOptions<E, R> {
|
|
18
|
+
readonly mode?: "observe" | "propagate";
|
|
25
19
|
readonly onFailure?: (cause: Cause.Cause<E>) => Effect.Effect<void, never, R>;
|
|
26
20
|
}
|
|
27
21
|
|
|
@@ -31,6 +25,10 @@ export interface WorkerContextService {
|
|
|
31
25
|
effect: Effect.Effect<A, E, R>,
|
|
32
26
|
options?: WorkerContextWaitUntilOptions<E, R2>,
|
|
33
27
|
): Effect.Effect<void, never, R | R2>;
|
|
28
|
+
waitUntilPropagating<A, E, R, R2 = never>(
|
|
29
|
+
effect: Effect.Effect<A, E, R>,
|
|
30
|
+
options?: Omit<WorkerContextWaitUntilOptions<E, R2>, "mode">,
|
|
31
|
+
): Effect.Effect<void, never, R | R2>;
|
|
34
32
|
readonly passThroughOnException: Effect.Effect<void>;
|
|
35
33
|
}
|
|
36
34
|
|
|
@@ -38,60 +36,6 @@ export class WorkerContext extends Context.Service<WorkerContext, WorkerContextS
|
|
|
38
36
|
"effect-cf/WorkerContext",
|
|
39
37
|
) {}
|
|
40
38
|
|
|
41
|
-
type RunWaitUntilEffect = <A, E>(
|
|
42
|
-
effect: Effect.Effect<A, E, never>,
|
|
43
|
-
) => Promise<Exit.Exit<A, unknown>>;
|
|
44
|
-
|
|
45
|
-
const fromExecutionContext = (
|
|
46
|
-
ctx: globalThis.ExecutionContext,
|
|
47
|
-
runPromiseExit: RunWaitUntilEffect,
|
|
48
|
-
): WorkerContextService => ({
|
|
49
|
-
raw: ctx,
|
|
50
|
-
waitUntil: <A, E, R, R2 = never>(
|
|
51
|
-
effect: Effect.Effect<A, E, R>,
|
|
52
|
-
options?: WorkerContextWaitUntilOptions<E, R2>,
|
|
53
|
-
) =>
|
|
54
|
-
Effect.context<R | R2>().pipe(
|
|
55
|
-
Effect.flatMap((context) =>
|
|
56
|
-
Effect.sync(() => {
|
|
57
|
-
const observed = Effect.exit(effect).pipe(
|
|
58
|
-
Effect.flatMap((exit) => {
|
|
59
|
-
if (Exit.isSuccess(exit)) {
|
|
60
|
-
return Effect.void;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const handleFailure =
|
|
64
|
-
options?.onFailure?.(exit.cause) ??
|
|
65
|
-
Effect.logError("WorkerContext.waitUntil failed", Cause.pretty(exit.cause));
|
|
66
|
-
|
|
67
|
-
return handleFailure.pipe(
|
|
68
|
-
Effect.catchCause((handlerCause) =>
|
|
69
|
-
Effect.logError(
|
|
70
|
-
"WorkerContext.waitUntil failure handler failed",
|
|
71
|
-
Cause.pretty(exit.cause),
|
|
72
|
-
Cause.pretty(handlerCause),
|
|
73
|
-
),
|
|
74
|
-
),
|
|
75
|
-
);
|
|
76
|
-
}),
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
ctx.waitUntil(
|
|
80
|
-
runPromiseExit(Effect.scoped(Effect.provideContext(observed, context))).then((exit) => {
|
|
81
|
-
if (Exit.isFailure(exit)) {
|
|
82
|
-
console.error(
|
|
83
|
-
"WorkerContext.waitUntil failure handler failed",
|
|
84
|
-
Cause.pretty(exit.cause),
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
}),
|
|
88
|
-
);
|
|
89
|
-
}),
|
|
90
|
-
),
|
|
91
|
-
),
|
|
92
|
-
passThroughOnException: Effect.sync(() => ctx.passThroughOnException()),
|
|
93
|
-
});
|
|
94
|
-
|
|
95
39
|
export class NativeRequest extends Context.Service<NativeRequest, Request>()(
|
|
96
40
|
"effect-cf/NativeRequest",
|
|
97
41
|
) {}
|
|
@@ -103,6 +47,12 @@ export type ReservedMethodName =
|
|
|
103
47
|
| RpcDefinition.ReservedMethodName
|
|
104
48
|
| "fetch"
|
|
105
49
|
| "connect"
|
|
50
|
+
| "queue"
|
|
51
|
+
| "scheduled"
|
|
52
|
+
| "tail"
|
|
53
|
+
| "tailStream"
|
|
54
|
+
| "test"
|
|
55
|
+
| "trace"
|
|
106
56
|
| "alarm"
|
|
107
57
|
| "webSocketMessage"
|
|
108
58
|
| "webSocketClose"
|
|
@@ -113,6 +63,12 @@ const reservedMethodNames = new Set<string>([
|
|
|
113
63
|
"dup",
|
|
114
64
|
"fetch",
|
|
115
65
|
"connect",
|
|
66
|
+
"queue",
|
|
67
|
+
"scheduled",
|
|
68
|
+
"tail",
|
|
69
|
+
"tailStream",
|
|
70
|
+
"test",
|
|
71
|
+
"trace",
|
|
116
72
|
"alarm",
|
|
117
73
|
"webSocketMessage",
|
|
118
74
|
"webSocketClose",
|
|
@@ -169,6 +125,7 @@ export type RpcHandlers<ROut, Api> = {
|
|
|
169
125
|
|
|
170
126
|
export interface WorkerOptions<ROut, Rpc extends WorkerRpc<ROut>> {
|
|
171
127
|
readonly fetch?: Effect.Effect<WorkerFetchSuccess, unknown, WorkerFetchContext<ROut>>;
|
|
128
|
+
readonly queue?: QueueHandler<ROut>;
|
|
172
129
|
readonly rpc?: Rpc;
|
|
173
130
|
}
|
|
174
131
|
|
|
@@ -181,6 +138,7 @@ export type WorkerClass<Rpc extends WorkerRpc<ROut>, ROut> = new (
|
|
|
181
138
|
env: WorkerEnv,
|
|
182
139
|
) => CloudflareWorkerEntrypoint<WorkerEnv> & {
|
|
183
140
|
fetch(request: Request): Promise<Response>;
|
|
141
|
+
queue(batch: globalThis.MessageBatch): Promise<void>;
|
|
184
142
|
} & WorkerRpcShape<Rpc, ROut>;
|
|
185
143
|
|
|
186
144
|
export interface FetchHandler<Env extends WorkerEnv = WorkerEnv> {
|
|
@@ -211,10 +169,29 @@ const renderFetchSuccess = <E, R>(
|
|
|
211
169
|
),
|
|
212
170
|
);
|
|
213
171
|
|
|
214
|
-
|
|
172
|
+
const isWorkerOptions = <ROut, Rpc extends WorkerRpc<ROut>>(
|
|
173
|
+
options: WorkerOptions<ROut, Rpc> | WorkerHandler<ROut>,
|
|
174
|
+
): options is WorkerOptions<ROut, Rpc> =>
|
|
175
|
+
typeof options === "object" &&
|
|
176
|
+
options !== null &&
|
|
177
|
+
("fetch" in options || "queue" in options || "rpc" in options);
|
|
178
|
+
|
|
179
|
+
export function make<ROut, LayerError>(
|
|
180
|
+
layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>,
|
|
181
|
+
fetch: WorkerHandler<ROut>,
|
|
182
|
+
): WorkerClass<Record<never, never>, ROut>;
|
|
183
|
+
export function make<ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Record<never, never>>(
|
|
215
184
|
layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>,
|
|
216
185
|
options: WorkerOptions<ROut, Rpc>,
|
|
217
|
-
): WorkerClass<Rpc, ROut
|
|
186
|
+
): WorkerClass<Rpc, ROut>;
|
|
187
|
+
export function make<ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Record<never, never>>(
|
|
188
|
+
layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>,
|
|
189
|
+
optionsOrFetch: WorkerOptions<ROut, Rpc> | WorkerHandler<ROut>,
|
|
190
|
+
): WorkerClass<Rpc, ROut> {
|
|
191
|
+
const options = isWorkerOptions(optionsOrFetch)
|
|
192
|
+
? optionsOrFetch
|
|
193
|
+
: ({ fetch: optionsOrFetch } as WorkerOptions<ROut, Rpc>);
|
|
194
|
+
|
|
218
195
|
class EffectWorker extends CloudflareWorkerEntrypoint<WorkerEnv> {
|
|
219
196
|
readonly runtime: ManagedRuntime.ManagedRuntime<RuntimeContext<ROut>, LayerError>;
|
|
220
197
|
|
|
@@ -222,7 +199,7 @@ export const make = <ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Recor
|
|
|
222
199
|
super(ctx, env);
|
|
223
200
|
|
|
224
201
|
let runWaitUntilEffect: RunWaitUntilEffect = () =>
|
|
225
|
-
Promise.
|
|
202
|
+
Promise.reject(new Error("WorkerContext runtime is not initialized"));
|
|
226
203
|
|
|
227
204
|
const services = Layer.mergeAll(
|
|
228
205
|
Layer.succeed(ExecutionContext, ctx),
|
|
@@ -269,6 +246,18 @@ export const make = <ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Recor
|
|
|
269
246
|
>,
|
|
270
247
|
);
|
|
271
248
|
}
|
|
249
|
+
|
|
250
|
+
queue(batch: globalThis.MessageBatch): Promise<void> {
|
|
251
|
+
const queueHandler = options.queue;
|
|
252
|
+
|
|
253
|
+
if (queueHandler === undefined) {
|
|
254
|
+
return Promise.resolve();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const messages = batch.messages.map((message) => fromMessage(message, message.body));
|
|
258
|
+
|
|
259
|
+
return this[RunSymbol](queueHandler(fromMessageBatch(batch, messages)));
|
|
260
|
+
}
|
|
272
261
|
}
|
|
273
262
|
|
|
274
263
|
Entrypoint.defineEntrypointRpcMethods<EffectWorker>(
|
|
@@ -280,7 +269,7 @@ export const make = <ROut, LayerError, const Rpc extends WorkerRpc<ROut> = Recor
|
|
|
280
269
|
);
|
|
281
270
|
|
|
282
271
|
return Entrypoint.assumeEntrypointClass<WorkerClass<Rpc, ROut>>(EffectWorker);
|
|
283
|
-
}
|
|
272
|
+
}
|
|
284
273
|
|
|
285
274
|
export const makeFetchHandler = <ROut, LayerError, Env extends WorkerEnv = WorkerEnv>(
|
|
286
275
|
layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>,
|
package/src/WorkerDefinition.ts
CHANGED