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,28 +1,77 @@
1
- import { Effect, type Layer } from "effect";
1
+ import { Context, Effect, type Layer } from "effect";
2
+ import type { Schema as S } from "effect";
2
3
 
4
+ import * as Binding from "./Binding";
3
5
  import type { WorkerEnvironment } from "./Environment";
4
6
  import * as WorkerEntrypoint from "./Worker";
5
7
  import type { WorkerRpcHandler } from "./Worker";
8
+ import type * as Rpc from "./Rpc";
6
9
  import * as RpcDefinition from "./RpcDefinition";
7
10
  import * as ServiceBinding from "./ServiceBinding";
8
11
 
12
+ export type ServiceFreeSchema = S.Codec<any, any, never, never>;
13
+
14
+ export interface Method<
15
+ Args extends ReadonlyArray<ServiceFreeSchema> = ReadonlyArray<ServiceFreeSchema>,
16
+ Success extends ServiceFreeSchema = ServiceFreeSchema,
17
+ > {
18
+ readonly args: Args;
19
+ readonly success: Success;
20
+ }
21
+
22
+ export namespace Method {
23
+ export type Any = Method<ReadonlyArray<ServiceFreeSchema>, ServiceFreeSchema>;
24
+
25
+ type ArgsFromSchemas<Args extends ReadonlyArray<ServiceFreeSchema>> = Args extends readonly []
26
+ ? []
27
+ : Args extends readonly [
28
+ infer Head extends ServiceFreeSchema,
29
+ ...infer Tail extends ReadonlyArray<ServiceFreeSchema>,
30
+ ]
31
+ ? [S.Schema.Type<Head>, ...ArgsFromSchemas<Tail>]
32
+ : Array<S.Schema.Type<Args[number]>>;
33
+
34
+ type EncodedArgsFromSchemas<Args extends ReadonlyArray<ServiceFreeSchema>> =
35
+ Args extends readonly []
36
+ ? []
37
+ : Args extends readonly [
38
+ infer Head extends ServiceFreeSchema,
39
+ ...infer Tail extends ReadonlyArray<ServiceFreeSchema>,
40
+ ]
41
+ ? [S.Codec.Encoded<Head>, ...EncodedArgsFromSchemas<Tail>]
42
+ : Array<S.Codec.Encoded<Args[number]>>;
43
+
44
+ export type Args<Self extends Any> = ArgsFromSchemas<Self["args"]>;
45
+
46
+ export type EncodedArgs<Self extends Any> = EncodedArgsFromSchemas<Self["args"]>;
47
+
48
+ export type Success<Self extends Any> = S.Schema.Type<Self["success"]>;
49
+
50
+ export type EncodedSuccess<Self extends Any> = S.Codec.Encoded<Self["success"]>;
51
+ }
52
+
53
+ export type Methods = Record<string, Method.Any>;
54
+
9
55
  /**
10
56
  * RPC contract for a Worker service.
11
57
  *
12
58
  * Create with {@link make} and reuse to type both worker implementations and
13
59
  * service bindings in other workers.
14
60
  */
15
- export type Definition<
16
- Id extends string = string,
17
- Methods extends RpcDefinition.Methods = RpcDefinition.Methods,
18
- > = RpcDefinition.Definition<Id, Methods>;
61
+ export interface Definition<Id extends string = string, MethodsShape extends Methods = Methods> {
62
+ readonly id: Id;
63
+ readonly methods: MethodsShape;
64
+ }
19
65
 
20
66
  export namespace Definition {
21
- export type Any = RpcDefinition.Definition.Any;
67
+ export type Any = Definition<string, Methods>;
22
68
  }
23
69
 
24
70
  export type ReservedMethodName = WorkerEntrypoint.ReservedMethodName;
25
71
 
72
+ export type NoReservedMethods<MethodsShape extends Methods> =
73
+ Extract<keyof MethodsShape, ReservedMethodName> extends never ? MethodsShape : never;
74
+
26
75
  const reservedMethodNames = new Set<string>([
27
76
  "constructor",
28
77
  "dup",
@@ -43,38 +92,27 @@ const reservedMethodNames = new Set<string>([
43
92
  /**
44
93
  * Promise-based client API derived from a {@link Definition}.
45
94
  */
46
- export type ServerApi<Self extends Definition.Any> = RpcDefinition.Definition.ServerApi<Self>;
47
-
48
- export type Api<Self extends Definition.Any> = RpcDefinition.Definition.Api<
49
- Self,
50
- ReservedMethodName
51
- >;
52
-
53
- declare const BindingServiceTypeId: unique symbol;
95
+ export type ServerApi<Self extends Definition.Any> = {
96
+ readonly [Key in keyof Self["methods"]]: (
97
+ ...args: Method.Args<Self["methods"][Key]>
98
+ ) => Promise<Method.Success<Self["methods"][Key]>>;
99
+ };
54
100
 
55
- /**
56
- * Nominal service marker for a worker binding created with {@link make}.
57
- */
58
- export interface BindingService<Id extends string, Self extends Definition.Any> {
59
- readonly [BindingServiceTypeId]: {
60
- readonly id: Id;
61
- readonly definition: Self;
62
- };
63
- }
101
+ export type Api<Self extends Definition.Any> = Rpc.Provider<ServerApi<Self>, ReservedMethodName>;
64
102
 
65
103
  /**
66
104
  * Effect handlers for each RPC method in a worker definition.
67
105
  */
68
106
  export type Handlers<ROut, Self extends Definition.Any> = {
69
107
  readonly [Key in keyof Self["methods"]]: (
70
- ...args: RpcDefinition.Method.Args<Self["methods"][Key]>
71
- ) => WorkerRpcHandler<ROut, RpcDefinition.Method.Success<Self["methods"][Key]>>;
108
+ ...args: Method.Args<Self["methods"][Key]>
109
+ ) => WorkerRpcHandler<ROut, Method.Success<Self["methods"][Key]>>;
72
110
  };
73
111
 
74
112
  type BoundaryHandlers<ROut, Self extends Definition.Any> = {
75
113
  readonly [Key in keyof Self["methods"]]: (
76
114
  ...args: Array<unknown>
77
- ) => WorkerRpcHandler<ROut, RpcDefinition.Method.EncodedSuccess<Self["methods"][Key]>>;
115
+ ) => WorkerRpcHandler<ROut, Method.EncodedSuccess<Self["methods"][Key]>>;
78
116
  };
79
117
 
80
118
  /**
@@ -87,10 +125,57 @@ export interface Options<ROut, Self extends Definition.Any> extends Omit<
87
125
  readonly rpc: Handlers<ROut, Self>;
88
126
  }
89
127
 
128
+ export type LayerOptions = {
129
+ readonly binding: string;
130
+ };
131
+
132
+ export type TagClass<Self, Id extends string, MethodsShape extends Methods> = Context.ServiceClass<
133
+ Self,
134
+ Id,
135
+ ServiceBinding.ServiceBindingEffectClient<
136
+ Api<Definition<Id, MethodsShape>>,
137
+ Definition<Id, MethodsShape>
138
+ >
139
+ > &
140
+ ServiceBinding.ServiceBindingStaticClient<
141
+ Self,
142
+ Api<Definition<Id, MethodsShape>>,
143
+ Definition<Id, MethodsShape>
144
+ > & {
145
+ readonly id: Id;
146
+ readonly methods: MethodsShape;
147
+ readonly make: <ROut, LayerError>(
148
+ layer: Layer.Layer<
149
+ ROut,
150
+ LayerError,
151
+ WorkerEntrypoint.ExecutionContext | WorkerEntrypoint.WorkerContext | WorkerEnvironment
152
+ >,
153
+ options: Options<ROut, Definition<Id, MethodsShape>>,
154
+ ) => WorkerEntrypoint.WorkerClass<Handlers<ROut, Definition<Id, MethodsShape>>, ROut>;
155
+ readonly layer: (
156
+ options: LayerOptions,
157
+ ) => Layer.Layer<
158
+ Self,
159
+ Binding.BindingNotFoundError | Binding.BindingValidationError,
160
+ WorkerEnvironment
161
+ >;
162
+ };
163
+
90
164
  /**
91
165
  * Defines a single RPC method schema in a worker definition.
92
166
  */
93
- export const method = RpcDefinition.method;
167
+ export const method = RpcDefinition.method as {
168
+ <Success extends ServiceFreeSchema>(definition: {
169
+ readonly success: Success;
170
+ }): Method<readonly [], Success>;
171
+ <
172
+ const Args extends ReadonlyArray<ServiceFreeSchema>,
173
+ Success extends ServiceFreeSchema,
174
+ >(definition: {
175
+ readonly args: Args;
176
+ readonly success: Success;
177
+ }): Method<Args, Success>;
178
+ };
94
179
 
95
180
  /**
96
181
  * Creates a typed worker RPC definition plus helpers for implementation and bindings.
@@ -105,9 +190,9 @@ export const method = RpcDefinition.method;
105
190
  * });
106
191
  * ```
107
192
  */
108
- const makeDefinition = <Id extends string, const MethodsShape extends RpcDefinition.Methods>(
193
+ const makeDefinition = <Id extends string, const MethodsShape extends Methods>(
109
194
  id: Id,
110
- methods: MethodsShape & RpcDefinition.NoReservedMethods<MethodsShape, ReservedMethodName>,
195
+ methods: MethodsShape & NoReservedMethods<MethodsShape>,
111
196
  ) => {
112
197
  type SelfDefinition = Definition<Id, MethodsShape>;
113
198
  RpcDefinition.assertNoReservedMethods("Worker", methods, reservedMethodNames);
@@ -126,49 +211,88 @@ const makeDefinition = <Id extends string, const MethodsShape extends RpcDefinit
126
211
  ...options,
127
212
  rpc: wrapHandlers(definition, options.rpc),
128
213
  }),
129
- Binding:
130
- <Self>() =>
131
- <BindingId extends string>(
132
- bindingId: BindingId,
133
- binding: Omit<ServiceBinding.ServiceBindingDefinition<SelfDefinition>, "definition">,
134
- ) =>
135
- ServiceBinding.Service<Self, Api<SelfDefinition>>()<BindingId, SelfDefinition>(bindingId, {
136
- ...binding,
137
- definition,
138
- }),
139
- binding: <BindingId extends string>(
140
- bindingId: BindingId,
141
- binding: Omit<ServiceBinding.ServiceBindingDefinition<SelfDefinition>, "definition">,
142
- ) =>
143
- ServiceBinding.Service<BindingService<BindingId, SelfDefinition>, Api<SelfDefinition>>()<
144
- BindingId,
145
- SelfDefinition
146
- >(bindingId, {
147
- ...binding,
148
- definition,
149
- }),
150
214
  });
151
215
  };
152
216
 
153
- export const make = makeDefinition;
217
+ export const make = <Id extends string, const MethodsShape extends Methods>(
218
+ id: Id,
219
+ methods: MethodsShape & NoReservedMethods<MethodsShape>,
220
+ ) =>
221
+ Tag<Definition<Id, MethodsShape>>()<Id, MethodsShape>(
222
+ id,
223
+ methods as MethodsShape & NoReservedMethods<MethodsShape>,
224
+ );
154
225
 
155
226
  export const Tag =
156
- <_Self>() =>
157
- <Id extends string, const MethodsShape extends RpcDefinition.Methods>(
227
+ <Self>() =>
228
+ <Id extends string, const MethodsShape extends Methods>(
158
229
  id: Id,
159
- methods: MethodsShape & RpcDefinition.NoReservedMethods<MethodsShape, ReservedMethodName>,
230
+ methods: MethodsShape & NoReservedMethods<MethodsShape>,
160
231
  ) => {
161
232
  const definition = makeDefinition<Id, MethodsShape>(id, methods);
233
+ type SelfDefinition = Definition<Id, MethodsShape>;
234
+ type ClientApi = Api<SelfDefinition>;
235
+ const tag = Context.Service<
236
+ Self,
237
+ ServiceBinding.ServiceBindingEffectClient<ClientApi, SelfDefinition>
238
+ >()(id);
239
+
240
+ const bindingDefinition = (binding: LayerOptions) => ({
241
+ ...binding,
242
+ definition,
243
+ });
244
+
245
+ const layer = (binding: LayerOptions) =>
246
+ ServiceBinding.layer<Self, ClientApi, SelfDefinition>(tag, bindingDefinition(binding));
247
+
248
+ const fetch = (input: RequestInfo | URL, init?: RequestInit) =>
249
+ Effect.gen(function* () {
250
+ const service = yield* tag;
251
+ return yield* service.fetch(input, init);
252
+ });
253
+
254
+ const rpc = <Method extends keyof ClientApi>(
255
+ method: Method,
256
+ ...args: ClientApi[Method] extends (...args: infer Args) => unknown ? Args : never
257
+ ) =>
258
+ Effect.gen(function* () {
259
+ const service = yield* tag;
260
+ return yield* service.rpc(method as never, ...(args as never));
261
+ });
262
+
263
+ const call = <Method extends keyof ClientApi>(
264
+ method: Method,
265
+ ...args: ClientApi[Method] extends (...args: infer Args) => unknown ? Args : never
266
+ ) =>
267
+ Effect.gen(function* () {
268
+ const service = yield* tag;
269
+ return yield* service.call(method as never, ...(args as never));
270
+ });
271
+
272
+ const scopedCall = <Method extends keyof ClientApi>(
273
+ method: Method,
274
+ ...args: ClientApi[Method] extends (...args: infer Args) => unknown ? Args : never
275
+ ) =>
276
+ Effect.gen(function* () {
277
+ const service = yield* tag;
278
+ return yield* service.scopedCall(method as never, ...(args as never));
279
+ });
162
280
 
163
- abstract class WorkerDefinitionClass {
164
- static readonly id = definition.id;
165
- static readonly methods = definition.methods;
166
- static readonly make = definition.make;
167
- static readonly Binding = definition.Binding;
168
- static readonly binding = definition.binding;
169
- }
281
+ const directMethods = ServiceBinding.makeDirectMethods<Self, ClientApi, SelfDefinition>(
282
+ definition,
283
+ call as never,
284
+ );
170
285
 
171
- return WorkerDefinitionClass as (abstract new () => object) & typeof definition;
286
+ return Object.assign(tag, directMethods, {
287
+ id: definition.id,
288
+ methods: definition.methods,
289
+ make: definition.make,
290
+ layer,
291
+ fetch,
292
+ rpc,
293
+ call,
294
+ scopedCall,
295
+ }) as unknown as TagClass<Self, Id, MethodsShape>;
172
296
  };
173
297
 
174
298
  export const Worker = Tag;
@@ -209,4 +333,4 @@ export type HandlerEffect<
209
333
  ROut,
210
334
  Self extends Definition.Any,
211
335
  Key extends keyof Self["methods"],
212
- > = WorkerRpcHandler<ROut, RpcDefinition.Method.Success<Self["methods"][Key]>>;
336
+ > = WorkerRpcHandler<ROut, Method.Success<Self["methods"][Key]>>;
package/src/Workflow.ts CHANGED
@@ -252,10 +252,6 @@ export const waitForEvent = <Payload>(
252
252
  workflowStep.waitForEvent<Payload>(name, options),
253
253
  );
254
254
 
255
- export const Tag = WorkflowDefinition.Tag;
256
-
257
- export const implement = WorkflowDefinition.implement;
258
-
259
255
  export type Definition<
260
256
  Id extends string = string,
261
257
  Payload extends WorkflowDefinition.Definition.Any["payload"] =
@@ -268,6 +264,29 @@ export namespace Definition {
268
264
  export type Any = WorkflowDefinition.Definition.Any;
269
265
  }
270
266
 
267
+ export type LayerOptions = WorkflowDefinition.LayerOptions;
268
+
269
+ export type TagClass<
270
+ Self,
271
+ Id extends string,
272
+ Payload extends WorkflowDefinition.Definition.Any["payload"],
273
+ Result extends WorkflowDefinition.Definition.Any["result"],
274
+ > = WorkflowDefinition.TagClass<Self, Id, Payload, Result>;
275
+
276
+ export const Tag: <Self>() => <
277
+ Id extends string,
278
+ Payload extends WorkflowDefinition.Definition.Any["payload"],
279
+ Result extends WorkflowDefinition.Definition.Any["result"],
280
+ >(
281
+ id: Id,
282
+ definition: {
283
+ readonly payload: Payload;
284
+ readonly result: Result;
285
+ },
286
+ ) => TagClass<Self, Id, Payload, Result> = WorkflowDefinition.Tag;
287
+
288
+ export const implement = WorkflowDefinition.implement;
289
+
271
290
  export type Handler<
272
291
  ROut,
273
292
  Self extends WorkflowDefinition.Definition.Any,
@@ -1,10 +1,8 @@
1
- import { Data, Effect, Option, Schema as S } from "effect";
1
+ import { Context, Data, Effect, Option, Schema as S } from "effect";
2
2
 
3
3
  import * as Binding from "./Binding";
4
4
  import type * as RpcDefinition from "./RpcDefinition";
5
5
 
6
- const TypeId = "effect-cf/WorkflowBinding" as const;
7
-
8
6
  export type WorkflowInstanceCreateOptions<Payload> = Omit<
9
7
  globalThis.WorkflowInstanceCreateOptions<Payload>,
10
8
  "params"
@@ -66,20 +64,27 @@ export interface WorkflowBindingDefinition<
66
64
  readonly result: Result;
67
65
  }
68
66
 
69
- declare const WorkflowServiceTypeId: unique symbol;
70
-
71
- export interface WorkflowService<
72
- Id extends string,
67
+ export interface WorkflowBindingClient<
73
68
  Payload extends RpcDefinition.ServiceFreeSchema,
74
69
  Result extends RpcDefinition.ServiceFreeSchema,
75
70
  > {
76
- readonly [WorkflowServiceTypeId]: {
77
- readonly id: Id;
78
- readonly payload: S.Schema.Type<Payload>;
79
- readonly encodedPayload: S.Codec.Encoded<Payload>;
80
- readonly result: S.Schema.Type<Result>;
81
- readonly encodedResult: S.Codec.Encoded<Result>;
82
- };
71
+ readonly create: (
72
+ payload: S.Schema.Type<Payload>,
73
+ options?: WorkflowInstanceCreateOptions<S.Codec.Encoded<Payload>>,
74
+ ) => Effect.Effect<
75
+ WorkflowInstance<S.Schema.Type<Result>>,
76
+ WorkflowOperationError | S.SchemaError
77
+ >;
78
+ readonly createBatch: (
79
+ batch: WorkflowInstanceCreateBatchOptions<S.Schema.Type<Payload>, S.Codec.Encoded<Payload>>,
80
+ ) => Effect.Effect<
81
+ ReadonlyArray<WorkflowInstance<S.Schema.Type<Result>>>,
82
+ WorkflowOperationError | S.SchemaError
83
+ >;
84
+ readonly get: (
85
+ instanceId: string,
86
+ ) => Effect.Effect<WorkflowInstance<S.Schema.Type<Result>>, WorkflowOperationError>;
87
+ readonly unsafeRaw: Effect.Effect<globalThis.Workflow<S.Codec.Encoded<Payload>>>;
83
88
  }
84
89
 
85
90
  export class WorkflowOperationError extends Data.TaggedError("WorkflowOperationError")<{
@@ -107,7 +112,7 @@ const tryWorkflowPromise = <A>(
107
112
  catch: (cause) => workflowError(binding, operation, cause),
108
113
  });
109
114
 
110
- const isWorkflow = <Payload>(value: unknown): value is globalThis.Workflow<Payload> => {
115
+ export const isWorkflow = <Payload>(value: unknown): value is globalThis.Workflow<Payload> => {
111
116
  if (typeof value !== "object" || value === null) {
112
117
  return false;
113
118
  }
@@ -121,102 +126,83 @@ const isWorkflow = <Payload>(value: unknown): value is globalThis.Workflow<Paylo
121
126
  );
122
127
  };
123
128
 
124
- export const make = <
125
- Id extends string,
129
+ export const makeClient = <
126
130
  Payload extends RpcDefinition.ServiceFreeSchema,
127
131
  Result extends RpcDefinition.ServiceFreeSchema,
128
132
  >(
129
- id: Id,
130
133
  definition: WorkflowBindingDefinition<Payload, Result>,
131
- ) => Service<WorkflowService<Id, Payload, Result>>()<Id, Payload, Result>(id, definition);
132
-
133
- export const Service =
134
- <Self>() =>
135
- <
136
- Id extends string,
137
- Payload extends RpcDefinition.ServiceFreeSchema,
138
- Result extends RpcDefinition.ServiceFreeSchema,
139
- >(
140
- id: Id,
141
- definition: WorkflowBindingDefinition<Payload, Result>,
142
- ) => {
143
- type PayloadValue = S.Schema.Type<Payload>;
144
- type EncodedPayload = S.Codec.Encoded<Payload>;
145
- type ResultValue = S.Schema.Type<Result>;
146
-
147
- const tag = Binding.Service<Self>()(
148
- id,
149
- definition.binding,
150
- (value): value is globalThis.Workflow<EncodedPayload> => isWorkflow<EncodedPayload>(value),
151
- );
152
-
153
- const encodePayload = S.encodeEffect(definition.payload);
154
- const decodeResult = S.decodeUnknownEffect(definition.result);
155
-
156
- const wrapInstance = (raw: globalThis.WorkflowInstance): WorkflowInstance<ResultValue> => {
157
- const operation = <A>(name: string, evaluate: () => Promise<A>) =>
158
- tryWorkflowPromise(definition.binding, name, evaluate);
159
-
160
- return {
161
- raw,
162
- id: raw.id,
163
- pause: operation("pause", () => raw.pause()),
164
- resume: operation("resume", () => raw.resume()),
165
- terminate: operation("terminate", () => raw.terminate()),
166
- restart: (options) =>
167
- operation("restart", () =>
168
- (raw as { restart(options?: WorkflowInstanceRestartOptions): Promise<void> }).restart(
169
- options,
170
- ),
134
+ ): ((
135
+ workflow: globalThis.Workflow<S.Codec.Encoded<Payload>>,
136
+ ) => WorkflowBindingClient<Payload, Result>) => {
137
+ type PayloadValue = S.Schema.Type<Payload>;
138
+ type EncodedPayload = S.Codec.Encoded<Payload>;
139
+ type ResultValue = S.Schema.Type<Result>;
140
+
141
+ const encodePayload = S.encodeEffect(definition.payload);
142
+ const decodeResult = S.decodeUnknownEffect(definition.result);
143
+
144
+ const wrapInstance = (raw: globalThis.WorkflowInstance): WorkflowInstance<ResultValue> => {
145
+ const operation = <A>(name: string, evaluate: () => Promise<A>) =>
146
+ tryWorkflowPromise(definition.binding, name, evaluate);
147
+
148
+ return {
149
+ raw,
150
+ id: raw.id,
151
+ pause: operation("pause", () => raw.pause()),
152
+ resume: operation("resume", () => raw.resume()),
153
+ terminate: operation("terminate", () => raw.terminate()),
154
+ restart: (options) =>
155
+ operation("restart", () =>
156
+ (raw as { restart(options?: WorkflowInstanceRestartOptions): Promise<void> }).restart(
157
+ options,
171
158
  ),
172
- status: operation("status", () => raw.status()).pipe(
173
- Effect.flatMap((status) =>
174
- Effect.gen(function* () {
175
- const output =
176
- status.output === undefined
177
- ? Option.none<ResultValue>()
178
- : Option.some(
179
- yield* decodeResult(status.output).pipe(
180
- Effect.mapError(
181
- (cause) =>
182
- new WorkflowResultDecodeError({
183
- binding: definition.binding,
184
- instanceId: raw.id,
185
- cause,
186
- }),
187
- ),
159
+ ),
160
+ status: operation("status", () => raw.status()).pipe(
161
+ Effect.flatMap((status) =>
162
+ Effect.gen(function* () {
163
+ const output =
164
+ status.output === undefined
165
+ ? Option.none<ResultValue>()
166
+ : Option.some(
167
+ yield* decodeResult(status.output).pipe(
168
+ Effect.mapError(
169
+ (cause) =>
170
+ new WorkflowResultDecodeError({
171
+ binding: definition.binding,
172
+ instanceId: raw.id,
173
+ cause,
174
+ }),
188
175
  ),
189
- );
190
-
191
- return {
192
- status: status.status,
193
- output,
194
- error: status.error === undefined ? Option.none() : Option.some(status.error),
195
- };
196
- }),
197
- ),
176
+ ),
177
+ );
178
+
179
+ return {
180
+ status: status.status,
181
+ output,
182
+ error: status.error === undefined ? Option.none() : Option.some(status.error),
183
+ };
184
+ }),
198
185
  ),
199
- sendEvent: (event) => operation("sendEvent", () => raw.sendEvent(event)),
200
- };
186
+ ),
187
+ sendEvent: (event) => operation("sendEvent", () => raw.sendEvent(event)),
201
188
  };
189
+ };
202
190
 
203
- const create = Effect.fnUntraced(function* (
191
+ return (workflow) => ({
192
+ create: Effect.fnUntraced(function* (
204
193
  payload: PayloadValue,
205
194
  options?: WorkflowInstanceCreateOptions<EncodedPayload>,
206
195
  ) {
207
- const workflow = yield* tag;
208
196
  const encoded = yield* encodePayload(payload);
209
197
  const raw = yield* tryWorkflowPromise(definition.binding, "create", () =>
210
198
  workflow.create({ ...options, params: encoded }),
211
199
  );
212
200
 
213
201
  return wrapInstance(raw);
214
- });
215
-
216
- const createBatch = Effect.fnUntraced(function* (
202
+ }),
203
+ createBatch: Effect.fnUntraced(function* (
217
204
  batch: WorkflowInstanceCreateBatchOptions<PayloadValue, EncodedPayload>,
218
205
  ) {
219
- const workflow = yield* tag;
220
206
  const encodedBatch: Array<globalThis.WorkflowInstanceCreateOptions<EncodedPayload>> = [];
221
207
 
222
208
  for (const item of batch) {
@@ -233,22 +219,27 @@ export const Service =
233
219
  );
234
220
 
235
221
  return rawInstances.map(wrapInstance);
236
- });
237
-
238
- const get = Effect.fnUntraced(function* (instanceId: string) {
239
- const workflow = yield* tag;
240
- const raw = yield* tryWorkflowPromise(definition.binding, "get", () =>
241
- workflow.get(instanceId),
242
- );
222
+ }),
223
+ get: (instanceId) =>
224
+ tryWorkflowPromise(definition.binding, "get", () => workflow.get(instanceId)).pipe(
225
+ Effect.map(wrapInstance),
226
+ ),
227
+ unsafeRaw: Effect.succeed(workflow),
228
+ });
229
+ };
243
230
 
244
- return wrapInstance(raw);
245
- });
246
-
247
- return Object.assign(tag, {
248
- [TypeId]: TypeId,
249
- binding: definition.binding,
250
- create,
251
- createBatch,
252
- get,
253
- });
254
- };
231
+ export const layer = <
232
+ Self,
233
+ Payload extends RpcDefinition.ServiceFreeSchema,
234
+ Result extends RpcDefinition.ServiceFreeSchema,
235
+ >(
236
+ tag: Context.Service<Self, WorkflowBindingClient<Payload, Result>>,
237
+ definition: WorkflowBindingDefinition<Payload, Result>,
238
+ ) =>
239
+ Binding.layer(
240
+ tag,
241
+ definition.binding,
242
+ (value): value is globalThis.Workflow<S.Codec.Encoded<Payload>> =>
243
+ isWorkflow<S.Codec.Encoded<Payload>>(value),
244
+ makeClient(definition),
245
+ );