@gaganref/confect-server 10.3.1-fork.9 → 10.3.1-fork.90
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.
- package/dist/ActionCall.d.ts +30 -0
- package/dist/ActionCall.d.ts.map +1 -0
- package/dist/ActionCall.js +41 -0
- package/dist/ActionCall.js.map +1 -0
- package/dist/ActionRunner.d.ts +1 -1
- package/dist/ActionRunner.d.ts.map +1 -1
- package/dist/ActionRunner.js +3 -3
- package/dist/ActionRunner.js.map +1 -1
- package/dist/AiGatewayDecisionClient.js +1 -1
- package/dist/AiGatewayLanguageClient.js +1 -1
- package/dist/Auth.d.ts +31 -2
- package/dist/Auth.d.ts.map +1 -1
- package/dist/Auth.js +23 -3
- package/dist/Auth.js.map +1 -1
- package/dist/Callback.d.ts +1 -1
- package/dist/Callback.d.ts.map +1 -1
- package/dist/Callback.js +6 -6
- package/dist/Callback.js.map +1 -1
- package/dist/ComponentCtx.d.ts +4 -0
- package/dist/ComponentCtx.d.ts.map +1 -1
- package/dist/ConvexConfigProvider.js +2 -2
- package/dist/ConvexFunctionDefinitions.d.ts.map +1 -1
- package/dist/ConvexFunctionDefinitions.js +4 -4
- package/dist/ConvexFunctionDefinitions.js.map +1 -1
- package/dist/ConvexLogger.js +1 -1
- package/dist/CronJobs.d.ts.map +1 -1
- package/dist/CronJobs.js +7 -6
- package/dist/CronJobs.js.map +1 -1
- package/dist/DatabaseSchema.js +2 -2
- package/dist/DatabaseWriter.d.ts +44 -2
- package/dist/DatabaseWriter.d.ts.map +1 -1
- package/dist/DatabaseWriter.js +59 -9
- package/dist/DatabaseWriter.js.map +1 -1
- package/dist/ExecutionMetadata.js +1 -1
- package/dist/FunctionImpl.js +2 -2
- package/dist/FunctionRegistryItem.d.ts +1 -0
- package/dist/FunctionRegistryItem.d.ts.map +1 -1
- package/dist/FunctionRegistryItem.js +2 -1
- package/dist/FunctionRegistryItem.js.map +1 -1
- package/dist/GroupImpl.d.ts +21 -2
- package/dist/GroupImpl.d.ts.map +1 -1
- package/dist/GroupImpl.js +21 -22
- package/dist/GroupImpl.js.map +1 -1
- package/dist/GroupRegistry.d.ts +1 -0
- package/dist/GroupRegistry.d.ts.map +1 -1
- package/dist/GroupRegistry.js +10 -3
- package/dist/GroupRegistry.js.map +1 -1
- package/dist/Handler.d.ts +8 -4
- package/dist/Handler.d.ts.map +1 -1
- package/dist/Handler.js.map +1 -1
- package/dist/HttpRouter.d.ts +3 -0
- package/dist/HttpRouter.d.ts.map +1 -1
- package/dist/HttpRouter.js +29 -10
- package/dist/HttpRouter.js.map +1 -1
- package/dist/MiddlewareImpl.js +1 -1
- package/dist/MountInit.d.ts +31 -0
- package/dist/MountInit.d.ts.map +1 -0
- package/dist/MountInit.js +49 -0
- package/dist/MountInit.js.map +1 -0
- package/dist/MutationRunner.d.ts +1 -1
- package/dist/MutationRunner.d.ts.map +1 -1
- package/dist/MutationRunner.js +3 -3
- package/dist/MutationRunner.js.map +1 -1
- package/dist/MutationTransactionContext.d.ts.map +1 -1
- package/dist/MutationTransactionContext.js +4 -3
- package/dist/MutationTransactionContext.js.map +1 -1
- package/dist/OfficialComponent.d.ts +60 -0
- package/dist/OfficialComponent.d.ts.map +1 -0
- package/dist/OfficialComponent.js +72 -0
- package/dist/OfficialComponent.js.map +1 -0
- package/dist/OrderedQuery.d.ts +4 -5
- package/dist/OrderedQuery.d.ts.map +1 -1
- package/dist/OrderedQuery.js.map +1 -1
- package/dist/QueryInitializer.js +2 -2
- package/dist/QueryRunner.js +2 -2
- package/dist/QueryStream.d.ts +120 -12
- package/dist/QueryStream.d.ts.map +1 -1
- package/dist/QueryStream.js +143 -41
- package/dist/QueryStream.js.map +1 -1
- package/dist/QueryStreamCursor.js +1 -1
- package/dist/QueryStreamIndexPrefix.js +1 -1
- package/dist/QueryStreamIndexRange.js +2 -2
- package/dist/QueryStreamKey.js +1 -1
- package/dist/QueryStreamKeyBounds.js +2 -2
- package/dist/QueryStreamKeyLayout.js +2 -2
- package/dist/QueryStreamKeyValues.js +2 -2
- package/dist/QueryStreamPagination.js +1 -1
- package/dist/QueryStreamReadBudget.d.ts +3 -2
- package/dist/QueryStreamReadBudget.d.ts.map +1 -1
- package/dist/QueryStreamReadBudget.js +8 -5
- package/dist/QueryStreamReadBudget.js.map +1 -1
- package/dist/QueryTransactionContext.js +2 -2
- package/dist/RegisteredConvexFunction.d.ts +10 -5
- package/dist/RegisteredConvexFunction.d.ts.map +1 -1
- package/dist/RegisteredConvexFunction.js +49 -29
- package/dist/RegisteredConvexFunction.js.map +1 -1
- package/dist/RegisteredFunction.d.ts +48 -22
- package/dist/RegisteredFunction.d.ts.map +1 -1
- package/dist/RegisteredFunction.js +163 -42
- package/dist/RegisteredFunction.js.map +1 -1
- package/dist/RegisteredNodeFunction.d.ts +1 -1
- package/dist/RegisteredNodeFunction.d.ts.map +1 -1
- package/dist/RegisteredNodeFunction.js +10 -6
- package/dist/RegisteredNodeFunction.js.map +1 -1
- package/dist/RegistryItems.d.ts +7 -0
- package/dist/RegistryItems.d.ts.map +1 -1
- package/dist/RegistryItems.js +8 -3
- package/dist/RegistryItems.js.map +1 -1
- package/dist/RequestMetadata.js +1 -1
- package/dist/Scheduler.d.ts +1 -1
- package/dist/Scheduler.d.ts.map +1 -1
- package/dist/Scheduler.js +14 -13
- package/dist/Scheduler.js.map +1 -1
- package/dist/Storage.js +1 -1
- package/dist/StorageActionWriter.js +1 -1
- package/dist/StorageReader.js +1 -1
- package/dist/StorageWriter.js +1 -1
- package/dist/Table.d.ts +6 -6
- package/dist/Table.d.ts.map +1 -1
- package/dist/TableInfo.d.ts +7 -7
- package/dist/TableInfo.d.ts.map +1 -1
- package/dist/TableInfo.js.map +1 -1
- package/dist/TransactionMetadata.js +1 -1
- package/dist/VectorSearch.js +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -18
- package/dist/internal/AiGatewayDecisionClient.js +1 -1
- package/dist/internal/AiGatewayLanguageClient.js +1 -1
- package/dist/internal/AiGatewayServiceToken.js +1 -1
- package/dist/internal/DocumentPatch.d.ts +16 -0
- package/dist/internal/DocumentPatch.d.ts.map +1 -0
- package/dist/internal/DocumentPatch.js +36 -0
- package/dist/internal/DocumentPatch.js.map +1 -0
- package/dist/internal/httpBody.d.ts +13 -0
- package/dist/internal/httpBody.d.ts.map +1 -0
- package/dist/internal/httpBody.js +47 -0
- package/dist/internal/httpBody.js.map +1 -0
- package/dist/internal/httpOptions.d.ts +4 -0
- package/dist/internal/httpOptions.d.ts.map +1 -0
- package/dist/internal/httpOptions.js +83 -0
- package/dist/internal/httpOptions.js.map +1 -0
- package/dist/internal/observability.d.ts +5 -0
- package/dist/internal/observability.d.ts.map +1 -0
- package/dist/internal/observability.js +21 -0
- package/dist/internal/observability.js.map +1 -0
- package/dist/internal/reservedArgument.d.ts +8 -0
- package/dist/internal/reservedArgument.d.ts.map +1 -0
- package/dist/internal/reservedArgument.js +30 -0
- package/dist/internal/reservedArgument.js.map +1 -0
- package/package.json +5 -5
- package/src/ActionCall.ts +83 -0
- package/src/ActionRunner.ts +3 -2
- package/src/Auth.ts +49 -1
- package/src/Callback.ts +3 -2
- package/src/ComponentCtx.ts +2 -0
- package/src/ConvexFunctionDefinitions.ts +2 -1
- package/src/CronJobs.ts +2 -1
- package/src/DatabaseWriter.ts +190 -26
- package/src/FunctionRegistryItem.ts +4 -0
- package/src/GroupImpl.ts +61 -8
- package/src/GroupRegistry.ts +7 -3
- package/src/Handler.ts +21 -5
- package/src/HttpRouter.ts +69 -5
- package/src/MountInit.ts +80 -0
- package/src/MutationRunner.ts +3 -2
- package/src/MutationTransactionContext.ts +2 -1
- package/src/OfficialComponent.ts +168 -0
- package/src/OrderedQuery.ts +4 -5
- package/src/QueryStream.ts +391 -61
- package/src/QueryStreamReadBudget.ts +19 -6
- package/src/RegisteredConvexFunction.ts +39 -2
- package/src/RegisteredFunction.ts +305 -49
- package/src/RegisteredNodeFunction.ts +11 -1
- package/src/RegistryItems.ts +31 -0
- package/src/Scheduler.ts +17 -19
- package/src/TableInfo.ts +18 -22
- package/src/index.ts +3 -0
- package/src/internal/DocumentPatch.ts +87 -0
- package/src/internal/httpBody.ts +72 -0
- package/src/internal/httpOptions.ts +154 -0
- package/src/internal/observability.ts +27 -0
- package/src/internal/reservedArgument.ts +56 -0
|
@@ -61,12 +61,14 @@ export const prepare = (
|
|
|
61
61
|
databaseSchema: DatabaseSchema.AnyWithProps,
|
|
62
62
|
item: FunctionRegistryItem.ConfectFunctionRegistryItem,
|
|
63
63
|
resolvedMiddlewares: ReadonlyArray<ResolvedMiddleware.ResolvedMiddleware> = [],
|
|
64
|
+
observability?: Layer.Layer<never>,
|
|
64
65
|
) =>
|
|
65
66
|
Match.value(item.functionType).pipe(
|
|
66
67
|
Match.when("query", () => {
|
|
67
68
|
const definition = queryFunction({
|
|
68
69
|
databaseSchema,
|
|
69
70
|
name: item.name,
|
|
71
|
+
observability,
|
|
70
72
|
functionVisibility: item.functionVisibility,
|
|
71
73
|
args: item.args,
|
|
72
74
|
returns: item.returns,
|
|
@@ -84,6 +86,8 @@ export const prepare = (
|
|
|
84
86
|
const definition = mutationFunction({
|
|
85
87
|
databaseSchema,
|
|
86
88
|
name: item.name,
|
|
89
|
+
reservedArgument: item.reservedArgument,
|
|
90
|
+
observability,
|
|
87
91
|
functionVisibility: item.functionVisibility,
|
|
88
92
|
args: item.args,
|
|
89
93
|
returns: item.returns,
|
|
@@ -100,6 +104,8 @@ export const prepare = (
|
|
|
100
104
|
Match.when("action", () => {
|
|
101
105
|
const definition = convexActionFunction(databaseSchema, {
|
|
102
106
|
name: item.name,
|
|
107
|
+
reservedArgument: item.reservedArgument,
|
|
108
|
+
observability,
|
|
103
109
|
functionVisibility: item.functionVisibility,
|
|
104
110
|
args: item.args,
|
|
105
111
|
returns: item.returns,
|
|
@@ -188,6 +194,7 @@ const queryFunction = <
|
|
|
188
194
|
error,
|
|
189
195
|
handler,
|
|
190
196
|
resolvedMiddlewares,
|
|
197
|
+
observability,
|
|
191
198
|
}: {
|
|
192
199
|
databaseSchema: DatabaseSchema_;
|
|
193
200
|
name: string;
|
|
@@ -199,6 +206,7 @@ const queryFunction = <
|
|
|
199
206
|
a: Args,
|
|
200
207
|
) => Effect.Effect<Returns, E, Handler.QueryServices<DatabaseSchema_>>;
|
|
201
208
|
resolvedMiddlewares: ReadonlyArray<ResolvedMiddleware.ResolvedMiddleware>;
|
|
209
|
+
observability?: Layer.Layer<never> | undefined;
|
|
202
210
|
}) => ({
|
|
203
211
|
args: compileArgsSchema(args, databaseSchema.target.scope),
|
|
204
212
|
returns: compileReturnsSchema(returns, databaseSchema.target.scope),
|
|
@@ -258,6 +266,11 @@ const queryFunction = <
|
|
|
258
266
|
RegisteredFunction.combineErrorSchemas(error, resolvedMiddlewares),
|
|
259
267
|
{
|
|
260
268
|
scheduler: new EffectScheduler.MixedScheduler("sync"),
|
|
269
|
+
invocation: Effect.promise(() => ctx.meta.getFunctionMetadata()),
|
|
270
|
+
clock: observability === undefined ? undefined : queryClock,
|
|
271
|
+
observability,
|
|
272
|
+
meta: ctx.meta,
|
|
273
|
+
functionType: "query",
|
|
261
274
|
},
|
|
262
275
|
),
|
|
263
276
|
),
|
|
@@ -274,6 +287,7 @@ export const mutationLayer = <Schema extends DatabaseSchema.AnyWithProps>(
|
|
|
274
287
|
RequestMetadata.layer(ctx.meta),
|
|
275
288
|
TransactionMetadata.layer(ctx.meta),
|
|
276
289
|
Auth.layerForTarget<Schema["target"]>(schema.target, ctx.auth),
|
|
290
|
+
Auth.mutationLayer(ctx.auth),
|
|
277
291
|
Scheduler.layer<DatabaseSchema.Scope<Schema>>(
|
|
278
292
|
ctx.scheduler,
|
|
279
293
|
schema.target.scope,
|
|
@@ -313,9 +327,12 @@ const mutationFunction = <
|
|
|
313
327
|
error,
|
|
314
328
|
handler,
|
|
315
329
|
resolvedMiddlewares,
|
|
330
|
+
observability,
|
|
331
|
+
reservedArgument,
|
|
316
332
|
}: {
|
|
317
333
|
databaseSchema: DatabaseSchema_;
|
|
318
334
|
name: string;
|
|
335
|
+
reservedArgument?: string | undefined;
|
|
319
336
|
functionVisibility: FunctionVisibility;
|
|
320
337
|
args: Schema.Codec<Args, ConvexArgs>;
|
|
321
338
|
returns: Schema.Codec<Returns, ConvexReturns>;
|
|
@@ -324,8 +341,14 @@ const mutationFunction = <
|
|
|
324
341
|
a: Args,
|
|
325
342
|
) => Effect.Effect<Returns, E, MutationServices<DatabaseSchema_>>;
|
|
326
343
|
resolvedMiddlewares: ReadonlyArray<ResolvedMiddleware.ResolvedMiddleware>;
|
|
344
|
+
observability?: Layer.Layer<never> | undefined;
|
|
327
345
|
}) => ({
|
|
328
|
-
args: compileArgsSchema(
|
|
346
|
+
args: compileArgsSchema(
|
|
347
|
+
args,
|
|
348
|
+
databaseSchema.target.scope,
|
|
349
|
+
reservedArgument,
|
|
350
|
+
name,
|
|
351
|
+
),
|
|
329
352
|
returns: compileReturnsSchema(returns, databaseSchema.target.scope),
|
|
330
353
|
handler: (
|
|
331
354
|
ctx: GenericMutationCtx<
|
|
@@ -335,7 +358,7 @@ const mutationFunction = <
|
|
|
335
358
|
): Promise<ConvexReturns> =>
|
|
336
359
|
Effect.gen(function* () {
|
|
337
360
|
const decodedArgs = yield* pipe(
|
|
338
|
-
actualArgs,
|
|
361
|
+
RegisteredFunction.domainArgs(actualArgs, reservedArgument),
|
|
339
362
|
Schema.decodeUnknownEffect(args),
|
|
340
363
|
Effect.catchTag("SchemaError", Effect.die),
|
|
341
364
|
);
|
|
@@ -360,6 +383,14 @@ const mutationFunction = <
|
|
|
360
383
|
RegisteredFunction.combineErrorSchemas(error, resolvedMiddlewares),
|
|
361
384
|
{
|
|
362
385
|
scheduler: new EffectScheduler.MixedScheduler("sync"),
|
|
386
|
+
invocation: RegisteredFunction.invocationMetadata(
|
|
387
|
+
ctx.meta,
|
|
388
|
+
actualArgs,
|
|
389
|
+
reservedArgument,
|
|
390
|
+
),
|
|
391
|
+
observability,
|
|
392
|
+
meta: ctx.meta,
|
|
393
|
+
functionType: "mutation",
|
|
363
394
|
},
|
|
364
395
|
),
|
|
365
396
|
),
|
|
@@ -382,8 +413,11 @@ const convexActionFunction = <
|
|
|
382
413
|
error,
|
|
383
414
|
handler,
|
|
384
415
|
resolvedMiddlewares,
|
|
416
|
+
observability,
|
|
417
|
+
reservedArgument,
|
|
385
418
|
}: {
|
|
386
419
|
name: string;
|
|
420
|
+
reservedArgument?: string | undefined;
|
|
387
421
|
functionVisibility: FunctionVisibility;
|
|
388
422
|
args: Schema.Codec<Args, ConvexArgs>;
|
|
389
423
|
returns: Schema.Codec<Returns, ConvexReturns>;
|
|
@@ -396,6 +430,7 @@ const convexActionFunction = <
|
|
|
396
430
|
RegisteredFunction.ActionServices<DatabaseSchema_>
|
|
397
431
|
>;
|
|
398
432
|
resolvedMiddlewares: ReadonlyArray<ResolvedMiddleware.ResolvedMiddleware>;
|
|
433
|
+
observability?: Layer.Layer<never> | undefined;
|
|
399
434
|
},
|
|
400
435
|
) =>
|
|
401
436
|
RegisteredFunction.actionFunctionBase({
|
|
@@ -407,6 +442,8 @@ const convexActionFunction = <
|
|
|
407
442
|
error,
|
|
408
443
|
handler,
|
|
409
444
|
resolvedMiddlewares,
|
|
445
|
+
observability,
|
|
446
|
+
reservedArgument,
|
|
410
447
|
createLayer: (ctx) =>
|
|
411
448
|
Layer.mergeAll(
|
|
412
449
|
RegisteredFunction.actionLayer(schema, ctx),
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export { Forward } from "./internal/reservedArgument.js";
|
|
2
|
+
import * as ActionCallSpec from "@confect/core/ActionCall";
|
|
3
|
+
import * as ActionCall from "./ActionCall.js";
|
|
1
4
|
import type { FunctionSpec, RuntimeAndFunctionType } from "@confect/core";
|
|
2
5
|
import * as IdScope from "@confect/core/IdScope";
|
|
3
6
|
import type * as FunctionProvenance from "@confect/core/FunctionProvenance";
|
|
@@ -9,6 +12,9 @@ import {
|
|
|
9
12
|
import {
|
|
10
13
|
type DefaultFunctionArgs,
|
|
11
14
|
type FunctionVisibility,
|
|
15
|
+
type FunctionMetadata,
|
|
16
|
+
type MutationMeta,
|
|
17
|
+
type QueryMeta,
|
|
12
18
|
type GenericActionCtx,
|
|
13
19
|
type GenericDataModel,
|
|
14
20
|
type StorageReader as ConvexStorageReader,
|
|
@@ -19,8 +25,15 @@ import {
|
|
|
19
25
|
import type { Value } from "convex/values";
|
|
20
26
|
import { ConvexError } from "convex/values";
|
|
21
27
|
import { pipe } from "effect/Function";
|
|
28
|
+
import * as Config from "effect/Config";
|
|
29
|
+
import * as Option from "effect/Option";
|
|
30
|
+
import * as ConvexConfigProvider from "./ConvexConfigProvider.js";
|
|
31
|
+
import * as Clock from "effect/Clock";
|
|
32
|
+
import * as Cause from "effect/Cause";
|
|
22
33
|
import * as Console from "effect/Console";
|
|
34
|
+
import * as Context from "effect/Context";
|
|
23
35
|
import * as Effect from "effect/Effect";
|
|
36
|
+
import * as Exit from "effect/Exit";
|
|
24
37
|
import * as Result from "effect/Result";
|
|
25
38
|
import * as Layer from "effect/Layer";
|
|
26
39
|
import * as Schema from "effect/Schema";
|
|
@@ -41,9 +54,58 @@ import * as Storage from "./Storage.js";
|
|
|
41
54
|
import * as StorageActionWriter from "./StorageActionWriter.js";
|
|
42
55
|
import type * as StorageReader from "./StorageReader.js";
|
|
43
56
|
import * as StorageWriter from "./StorageWriter.js";
|
|
57
|
+
import * as Tracer from "effect/Tracer";
|
|
58
|
+
import * as ObservabilityRuntime from "./internal/observability.js";
|
|
44
59
|
import * as VectorSearch from "./VectorSearch.js";
|
|
45
60
|
import type * as Handler from "./Handler.js";
|
|
46
61
|
|
|
62
|
+
export interface ReceivedValue {
|
|
63
|
+
readonly value: unknown;
|
|
64
|
+
readonly requestId: string;
|
|
65
|
+
readonly deployment: string | undefined;
|
|
66
|
+
readonly visibility?: FunctionVisibility;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const Received = Context.Reference<ReceivedValue | undefined>(
|
|
70
|
+
"@confect/server/RegisteredFunction/Received",
|
|
71
|
+
{ defaultValue: () => undefined },
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
export const invocationMetadata = (
|
|
75
|
+
meta: Pick<MutationMeta, "getFunctionMetadata" | "getRequestMetadata">,
|
|
76
|
+
args: DefaultFunctionArgs,
|
|
77
|
+
reservedArgument?: string,
|
|
78
|
+
): Effect.Effect<FunctionMetadata & { readonly received?: ReceivedValue }> =>
|
|
79
|
+
Effect.gen(function* () {
|
|
80
|
+
const metadata = yield* Effect.promise(() => meta.getFunctionMetadata());
|
|
81
|
+
if (reservedArgument === undefined) return metadata;
|
|
82
|
+
const { requestId } = yield* Effect.promise(() =>
|
|
83
|
+
meta.getRequestMetadata(),
|
|
84
|
+
);
|
|
85
|
+
const deployment = yield* Config.String("CONVEX_CLOUD_URL").pipe(
|
|
86
|
+
Config.option,
|
|
87
|
+
Effect.map(Option.getOrUndefined),
|
|
88
|
+
Effect.provide(ConvexConfigProvider.layer),
|
|
89
|
+
Effect.orDie,
|
|
90
|
+
);
|
|
91
|
+
return {
|
|
92
|
+
...metadata,
|
|
93
|
+
received: {
|
|
94
|
+
value: args[reservedArgument],
|
|
95
|
+
requestId,
|
|
96
|
+
deployment,
|
|
97
|
+
...(metadata.visibility === undefined
|
|
98
|
+
? {}
|
|
99
|
+
: { visibility: metadata.visibility }),
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
export const Observability = Context.Reference<Layer.Layer<never> | undefined>(
|
|
105
|
+
"@confect/server/Observability",
|
|
106
|
+
{ defaultValue: () => undefined },
|
|
107
|
+
);
|
|
108
|
+
|
|
47
109
|
export type Any =
|
|
48
110
|
| RegisteredQuery<FunctionVisibility, DefaultFunctionArgs, any>
|
|
49
111
|
| RegisteredMutation<FunctionVisibility, DefaultFunctionArgs, any>
|
|
@@ -182,71 +244,193 @@ export const combineErrorSchemas = (
|
|
|
182
244
|
: Schema.Union(schemas);
|
|
183
245
|
};
|
|
184
246
|
|
|
247
|
+
type InvocationMeta = Pick<QueryMeta, "getFunctionMetadata"> &
|
|
248
|
+
Partial<Pick<MutationMeta, "getRequestMetadata">>;
|
|
249
|
+
|
|
250
|
+
type InvocationFunctionType = "query" | "mutation" | "action";
|
|
251
|
+
|
|
185
252
|
/**
|
|
186
|
-
*
|
|
187
|
-
*
|
|
253
|
+
* What `@confect/test` installs on `globalThis` under {@link testInvocation}.
|
|
254
|
+
* `start` runs `run` with the services of the test invocation the handler
|
|
255
|
+
* belongs to, with the handler's `Date`, `Math.random` and
|
|
256
|
+
* `crypto.getRandomValues` pinned to that invocation, or answers `undefined`
|
|
257
|
+
* when none is bound. `functionType` decides how `Date` reads: a query or
|
|
258
|
+
* mutation keeps its start time, an action follows the clock. Production never
|
|
259
|
+
* installs it.
|
|
260
|
+
*/
|
|
261
|
+
type TestInvocation = {
|
|
262
|
+
readonly start: <A>(
|
|
263
|
+
meta: InvocationMeta,
|
|
264
|
+
run: (services: Context.Context<never>) => Promise<A>,
|
|
265
|
+
functionType: InvocationFunctionType,
|
|
266
|
+
) => Promise<A> | undefined;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const testInvocation = Symbol.for("@confect/test/Invocation");
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Run the `Effect` as a `Promise`. Inspect the complete `Exit` before encoding
|
|
273
|
+
* a declared error so a typed failure cannot hide a defect.
|
|
188
274
|
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
* - Without a schema: every failure is converted to a defect via `Effect.orDie`,
|
|
195
|
-
* so nothing—not even a `ConvexError` the handler placed in its error
|
|
196
|
-
* channel—reaches the client as a `ConvexError`. The fiber dies and
|
|
197
|
-
* `runPromise` rejects with a generic failure.
|
|
275
|
+
* Any `Die` reason takes the defect path. Without a `Die`, the first `Fail` in
|
|
276
|
+
* cause order is schema-encoded and thrown as a `ConvexError` outside the
|
|
277
|
+
* Effect runtime so Convex surfaces its data to the client. Other failures and
|
|
278
|
+
* interruptions alongside that `Fail` are ignored. Without an error schema, the
|
|
279
|
+
* selected failure is treated as a defect.
|
|
198
280
|
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
281
|
+
* A lone `ConvexError` defect or a selected undeclared `ConvexError` failure is
|
|
282
|
+
* rethrown bare so it keeps Convex's meaning. Pagination and Workpool rely on
|
|
283
|
+
* its data for their control signals. Other causes with a `Die`, interrupt-only
|
|
284
|
+
* or empty causes, and error-encoding failures reject with a plain `Error`
|
|
285
|
+
* whose message renders the complete cause and whose `cause` holds it for
|
|
286
|
+
* server diagnostics.
|
|
204
287
|
*
|
|
205
288
|
* A `scheduler` in `runOptions` must be passed here as a run option rather than
|
|
206
289
|
* provided via `Effect.provideService` inside `effect`: the run option lands in
|
|
207
290
|
* the fiber's root context, while a service provided within `effect` pops
|
|
208
|
-
* before the
|
|
209
|
-
*
|
|
210
|
-
*
|
|
291
|
+
* before the exit/encoding wrappers this function adds. The fiber's op counter
|
|
292
|
+
* survives context pops, so a cooperative yield can fire inside those wrappers.
|
|
293
|
+
* Only a root-context scheduler covers them.
|
|
294
|
+
*
|
|
295
|
+
* Under `@confect/test`, a handler reached from a bound test invocation starts
|
|
296
|
+
* with that invocation's services through `Effect.runPromiseWith`, on a fiber
|
|
297
|
+
* of its own. Every other handler starts with `Effect.runPromise`.
|
|
211
298
|
*/
|
|
212
299
|
export const runHandlerPromise =
|
|
213
300
|
(
|
|
214
301
|
errorSchema: Schema.Codec<any, any> | undefined,
|
|
215
302
|
runOptions?: {
|
|
216
303
|
readonly scheduler?: EffectScheduler.Scheduler | undefined;
|
|
304
|
+
readonly clock?: Clock.Clock | undefined;
|
|
305
|
+
readonly invocation?:
|
|
306
|
+
| Effect.Effect<
|
|
307
|
+
FunctionMetadata & { readonly received?: ReceivedValue }
|
|
308
|
+
>
|
|
309
|
+
| undefined;
|
|
310
|
+
readonly observability?: Layer.Layer<never> | undefined;
|
|
311
|
+
readonly meta?: InvocationMeta | undefined;
|
|
312
|
+
readonly functionType?: InvocationFunctionType | undefined;
|
|
217
313
|
},
|
|
218
314
|
) =>
|
|
219
315
|
<A, E>(effect: Effect.Effect<A, E>): Promise<A> => {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
316
|
+
const { observability, invocation, clock, meta, functionType } =
|
|
317
|
+
runOptions ?? {};
|
|
318
|
+
let encodedError: Exit.Exit<any, any> | undefined;
|
|
319
|
+
let undeclared: { readonly error: unknown } | undefined;
|
|
320
|
+
const observed = Effect.tapCause(effect, (cause) =>
|
|
321
|
+
Effect.gen(function* () {
|
|
322
|
+
const reason =
|
|
323
|
+
cause.reasons.find(Cause.isDieReason) ??
|
|
324
|
+
cause.reasons.find(Cause.isFailReason);
|
|
325
|
+
if (reason?._tag === "Fail" && errorSchema !== undefined) {
|
|
326
|
+
encodedError = yield* Effect.exit(
|
|
327
|
+
Schema.encodeEffect(errorSchema)(reason.error),
|
|
328
|
+
);
|
|
329
|
+
// An encoding failure is a defect, even when it dies with a ConvexError.
|
|
330
|
+
if (Exit.isFailure(encodedError)) {
|
|
331
|
+
const encoding = encodedError.cause;
|
|
332
|
+
return yield* Cause.squash(encoding) instanceof ConvexError
|
|
333
|
+
? Effect.die(
|
|
334
|
+
new Error(Cause.pretty(encoding), { cause: encoding }),
|
|
335
|
+
)
|
|
336
|
+
: Effect.orDie(encodedError);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// With no error schema a failure is a defect, so the root span ends as one.
|
|
340
|
+
if (
|
|
341
|
+
reason?._tag === "Fail" &&
|
|
342
|
+
errorSchema === undefined &&
|
|
343
|
+
!(reason.error instanceof ConvexError)
|
|
344
|
+
) {
|
|
345
|
+
undeclared = { error: reason.error };
|
|
346
|
+
return yield* Effect.die(reason.error);
|
|
347
|
+
}
|
|
348
|
+
}),
|
|
227
349
|
);
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
Effect.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
350
|
+
const withConvexError: Effect.Effect<Result.Result<A, ConvexError<any>>> =
|
|
351
|
+
Effect.gen(function* () {
|
|
352
|
+
const exit = yield* Effect.exit(
|
|
353
|
+
observability === undefined || invocation === undefined
|
|
354
|
+
? effect
|
|
355
|
+
: Effect.flatMap(
|
|
356
|
+
invocation,
|
|
357
|
+
({ name, type, componentPath, received }) =>
|
|
358
|
+
Effect.useSpan(
|
|
359
|
+
name,
|
|
360
|
+
{
|
|
361
|
+
root: true,
|
|
362
|
+
attributes: { kind: type, componentPath },
|
|
363
|
+
},
|
|
364
|
+
(span) =>
|
|
365
|
+
Effect.provideService(observed, Tracer.ParentSpan, span),
|
|
366
|
+
).pipe(Effect.provideService(Received, received)),
|
|
240
367
|
),
|
|
241
|
-
|
|
368
|
+
);
|
|
369
|
+
if (Exit.isSuccess(exit)) {
|
|
370
|
+
return Result.succeed(exit.value);
|
|
371
|
+
}
|
|
372
|
+
if (undeclared !== undefined)
|
|
373
|
+
return yield* Effect.die(undeclared.error);
|
|
374
|
+
|
|
375
|
+
const cause =
|
|
376
|
+
encodedError !== undefined && Exit.isFailure(encodedError)
|
|
377
|
+
? encodedError.cause
|
|
378
|
+
: exit.cause;
|
|
379
|
+
const reason =
|
|
380
|
+
cause.reasons.find(Cause.isDieReason) ??
|
|
381
|
+
cause.reasons.find(Cause.isFailReason);
|
|
382
|
+
if (
|
|
383
|
+
encodedError === undefined &&
|
|
384
|
+
reason?._tag === "Die" &&
|
|
385
|
+
cause.reasons.length === 1 &&
|
|
386
|
+
reason.defect instanceof ConvexError
|
|
387
|
+
) {
|
|
388
|
+
return Result.fail(reason.defect);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (reason?._tag === "Fail") {
|
|
392
|
+
if (errorSchema === undefined) {
|
|
393
|
+
if (reason.error instanceof ConvexError) {
|
|
394
|
+
return Result.fail(reason.error);
|
|
395
|
+
}
|
|
396
|
+
return yield* Effect.die(reason.error);
|
|
397
|
+
}
|
|
398
|
+
const encoded =
|
|
399
|
+
encodedError ??
|
|
400
|
+
(yield* Effect.exit(
|
|
401
|
+
Schema.encodeEffect(errorSchema)(reason.error),
|
|
402
|
+
));
|
|
403
|
+
if (Exit.isSuccess(encoded)) {
|
|
404
|
+
return Result.fail(new ConvexError(encoded.value));
|
|
405
|
+
}
|
|
406
|
+
return yield* Effect.die(
|
|
407
|
+
new Error(Cause.pretty(encoded.cause), { cause: encoded.cause }),
|
|
242
408
|
);
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
409
|
+
}
|
|
410
|
+
return yield* Effect.die(new Error(Cause.pretty(cause), { cause }));
|
|
411
|
+
});
|
|
412
|
+
const program = withConvexError.pipe(
|
|
413
|
+
Effect.provide(
|
|
414
|
+
observability === undefined
|
|
415
|
+
? ConvexLogger.layer
|
|
416
|
+
: ObservabilityRuntime.memoized(observability),
|
|
247
417
|
),
|
|
248
|
-
|
|
249
|
-
|
|
418
|
+
Effect.provideService(Console.Console, globalThis.console),
|
|
419
|
+
clock === undefined
|
|
420
|
+
? (self) => self
|
|
421
|
+
: Effect.provideService(Clock.Clock, clock),
|
|
422
|
+
);
|
|
423
|
+
const started =
|
|
424
|
+
meta === undefined || functionType === undefined
|
|
425
|
+
? undefined
|
|
426
|
+
: (globalThis as { [testInvocation]?: TestInvocation })[
|
|
427
|
+
testInvocation
|
|
428
|
+
]?.start(
|
|
429
|
+
meta,
|
|
430
|
+
(services) => Effect.runPromiseWith(services)(program, runOptions),
|
|
431
|
+
functionType,
|
|
432
|
+
);
|
|
433
|
+
return (started ?? Effect.runPromise(program, runOptions)).then(
|
|
250
434
|
Result.match({
|
|
251
435
|
onFailure: (error) => {
|
|
252
436
|
throw error;
|
|
@@ -256,6 +440,16 @@ export const runHandlerPromise =
|
|
|
256
440
|
);
|
|
257
441
|
};
|
|
258
442
|
|
|
443
|
+
export const domainArgs = (
|
|
444
|
+
args: DefaultFunctionArgs,
|
|
445
|
+
reservedArgument?: string,
|
|
446
|
+
): DefaultFunctionArgs =>
|
|
447
|
+
reservedArgument === undefined
|
|
448
|
+
? args
|
|
449
|
+
: Object.fromEntries(
|
|
450
|
+
Object.entries(args).filter(([key]) => key !== reservedArgument),
|
|
451
|
+
);
|
|
452
|
+
|
|
259
453
|
export const actionFunctionBase = <
|
|
260
454
|
Schema extends DatabaseSchema.AnyWithProps,
|
|
261
455
|
Args,
|
|
@@ -274,8 +468,11 @@ export const actionFunctionBase = <
|
|
|
274
468
|
resolvedMiddlewares = [],
|
|
275
469
|
createLayer,
|
|
276
470
|
scope = IdScope.app,
|
|
471
|
+
observability,
|
|
472
|
+
reservedArgument,
|
|
277
473
|
}: {
|
|
278
474
|
name: string;
|
|
475
|
+
reservedArgument?: string | undefined;
|
|
279
476
|
functionVisibility: FunctionVisibility;
|
|
280
477
|
args: Schema.Codec<Args, ConvexArgs>;
|
|
281
478
|
returns: Schema.Codec<Returns, ConvexReturns>;
|
|
@@ -286,8 +483,9 @@ export const actionFunctionBase = <
|
|
|
286
483
|
ctx: GenericActionCtx<DataModel.ToConvex<DataModel.FromSchema<Schema>>>,
|
|
287
484
|
) => Layer.Layer<R>;
|
|
288
485
|
scope?: IdScope.IdScope;
|
|
486
|
+
observability?: Layer.Layer<never> | undefined;
|
|
289
487
|
}) => ({
|
|
290
|
-
args: compileArgsSchema(args, scope),
|
|
488
|
+
args: compileArgsSchema(args, scope, reservedArgument, name),
|
|
291
489
|
returns: compileReturnsSchema(returns, scope),
|
|
292
490
|
handler: (
|
|
293
491
|
ctx: GenericActionCtx<DataModel.ToConvex<DataModel.FromSchema<Schema>>>,
|
|
@@ -295,10 +493,16 @@ export const actionFunctionBase = <
|
|
|
295
493
|
): Promise<ConvexReturns> =>
|
|
296
494
|
Effect.gen(function* () {
|
|
297
495
|
const decodedArgs = yield* pipe(
|
|
298
|
-
actualArgs,
|
|
496
|
+
domainArgs(actualArgs, reservedArgument),
|
|
299
497
|
Schema.decodeUnknownEffect(args),
|
|
300
498
|
Effect.catchTag("SchemaError", Effect.die),
|
|
301
499
|
);
|
|
500
|
+
const restricted = resolvedMiddlewares.some(
|
|
501
|
+
({ middlewareSpec }) =>
|
|
502
|
+
middlewareSpec.key === ActionCallSpec.Middleware.key,
|
|
503
|
+
)
|
|
504
|
+
? restrict(ctx)
|
|
505
|
+
: undefined;
|
|
302
506
|
// oxlint-disable-next-line effecttsgo/any-unknown-in-error-context -- Middleware errors are intentionally erased here and validated by runHandlerPromise against the combined error schema below.
|
|
303
507
|
const decodedReturns = yield* applyMiddleware(
|
|
304
508
|
handler(decodedArgs),
|
|
@@ -309,13 +513,21 @@ export const actionFunctionBase = <
|
|
|
309
513
|
functionVisibility,
|
|
310
514
|
args: decodedArgs,
|
|
311
515
|
},
|
|
312
|
-
).pipe(Effect.provide(createLayer(ctx)));
|
|
516
|
+
).pipe(Effect.provide(createLayer(restricted?.ctx ?? ctx)));
|
|
517
|
+
if (restricted !== undefined) yield* restricted.check;
|
|
313
518
|
return yield* pipe(
|
|
314
519
|
decodedReturns,
|
|
315
520
|
Schema.encodeEffect(returns),
|
|
316
521
|
Effect.catchTag("SchemaError", Effect.die),
|
|
317
522
|
);
|
|
318
|
-
}).pipe(
|
|
523
|
+
}).pipe(
|
|
524
|
+
runHandlerPromise(combineErrorSchemas(error, resolvedMiddlewares), {
|
|
525
|
+
invocation: invocationMetadata(ctx.meta, actualArgs, reservedArgument),
|
|
526
|
+
observability,
|
|
527
|
+
meta: ctx.meta,
|
|
528
|
+
functionType: "action",
|
|
529
|
+
}),
|
|
530
|
+
),
|
|
319
531
|
});
|
|
320
532
|
|
|
321
533
|
export type ActionServices<
|
|
@@ -389,3 +601,47 @@ export const storageLayer = <Scope extends IdScope.IdScope>(
|
|
|
389
601
|
Storage.layer(reader) as Layer.Layer<
|
|
390
602
|
Storage.Storage | StorageReader.ForScope<Scope>
|
|
391
603
|
>;
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Shares one dispatch budget across the entire middleware chain.
|
|
607
|
+
*/
|
|
608
|
+
const restrict = <Model extends GenericDataModel>(
|
|
609
|
+
ctx: GenericActionCtx<Model>,
|
|
610
|
+
) => {
|
|
611
|
+
let dispatched = false;
|
|
612
|
+
const claim = () => {
|
|
613
|
+
if (dispatched) throw new ActionCall.ActionCallAlreadyUsed();
|
|
614
|
+
dispatched = true;
|
|
615
|
+
};
|
|
616
|
+
const restricted: GenericActionCtx<Model> = {
|
|
617
|
+
...ctx,
|
|
618
|
+
scheduler: {
|
|
619
|
+
runAfter: () => {
|
|
620
|
+
throw new ActionCall.SchedulingNotAllowed();
|
|
621
|
+
},
|
|
622
|
+
runAt: () => {
|
|
623
|
+
throw new ActionCall.SchedulingNotAllowed();
|
|
624
|
+
},
|
|
625
|
+
cancel: () => {
|
|
626
|
+
throw new ActionCall.SchedulingNotAllowed();
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
runQuery: (...args) => {
|
|
630
|
+
claim();
|
|
631
|
+
return ctx.runQuery(...args);
|
|
632
|
+
},
|
|
633
|
+
runMutation: (...args) => {
|
|
634
|
+
claim();
|
|
635
|
+
return ctx.runMutation(...args);
|
|
636
|
+
},
|
|
637
|
+
runAction: () => {
|
|
638
|
+
throw new ActionCall.NestedActionNotAllowed();
|
|
639
|
+
},
|
|
640
|
+
};
|
|
641
|
+
return {
|
|
642
|
+
ctx: restricted,
|
|
643
|
+
check: Effect.suspend(() =>
|
|
644
|
+
dispatched ? Effect.void : Effect.die(new ActionCall.ActionCallNotUsed()),
|
|
645
|
+
),
|
|
646
|
+
};
|
|
647
|
+
};
|
|
@@ -23,7 +23,7 @@ export const buildForGroup = <Group extends GroupSpec.AnyWithProps>(
|
|
|
23
23
|
databaseSchema: DatabaseSchema.AnyWithProps,
|
|
24
24
|
groupLayer: Layer.Layer<GroupImpl.GroupImpl<"Finalized">>,
|
|
25
25
|
): RegisteredFunctions.RegisteredFunctionsForGroupSpec<Group> => {
|
|
26
|
-
const { functionRegistryItems, middlewareRegistryItems } =
|
|
26
|
+
const { functionRegistryItems, middlewareRegistryItems, observability } =
|
|
27
27
|
GroupRegistry.make(groupLayer);
|
|
28
28
|
return mapLeaves<FunctionRegistryItem.AnyWithProps, RegisteredFunction.Any>(
|
|
29
29
|
functionRegistryItems as {
|
|
@@ -38,6 +38,7 @@ export const buildForGroup = <Group extends GroupSpec.AnyWithProps>(
|
|
|
38
38
|
databaseSchema,
|
|
39
39
|
confect,
|
|
40
40
|
ResolvedMiddleware.resolve(confect, middlewareRegistryItems),
|
|
41
|
+
observability,
|
|
41
42
|
),
|
|
42
43
|
),
|
|
43
44
|
Match.exhaustive,
|
|
@@ -49,6 +50,7 @@ export const make = (
|
|
|
49
50
|
databaseSchema: DatabaseSchema.AnyWithProps,
|
|
50
51
|
item: FunctionRegistryItem.ConfectFunctionRegistryItem,
|
|
51
52
|
resolvedMiddlewares: ReadonlyArray<ResolvedMiddleware.ResolvedMiddleware> = [],
|
|
53
|
+
observability?: Layer.Layer<never>,
|
|
52
54
|
): RegisteredFunction.Any => {
|
|
53
55
|
const genericFunction = Match.value(item.functionVisibility).pipe(
|
|
54
56
|
Match.when("public", () => actionGeneric),
|
|
@@ -59,6 +61,8 @@ export const make = (
|
|
|
59
61
|
return genericFunction(
|
|
60
62
|
nodeActionFunction(databaseSchema, {
|
|
61
63
|
name: item.name,
|
|
64
|
+
reservedArgument: item.reservedArgument,
|
|
65
|
+
observability,
|
|
62
66
|
functionVisibility: item.functionVisibility,
|
|
63
67
|
args: item.args,
|
|
64
68
|
returns: item.returns,
|
|
@@ -86,8 +90,11 @@ const nodeActionFunction = <
|
|
|
86
90
|
error,
|
|
87
91
|
handler,
|
|
88
92
|
resolvedMiddlewares,
|
|
93
|
+
observability,
|
|
94
|
+
reservedArgument,
|
|
89
95
|
}: {
|
|
90
96
|
name: string;
|
|
97
|
+
reservedArgument?: string | undefined;
|
|
91
98
|
functionVisibility: FunctionVisibility;
|
|
92
99
|
args: Schema.Codec<Args, ConvexArgs>;
|
|
93
100
|
returns: Schema.Codec<Returns, ConvexReturns>;
|
|
@@ -101,6 +108,7 @@ const nodeActionFunction = <
|
|
|
101
108
|
| NodeServices.NodeServices
|
|
102
109
|
>;
|
|
103
110
|
resolvedMiddlewares: ReadonlyArray<ResolvedMiddleware.ResolvedMiddleware>;
|
|
111
|
+
observability?: Layer.Layer<never> | undefined;
|
|
104
112
|
},
|
|
105
113
|
) =>
|
|
106
114
|
RegisteredFunction.actionFunctionBase({
|
|
@@ -112,6 +120,8 @@ const nodeActionFunction = <
|
|
|
112
120
|
error,
|
|
113
121
|
handler,
|
|
114
122
|
resolvedMiddlewares,
|
|
123
|
+
observability,
|
|
124
|
+
reservedArgument,
|
|
115
125
|
createLayer: (ctx) =>
|
|
116
126
|
Layer.mergeAll(
|
|
117
127
|
RegisteredFunction.actionLayer(databaseSchema, ctx),
|