effect-cf 0.6.0 → 0.8.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.
@@ -1,4 +1,4 @@
1
- import { Data, Effect, type Scope } from "effect";
1
+ import { Context, Data, Effect, type Scope } from "effect";
2
2
 
3
3
  import * as Binding from "./Binding";
4
4
  import * as CloudflareRpc from "./Rpc";
@@ -74,6 +74,10 @@ type ServiceMethodSuccess<Api, Method extends keyof Api> = RpcInvocation.AsyncMe
74
74
  Api,
75
75
  Method
76
76
  >;
77
+ type ServiceMethodCloudflareReturn<
78
+ Api,
79
+ Method extends keyof Api,
80
+ > = RpcInvocation.AsyncMethodCloudflareReturn<Api, Method>;
77
81
 
78
82
  type ServiceCall<R, Api> = <Method extends ServiceMethodKey<Api>>(
79
83
  method: Method,
@@ -98,31 +102,274 @@ export type ServiceBindingEffectClient<
98
102
  Api extends object,
99
103
  Definition extends WorkerDefinition.Definition.Any | undefined = undefined,
100
104
  > = DirectMethods<never, Definition> & {
105
+ /**
106
+ * Forwards an HTTP request to the bound Worker service.
107
+ *
108
+ * Use this when the service binding is acting as an HTTP origin rather than a
109
+ * Cloudflare RPC target.
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * import { Effect } from "effect";
114
+ *
115
+ * const program = Effect.gen(function* () {
116
+ * const api = yield* ApiWorker;
117
+ * return yield* api.fetch(new Request("https://internal.example/users"));
118
+ * });
119
+ * ```
120
+ */
101
121
  readonly fetch: (
102
122
  input: RequestInfo | URL,
103
123
  init?: RequestInit,
104
124
  ) => Effect.Effect<globalThis.Response, ServiceBindingFetchError>;
125
+ /**
126
+ * Invokes a Worker RPC method and returns Cloudflare's raw RPC result.
127
+ *
128
+ * This preserves Cloudflare RPC behavior such as promise-like pipelining and
129
+ * transferable / disposable result objects. It does not resolve the returned
130
+ * promise-like value and it does not decode definition-backed success schemas.
131
+ *
132
+ * Most application code should use {@link call} instead.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * import { Effect } from "effect";
137
+ *
138
+ * const program = Effect.gen(function* () {
139
+ * const counter = yield* CounterService;
140
+ *
141
+ * const result = yield* counter.rpc("increment", 41);
142
+ * const value = yield* Effect.promise(() => result);
143
+ *
144
+ * return value;
145
+ * });
146
+ * ```
147
+ */
105
148
  readonly rpc: <Method extends ServiceMethodKey<Api>>(
106
149
  method: Method,
107
150
  ...args: ServiceMethodArgs<Api, Method>
108
- ) => Effect.Effect<ServiceMethodSuccess<Api, Method>, ServiceBindingRpcError>;
151
+ ) => Effect.Effect<ServiceMethodCloudflareReturn<Api, Method>, ServiceBindingRpcError>;
152
+ /**
153
+ * Invokes a Worker RPC method, resolves Cloudflare's RPC result, and decodes
154
+ * the success value when the binding was created from a definition.
155
+ *
156
+ * This is the normal choice when application code wants the final typed value.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * import { Effect } from "effect";
161
+ *
162
+ * const program = Effect.gen(function* () {
163
+ * const counter = yield* CounterService;
164
+ * const value = yield* counter.call("increment", 41);
165
+ *
166
+ * return value;
167
+ * });
168
+ * ```
169
+ */
109
170
  readonly call: <Method extends ServiceMethodKey<Api>>(
110
171
  method: Method,
111
172
  ...args: ServiceMethodArgs<Api, Method>
112
173
  ) => Effect.Effect<ServiceMethodSuccess<Api, Method>, ServiceBindingRpcError>;
174
+ /**
175
+ * Invokes a Worker RPC method in the current `Scope`, resolves Cloudflare's RPC
176
+ * result, decodes definition-backed success values, and disposes the resolved
177
+ * result when the scope closes if it implements `Symbol.dispose`.
178
+ *
179
+ * Use this for RPC methods that return Cloudflare RPC resources or other
180
+ * disposable objects whose lifetime should be tied to an Effect scope.
181
+ *
182
+ * @example
183
+ * ```ts
184
+ * import { Effect } from "effect";
185
+ *
186
+ * const program = Effect.scoped(
187
+ * Effect.gen(function* () {
188
+ * const files = yield* FileService;
189
+ * const handle = yield* files.scopedCall("open", "report.csv");
190
+ *
191
+ * return yield* handle.read();
192
+ * }),
193
+ * );
194
+ * ```
195
+ */
113
196
  readonly scopedCall: <Method extends ServiceMethodKey<Api>>(
114
197
  method: Method,
115
198
  ...args: ServiceMethodArgs<Api, Method>
116
199
  ) => Effect.Effect<Awaited<ServiceMethodSuccess<Api, Method>>, unknown, Scope.Scope>;
117
200
  };
118
201
 
202
+ export type ServiceBindingStaticClient<
203
+ R,
204
+ Api extends object,
205
+ Definition extends WorkerDefinition.Definition.Any | undefined = undefined,
206
+ > = DirectMethods<R, Definition> & {
207
+ readonly fetch: (
208
+ input: RequestInfo | URL,
209
+ init?: RequestInit,
210
+ ) => Effect.Effect<globalThis.Response, ServiceBindingFetchError, R>;
211
+ readonly rpc: <Method extends ServiceMethodKey<Api>>(
212
+ method: Method,
213
+ ...args: ServiceMethodArgs<Api, Method>
214
+ ) => Effect.Effect<ServiceMethodCloudflareReturn<Api, Method>, ServiceBindingRpcError, R>;
215
+ readonly call: <Method extends ServiceMethodKey<Api>>(
216
+ method: Method,
217
+ ...args: ServiceMethodArgs<Api, Method>
218
+ ) => Effect.Effect<ServiceMethodSuccess<Api, Method>, ServiceBindingRpcError, R>;
219
+ readonly scopedCall: <Method extends ServiceMethodKey<Api>>(
220
+ method: Method,
221
+ ...args: ServiceMethodArgs<Api, Method>
222
+ ) => Effect.Effect<Awaited<ServiceMethodSuccess<Api, Method>>, unknown, Scope.Scope | R>;
223
+ };
224
+
225
+ export const isServiceBindingClient = <Api extends object>(
226
+ value: unknown,
227
+ ): value is ServiceBindingClient<Api> =>
228
+ typeof value === "object" && value !== null && typeof Reflect.get(value, "fetch") === "function";
229
+
230
+ export const makeClient = <
231
+ Api extends object,
232
+ const Definition extends WorkerDefinition.Definition.Any | undefined = undefined,
233
+ >(
234
+ definition: ServiceBindingDefinition<Definition>,
235
+ ): ((service: ServiceBindingClient<Api>) => ServiceBindingEffectClient<Api, Definition>) => {
236
+ return (service: ServiceBindingClient<Api>) => {
237
+ const fetch = (input: RequestInfo | URL, init?: RequestInit) =>
238
+ Effect.tryPromise({
239
+ try: () => service.fetch(input, init),
240
+ catch: (cause) => new ServiceBindingFetchError({ binding: definition.binding, cause }),
241
+ });
242
+
243
+ const rpc = <Method extends ServiceMethodKey<Api>>(
244
+ method: Method,
245
+ ...args: ServiceMethodArgs<Api, Method>
246
+ ) =>
247
+ Effect.gen(function* () {
248
+ const methodName = String(method);
249
+ const encodedArgs =
250
+ definition.definition === undefined
251
+ ? args
252
+ : yield* RpcDefinition.encodeArgs(
253
+ definition.definition,
254
+ methodName as RpcDefinition.Definition.MethodNames<NonNullable<Definition>>,
255
+ args as never,
256
+ ).pipe(
257
+ Effect.mapError(
258
+ (cause) =>
259
+ new ServiceBindingRpcError({
260
+ binding: definition.binding,
261
+ method: methodName,
262
+ cause,
263
+ }),
264
+ ),
265
+ );
266
+
267
+ return yield* RpcInvocation.invokeRpcMethod(
268
+ service,
269
+ method,
270
+ encodedArgs as ServiceMethodArgs<Api, Method>,
271
+ (cause) =>
272
+ new ServiceBindingRpcError({
273
+ binding: definition.binding,
274
+ method: methodName,
275
+ cause,
276
+ }),
277
+ );
278
+ });
279
+
280
+ const decodeSuccess = <Method extends ServiceMethodKey<Api>>(
281
+ methodName: string,
282
+ value: Awaited<ServiceMethodCloudflareReturn<Api, Method>>,
283
+ ) =>
284
+ Effect.gen(function* () {
285
+ if (definition.definition === undefined) {
286
+ return value as ServiceMethodSuccess<Api, Method>;
287
+ }
288
+
289
+ const decoded = yield* RpcDefinition.decodeSuccess(
290
+ definition.definition,
291
+ methodName as RpcDefinition.Definition.MethodNames<NonNullable<Definition>>,
292
+ value,
293
+ ).pipe(
294
+ Effect.mapError(
295
+ (cause) =>
296
+ new ServiceBindingRpcError({
297
+ binding: definition.binding,
298
+ method: methodName,
299
+ cause,
300
+ }),
301
+ ),
302
+ );
303
+
304
+ return decoded as ServiceMethodSuccess<Api, Method>;
305
+ });
306
+
307
+ const call = <Method extends ServiceMethodKey<Api>>(
308
+ method: Method,
309
+ ...args: ServiceMethodArgs<Api, Method>
310
+ ) =>
311
+ Effect.gen(function* () {
312
+ const methodName = String(method);
313
+ const value = yield* CloudflareRpc.resolve(yield* rpc(method, ...args)).pipe(
314
+ Effect.mapError(
315
+ (cause) =>
316
+ new ServiceBindingRpcError({
317
+ binding: definition.binding,
318
+ method: methodName,
319
+ cause,
320
+ }),
321
+ ),
322
+ );
323
+
324
+ return yield* decodeSuccess<Method>(methodName, value);
325
+ });
326
+
327
+ const scopedCall = <Method extends ServiceMethodKey<Api>>(
328
+ method: Method,
329
+ ...args: ServiceMethodArgs<Api, Method>
330
+ ) =>
331
+ Effect.gen(function* () {
332
+ const methodName = String(method);
333
+ const result = yield* rpc(method, ...args);
334
+ const value = yield* CloudflareRpc.scoped(result);
335
+ return yield* decodeSuccess<Method>(methodName, value);
336
+ });
337
+
338
+ const directMethods = makeDirectMethods<never, Api, Definition>(definition.definition, call);
339
+
340
+ return Object.assign(directMethods, {
341
+ fetch,
342
+ rpc,
343
+ call,
344
+ scopedCall,
345
+ }) as ServiceBindingEffectClient<Api, Definition>;
346
+ };
347
+ };
348
+
349
+ export const layer = <
350
+ Self,
351
+ Api extends object,
352
+ const Definition extends WorkerDefinition.Definition.Any | undefined = undefined,
353
+ >(
354
+ tag: Context.Service<Self, ServiceBindingEffectClient<Api, Definition>>,
355
+ definition: ServiceBindingDefinition<Definition>,
356
+ ) =>
357
+ Binding.layer(
358
+ tag,
359
+ definition.binding,
360
+ (value): value is ServiceBindingClient<Api> => isServiceBindingClient<Api>(value),
361
+ makeClient<Api, Definition>(definition),
362
+ );
363
+
119
364
  /**
120
365
  * Creates a typed Effect service for a Worker service binding.
121
366
  *
122
367
  * Returned value includes:
123
368
  * - a Context tag for dependency injection
124
369
  * - `fetch(...)` for raw HTTP forwarding
125
- * - `call(...)` for generic RPC invocation
370
+ * - `rpc(...)` for raw Cloudflare RPC results
371
+ * - `call(...)` for resolved and decoded RPC results
372
+ * - `scopedCall(...)` for scoped and decoded disposable RPC results
126
373
  * - direct RPC methods when `definition` is provided
127
374
  *
128
375
  * @example
@@ -134,10 +381,11 @@ export type ServiceBindingEffectClient<
134
381
  * }),
135
382
  * });
136
383
  *
137
- * const CounterService = Counter.binding("COUNTER", { binding: "COUNTER" });
384
+ * const CounterLive = Counter.layer({ binding: "COUNTER" });
138
385
  *
139
386
  * const program = Effect.gen(function* () {
140
- * const next = yield* CounterService.increment(1);
387
+ * const counter = yield* Counter;
388
+ * const next = yield* counter.increment(1);
141
389
  * return next;
142
390
  * });
143
391
  * ```
@@ -153,119 +401,11 @@ export const Service =
153
401
  ) => {
154
402
  type ServiceApi = ApiOrDefinition<Api, Definition>;
155
403
 
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
-
263
404
  const tag = Binding.Service<Self>()(
264
405
  id,
265
406
  definition.binding,
266
- (value): value is ServiceBindingClient<ServiceApi> =>
267
- typeof value === "object" && value !== null && "fetch" in value,
268
- makeClient,
407
+ (value): value is ServiceBindingClient<ServiceApi> => isServiceBindingClient(value),
408
+ makeClient<ServiceApi, Definition>(definition),
269
409
  );
270
410
 
271
411
  const fetch = (input: RequestInfo | URL, init?: RequestInit) =>
@@ -324,7 +464,11 @@ export const Service =
324
464
  };
325
465
  };
326
466
 
327
- const makeDirectMethods = <R, Api, Definition extends WorkerDefinition.Definition.Any | undefined>(
467
+ export const makeDirectMethods = <
468
+ R,
469
+ Api,
470
+ Definition extends WorkerDefinition.Definition.Any | undefined,
471
+ >(
328
472
  rpcDefinition: Definition | undefined,
329
473
  call: ServiceCall<R, Api>,
330
474
  ): DirectMethods<R, Definition> => {
package/src/Worker.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  import { WorkerEntrypoint as CloudflareWorkerEntrypoint } from "cloudflare:workers";
2
2
  import { Cause, ConfigProvider, Context, Effect, Layer, ManagedRuntime, type Scope } from "effect";
3
+ import type { Schema as S } from "effect";
3
4
  import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
4
5
 
6
+ import type * as Binding from "./Binding";
5
7
  import { WorkerConfig, WorkerEnvironment, type WorkerEnv } from "./Environment";
6
8
  import { fromMessage, fromMessageBatch, type QueueHandler } from "./Queue";
9
+ import type * as Rpc from "./Rpc";
7
10
  import type * as RpcDefinition from "./RpcDefinition";
11
+ import type * as ServiceBinding from "./ServiceBinding";
8
12
  import * as WorkerDefinition from "./WorkerDefinition";
9
13
  import * as Entrypoint from "./internal/Entrypoint";
10
14
  import { fromExecutionContext, type RunWaitUntilEffect } from "./internal/WorkerContext";
@@ -282,38 +286,128 @@ export const makeFetchHandler = <ROut, LayerError, Env extends WorkerEnv = Worke
282
286
  };
283
287
  };
284
288
 
285
- export const Tag = WorkerDefinition.Tag;
289
+ export type ServiceFreeSchema = S.Codec<any, any, never, never>;
286
290
 
287
- export const method = WorkerDefinition.method;
291
+ export interface Method<
292
+ Args extends ReadonlyArray<ServiceFreeSchema> = ReadonlyArray<ServiceFreeSchema>,
293
+ Success extends ServiceFreeSchema = ServiceFreeSchema,
294
+ > {
295
+ readonly args: Args;
296
+ readonly success: Success;
297
+ }
298
+
299
+ export namespace Method {
300
+ export type Any = Method<ReadonlyArray<ServiceFreeSchema>, ServiceFreeSchema>;
301
+
302
+ type ArgsFromSchemas<Args extends ReadonlyArray<ServiceFreeSchema>> = Args extends readonly []
303
+ ? []
304
+ : Args extends readonly [
305
+ infer Head extends ServiceFreeSchema,
306
+ ...infer Tail extends ReadonlyArray<ServiceFreeSchema>,
307
+ ]
308
+ ? [S.Schema.Type<Head>, ...ArgsFromSchemas<Tail>]
309
+ : Array<S.Schema.Type<Args[number]>>;
288
310
 
289
- export const implement = WorkerDefinition.implement;
311
+ export type Args<Self extends Any> = ArgsFromSchemas<Self["args"]>;
312
+
313
+ export type Success<Self extends Any> = S.Schema.Type<Self["success"]>;
314
+ }
290
315
 
291
- export type Definition<
292
- Id extends string = string,
293
- Methods extends RpcDefinition.Methods = RpcDefinition.Methods,
294
- > = WorkerDefinition.Definition<Id, Methods>;
316
+ export type Methods = Record<string, Method.Any>;
317
+
318
+ export type NoReservedMethods<MethodsShape extends Methods> =
319
+ Extract<keyof MethodsShape, ReservedMethodName> extends never ? MethodsShape : never;
320
+
321
+ export interface Definition<Id extends string = string, MethodsShape extends Methods = Methods> {
322
+ readonly id: Id;
323
+ readonly methods: MethodsShape;
324
+ }
295
325
 
296
326
  export namespace Definition {
297
- export type Any = WorkerDefinition.Definition.Any;
327
+ export type Any = Definition<string, Methods>;
298
328
  }
299
329
 
300
- export type ServerApi<Self extends WorkerDefinition.Definition.Any> =
301
- WorkerDefinition.ServerApi<Self>;
330
+ export type ServerApi<Self extends Definition.Any> = {
331
+ readonly [Key in keyof Self["methods"]]: (
332
+ ...args: Method.Args<Self["methods"][Key]>
333
+ ) => Promise<Method.Success<Self["methods"][Key]>>;
334
+ };
335
+
336
+ export type Api<Self extends Definition.Any> = Rpc.Provider<ServerApi<Self>, ReservedMethodName>;
302
337
 
303
- export type Api<Self extends WorkerDefinition.Definition.Any> = WorkerDefinition.Api<Self>;
338
+ export type Handlers<ROut, Self extends Definition.Any> = {
339
+ readonly [Key in keyof Self["methods"]]: (
340
+ ...args: Method.Args<Self["methods"][Key]>
341
+ ) => WorkerRpcHandler<ROut, Method.Success<Self["methods"][Key]>>;
342
+ };
304
343
 
305
- export type Handlers<
306
- ROut,
307
- Self extends WorkerDefinition.Definition.Any,
308
- > = WorkerDefinition.Handlers<ROut, Self>;
344
+ export interface Options<ROut, Self extends Definition.Any> extends Omit<
345
+ WorkerOptions<ROut, Handlers<ROut, Self>>,
346
+ "rpc"
347
+ > {
348
+ readonly rpc: Handlers<ROut, Self>;
349
+ }
309
350
 
310
- export type Options<ROut, Self extends WorkerDefinition.Definition.Any> = WorkerDefinition.Options<
351
+ export type LayerOptions = WorkerDefinition.LayerOptions;
352
+
353
+ export type TagClass<Self, Id extends string, MethodsShape extends Methods> = Context.ServiceClass<
354
+ Self,
355
+ Id,
356
+ ServiceBinding.ServiceBindingEffectClient<
357
+ Api<Definition<Id, MethodsShape>>,
358
+ Definition<Id, MethodsShape>
359
+ >
360
+ > &
361
+ ServiceBinding.ServiceBindingStaticClient<
362
+ Self,
363
+ Api<Definition<Id, MethodsShape>>,
364
+ Definition<Id, MethodsShape>
365
+ > & {
366
+ readonly id: Id;
367
+ readonly methods: MethodsShape;
368
+ readonly make: <ROut, LayerError>(
369
+ layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>,
370
+ options: Options<ROut, Definition<Id, MethodsShape>>,
371
+ ) => WorkerClass<Handlers<ROut, Definition<Id, MethodsShape>>, ROut>;
372
+ readonly layer: (
373
+ options: LayerOptions,
374
+ ) => Layer.Layer<
375
+ Self,
376
+ Binding.BindingNotFoundError | Binding.BindingValidationError,
377
+ WorkerEnvironment
378
+ >;
379
+ };
380
+
381
+ export type TagFactory = <Self>() => <Id extends string, const MethodsShape extends Methods>(
382
+ id: Id,
383
+ methods: MethodsShape & NoReservedMethods<MethodsShape>,
384
+ ) => TagClass<Self, Id, MethodsShape>;
385
+
386
+ export const Tag = WorkerDefinition.Tag as unknown as TagFactory;
387
+
388
+ export const method = WorkerDefinition.method as {
389
+ <Success extends ServiceFreeSchema>(definition: {
390
+ readonly success: Success;
391
+ }): Method<readonly [], Success>;
392
+ <
393
+ const Args extends ReadonlyArray<ServiceFreeSchema>,
394
+ Success extends ServiceFreeSchema,
395
+ >(definition: {
396
+ readonly args: Args;
397
+ readonly success: Success;
398
+ }): Method<Args, Success>;
399
+ };
400
+
401
+ export const implement = WorkerDefinition.implement as unknown as <
311
402
  ROut,
312
- Self
313
- >;
403
+ const Self extends Definition.Any,
404
+ >(
405
+ _definition: Self,
406
+ handlers: Handlers<ROut, Self>,
407
+ ) => Handlers<ROut, Self>;
314
408
 
315
409
  export type HandlerEffect<
316
410
  ROut,
317
- Self extends WorkerDefinition.Definition.Any,
411
+ Self extends Definition.Any,
318
412
  Key extends keyof Self["methods"],
319
- > = WorkerDefinition.HandlerEffect<ROut, Self, Key>;
413
+ > = WorkerRpcHandler<ROut, Method.Success<Self["methods"][Key]>>;