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,22 +1,68 @@
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 * as DurableObjectEntrypoint from "./DurableObject";
4
6
  import type { DurableObjectHandler } from "./DurableObject";
5
7
  import * as DurableObjectNamespace from "./DurableObjectNamespace";
6
8
  import type { DurableObjectState } from "./DurableObjectState";
9
+ import type * as Rpc from "./Rpc";
7
10
  import * as RpcDefinition from "./RpcDefinition";
8
11
  import type { WorkerEnvironment } from "./Environment";
9
12
 
13
+ export type ServiceFreeSchema = S.Codec<any, any, never, never>;
14
+
15
+ export interface Method<
16
+ Args extends ReadonlyArray<ServiceFreeSchema> = ReadonlyArray<ServiceFreeSchema>,
17
+ Success extends ServiceFreeSchema = ServiceFreeSchema,
18
+ > {
19
+ readonly args: Args;
20
+ readonly success: Success;
21
+ }
22
+
23
+ export namespace Method {
24
+ export type Any = Method<ReadonlyArray<ServiceFreeSchema>, ServiceFreeSchema>;
25
+
26
+ type ArgsFromSchemas<Args extends ReadonlyArray<ServiceFreeSchema>> = Args extends readonly []
27
+ ? []
28
+ : Args extends readonly [
29
+ infer Head extends ServiceFreeSchema,
30
+ ...infer Tail extends ReadonlyArray<ServiceFreeSchema>,
31
+ ]
32
+ ? [S.Schema.Type<Head>, ...ArgsFromSchemas<Tail>]
33
+ : Array<S.Schema.Type<Args[number]>>;
34
+
35
+ type EncodedArgsFromSchemas<Args extends ReadonlyArray<ServiceFreeSchema>> =
36
+ Args extends readonly []
37
+ ? []
38
+ : Args extends readonly [
39
+ infer Head extends ServiceFreeSchema,
40
+ ...infer Tail extends ReadonlyArray<ServiceFreeSchema>,
41
+ ]
42
+ ? [S.Codec.Encoded<Head>, ...EncodedArgsFromSchemas<Tail>]
43
+ : Array<S.Codec.Encoded<Args[number]>>;
44
+
45
+ export type Args<Self extends Any> = ArgsFromSchemas<Self["args"]>;
46
+
47
+ export type EncodedArgs<Self extends Any> = EncodedArgsFromSchemas<Self["args"]>;
48
+
49
+ export type Success<Self extends Any> = S.Schema.Type<Self["success"]>;
50
+
51
+ export type EncodedSuccess<Self extends Any> = S.Codec.Encoded<Self["success"]>;
52
+ }
53
+
54
+ export type Methods = Record<string, Method.Any>;
55
+
10
56
  /**
11
57
  * RPC contract for a Durable Object class.
12
58
  */
13
- export type Definition<
14
- Id extends string = string,
15
- Methods extends RpcDefinition.Methods = RpcDefinition.Methods,
16
- > = RpcDefinition.Definition<Id, Methods>;
59
+ export interface Definition<Id extends string = string, MethodsShape extends Methods = Methods> {
60
+ readonly id: Id;
61
+ readonly methods: MethodsShape;
62
+ }
17
63
 
18
64
  export namespace Definition {
19
- export type Any = RpcDefinition.Definition.Any;
65
+ export type Any = Definition<string, Methods>;
20
66
  }
21
67
 
22
68
  export type ReservedMethodName =
@@ -27,6 +73,9 @@ export type ReservedMethodName =
27
73
  | "webSocketClose"
28
74
  | "webSocketError";
29
75
 
76
+ export type NoReservedMethods<MethodsShape extends Methods> =
77
+ Extract<keyof MethodsShape, ReservedMethodName> extends never ? MethodsShape : never;
78
+
30
79
  const reservedMethodNames = new Set<string>([
31
80
  "constructor",
32
81
  "dup",
@@ -40,38 +89,27 @@ const reservedMethodNames = new Set<string>([
40
89
  /**
41
90
  * Promise-based client API derived from a Durable Object definition.
42
91
  */
43
- export type ServerApi<Self extends Definition.Any> = RpcDefinition.Definition.ServerApi<Self>;
44
-
45
- export type Api<Self extends Definition.Any> = RpcDefinition.Definition.Api<
46
- Self,
47
- ReservedMethodName
48
- >;
92
+ export type ServerApi<Self extends Definition.Any> = {
93
+ readonly [Key in keyof Self["methods"]]: (
94
+ ...args: Method.Args<Self["methods"][Key]>
95
+ ) => Promise<Method.Success<Self["methods"][Key]>>;
96
+ };
49
97
 
50
- declare const NamespaceServiceTypeId: unique symbol;
51
-
52
- /**
53
- * Nominal service marker for a Durable Object namespace binding.
54
- */
55
- export interface NamespaceService<Id extends string, Self extends Definition.Any> {
56
- readonly [NamespaceServiceTypeId]: {
57
- readonly id: Id;
58
- readonly definition: Self;
59
- };
60
- }
98
+ export type Api<Self extends Definition.Any> = Rpc.Provider<ServerApi<Self>, ReservedMethodName>;
61
99
 
62
100
  /**
63
101
  * Effect handlers for each RPC method in a Durable Object definition.
64
102
  */
65
103
  export type Handlers<ROut, Self extends Definition.Any> = {
66
104
  readonly [Key in keyof Self["methods"]]: (
67
- ...args: RpcDefinition.Method.Args<Self["methods"][Key]>
68
- ) => DurableObjectHandler<ROut, RpcDefinition.Method.Success<Self["methods"][Key]>>;
105
+ ...args: Method.Args<Self["methods"][Key]>
106
+ ) => DurableObjectHandler<ROut, Method.Success<Self["methods"][Key]>>;
69
107
  };
70
108
 
71
109
  type BoundaryHandlers<ROut, Self extends Definition.Any> = {
72
110
  readonly [Key in keyof Self["methods"]]: (
73
111
  ...args: Array<unknown>
74
- ) => DurableObjectHandler<ROut, RpcDefinition.Method.EncodedSuccess<Self["methods"][Key]>>;
112
+ ) => DurableObjectHandler<ROut, Method.EncodedSuccess<Self["methods"][Key]>>;
75
113
  };
76
114
 
77
115
  /**
@@ -84,10 +122,56 @@ export interface Options<ROut, Self extends Definition.Any> extends Omit<
84
122
  readonly rpc: Handlers<ROut, Self>;
85
123
  }
86
124
 
125
+ export type LayerOptions = {
126
+ readonly binding: string;
127
+ };
128
+
129
+ export type TagClass<Self, Id extends string, MethodsShape extends Methods> = Context.ServiceClass<
130
+ Self,
131
+ Id,
132
+ DurableObjectNamespace.DurableObjectNamespaceEffectClient<
133
+ Api<Definition<Id, MethodsShape>>,
134
+ Definition<Id, MethodsShape>
135
+ >
136
+ > &
137
+ DurableObjectNamespace.DurableObjectNamespaceStaticClient<
138
+ Self,
139
+ Api<Definition<Id, MethodsShape>>,
140
+ Definition<Id, MethodsShape>
141
+ > & {
142
+ readonly id: Id;
143
+ readonly methods: MethodsShape;
144
+ readonly make: <ROut, LayerError>(
145
+ layer: Layer.Layer<ROut, LayerError, DurableObjectState | WorkerEnvironment>,
146
+ options: Options<ROut, Definition<Id, MethodsShape>>,
147
+ ) => DurableObjectEntrypoint.DurableObjectClass<
148
+ Handlers<ROut, Definition<Id, MethodsShape>>,
149
+ ROut
150
+ >;
151
+ readonly layer: (
152
+ options: LayerOptions,
153
+ ) => Layer.Layer<
154
+ Self,
155
+ Binding.BindingNotFoundError | Binding.BindingValidationError,
156
+ WorkerEnvironment
157
+ >;
158
+ };
159
+
87
160
  /**
88
161
  * Defines a single RPC method schema in a Durable Object definition.
89
162
  */
90
- export const method = RpcDefinition.method;
163
+ export const method = RpcDefinition.method as {
164
+ <Success extends ServiceFreeSchema>(definition: {
165
+ readonly success: Success;
166
+ }): Method<readonly [], Success>;
167
+ <
168
+ const Args extends ReadonlyArray<ServiceFreeSchema>,
169
+ Success extends ServiceFreeSchema,
170
+ >(definition: {
171
+ readonly args: Args;
172
+ readonly success: Success;
173
+ }): Method<Args, Success>;
174
+ };
91
175
 
92
176
  /**
93
177
  * Creates a Durable Object RPC definition plus implementation/binding helpers.
@@ -102,9 +186,9 @@ export const method = RpcDefinition.method;
102
186
  * });
103
187
  * ```
104
188
  */
105
- const makeDefinition = <Id extends string, const MethodsShape extends RpcDefinition.Methods>(
189
+ const makeDefinition = <Id extends string, const MethodsShape extends Methods>(
106
190
  id: Id,
107
- methods: MethodsShape & RpcDefinition.NoReservedMethods<MethodsShape, ReservedMethodName>,
191
+ methods: MethodsShape & NoReservedMethods<MethodsShape>,
108
192
  ) => {
109
193
  type SelfDefinition = Definition<Id, MethodsShape>;
110
194
  RpcDefinition.assertNoReservedMethods("Durable Object", methods, reservedMethodNames);
@@ -119,58 +203,153 @@ const makeDefinition = <Id extends string, const MethodsShape extends RpcDefinit
119
203
  ...options,
120
204
  rpc: wrapHandlers(definition, options.rpc),
121
205
  }),
122
- Namespace:
123
- <Self>() =>
124
- <BindingId extends string>(
125
- bindingId: BindingId,
126
- binding: Omit<
127
- DurableObjectNamespace.DurableObjectNamespaceBindingDefinition<SelfDefinition>,
128
- "definition"
129
- >,
130
- ) =>
131
- DurableObjectNamespace.Service<Self, Api<SelfDefinition>>()<BindingId, SelfDefinition>(
132
- bindingId,
133
- {
134
- ...binding,
135
- definition,
136
- },
137
- ),
138
- namespace: <BindingId extends string>(
139
- bindingId: BindingId,
140
- binding: Omit<
141
- DurableObjectNamespace.DurableObjectNamespaceBindingDefinition<SelfDefinition>,
142
- "definition"
143
- >,
144
- ) =>
145
- DurableObjectNamespace.Service<
146
- NamespaceService<BindingId, SelfDefinition>,
147
- Api<SelfDefinition>
148
- >()<BindingId, SelfDefinition>(bindingId, {
149
- ...binding,
150
- definition,
151
- }),
152
206
  });
153
207
  };
154
208
 
155
- export const make = makeDefinition;
209
+ export const make = <Id extends string, const MethodsShape extends Methods>(
210
+ id: Id,
211
+ methods: MethodsShape & NoReservedMethods<MethodsShape>,
212
+ ) =>
213
+ Tag<Definition<Id, MethodsShape>>()<Id, MethodsShape>(
214
+ id,
215
+ methods as MethodsShape & NoReservedMethods<MethodsShape>,
216
+ );
156
217
 
157
218
  export const Tag =
158
- <_Self>() =>
159
- <Id extends string, const MethodsShape extends RpcDefinition.Methods>(
219
+ <Self>() =>
220
+ <Id extends string, const MethodsShape extends Methods>(
160
221
  id: Id,
161
- methods: MethodsShape & RpcDefinition.NoReservedMethods<MethodsShape, ReservedMethodName>,
222
+ methods: MethodsShape & NoReservedMethods<MethodsShape>,
162
223
  ) => {
163
224
  const definition = makeDefinition<Id, MethodsShape>(id, methods);
225
+ type SelfDefinition = Definition<Id, MethodsShape>;
226
+ type ClientApi = Api<SelfDefinition>;
227
+ const tag = Context.Service<
228
+ Self,
229
+ DurableObjectNamespace.DurableObjectNamespaceEffectClient<ClientApi, SelfDefinition>
230
+ >()(id);
231
+
232
+ const bindingDefinition = (binding: LayerOptions) => ({
233
+ ...binding,
234
+ definition,
235
+ });
236
+
237
+ const layer = (binding: LayerOptions) =>
238
+ DurableObjectNamespace.layer<Self, ClientApi, SelfDefinition>(
239
+ tag,
240
+ bindingDefinition(binding),
241
+ );
242
+
243
+ const newUniqueId = Effect.fnUntraced(function* (
244
+ options?: globalThis.DurableObjectNamespaceNewUniqueIdOptions,
245
+ ) {
246
+ const namespace = yield* tag;
247
+ return yield* namespace.newUniqueId(options);
248
+ });
249
+
250
+ const idFromName = Effect.fnUntraced(function* (name: string) {
251
+ const namespace = yield* tag;
252
+ return yield* namespace.idFromName(name);
253
+ });
254
+
255
+ const idFromString = Effect.fnUntraced(function* (value: string) {
256
+ const namespace = yield* tag;
257
+ return yield* namespace.idFromString(value);
258
+ });
259
+
260
+ const get = Effect.fnUntraced(function* (
261
+ objectId: globalThis.DurableObjectId,
262
+ options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
263
+ ) {
264
+ const namespace = yield* tag;
265
+ return yield* namespace.get(objectId, options);
266
+ });
267
+
268
+ const getByName = Effect.fnUntraced(function* (
269
+ name: string,
270
+ options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
271
+ ) {
272
+ const namespace = yield* tag;
273
+ return yield* namespace.getByName(name, options);
274
+ });
275
+
276
+ const jurisdiction = Effect.fnUntraced(function* (value: globalThis.DurableObjectJurisdiction) {
277
+ const namespace = yield* tag;
278
+ return yield* namespace.jurisdiction(value);
279
+ });
280
+
281
+ const fetch = (
282
+ stub: DurableObjectNamespace.DurableObjectStubClient<ClientApi>,
283
+ input: RequestInfo | URL,
284
+ init?: RequestInit,
285
+ ) =>
286
+ Effect.gen(function* () {
287
+ const namespace = yield* tag;
288
+ return yield* namespace.fetch(stub, input, init);
289
+ });
290
+
291
+ const rpc = <Method extends keyof ClientApi>(
292
+ stub: DurableObjectNamespace.DurableObjectStubClient<ClientApi>,
293
+ method: Method,
294
+ ...args: ClientApi[Method] extends (...args: infer Args) => unknown ? Args : never
295
+ ) =>
296
+ Effect.gen(function* () {
297
+ const namespace = yield* tag;
298
+ return yield* namespace.rpc(stub, method as never, ...(args as never));
299
+ });
300
+
301
+ const call = <Method extends keyof ClientApi>(
302
+ stub: DurableObjectNamespace.DurableObjectStubClient<ClientApi>,
303
+ method: Method,
304
+ ...args: ClientApi[Method] extends (...args: infer Args) => unknown ? Args : never
305
+ ) =>
306
+ Effect.gen(function* () {
307
+ const namespace = yield* tag;
308
+ return yield* namespace.call(stub, method as never, ...(args as never));
309
+ });
310
+
311
+ const scopedCall = <Method extends keyof ClientApi>(
312
+ stub: DurableObjectNamespace.DurableObjectStubClient<ClientApi>,
313
+ method: Method,
314
+ ...args: ClientApi[Method] extends (...args: infer Args) => unknown ? Args : never
315
+ ) =>
316
+ Effect.gen(function* () {
317
+ const namespace = yield* tag;
318
+ return yield* namespace.scopedCall(stub, method as never, ...(args as never));
319
+ });
320
+
321
+ const unsafeRaw = Effect.fnUntraced(function* () {
322
+ const namespace = yield* tag;
323
+ return yield* namespace.unsafeRaw;
324
+ });
164
325
 
165
- abstract class DurableObjectDefinitionClass {
166
- static readonly id = definition.id;
167
- static readonly methods = definition.methods;
168
- static readonly make = definition.make;
169
- static readonly Namespace = definition.Namespace;
170
- static readonly namespace = definition.namespace;
171
- }
326
+ const directMethods = DurableObjectNamespace.makeDirectMethods<Self, ClientApi, SelfDefinition>(
327
+ definition,
328
+ {
329
+ call: call as never,
330
+ fetch,
331
+ get,
332
+ getByName,
333
+ },
334
+ );
172
335
 
173
- return DurableObjectDefinitionClass as (abstract new () => object) & typeof definition;
336
+ return Object.assign(tag, directMethods, {
337
+ id: definition.id,
338
+ methods: definition.methods,
339
+ make: definition.make,
340
+ layer,
341
+ newUniqueId,
342
+ idFromName,
343
+ idFromString,
344
+ get,
345
+ getByName,
346
+ jurisdiction,
347
+ fetch,
348
+ rpc,
349
+ call,
350
+ scopedCall,
351
+ unsafeRaw,
352
+ }) as unknown as TagClass<Self, Id, MethodsShape>;
174
353
  };
175
354
 
176
355
  export const DurableObject = Tag;
@@ -211,4 +390,4 @@ export type HandlerEffect<
211
390
  ROut,
212
391
  Self extends Definition.Any,
213
392
  Key extends keyof Self["methods"],
214
- > = DurableObjectHandler<ROut, RpcDefinition.Method.Success<Self["methods"][Key]>>;
393
+ > = DurableObjectHandler<ROut, Method.Success<Self["methods"][Key]>>;