effect-cf 0.5.0 → 0.6.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 +6 -0
- package/README.md +7 -1
- package/dist/index.d.mts +173 -345
- package/dist/index.mjs +210 -103
- package/package.json +1 -1
- package/src/Binding.ts +21 -5
- package/src/DurableObjectNamespace.ts +227 -32
- package/src/Kv.ts +133 -80
- package/src/QueueBinding.ts +51 -18
- package/src/ServiceBinding.ts +147 -84
package/src/QueueBinding.ts
CHANGED
|
@@ -19,6 +19,19 @@ export interface QueueBindingDefinition<Message extends RpcDefinition.ServiceFre
|
|
|
19
19
|
readonly message: Message;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
export interface QueueBindingClient<Message extends RpcDefinition.ServiceFreeSchema> {
|
|
23
|
+
readonly send: (
|
|
24
|
+
message: S.Schema.Type<Message>,
|
|
25
|
+
options?: QueueSendOptions,
|
|
26
|
+
) => Effect.Effect<void, QueueOperationError | S.SchemaError>;
|
|
27
|
+
readonly sendBatch: (
|
|
28
|
+
messages: Iterable<MessageSendRequest<S.Schema.Type<Message>>>,
|
|
29
|
+
options?: QueueSendBatchOptions,
|
|
30
|
+
) => Effect.Effect<void, QueueOperationError | S.SchemaError>;
|
|
31
|
+
readonly metrics: () => Effect.Effect<QueueMetrics, QueueOperationError>;
|
|
32
|
+
readonly unsafeRaw: Effect.Effect<globalThis.Queue<S.Codec.Encoded<Message>>>;
|
|
33
|
+
}
|
|
34
|
+
|
|
22
35
|
declare const QueueServiceTypeId: unique symbol;
|
|
23
36
|
|
|
24
37
|
/** Nominal service marker for Queue services created with {@link make}. */
|
|
@@ -81,19 +94,45 @@ export const Service =
|
|
|
81
94
|
type Body = S.Schema.Type<Message>;
|
|
82
95
|
type EncodedBody = S.Codec.Encoded<Message>;
|
|
83
96
|
|
|
97
|
+
const encodeMessage = S.encodeEffect(definition.message);
|
|
98
|
+
|
|
99
|
+
const makeClient = (queue: globalThis.Queue<EncodedBody>): QueueBindingClient<Message> => ({
|
|
100
|
+
send: Effect.fnUntraced(function* (message: Body, options?: QueueSendOptions) {
|
|
101
|
+
const encoded = yield* encodeMessage(message);
|
|
102
|
+
|
|
103
|
+
yield* tryQueuePromise(definition.binding, "send", () => queue.send(encoded, options));
|
|
104
|
+
}),
|
|
105
|
+
sendBatch: Effect.fnUntraced(function* (
|
|
106
|
+
messages: Iterable<MessageSendRequest<Body>>,
|
|
107
|
+
options?: QueueSendBatchOptions,
|
|
108
|
+
) {
|
|
109
|
+
const encodedMessages: Array<MessageSendRequest<EncodedBody>> = [];
|
|
110
|
+
|
|
111
|
+
for (const message of messages) {
|
|
112
|
+
encodedMessages.push({
|
|
113
|
+
...message,
|
|
114
|
+
body: yield* encodeMessage(message.body),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
yield* tryQueuePromise(definition.binding, "sendBatch", () =>
|
|
119
|
+
queue.sendBatch(encodedMessages, options),
|
|
120
|
+
);
|
|
121
|
+
}),
|
|
122
|
+
metrics: () => tryQueuePromise(definition.binding, "metrics", () => queue.metrics()),
|
|
123
|
+
unsafeRaw: Effect.succeed(queue),
|
|
124
|
+
});
|
|
125
|
+
|
|
84
126
|
const tag = Binding.Service<Self>()(
|
|
85
127
|
id,
|
|
86
128
|
definition.binding,
|
|
87
129
|
(value): value is globalThis.Queue<EncodedBody> => isQueue<EncodedBody>(value),
|
|
130
|
+
makeClient,
|
|
88
131
|
);
|
|
89
132
|
|
|
90
|
-
const encodeMessage = S.encodeEffect(definition.message);
|
|
91
|
-
|
|
92
133
|
const send = Effect.fnUntraced(function* (message: Body, options?: QueueSendOptions) {
|
|
93
134
|
const queue = yield* tag;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return yield* tryQueuePromise(definition.binding, "send", () => queue.send(encoded, options));
|
|
135
|
+
yield* queue.send(message, options);
|
|
97
136
|
});
|
|
98
137
|
|
|
99
138
|
const sendBatch = Effect.fnUntraced(function* (
|
|
@@ -101,24 +140,17 @@ export const Service =
|
|
|
101
140
|
options?: QueueSendBatchOptions,
|
|
102
141
|
) {
|
|
103
142
|
const queue = yield* tag;
|
|
104
|
-
|
|
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
|
-
);
|
|
143
|
+
yield* queue.sendBatch(messages, options);
|
|
116
144
|
});
|
|
117
145
|
|
|
118
146
|
const metrics = Effect.fnUntraced(function* () {
|
|
119
147
|
const queue = yield* tag;
|
|
148
|
+
return yield* queue.metrics();
|
|
149
|
+
});
|
|
120
150
|
|
|
121
|
-
|
|
151
|
+
const unsafeRaw = Effect.fnUntraced(function* () {
|
|
152
|
+
const queue = yield* tag;
|
|
153
|
+
return yield* queue.unsafeRaw;
|
|
122
154
|
});
|
|
123
155
|
|
|
124
156
|
return Object.assign(tag, {
|
|
@@ -127,5 +159,6 @@ export const Service =
|
|
|
127
159
|
send,
|
|
128
160
|
sendBatch,
|
|
129
161
|
metrics,
|
|
162
|
+
unsafeRaw,
|
|
130
163
|
});
|
|
131
164
|
};
|
package/src/ServiceBinding.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Data, Effect } from "effect";
|
|
1
|
+
import { Data, Effect, type Scope } from "effect";
|
|
2
2
|
|
|
3
3
|
import * as Binding from "./Binding";
|
|
4
4
|
import * as CloudflareRpc from "./Rpc";
|
|
@@ -75,25 +75,47 @@ type ServiceMethodSuccess<Api, Method extends keyof Api> = RpcInvocation.AsyncMe
|
|
|
75
75
|
Method
|
|
76
76
|
>;
|
|
77
77
|
|
|
78
|
-
type ServiceCall<
|
|
78
|
+
type ServiceCall<R, Api> = <Method extends ServiceMethodKey<Api>>(
|
|
79
79
|
method: Method,
|
|
80
80
|
...args: ServiceMethodArgs<Api, Method>
|
|
81
|
-
) => Effect.Effect<ServiceMethodSuccess<Api, Method>, ServiceBindingRpcError,
|
|
81
|
+
) => Effect.Effect<ServiceMethodSuccess<Api, Method>, ServiceBindingRpcError, R>;
|
|
82
82
|
|
|
83
|
-
type DefinitionDirectMethods<
|
|
83
|
+
type DefinitionDirectMethods<R, Definition extends WorkerDefinition.Definition.Any> = {
|
|
84
84
|
readonly [Method in RpcDefinition.Definition.MethodNames<Definition>]: (
|
|
85
85
|
...args: RpcDefinition.Method.Args<Definition["methods"][Method]>
|
|
86
86
|
) => Effect.Effect<
|
|
87
87
|
RpcDefinition.Method.Success<Definition["methods"][Method]>,
|
|
88
88
|
ServiceBindingRpcError,
|
|
89
|
-
|
|
89
|
+
R
|
|
90
90
|
>;
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
-
type DirectMethods<
|
|
94
|
-
? DefinitionDirectMethods<
|
|
93
|
+
type DirectMethods<R, Definition> = Definition extends WorkerDefinition.Definition.Any
|
|
94
|
+
? DefinitionDirectMethods<R, Definition>
|
|
95
95
|
: {};
|
|
96
96
|
|
|
97
|
+
export type ServiceBindingEffectClient<
|
|
98
|
+
Api extends object,
|
|
99
|
+
Definition extends WorkerDefinition.Definition.Any | undefined = undefined,
|
|
100
|
+
> = DirectMethods<never, Definition> & {
|
|
101
|
+
readonly fetch: (
|
|
102
|
+
input: RequestInfo | URL,
|
|
103
|
+
init?: RequestInit,
|
|
104
|
+
) => Effect.Effect<globalThis.Response, ServiceBindingFetchError>;
|
|
105
|
+
readonly rpc: <Method extends ServiceMethodKey<Api>>(
|
|
106
|
+
method: Method,
|
|
107
|
+
...args: ServiceMethodArgs<Api, Method>
|
|
108
|
+
) => Effect.Effect<ServiceMethodSuccess<Api, Method>, ServiceBindingRpcError>;
|
|
109
|
+
readonly call: <Method extends ServiceMethodKey<Api>>(
|
|
110
|
+
method: Method,
|
|
111
|
+
...args: ServiceMethodArgs<Api, Method>
|
|
112
|
+
) => Effect.Effect<ServiceMethodSuccess<Api, Method>, ServiceBindingRpcError>;
|
|
113
|
+
readonly scopedCall: <Method extends ServiceMethodKey<Api>>(
|
|
114
|
+
method: Method,
|
|
115
|
+
...args: ServiceMethodArgs<Api, Method>
|
|
116
|
+
) => Effect.Effect<Awaited<ServiceMethodSuccess<Api, Method>>, unknown, Scope.Scope>;
|
|
117
|
+
};
|
|
118
|
+
|
|
97
119
|
/**
|
|
98
120
|
* Creates a typed Effect service for a Worker service binding.
|
|
99
121
|
*
|
|
@@ -131,21 +153,125 @@ export const Service =
|
|
|
131
153
|
) => {
|
|
132
154
|
type ServiceApi = ApiOrDefinition<Api, Definition>;
|
|
133
155
|
|
|
156
|
+
const makeClient = (
|
|
157
|
+
service: ServiceBindingClient<ServiceApi>,
|
|
158
|
+
): ServiceBindingEffectClient<ServiceApi, Definition> => {
|
|
159
|
+
const fetch = (input: RequestInfo | URL, init?: RequestInit) =>
|
|
160
|
+
Effect.tryPromise({
|
|
161
|
+
try: () => service.fetch(input, init),
|
|
162
|
+
catch: (cause) => new ServiceBindingFetchError({ binding: definition.binding, cause }),
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const rpc = <Method extends ServiceMethodKey<ServiceApi>>(
|
|
166
|
+
method: Method,
|
|
167
|
+
...args: ServiceMethodArgs<ServiceApi, Method>
|
|
168
|
+
) =>
|
|
169
|
+
Effect.gen(function* () {
|
|
170
|
+
const methodName = String(method);
|
|
171
|
+
const encodedArgs =
|
|
172
|
+
definition.definition === undefined
|
|
173
|
+
? args
|
|
174
|
+
: yield* RpcDefinition.encodeArgs(
|
|
175
|
+
definition.definition,
|
|
176
|
+
methodName as RpcDefinition.Definition.MethodNames<NonNullable<Definition>>,
|
|
177
|
+
args as never,
|
|
178
|
+
).pipe(
|
|
179
|
+
Effect.mapError(
|
|
180
|
+
(cause) =>
|
|
181
|
+
new ServiceBindingRpcError({
|
|
182
|
+
binding: definition.binding,
|
|
183
|
+
method: methodName,
|
|
184
|
+
cause,
|
|
185
|
+
}),
|
|
186
|
+
),
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
return yield* RpcInvocation.invokeRpcMethod(
|
|
190
|
+
service,
|
|
191
|
+
method,
|
|
192
|
+
encodedArgs as ServiceMethodArgs<ServiceApi, Method>,
|
|
193
|
+
(cause) =>
|
|
194
|
+
new ServiceBindingRpcError({
|
|
195
|
+
binding: definition.binding,
|
|
196
|
+
method: methodName,
|
|
197
|
+
cause,
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const call = <Method extends ServiceMethodKey<ServiceApi>>(
|
|
203
|
+
method: Method,
|
|
204
|
+
...args: ServiceMethodArgs<ServiceApi, Method>
|
|
205
|
+
) =>
|
|
206
|
+
Effect.gen(function* () {
|
|
207
|
+
const methodName = String(method);
|
|
208
|
+
const value = yield* CloudflareRpc.resolve(yield* rpc(method, ...args)).pipe(
|
|
209
|
+
Effect.mapError(
|
|
210
|
+
(cause) =>
|
|
211
|
+
new ServiceBindingRpcError({
|
|
212
|
+
binding: definition.binding,
|
|
213
|
+
method: methodName,
|
|
214
|
+
cause,
|
|
215
|
+
}),
|
|
216
|
+
),
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
if (definition.definition === undefined) {
|
|
220
|
+
return value as ServiceMethodSuccess<ServiceApi, Method>;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const decoded = yield* RpcDefinition.decodeSuccess(
|
|
224
|
+
definition.definition,
|
|
225
|
+
methodName as RpcDefinition.Definition.MethodNames<NonNullable<Definition>>,
|
|
226
|
+
value,
|
|
227
|
+
).pipe(
|
|
228
|
+
Effect.mapError(
|
|
229
|
+
(cause) =>
|
|
230
|
+
new ServiceBindingRpcError({
|
|
231
|
+
binding: definition.binding,
|
|
232
|
+
method: methodName,
|
|
233
|
+
cause,
|
|
234
|
+
}),
|
|
235
|
+
),
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
return decoded as ServiceMethodSuccess<ServiceApi, Method>;
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const scopedCall = <Method extends ServiceMethodKey<ServiceApi>>(
|
|
242
|
+
method: Method,
|
|
243
|
+
...args: ServiceMethodArgs<ServiceApi, Method>
|
|
244
|
+
) =>
|
|
245
|
+
Effect.gen(function* () {
|
|
246
|
+
const result = yield* rpc(method, ...args);
|
|
247
|
+
return yield* CloudflareRpc.scoped(result);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const directMethods = makeDirectMethods<never, ServiceApi, Definition>(
|
|
251
|
+
definition.definition,
|
|
252
|
+
call,
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
return Object.assign(directMethods, {
|
|
256
|
+
fetch,
|
|
257
|
+
rpc,
|
|
258
|
+
call,
|
|
259
|
+
scopedCall,
|
|
260
|
+
}) as ServiceBindingEffectClient<ServiceApi, Definition>;
|
|
261
|
+
};
|
|
262
|
+
|
|
134
263
|
const tag = Binding.Service<Self>()(
|
|
135
264
|
id,
|
|
136
265
|
definition.binding,
|
|
137
266
|
(value): value is ServiceBindingClient<ServiceApi> =>
|
|
138
267
|
typeof value === "object" && value !== null && "fetch" in value,
|
|
268
|
+
makeClient,
|
|
139
269
|
);
|
|
140
270
|
|
|
141
271
|
const fetch = (input: RequestInfo | URL, init?: RequestInit) =>
|
|
142
272
|
Effect.gen(function* () {
|
|
143
273
|
const service = yield* tag;
|
|
144
|
-
|
|
145
|
-
return yield* Effect.tryPromise({
|
|
146
|
-
try: () => service.fetch(input, init),
|
|
147
|
-
catch: (cause) => new ServiceBindingFetchError({ binding: definition.binding, cause }),
|
|
148
|
-
});
|
|
274
|
+
return yield* service.fetch(input, init);
|
|
149
275
|
});
|
|
150
276
|
|
|
151
277
|
const rpc = <Method extends ServiceMethodKey<ServiceApi>>(
|
|
@@ -154,36 +280,7 @@ export const Service =
|
|
|
154
280
|
) =>
|
|
155
281
|
Effect.gen(function* () {
|
|
156
282
|
const service = yield* tag;
|
|
157
|
-
|
|
158
|
-
const encodedArgs =
|
|
159
|
-
definition.definition === undefined
|
|
160
|
-
? args
|
|
161
|
-
: yield* RpcDefinition.encodeArgs(
|
|
162
|
-
definition.definition,
|
|
163
|
-
methodName as RpcDefinition.Definition.MethodNames<NonNullable<Definition>>,
|
|
164
|
-
args as never,
|
|
165
|
-
).pipe(
|
|
166
|
-
Effect.mapError(
|
|
167
|
-
(cause) =>
|
|
168
|
-
new ServiceBindingRpcError({
|
|
169
|
-
binding: definition.binding,
|
|
170
|
-
method: methodName,
|
|
171
|
-
cause,
|
|
172
|
-
}),
|
|
173
|
-
),
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
return yield* RpcInvocation.invokeRpcMethod(
|
|
177
|
-
service,
|
|
178
|
-
method,
|
|
179
|
-
encodedArgs as ServiceMethodArgs<ServiceApi, Method>,
|
|
180
|
-
(cause) =>
|
|
181
|
-
new ServiceBindingRpcError({
|
|
182
|
-
binding: definition.binding,
|
|
183
|
-
method: methodName,
|
|
184
|
-
cause,
|
|
185
|
-
}),
|
|
186
|
-
);
|
|
283
|
+
return yield* service.rpc(method, ...args);
|
|
187
284
|
});
|
|
188
285
|
|
|
189
286
|
const call = <Method extends ServiceMethodKey<ServiceApi>>(
|
|
@@ -191,38 +288,8 @@ export const Service =
|
|
|
191
288
|
...args: ServiceMethodArgs<ServiceApi, Method>
|
|
192
289
|
) =>
|
|
193
290
|
Effect.gen(function* () {
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
Effect.mapError(
|
|
197
|
-
(cause) =>
|
|
198
|
-
new ServiceBindingRpcError({
|
|
199
|
-
binding: definition.binding,
|
|
200
|
-
method: methodName,
|
|
201
|
-
cause,
|
|
202
|
-
}),
|
|
203
|
-
),
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
if (definition.definition === undefined) {
|
|
207
|
-
return value as ServiceMethodSuccess<ServiceApi, Method>;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const decoded = yield* RpcDefinition.decodeSuccess(
|
|
211
|
-
definition.definition,
|
|
212
|
-
methodName as RpcDefinition.Definition.MethodNames<NonNullable<Definition>>,
|
|
213
|
-
value,
|
|
214
|
-
).pipe(
|
|
215
|
-
Effect.mapError(
|
|
216
|
-
(cause) =>
|
|
217
|
-
new ServiceBindingRpcError({
|
|
218
|
-
binding: definition.binding,
|
|
219
|
-
method: methodName,
|
|
220
|
-
cause,
|
|
221
|
-
}),
|
|
222
|
-
),
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
return decoded as ServiceMethodSuccess<ServiceApi, Method>;
|
|
291
|
+
const service = yield* tag;
|
|
292
|
+
return yield* service.call(method, ...args);
|
|
226
293
|
});
|
|
227
294
|
|
|
228
295
|
const scopedCall = <Method extends ServiceMethodKey<ServiceApi>>(
|
|
@@ -230,8 +297,8 @@ export const Service =
|
|
|
230
297
|
...args: ServiceMethodArgs<ServiceApi, Method>
|
|
231
298
|
) =>
|
|
232
299
|
Effect.gen(function* () {
|
|
233
|
-
const
|
|
234
|
-
return yield*
|
|
300
|
+
const service = yield* tag;
|
|
301
|
+
return yield* service.scopedCall(method, ...args);
|
|
235
302
|
});
|
|
236
303
|
|
|
237
304
|
const directMethods = makeDirectMethods<Self, ServiceApi, Definition>(
|
|
@@ -257,14 +324,10 @@ export const Service =
|
|
|
257
324
|
};
|
|
258
325
|
};
|
|
259
326
|
|
|
260
|
-
const makeDirectMethods = <
|
|
261
|
-
Self,
|
|
262
|
-
Api,
|
|
263
|
-
Definition extends WorkerDefinition.Definition.Any | undefined,
|
|
264
|
-
>(
|
|
327
|
+
const makeDirectMethods = <R, Api, Definition extends WorkerDefinition.Definition.Any | undefined>(
|
|
265
328
|
rpcDefinition: Definition | undefined,
|
|
266
|
-
call: ServiceCall<
|
|
267
|
-
): DirectMethods<
|
|
329
|
+
call: ServiceCall<R, Api>,
|
|
330
|
+
): DirectMethods<R, Definition> => {
|
|
268
331
|
const methods = {} as Record<string, unknown>;
|
|
269
332
|
|
|
270
333
|
if (rpcDefinition !== undefined) {
|
|
@@ -274,5 +337,5 @@ const makeDirectMethods = <
|
|
|
274
337
|
}
|
|
275
338
|
}
|
|
276
339
|
|
|
277
|
-
return methods as DirectMethods<
|
|
340
|
+
return methods as DirectMethods<R, Definition>;
|
|
278
341
|
};
|