@confect/server 6.0.0 → 7.0.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.
@@ -8,7 +8,9 @@ import {
8
8
  type RegisteredMutation,
9
9
  type RegisteredQuery,
10
10
  } from "convex/server";
11
- import { Effect, Layer, pipe, Schema } from "effect";
11
+ import type { Value } from "convex/values";
12
+ import { ConvexError } from "convex/values";
13
+ import { Effect, Either, Layer, pipe, Schema } from "effect";
12
14
  import * as ActionCtx from "./ActionCtx";
13
15
  import * as ActionRunner from "./ActionRunner";
14
16
  import * as Auth from "./Auth";
@@ -18,9 +20,9 @@ import * as MutationRunner from "./MutationRunner";
18
20
  import * as QueryRunner from "./QueryRunner";
19
21
  import * as Scheduler from "./Scheduler";
20
22
  import * as SchemaToValidator from "./SchemaToValidator";
21
- import { StorageActionWriter } from "./StorageActionWriter";
22
- import { StorageReader } from "./StorageReader";
23
- import { StorageWriter } from "./StorageWriter";
23
+ import * as StorageActionWriter from "./StorageActionWriter";
24
+ import * as StorageReader from "./StorageReader";
25
+ import * as StorageWriter from "./StorageWriter";
24
26
  import * as VectorSearch from "./VectorSearch";
25
27
 
26
28
  export type Any =
@@ -111,6 +113,48 @@ export type RegisteredFunction<
111
113
  ? ConfectRegisteredFunction<FunctionSpec_>
112
114
  : never;
113
115
 
116
+ /**
117
+ * Run the `Effect` as a `Promise`. The error schema acts as an allowlist of
118
+ * failures that may be surfaced to the client as a `ConvexError`:
119
+ *
120
+ * - With a schema: typed errors are schema-encoded and wrapped in a
121
+ * `ConvexError`, then thrown so Convex surfaces the data to the client.
122
+ * `Effect.either` escapes the failure channel before `runPromise` so the thrown
123
+ * `ConvexError` retains its `Symbol.for("ConvexError")` identity instead of
124
+ * being wrapped in Effect's `FiberFailure`.
125
+ *
126
+ * - Without a schema: every failure is converted to a defect via
127
+ * `Effect.orDie`, so nothing—not even a `ConvexError` the handler placed in its
128
+ * error channel—reaches the client as a `ConvexError`. The fiber dies and
129
+ * `runPromise` rejects with a generic failure.
130
+ */
131
+ export const runHandlerPromise =
132
+ (errorSchema: Schema.Schema.AnyNoContext | undefined) =>
133
+ <A, E>(effect: Effect.Effect<A, E>): Promise<A> => {
134
+ if (errorSchema === undefined) {
135
+ return Effect.runPromise(Effect.orDie(effect));
136
+ }
137
+ const withConvexError = effect.pipe(
138
+ Effect.catchAll((typedError) =>
139
+ pipe(
140
+ Schema.encode(errorSchema)(typedError),
141
+ Effect.orDie,
142
+ Effect.andThen((encodedError) =>
143
+ Effect.fail(new ConvexError(encodedError)),
144
+ ),
145
+ ),
146
+ ),
147
+ );
148
+ return Effect.runPromise(Effect.either(withConvexError)).then(
149
+ Either.match({
150
+ onLeft: (error) => {
151
+ throw error;
152
+ },
153
+ onRight: (value) => value,
154
+ }),
155
+ );
156
+ };
157
+
114
158
  export const actionFunctionBase = <
115
159
  Schema extends DatabaseSchema.AnyWithProps,
116
160
  Args,
@@ -122,11 +166,13 @@ export const actionFunctionBase = <
122
166
  >({
123
167
  args,
124
168
  returns,
169
+ error,
125
170
  handler,
126
171
  createLayer,
127
172
  }: {
128
173
  args: Schema.Schema<Args, ConvexArgs>;
129
174
  returns: Schema.Schema<Returns, ConvexReturns>;
175
+ error: Schema.Schema<Error, Value> | undefined;
130
176
  handler: (a: Args) => Effect.Effect<Returns, E, R>;
131
177
  createLayer: (
132
178
  ctx: GenericActionCtx<DataModel.ToConvex<DataModel.FromSchema<Schema>>>,
@@ -138,18 +184,17 @@ export const actionFunctionBase = <
138
184
  ctx: GenericActionCtx<DataModel.ToConvex<DataModel.FromSchema<Schema>>>,
139
185
  actualArgs: ConvexArgs,
140
186
  ): Promise<ConvexReturns> =>
141
- pipe(
142
- actualArgs,
143
- Schema.decode(args),
144
- Effect.orDie,
145
- Effect.andThen((decodedArgs) =>
146
- handler(decodedArgs).pipe(Effect.provide(createLayer(ctx))),
147
- ),
148
- Effect.andThen((convexReturns) =>
149
- Schema.encodeUnknown(returns)(convexReturns),
150
- ),
151
- Effect.runPromise,
152
- ),
187
+ Effect.gen(function* () {
188
+ const decodedArgs = yield* pipe(
189
+ actualArgs,
190
+ Schema.decode(args),
191
+ Effect.orDie,
192
+ );
193
+ const decodedReturns = yield* handler(decodedArgs).pipe(
194
+ Effect.provide(createLayer(ctx)),
195
+ );
196
+ return yield* pipe(decodedReturns, Schema.encode(returns), Effect.orDie);
197
+ }).pipe(runHandlerPromise(error)),
153
198
  });
154
199
 
155
200
  export type ActionServices<
@@ -157,9 +202,9 @@ export type ActionServices<
157
202
  > =
158
203
  | Scheduler.Scheduler
159
204
  | Auth.Auth
160
- | StorageReader
161
- | StorageWriter
162
- | StorageActionWriter
205
+ | StorageReader.StorageReader
206
+ | StorageWriter.StorageWriter
207
+ | StorageActionWriter.StorageActionWriter
163
208
  | QueryRunner.QueryRunner
164
209
  | MutationRunner.MutationRunner
165
210
  | ActionRunner.ActionRunner
@@ -179,9 +224,9 @@ export const actionLayer = <
179
224
  Layer.mergeAll(
180
225
  Scheduler.layer(ctx.scheduler),
181
226
  Auth.layer(ctx.auth),
182
- StorageReader.layer(ctx.storage),
183
- StorageWriter.layer(ctx.storage),
184
- StorageActionWriter.layer(ctx.storage),
227
+ StorageReader.StorageReader.layer(ctx.storage),
228
+ StorageWriter.StorageWriter.layer(ctx.storage),
229
+ StorageActionWriter.StorageActionWriter.layer(ctx.storage),
185
230
  QueryRunner.layer(ctx.runQuery),
186
231
  MutationRunner.layer(ctx.runMutation),
187
232
  ActionRunner.layer(ctx.runAction),
@@ -33,6 +33,7 @@ export const make = <Api_ extends Api.AnyWithPropsWithRuntime<"Node">>(
33
33
  nodeActionFunction(api.databaseSchema, {
34
34
  args: functionProvenance.args,
35
35
  returns: functionProvenance.returns,
36
+ error: functionProvenance.error,
36
37
  handler: handler as Handler.AnyConfectProvenance,
37
38
  }),
38
39
  );
@@ -52,10 +53,12 @@ const nodeActionFunction = <
52
53
  {
53
54
  args,
54
55
  returns,
56
+ error,
55
57
  handler,
56
58
  }: {
57
59
  args: Schema.Schema<Args, ConvexArgs>;
58
60
  returns: Schema.Schema<Returns, ConvexReturns>;
61
+ error: Schema.Schema.AnyNoContext | undefined;
59
62
  handler: (
60
63
  a: Args,
61
64
  ) => Effect.Effect<
@@ -69,6 +72,7 @@ const nodeActionFunction = <
69
72
  RegisteredFunction.actionFunctionBase({
70
73
  args,
71
74
  returns,
75
+ error,
72
76
  handler,
73
77
  createLayer: (ctx) =>
74
78
  Layer.mergeAll(