effect-cf 0.18.0 → 0.20.1

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,7 +1,6 @@
1
- import { Context, Effect, type Layer } from "effect";
2
- import type { Schema as S } from "effect";
1
+ import { Context, Effect, type Layer, type Schema as S } from "effect";
3
2
 
4
- import * as Binding from "./Binding";
3
+ import type * as Binding from "./Binding";
5
4
  import type { WorkerEnvironment } from "./Environment";
6
5
  import * as WorkerEntrypoint from "./Worker";
7
6
  import type { WorkerRpcHandler } from "./Worker";
@@ -9,6 +8,13 @@ import type * as Rpc from "./Rpc";
9
8
  import * as RpcDefinition from "./RpcDefinition";
10
9
  import * as ServiceBinding from "./ServiceBinding";
11
10
 
11
+ /**
12
+ * The client tuple types are re-established by the final `TagClass` cast, so
13
+ * these internal invocations erase the binding client's generic argument
14
+ * tuples instead of instantiating them at `never`.
15
+ */
16
+ type UnsafeInvoke<E> = (...args: ReadonlyArray<unknown>) => Effect.Effect<unknown, E>;
17
+
12
18
  export type ServiceFreeSchema = S.Codec<any, any, never, never>;
13
19
 
14
20
  export interface Method<
@@ -238,6 +244,7 @@ export const Tag =
238
244
  methods: MethodsShape & NoReservedMethods<MethodsShape>,
239
245
  ) => {
240
246
  const definition = makeDefinition<Id, MethodsShape>(id, methods);
247
+
241
248
  type SelfDefinition = Definition<Id, MethodsShape>;
242
249
  type ClientApi = Api<SelfDefinition>;
243
250
  const tag = Context.Service<
@@ -256,6 +263,7 @@ export const Tag =
256
263
  const fetch = (input: RequestInfo | URL, init?: RequestInit) =>
257
264
  Effect.gen(function* () {
258
265
  const service = yield* tag;
266
+
259
267
  return yield* service.fetch(input, init);
260
268
  });
261
269
 
@@ -265,7 +273,11 @@ export const Tag =
265
273
  ) =>
266
274
  Effect.gen(function* () {
267
275
  const service = yield* tag;
268
- return yield* service.rpc(method as never, ...(args as never));
276
+
277
+ return yield* (service.rpc as UnsafeInvoke<ServiceBinding.ServiceBindingRpcError>)(
278
+ method,
279
+ ...args,
280
+ );
269
281
  });
270
282
 
271
283
  const call = <Method extends keyof ClientApi>(
@@ -274,7 +286,11 @@ export const Tag =
274
286
  ) =>
275
287
  Effect.gen(function* () {
276
288
  const service = yield* tag;
277
- return yield* service.call(method as never, ...(args as never));
289
+
290
+ return yield* (service.call as UnsafeInvoke<ServiceBinding.ServiceBindingRpcError>)(
291
+ method,
292
+ ...args,
293
+ );
278
294
  });
279
295
 
280
296
  const scopedCall = <Method extends keyof ClientApi>(
@@ -283,7 +299,11 @@ export const Tag =
283
299
  ) =>
284
300
  Effect.gen(function* () {
285
301
  const service = yield* tag;
286
- return yield* service.scopedCall(method as never, ...(args as never));
302
+
303
+ return yield* (service.scopedCall as UnsafeInvoke<ServiceBinding.ServiceBindingRpcError>)(
304
+ method,
305
+ ...args,
306
+ );
287
307
  });
288
308
 
289
309
  const directMethods = ServiceBinding.makeDirectMethods<Self, ClientApi, SelfDefinition>(
@@ -315,10 +335,12 @@ const wrapHandlers = <ROut, const Self extends Definition.Any>(
315
335
  RpcDefinition.Definition.MethodNames<Self>
316
336
  >) {
317
337
  const handler = handlers[key];
338
+
318
339
  wrapped[key] = (...args: Array<unknown>) =>
319
340
  Effect.gen(function* () {
320
341
  const decodedArgs = yield* RpcDefinition.decodeArgs(definition, key, args);
321
342
  const value = yield* handler(...decodedArgs);
343
+
322
344
  return yield* RpcDefinition.encodeSuccess(definition, key, value);
323
345
  });
324
346
  }
@@ -4,7 +4,7 @@ import type {
4
4
  WorkflowInstance as CloudflareWorkflowInstance,
5
5
  WorkflowInstanceCreateOptions as CloudflareWorkflowInstanceCreateOptions,
6
6
  } from "@cloudflare/workers-types";
7
- import { Context, Data, Effect, Option, Schema as S } from "effect";
7
+ import { type Context, Data, Effect, Option, Schema as S } from "effect";
8
8
 
9
9
  import * as Binding from "./Binding";
10
10
  import type * as RpcDefinition from "./RpcDefinition";
@@ -187,7 +187,10 @@ export const makeClient = <
187
187
  return {
188
188
  status: status.status,
189
189
  output,
190
- error: status.error == null ? Option.none() : Option.some(status.error),
190
+ error:
191
+ status.error === null || status.error === undefined
192
+ ? Option.none()
193
+ : Option.some(status.error),
191
194
  };
192
195
  }),
193
196
  ),
@@ -1,6 +1,6 @@
1
1
  import { Context, Effect, Schema as S, type Layer } from "effect";
2
2
 
3
- import * as Binding from "./Binding";
3
+ import type * as Binding from "./Binding";
4
4
  import type { WorkerEnvironment } from "./Environment";
5
5
  import type { ExecutionContext, WorkerContext } from "./Worker";
6
6
  import type * as RpcDefinition from "./RpcDefinition";
@@ -162,6 +162,7 @@ export const Tag =
162
162
  options?: WorkflowBinding.WorkflowInstanceCreateOptions<S.Codec.Encoded<Payload>>,
163
163
  ) {
164
164
  const workflow = yield* tag;
165
+
165
166
  return yield* workflow.create(payload, options);
166
167
  });
167
168
 
@@ -172,16 +173,19 @@ export const Tag =
172
173
  >,
173
174
  ) {
174
175
  const workflow = yield* tag;
176
+
175
177
  return yield* workflow.createBatch(batch);
176
178
  });
177
179
 
178
180
  const get = Effect.fnUntraced(function* (instanceId: string) {
179
181
  const workflow = yield* tag;
182
+
180
183
  return yield* workflow.get(instanceId);
181
184
  });
182
185
 
183
186
  const unsafeRaw = Effect.fnUntraced(function* () {
184
187
  const workflow = yield* tag;
188
+
185
189
  return yield* workflow.unsafeRaw;
186
190
  });
187
191
 
@@ -222,6 +226,7 @@ const wrapHandler = <ROut, const Self extends Definition.Any>(
222
226
  const result = yield* handler(decodedPayload as S.Schema.Type<Self["payload"]>).pipe(
223
227
  Effect.provideService(WorkflowEntrypoint.WorkflowEvent, decodedEvent),
224
228
  );
229
+
225
230
  return yield* encodeResult(result as S.Schema.Type<Self["result"]>);
226
231
  });
227
232
  };
@@ -8,8 +8,16 @@ export const clock: Clock.Clock = {
8
8
  currentTimeMillis: Effect.sync(() => clock.currentTimeMillisUnsafe()),
9
9
  currentTimeNanosUnsafe: () => BigInt(Date.now()) * nanosPerMilli,
10
10
  currentTimeNanos: Effect.sync(() => clock.currentTimeNanosUnsafe()),
11
+ // Workers expose `performance.now()` as time since worker start. It advances
12
+ // only across I/O, like `Date.now()`, but it never moves backward.
13
+ monotonicTimeNanosUnsafe: () =>
14
+ typeof performance === "undefined"
15
+ ? BigInt(Date.now()) * nanosPerMilli
16
+ : BigInt(Math.round(performance.now() * 1_000_000)),
17
+ monotonicTimeNanos: Effect.sync(() => clock.monotonicTimeNanosUnsafe()),
11
18
  sleep: (duration) => {
12
19
  const millis = Duration.toMillis(duration);
20
+
13
21
  if (millis <= 0) {
14
22
  return Effect.yieldNow;
15
23
  }
@@ -20,6 +28,7 @@ export const clock: Clock.Clock = {
20
28
  }
21
29
 
22
30
  const handle = setTimeout(() => resume(Effect.void), millis);
31
+
23
32
  return Effect.sync(() => clearTimeout(handle));
24
33
  });
25
34
  },
@@ -66,6 +66,7 @@ export const invokeRpcMethod = <Api, Method extends AsyncMethodKey<Api>, Error>(
66
66
  ): Effect.Effect<AsyncMethodCloudflareReturn<Api, Method>, Error> =>
67
67
  Effect.gen(function* () {
68
68
  const fn = yield* lookupRpcMethod<Api, Method, Error>(target, method, makeError);
69
+
69
70
  return yield* Effect.try({
70
71
  try: () => fn(...args),
71
72
  catch: makeError,
@@ -1,156 +0,0 @@
1
- import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
2
- import { Config, ConfigProvider, Context, Data, Effect, Layer } from "effect";
3
- //#region src/Environment.ts
4
- /**
5
- * Context service for reading worker bindings from the current `env` object.
6
- */
7
- var WorkerEnvironment = class extends Context.Service()("effect-cf/WorkerEnvironment") {};
8
- let WorkerConfig;
9
- (function(_WorkerConfig) {
10
- _WorkerConfig.string = (name) => Config.string(name);
11
- _WorkerConfig.redacted = (name) => Config.redacted(name);
12
- _WorkerConfig.number = (name) => Config.number(name);
13
- _WorkerConfig.integer = (name) => Config.int(name);
14
- _WorkerConfig.boolean = (name) => Config.boolean(name);
15
- const providerFromEnv = _WorkerConfig.providerFromEnv = (env) => ConfigProvider.fromUnknown(env);
16
- const providerWith = _WorkerConfig.providerWith = (makeProvider) => Effect.map(WorkerEnvironment, makeProvider);
17
- const provider = _WorkerConfig.provider = providerWith(providerFromEnv);
18
- _WorkerConfig.layer = _WorkerConfig.providerLayer = ConfigProvider.layer(provider);
19
- _WorkerConfig.layerWith = (makeProvider) => ConfigProvider.layer(providerWith(makeProvider));
20
- })(WorkerConfig || (WorkerConfig = {}));
21
- //#endregion
22
- //#region src/Binding.ts
23
- var Binding_exports = /* @__PURE__ */ __exportAll({
24
- BindingNotFoundError: () => BindingNotFoundError,
25
- BindingValidationError: () => BindingValidationError,
26
- Service: () => Service,
27
- TypeId: () => TypeId,
28
- layer: () => layer$1
29
- });
30
- /** Internal type id marker used by binding helper services. */
31
- const TypeId = "effect-cf/Binding";
32
- /** Error raised when a configured binding does not exist on `env`. */
33
- var BindingNotFoundError = class extends Data.TaggedError("BindingNotFoundError") {};
34
- /** Error raised when a binding exists but does not match the expected shape. */
35
- var BindingValidationError = class extends Data.TaggedError("BindingValidationError") {};
36
- const defaultExpected = "Cloudflare binding resource";
37
- const isPropertyTarget = (value) => (typeof value === "object" || typeof value === "function") && value !== null;
38
- const getObjectName = (value) => {
39
- const tag = (() => {
40
- try {
41
- return Object.prototype.toString.call(value).slice(8, -1);
42
- } catch {
43
- return typeof value;
44
- }
45
- })();
46
- const constructorName = (() => {
47
- try {
48
- return "constructor" in value && typeof value.constructor === "function" && typeof value.constructor.name === "string" ? value.constructor.name : void 0;
49
- } catch {
50
- return;
51
- }
52
- })();
53
- if (tag !== "Object") return tag;
54
- if (constructorName !== void 0 && constructorName !== "" && constructorName !== "Object") return constructorName;
55
- return tag;
56
- };
57
- const propertyNames = (value) => {
58
- const names = /* @__PURE__ */ new Set();
59
- for (const target of [value, Object.getPrototypeOf(value)]) {
60
- if (target === null || target === Object.prototype || target === Function.prototype) continue;
61
- try {
62
- for (const name of Object.getOwnPropertyNames(target)) names.add(name);
63
- } catch {
64
- continue;
65
- }
66
- }
67
- return [...names].filter((name) => name !== "constructor").sort();
68
- };
69
- const isMethod = (value, name) => {
70
- try {
71
- return typeof Reflect.get(value, name) === "function";
72
- } catch {
73
- return false;
74
- }
75
- };
76
- const describeActual = (value) => {
77
- if (value === null) return "null";
78
- if (typeof value !== "object" && typeof value !== "function") return typeof value;
79
- const names = propertyNames(value);
80
- const methods = names.filter((name) => isMethod(value, name));
81
- const properties = names.filter((name) => !methods.includes(name));
82
- const details = [methods.length > 0 ? `methods ${methods.join(", ")}` : void 0, properties.length > 0 ? `properties ${properties.join(", ")}` : void 0].filter((detail) => detail !== void 0);
83
- if (details.length === 0) return getObjectName(value);
84
- return `${getObjectName(value)} with ${details.join("; ")}`;
85
- };
86
- const getBinding = (env, binding, isResource, options) => Effect.gen(function* () {
87
- if (!isPropertyTarget(env)) {
88
- const actual = describeActual(env);
89
- return yield* Effect.fail(new BindingValidationError({
90
- binding,
91
- expected: "WorkerEnvironment object",
92
- actual,
93
- message: `Cloudflare binding "${binding}" failed validation. Expected WorkerEnvironment object; got ${actual}`
94
- }));
95
- }
96
- const resource = Reflect.get(env, binding);
97
- if (resource === void 0) return yield* Effect.fail(new BindingNotFoundError({
98
- binding,
99
- message: `Cloudflare binding "${binding}" was not found in WorkerEnvironment`
100
- }));
101
- if (!isResource(resource)) {
102
- const expected = options?.expected ?? defaultExpected;
103
- const actual = describeActual(resource);
104
- return yield* Effect.fail(new BindingValidationError({
105
- binding,
106
- expected,
107
- actual,
108
- message: `Cloudflare binding "${binding}" failed validation. Expected ${expected}; got ${actual}`
109
- }));
110
- }
111
- return resource;
112
- });
113
- const layer$1 = (tag, binding, isResource, wrap, options) => Layer.effect(tag, Effect.gen(function* () {
114
- const resource = yield* getBinding(yield* WorkerEnvironment, binding, isResource, options);
115
- return wrap === void 0 ? resource : wrap(resource);
116
- }));
117
- const Service = () => (id, binding, isResource, wrap, options) => {
118
- const tag = Context.Service()(id);
119
- const serviceLayer = layer$1(tag, binding, isResource, wrap, options);
120
- return Object.assign(tag, {
121
- [TypeId]: TypeId,
122
- binding,
123
- layer: serviceLayer
124
- });
125
- };
126
- //#endregion
127
- //#region src/Hyperdrive.ts
128
- var Hyperdrive_exports = /* @__PURE__ */ __exportAll({
129
- Tag: () => Tag,
130
- isHyperdrive: () => isHyperdrive,
131
- layer: () => layer,
132
- make: () => make,
133
- makeClient: () => makeClient
134
- });
135
- const expectedHyperdrive = "Hyperdrive binding with connectionString";
136
- const isHyperdrive = (value) => {
137
- if (typeof value !== "object" || value === null) return false;
138
- return typeof value.connectionString === "string";
139
- };
140
- const makeClient = (definition) => (hyperdrive) => ({
141
- definition,
142
- connectionString: hyperdrive.connectionString,
143
- unsafeRaw: Effect.succeed(hyperdrive)
144
- });
145
- const layer = (tag, definition) => layer$1(tag, definition.binding, isHyperdrive, makeClient(definition), { expected: expectedHyperdrive });
146
- const make = (id) => Tag()(id);
147
- const Tag = () => (id) => {
148
- const tag = Context.Service()(id);
149
- const makeLayer = (definition) => layer(tag, definition);
150
- return Object.assign(tag, {
151
- id,
152
- layer: makeLayer
153
- });
154
- };
155
- //#endregion
156
- export { WorkerConfig as a, layer$1 as i, Binding_exports as n, WorkerEnvironment as o, Service as r, Hyperdrive_exports as t };