@confect/server 1.0.0-next.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.
- package/CHANGELOG.md +12 -0
- package/LICENSE +7 -0
- package/dist/ActionCtx.d.ts +12 -0
- package/dist/ActionCtx.d.ts.map +1 -0
- package/dist/ActionCtx.js +10 -0
- package/dist/ActionCtx.js.map +1 -0
- package/dist/ActionRunner.d.ts +15 -0
- package/dist/ActionRunner.d.ts.map +1 -0
- package/dist/ActionRunner.js +23 -0
- package/dist/ActionRunner.js.map +1 -0
- package/dist/Api.d.ts +27 -0
- package/dist/Api.d.ts.map +1 -0
- package/dist/Api.js +26 -0
- package/dist/Api.js.map +1 -0
- package/dist/Auth.d.ts +30 -0
- package/dist/Auth.d.ts.map +1 -0
- package/dist/Auth.js +24 -0
- package/dist/Auth.js.map +1 -0
- package/dist/DataModel.d.ts +33 -0
- package/dist/DataModel.d.ts.map +1 -0
- package/dist/DataModel.js +6 -0
- package/dist/DataModel.js.map +1 -0
- package/dist/DatabaseReader.d.ts +73 -0
- package/dist/DatabaseReader.d.ts.map +1 -0
- package/dist/DatabaseReader.js +32 -0
- package/dist/DatabaseReader.js.map +1 -0
- package/dist/DatabaseSchema.d.ts +139 -0
- package/dist/DatabaseSchema.d.ts.map +1 -0
- package/dist/DatabaseSchema.js +45 -0
- package/dist/DatabaseSchema.js.map +1 -0
- package/dist/DatabaseWriter.d.ts +39 -0
- package/dist/DatabaseWriter.d.ts.map +1 -0
- package/dist/DatabaseWriter.js +43 -0
- package/dist/DatabaseWriter.js.map +1 -0
- package/dist/Document.d.ts +47 -0
- package/dist/Document.d.ts.map +1 -0
- package/dist/Document.js +66 -0
- package/dist/Document.js.map +1 -0
- package/dist/FunctionImpl.d.ts +34 -0
- package/dist/FunctionImpl.d.ts.map +1 -0
- package/dist/FunctionImpl.js +35 -0
- package/dist/FunctionImpl.js.map +1 -0
- package/dist/GroupImpl.d.ts +24 -0
- package/dist/GroupImpl.d.ts.map +1 -0
- package/dist/GroupImpl.js +14 -0
- package/dist/GroupImpl.js.map +1 -0
- package/dist/Handler.d.ts +31 -0
- package/dist/Handler.d.ts.map +1 -0
- package/dist/Handler.js +6 -0
- package/dist/Handler.js.map +1 -0
- package/dist/HttpApi.d.ts +26 -0
- package/dist/HttpApi.d.ts.map +1 -0
- package/dist/HttpApi.js +74 -0
- package/dist/HttpApi.js.map +1 -0
- package/dist/Impl.d.ts +24 -0
- package/dist/Impl.d.ts.map +1 -0
- package/dist/Impl.js +28 -0
- package/dist/Impl.js.map +1 -0
- package/dist/MutationCtx.d.ts +12 -0
- package/dist/MutationCtx.d.ts.map +1 -0
- package/dist/MutationCtx.js +10 -0
- package/dist/MutationCtx.js.map +1 -0
- package/dist/MutationRunner.d.ts +24 -0
- package/dist/MutationRunner.d.ts.map +1 -0
- package/dist/MutationRunner.js +33 -0
- package/dist/MutationRunner.js.map +1 -0
- package/dist/OrderedQuery.d.ts +23 -0
- package/dist/OrderedQuery.d.ts.map +1 -0
- package/dist/OrderedQuery.js +34 -0
- package/dist/OrderedQuery.js.map +1 -0
- package/dist/QueryCtx.d.ts +12 -0
- package/dist/QueryCtx.d.ts.map +1 -0
- package/dist/QueryCtx.js +10 -0
- package/dist/QueryCtx.js.map +1 -0
- package/dist/QueryInitializer.d.ts +49 -0
- package/dist/QueryInitializer.d.ts.map +1 -0
- package/dist/QueryInitializer.js +83 -0
- package/dist/QueryInitializer.js.map +1 -0
- package/dist/QueryRunner.d.ts +14 -0
- package/dist/QueryRunner.d.ts.map +1 -0
- package/dist/QueryRunner.js +23 -0
- package/dist/QueryRunner.js.map +1 -0
- package/dist/RegisteredFunctions.d.ts +66 -0
- package/dist/RegisteredFunctions.d.ts.map +1 -0
- package/dist/RegisteredFunctions.js +71 -0
- package/dist/RegisteredFunctions.js.map +1 -0
- package/dist/Registry.d.ts +15 -0
- package/dist/Registry.d.ts.map +1 -0
- package/dist/Registry.js +10 -0
- package/dist/Registry.js.map +1 -0
- package/dist/RegistryItem.d.ts +31 -0
- package/dist/RegistryItem.d.ts.map +1 -0
- package/dist/RegistryItem.js +20 -0
- package/dist/RegistryItem.js.map +1 -0
- package/dist/Scheduler.d.ts +23 -0
- package/dist/Scheduler.d.ts.map +1 -0
- package/dist/Scheduler.js +24 -0
- package/dist/Scheduler.js.map +1 -0
- package/dist/SchemaToValidator.d.ts +88 -0
- package/dist/SchemaToValidator.d.ts.map +1 -0
- package/dist/SchemaToValidator.js +155 -0
- package/dist/SchemaToValidator.js.map +1 -0
- package/dist/Storage.d.ts +69 -0
- package/dist/Storage.d.ts.map +1 -0
- package/dist/Storage.js +46 -0
- package/dist/Storage.js.map +1 -0
- package/dist/Table.d.ts +247 -0
- package/dist/Table.d.ts.map +1 -0
- package/dist/Table.js +97 -0
- package/dist/Table.js.map +1 -0
- package/dist/TableInfo.d.ts +48 -0
- package/dist/TableInfo.d.ts.map +1 -0
- package/dist/TableInfo.js +6 -0
- package/dist/TableInfo.js.map +1 -0
- package/dist/VectorSearch.d.ts +42 -0
- package/dist/VectorSearch.d.ts.map +1 -0
- package/dist/VectorSearch.js +16 -0
- package/dist/VectorSearch.js.map +1 -0
- package/dist/_virtual/rolldown_runtime.js +13 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +31 -0
- package/dist/internal/utils.d.ts +15 -0
- package/dist/internal/utils.d.ts.map +1 -0
- package/dist/internal/utils.js +49 -0
- package/dist/internal/utils.js.map +1 -0
- package/package.json +90 -0
- package/src/ActionCtx.ts +9 -0
- package/src/ActionRunner.ts +28 -0
- package/src/Api.ts +63 -0
- package/src/Auth.ts +31 -0
- package/src/DataModel.ts +69 -0
- package/src/DatabaseReader.ts +75 -0
- package/src/DatabaseSchema.ts +134 -0
- package/src/DatabaseWriter.ts +166 -0
- package/src/Document.ts +200 -0
- package/src/FunctionImpl.ts +112 -0
- package/src/GroupImpl.ts +60 -0
- package/src/Handler.ts +105 -0
- package/src/HttpApi.ts +232 -0
- package/src/Impl.ts +57 -0
- package/src/MutationCtx.ts +11 -0
- package/src/MutationRunner.ts +41 -0
- package/src/OrderedQuery.ts +109 -0
- package/src/QueryCtx.ts +9 -0
- package/src/QueryInitializer.ts +308 -0
- package/src/QueryRunner.ts +29 -0
- package/src/RegisteredFunctions.ts +381 -0
- package/src/Registry.ts +13 -0
- package/src/RegistryItem.ts +44 -0
- package/src/Scheduler.ts +39 -0
- package/src/SchemaToValidator.ts +619 -0
- package/src/Storage.ts +86 -0
- package/src/Table.ts +439 -0
- package/src/TableInfo.ts +91 -0
- package/src/VectorSearch.ts +46 -0
- package/src/index.ts +29 -0
- package/src/internal/utils.ts +87 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type * as FunctionSpec from "@confect/core/FunctionSpec";
|
|
2
|
+
import type * as GroupPath from "@confect/core/GroupPath";
|
|
3
|
+
import type * as GroupSpec from "@confect/core/GroupSpec";
|
|
4
|
+
import { Array, Context, Effect, Layer, Ref, String } from "effect";
|
|
5
|
+
import type * as Api from "./Api";
|
|
6
|
+
import type * as Handler from "./Handler";
|
|
7
|
+
import { setNestedProperty } from "./internal/utils";
|
|
8
|
+
import * as Registry from "./Registry";
|
|
9
|
+
import * as RegistryItem from "./RegistryItem";
|
|
10
|
+
|
|
11
|
+
export interface FunctionImpl<
|
|
12
|
+
GroupPath_ extends string,
|
|
13
|
+
FunctionName extends string,
|
|
14
|
+
> {
|
|
15
|
+
readonly groupPath: GroupPath_;
|
|
16
|
+
readonly functionName: FunctionName;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const FunctionImpl = <
|
|
20
|
+
GroupPath_ extends string,
|
|
21
|
+
FunctionName extends string,
|
|
22
|
+
>({
|
|
23
|
+
groupPath,
|
|
24
|
+
functionName,
|
|
25
|
+
}: {
|
|
26
|
+
groupPath: GroupPath_;
|
|
27
|
+
functionName: FunctionName;
|
|
28
|
+
}) =>
|
|
29
|
+
Context.GenericTag<FunctionImpl<GroupPath_, FunctionName>>(
|
|
30
|
+
`@confect/server/FunctionImpl/${groupPath}/${functionName}`,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export const make = <
|
|
34
|
+
Api_ extends Api.AnyWithProps,
|
|
35
|
+
const GroupPath_ extends GroupPath.All<Api.Groups<Api_>>,
|
|
36
|
+
const FunctionName extends FunctionSpec.Name<
|
|
37
|
+
GroupSpec.Functions<GroupPath.GroupAt<Api.Groups<Api_>, GroupPath_>>
|
|
38
|
+
>,
|
|
39
|
+
>(
|
|
40
|
+
api: Api_,
|
|
41
|
+
groupPath: GroupPath_,
|
|
42
|
+
functionName: FunctionName,
|
|
43
|
+
handler: Handler.WithName<
|
|
44
|
+
Api.Schema<Api_>,
|
|
45
|
+
GroupSpec.Functions<GroupPath.GroupAt<Api.Groups<Api_>, GroupPath_>>,
|
|
46
|
+
FunctionName
|
|
47
|
+
>,
|
|
48
|
+
): Layer.Layer<FunctionImpl<GroupPath_, FunctionName>> => {
|
|
49
|
+
const groupPathParts = String.split(groupPath, ".");
|
|
50
|
+
const [firstGroupPathPart, ...restGroupPathParts] = groupPathParts;
|
|
51
|
+
|
|
52
|
+
const group_: GroupSpec.AnyWithProps = Array.reduce(
|
|
53
|
+
restGroupPathParts,
|
|
54
|
+
(api as any).spec.groups[firstGroupPathPart as any]!,
|
|
55
|
+
(currentGroup: any, groupPathPart: any) =>
|
|
56
|
+
currentGroup.groups[groupPathPart],
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const function_ = group_.functions[functionName]!;
|
|
60
|
+
|
|
61
|
+
return Layer.effect(
|
|
62
|
+
FunctionImpl<GroupPath_, FunctionName>({
|
|
63
|
+
groupPath,
|
|
64
|
+
functionName,
|
|
65
|
+
}),
|
|
66
|
+
Effect.gen(function* () {
|
|
67
|
+
const registry = yield* Registry.Registry;
|
|
68
|
+
|
|
69
|
+
yield* Ref.update(registry, (registryItems) =>
|
|
70
|
+
setNestedProperty(
|
|
71
|
+
registryItems,
|
|
72
|
+
[...groupPathParts, functionName],
|
|
73
|
+
RegistryItem.make({
|
|
74
|
+
function_,
|
|
75
|
+
handler: handler as Handler.AnyWithProps,
|
|
76
|
+
}),
|
|
77
|
+
),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
groupPath,
|
|
82
|
+
functionName,
|
|
83
|
+
};
|
|
84
|
+
}),
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get the function implementation service type for a specific group path and function name.
|
|
90
|
+
*/
|
|
91
|
+
export type ForGroupPathAndFunction<
|
|
92
|
+
GroupPath_ extends string,
|
|
93
|
+
FunctionName extends string,
|
|
94
|
+
> = FunctionImpl<GroupPath_, FunctionName>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Get all function implementation services required for a group at a given path.
|
|
98
|
+
*/
|
|
99
|
+
export type FromGroupAtPath<
|
|
100
|
+
GroupPath_ extends string,
|
|
101
|
+
Group extends GroupSpec.AnyWithProps,
|
|
102
|
+
> =
|
|
103
|
+
GroupPath.GroupAt<Group, GroupPath_> extends infer GroupAtPath extends
|
|
104
|
+
GroupSpec.AnyWithProps
|
|
105
|
+
? FunctionSpec.Name<
|
|
106
|
+
GroupSpec.Functions<GroupAtPath>
|
|
107
|
+
> extends infer FunctionNames extends string
|
|
108
|
+
? FunctionNames extends string
|
|
109
|
+
? FunctionImpl<GroupPath_, FunctionNames>
|
|
110
|
+
: never
|
|
111
|
+
: never
|
|
112
|
+
: never;
|
package/src/GroupImpl.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type * as GroupPath from "@confect/core/GroupPath";
|
|
2
|
+
import type * as GroupSpec from "@confect/core/GroupSpec";
|
|
3
|
+
import { Context, Layer } from "effect";
|
|
4
|
+
import type * as Api from "./Api";
|
|
5
|
+
import type * as FunctionImpl from "./FunctionImpl";
|
|
6
|
+
|
|
7
|
+
export interface GroupImpl<GroupPath_ extends string> {
|
|
8
|
+
readonly groupPath: GroupPath_;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const GroupImpl = <GroupPath_ extends string>({
|
|
12
|
+
groupPath,
|
|
13
|
+
}: {
|
|
14
|
+
groupPath: GroupPath_;
|
|
15
|
+
}) =>
|
|
16
|
+
Context.GenericTag<GroupImpl<GroupPath_>>(
|
|
17
|
+
`@confect/server/GroupImpl/${groupPath}`,
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export const make = <
|
|
21
|
+
Api_ extends Api.AnyWithProps,
|
|
22
|
+
const GroupPath_ extends GroupPath.All<Api.Groups<Api_>>,
|
|
23
|
+
>(
|
|
24
|
+
_api: Api_,
|
|
25
|
+
groupPath: GroupPath_,
|
|
26
|
+
): Layer.Layer<
|
|
27
|
+
GroupImpl<GroupPath_>,
|
|
28
|
+
never,
|
|
29
|
+
| FromGroupWithPath<GroupPath_, Api.Groups<Api_>>
|
|
30
|
+
| FunctionImpl.FromGroupAtPath<GroupPath_, Api.Groups<Api_>>
|
|
31
|
+
> =>
|
|
32
|
+
Layer.succeed(
|
|
33
|
+
GroupImpl<GroupPath_>({
|
|
34
|
+
groupPath,
|
|
35
|
+
}),
|
|
36
|
+
{
|
|
37
|
+
groupPath,
|
|
38
|
+
},
|
|
39
|
+
) as Layer.Layer<
|
|
40
|
+
GroupImpl<GroupPath_>,
|
|
41
|
+
never,
|
|
42
|
+
| FromGroupWithPath<GroupPath_, Api.Groups<Api_>>
|
|
43
|
+
| FunctionImpl.FromGroupAtPath<GroupPath_, Api.Groups<Api_>>
|
|
44
|
+
>;
|
|
45
|
+
|
|
46
|
+
export type FromGroups<Groups extends GroupSpec.Any> = Groups extends never
|
|
47
|
+
? never
|
|
48
|
+
: Groups extends GroupSpec.AnyWithProps
|
|
49
|
+
? GroupImpl<GroupSpec.Name<Groups>>
|
|
50
|
+
: never;
|
|
51
|
+
|
|
52
|
+
export type FromGroupWithPath<
|
|
53
|
+
GroupPath_ extends string,
|
|
54
|
+
Group extends GroupSpec.AnyWithProps,
|
|
55
|
+
> =
|
|
56
|
+
GroupPath.SubGroupsAt<Group, GroupPath_> extends infer SubGroupPaths
|
|
57
|
+
? SubGroupPaths extends string
|
|
58
|
+
? GroupImpl<SubGroupPaths>
|
|
59
|
+
: never
|
|
60
|
+
: never;
|
package/src/Handler.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { FunctionSpec } from "@confect/core";
|
|
2
|
+
import type { Effect } from "effect";
|
|
3
|
+
import type * as ActionCtx from "./ActionCtx";
|
|
4
|
+
import type * as ActionRunner from "./ActionRunner";
|
|
5
|
+
import type * as Auth from "./Auth";
|
|
6
|
+
import type * as DatabaseReader from "./DatabaseReader";
|
|
7
|
+
import type * as DatabaseSchema from "./DatabaseSchema";
|
|
8
|
+
import type * as DatabaseWriter from "./DatabaseWriter";
|
|
9
|
+
import type * as DataModel from "./DataModel";
|
|
10
|
+
import type * as MutationCtx from "./MutationCtx";
|
|
11
|
+
import type * as MutationRunner from "./MutationRunner";
|
|
12
|
+
import type * as QueryCtx from "./QueryCtx";
|
|
13
|
+
import type * as QueryRunner from "./QueryRunner";
|
|
14
|
+
import type * as Scheduler from "./Scheduler";
|
|
15
|
+
import type {
|
|
16
|
+
StorageActionWriter,
|
|
17
|
+
StorageReader,
|
|
18
|
+
StorageWriter,
|
|
19
|
+
} from "./Storage";
|
|
20
|
+
import type * as VectorSearch from "./VectorSearch";
|
|
21
|
+
|
|
22
|
+
export type Handler<
|
|
23
|
+
DatabaseSchema_ extends DatabaseSchema.AnyWithProps,
|
|
24
|
+
FunctionSpec_ extends FunctionSpec.AnyWithProps,
|
|
25
|
+
> =
|
|
26
|
+
FunctionSpec_ extends FunctionSpec.WithFunctionType<FunctionSpec_, "query">
|
|
27
|
+
? Query<DatabaseSchema_, FunctionSpec_>
|
|
28
|
+
: FunctionSpec_ extends FunctionSpec.WithFunctionType<
|
|
29
|
+
FunctionSpec_,
|
|
30
|
+
"mutation"
|
|
31
|
+
>
|
|
32
|
+
? Mutation<DatabaseSchema_, FunctionSpec_>
|
|
33
|
+
: FunctionSpec_ extends FunctionSpec.WithFunctionType<
|
|
34
|
+
FunctionSpec_,
|
|
35
|
+
"action"
|
|
36
|
+
>
|
|
37
|
+
? Action<DatabaseSchema_, FunctionSpec_>
|
|
38
|
+
: never;
|
|
39
|
+
|
|
40
|
+
export type Query<
|
|
41
|
+
DatabaseSchema_ extends DatabaseSchema.AnyWithProps,
|
|
42
|
+
FunctionSpec_ extends FunctionSpec.AnyWithPropsWithFunctionType<"query">,
|
|
43
|
+
> = Base<
|
|
44
|
+
FunctionSpec_,
|
|
45
|
+
| DatabaseReader.DatabaseReader<DatabaseSchema_>
|
|
46
|
+
| Auth.Auth
|
|
47
|
+
| StorageReader
|
|
48
|
+
| QueryRunner.QueryRunner
|
|
49
|
+
| QueryCtx.QueryCtx<DataModel.ToConvex<DataModel.FromSchema<DatabaseSchema_>>>
|
|
50
|
+
>;
|
|
51
|
+
|
|
52
|
+
export type Mutation<
|
|
53
|
+
DatabaseSchema_ extends DatabaseSchema.AnyWithProps,
|
|
54
|
+
FunctionSpec_ extends FunctionSpec.AnyWithPropsWithFunctionType<"mutation">,
|
|
55
|
+
> = Base<
|
|
56
|
+
FunctionSpec_,
|
|
57
|
+
| DatabaseReader.DatabaseReader<DatabaseSchema_>
|
|
58
|
+
| DatabaseWriter.DatabaseWriter<DatabaseSchema_>
|
|
59
|
+
| Auth.Auth
|
|
60
|
+
| Scheduler.Scheduler
|
|
61
|
+
| StorageReader
|
|
62
|
+
| StorageWriter
|
|
63
|
+
| QueryRunner.QueryRunner
|
|
64
|
+
| MutationRunner.MutationRunner
|
|
65
|
+
| MutationCtx.MutationCtx<
|
|
66
|
+
DataModel.ToConvex<DataModel.FromSchema<DatabaseSchema_>>
|
|
67
|
+
>
|
|
68
|
+
>;
|
|
69
|
+
|
|
70
|
+
export type Action<
|
|
71
|
+
DatabaseSchema_ extends DatabaseSchema.AnyWithProps,
|
|
72
|
+
FunctionSpec_ extends FunctionSpec.AnyWithPropsWithFunctionType<"action">,
|
|
73
|
+
> = Base<
|
|
74
|
+
FunctionSpec_,
|
|
75
|
+
| Scheduler.Scheduler
|
|
76
|
+
| Auth.Auth
|
|
77
|
+
| StorageReader
|
|
78
|
+
| StorageWriter
|
|
79
|
+
| StorageActionWriter
|
|
80
|
+
| QueryRunner.QueryRunner
|
|
81
|
+
| MutationRunner.MutationRunner
|
|
82
|
+
| ActionRunner.ActionRunner
|
|
83
|
+
| VectorSearch.VectorSearch<DataModel.FromSchema<DatabaseSchema_>>
|
|
84
|
+
| ActionCtx.ActionCtx<
|
|
85
|
+
DataModel.ToConvex<DataModel.FromSchema<DatabaseSchema_>>
|
|
86
|
+
>
|
|
87
|
+
>;
|
|
88
|
+
|
|
89
|
+
type Base<FunctionSpec_ extends FunctionSpec.AnyWithProps, R> = (
|
|
90
|
+
args: FunctionSpec.Args<FunctionSpec_>["Type"],
|
|
91
|
+
) => Effect.Effect<FunctionSpec.Returns<FunctionSpec_>["Type"], never, R>;
|
|
92
|
+
|
|
93
|
+
export type AnyWithProps = Handler<
|
|
94
|
+
DatabaseSchema.AnyWithProps,
|
|
95
|
+
FunctionSpec.AnyWithProps
|
|
96
|
+
>;
|
|
97
|
+
|
|
98
|
+
export type WithName<
|
|
99
|
+
DatabaseSchema_ extends DatabaseSchema.AnyWithProps,
|
|
100
|
+
FunctionSpec_ extends FunctionSpec.AnyWithProps,
|
|
101
|
+
FunctionName extends string,
|
|
102
|
+
> = Handler<
|
|
103
|
+
DatabaseSchema_,
|
|
104
|
+
FunctionSpec.WithName<FunctionSpec_, FunctionName>
|
|
105
|
+
>;
|
package/src/HttpApi.ts
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type HttpApi,
|
|
3
|
+
HttpApiBuilder,
|
|
4
|
+
HttpApiScalar,
|
|
5
|
+
type HttpApp,
|
|
6
|
+
type HttpRouter,
|
|
7
|
+
HttpServer,
|
|
8
|
+
} from "@effect/platform";
|
|
9
|
+
import {
|
|
10
|
+
type HttpRouter as ConvexHttpRouter,
|
|
11
|
+
type GenericActionCtx,
|
|
12
|
+
type GenericDataModel,
|
|
13
|
+
httpActionGeneric,
|
|
14
|
+
httpRouter,
|
|
15
|
+
ROUTABLE_HTTP_METHODS,
|
|
16
|
+
type RouteSpecWithPathPrefix,
|
|
17
|
+
} from "convex/server";
|
|
18
|
+
import { Array, Layer, pipe, Record } from "effect";
|
|
19
|
+
import * as ActionRunner from "./ActionRunner";
|
|
20
|
+
import * as Auth from "./Auth";
|
|
21
|
+
import * as MutationRunner from "./MutationRunner";
|
|
22
|
+
import * as QueryRunner from "./QueryRunner";
|
|
23
|
+
import * as Scheduler from "./Scheduler";
|
|
24
|
+
import { StorageActionWriter, StorageReader, StorageWriter } from "./Storage";
|
|
25
|
+
import * as ActionCtx from "./ActionCtx";
|
|
26
|
+
|
|
27
|
+
type Middleware = (
|
|
28
|
+
httpApp: HttpApp.Default,
|
|
29
|
+
) => HttpApp.Default<
|
|
30
|
+
never,
|
|
31
|
+
HttpApi.Api | HttpApiBuilder.Router | HttpRouter.HttpRouter.DefaultServices
|
|
32
|
+
>;
|
|
33
|
+
|
|
34
|
+
const makeHandler =
|
|
35
|
+
<DataModel extends GenericDataModel>({
|
|
36
|
+
pathPrefix,
|
|
37
|
+
apiLive,
|
|
38
|
+
middleware,
|
|
39
|
+
scalar,
|
|
40
|
+
}: {
|
|
41
|
+
pathPrefix: RoutePath;
|
|
42
|
+
apiLive: Layer.Layer<
|
|
43
|
+
HttpApi.Api,
|
|
44
|
+
never,
|
|
45
|
+
| QueryRunner.QueryRunner
|
|
46
|
+
| MutationRunner.MutationRunner
|
|
47
|
+
| ActionRunner.ActionRunner
|
|
48
|
+
| Scheduler.Scheduler
|
|
49
|
+
| Auth.Auth
|
|
50
|
+
| StorageReader
|
|
51
|
+
| StorageWriter
|
|
52
|
+
| StorageActionWriter
|
|
53
|
+
| GenericActionCtx<DataModel>
|
|
54
|
+
>;
|
|
55
|
+
middleware?: Middleware;
|
|
56
|
+
scalar?: HttpApiScalar.ScalarConfig;
|
|
57
|
+
}) =>
|
|
58
|
+
(ctx: GenericActionCtx<DataModel>, request: Request): Promise<Response> => {
|
|
59
|
+
const ApiLive = apiLive.pipe(
|
|
60
|
+
Layer.provide(
|
|
61
|
+
Layer.mergeAll(
|
|
62
|
+
QueryRunner.layer(ctx.runQuery),
|
|
63
|
+
MutationRunner.layer(ctx.runMutation),
|
|
64
|
+
ActionRunner.layer(ctx.runAction),
|
|
65
|
+
Scheduler.layer(ctx.scheduler),
|
|
66
|
+
Auth.layer(ctx.auth),
|
|
67
|
+
StorageReader.layer(ctx.storage),
|
|
68
|
+
StorageWriter.layer(ctx.storage),
|
|
69
|
+
StorageActionWriter.layer(ctx.storage),
|
|
70
|
+
Layer.succeed(ActionCtx.ActionCtx<DataModel>(), ctx),
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const ApiDocsLive = HttpApiScalar.layer({
|
|
76
|
+
path: `${pathPrefix}docs`,
|
|
77
|
+
scalar: {
|
|
78
|
+
baseServerURL: `${process.env["CONVEX_SITE_URL"]}${pathPrefix}`,
|
|
79
|
+
...scalar,
|
|
80
|
+
},
|
|
81
|
+
}).pipe(Layer.provide(ApiLive));
|
|
82
|
+
|
|
83
|
+
const EnvLive = Layer.mergeAll(
|
|
84
|
+
ApiLive,
|
|
85
|
+
ApiDocsLive,
|
|
86
|
+
HttpServer.layerContext,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const { handler } = HttpApiBuilder.toWebHandler(
|
|
90
|
+
EnvLive,
|
|
91
|
+
middleware ? { middleware } : {},
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
return handler(request);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const makeHttpAction = <DataModel extends GenericDataModel>({
|
|
98
|
+
pathPrefix,
|
|
99
|
+
apiLive,
|
|
100
|
+
middleware,
|
|
101
|
+
scalar,
|
|
102
|
+
}: {
|
|
103
|
+
pathPrefix: RoutePath;
|
|
104
|
+
apiLive: Layer.Layer<
|
|
105
|
+
HttpApi.Api,
|
|
106
|
+
never,
|
|
107
|
+
| QueryRunner.QueryRunner
|
|
108
|
+
| MutationRunner.MutationRunner
|
|
109
|
+
| ActionRunner.ActionRunner
|
|
110
|
+
| Scheduler.Scheduler
|
|
111
|
+
| Auth.Auth
|
|
112
|
+
| StorageReader
|
|
113
|
+
| StorageWriter
|
|
114
|
+
| StorageActionWriter
|
|
115
|
+
| GenericActionCtx<DataModel>
|
|
116
|
+
>;
|
|
117
|
+
middleware?: Middleware;
|
|
118
|
+
scalar?: HttpApiScalar.ScalarConfig;
|
|
119
|
+
}) =>
|
|
120
|
+
httpActionGeneric(
|
|
121
|
+
makeHandler<DataModel>({
|
|
122
|
+
pathPrefix,
|
|
123
|
+
apiLive,
|
|
124
|
+
...(middleware ? { middleware } : {}),
|
|
125
|
+
...(scalar ? { scalar } : {}),
|
|
126
|
+
}) as unknown as (
|
|
127
|
+
ctx: GenericActionCtx<GenericDataModel>,
|
|
128
|
+
request: Request,
|
|
129
|
+
) => Promise<Response>,
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
export type HttpApi_ = {
|
|
133
|
+
apiLive: Layer.Layer<
|
|
134
|
+
HttpApi.Api,
|
|
135
|
+
never,
|
|
136
|
+
| QueryRunner.QueryRunner
|
|
137
|
+
| MutationRunner.MutationRunner
|
|
138
|
+
| ActionRunner.ActionRunner
|
|
139
|
+
| Scheduler.Scheduler
|
|
140
|
+
| Auth.Auth
|
|
141
|
+
| StorageReader
|
|
142
|
+
| StorageWriter
|
|
143
|
+
| StorageActionWriter
|
|
144
|
+
>;
|
|
145
|
+
middleware?: Middleware;
|
|
146
|
+
scalar?: HttpApiScalar.ScalarConfig;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export type RoutePath = "/" | `/${string}/`;
|
|
150
|
+
|
|
151
|
+
const mountEffectHttpApi =
|
|
152
|
+
<DataModel extends GenericDataModel>({
|
|
153
|
+
pathPrefix,
|
|
154
|
+
apiLive,
|
|
155
|
+
middleware,
|
|
156
|
+
scalar,
|
|
157
|
+
}: {
|
|
158
|
+
pathPrefix: RoutePath;
|
|
159
|
+
apiLive: Layer.Layer<
|
|
160
|
+
HttpApi.Api,
|
|
161
|
+
never,
|
|
162
|
+
| QueryRunner.QueryRunner
|
|
163
|
+
| MutationRunner.MutationRunner
|
|
164
|
+
| ActionRunner.ActionRunner
|
|
165
|
+
| Scheduler.Scheduler
|
|
166
|
+
| Auth.Auth
|
|
167
|
+
| StorageReader
|
|
168
|
+
| StorageWriter
|
|
169
|
+
| StorageActionWriter
|
|
170
|
+
| GenericActionCtx<DataModel>
|
|
171
|
+
>;
|
|
172
|
+
middleware?: Middleware;
|
|
173
|
+
scalar?: HttpApiScalar.ScalarConfig;
|
|
174
|
+
}) =>
|
|
175
|
+
(convexHttpRouter: ConvexHttpRouter): ConvexHttpRouter => {
|
|
176
|
+
const handler = makeHttpAction<DataModel>({
|
|
177
|
+
pathPrefix,
|
|
178
|
+
apiLive,
|
|
179
|
+
...(middleware ? { middleware } : {}),
|
|
180
|
+
...(scalar ? { scalar } : {}),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
Array.forEach(ROUTABLE_HTTP_METHODS, (method) => {
|
|
184
|
+
const routeSpec: RouteSpecWithPathPrefix = {
|
|
185
|
+
pathPrefix,
|
|
186
|
+
method,
|
|
187
|
+
handler,
|
|
188
|
+
};
|
|
189
|
+
convexHttpRouter.route(routeSpec);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return convexHttpRouter;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
type HttpApis = Partial<Record<RoutePath, HttpApi_>>;
|
|
196
|
+
|
|
197
|
+
export const make = (httpApis: HttpApis): ConvexHttpRouter => {
|
|
198
|
+
applyMonkeyPatches();
|
|
199
|
+
|
|
200
|
+
return pipe(
|
|
201
|
+
httpApis as Record<RoutePath, HttpApi_>,
|
|
202
|
+
Record.toEntries,
|
|
203
|
+
Array.reduce(
|
|
204
|
+
httpRouter(),
|
|
205
|
+
(convexHttpRouter, [pathPrefix, { apiLive, middleware, scalar }]) =>
|
|
206
|
+
mountEffectHttpApi({
|
|
207
|
+
pathPrefix: pathPrefix as RoutePath,
|
|
208
|
+
apiLive,
|
|
209
|
+
...(middleware ? { middleware } : {}),
|
|
210
|
+
...(scalar ? { scalar } : {}),
|
|
211
|
+
})(convexHttpRouter),
|
|
212
|
+
),
|
|
213
|
+
);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const applyMonkeyPatches = () => {
|
|
217
|
+
// These are necessary until the Convex runtime supports these APIs. See https://discord.com/channels/1019350475847499849/1281364098419785760
|
|
218
|
+
|
|
219
|
+
// eslint-disable-next-line no-global-assign
|
|
220
|
+
URL = class extends URL {
|
|
221
|
+
override get username() {
|
|
222
|
+
return "";
|
|
223
|
+
}
|
|
224
|
+
override get password() {
|
|
225
|
+
return "";
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
Object.defineProperty(Request.prototype, "signal", {
|
|
230
|
+
get: () => new AbortSignal(),
|
|
231
|
+
});
|
|
232
|
+
};
|
package/src/Impl.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Predicate } from "effect";
|
|
2
|
+
import type * as Api from "./Api";
|
|
3
|
+
import type { Groups as ApiGroups } from "./Api";
|
|
4
|
+
import type * as GroupImpl from "./GroupImpl";
|
|
5
|
+
|
|
6
|
+
export const TypeId = "@confect/server/Impl";
|
|
7
|
+
export type TypeId = typeof TypeId;
|
|
8
|
+
|
|
9
|
+
export const isImpl = (u: unknown): u is AnyWithProps =>
|
|
10
|
+
Predicate.hasProperty(u, TypeId);
|
|
11
|
+
|
|
12
|
+
export interface Impl<
|
|
13
|
+
Api_ extends Api.AnyWithProps,
|
|
14
|
+
FinalizationStatus_ extends FinalizationStatus,
|
|
15
|
+
> {
|
|
16
|
+
readonly [TypeId]: TypeId;
|
|
17
|
+
readonly api: Api_;
|
|
18
|
+
readonly finalizationStatus: FinalizationStatus_;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type FinalizationStatus = "Unfinalized" | "Finalized";
|
|
22
|
+
|
|
23
|
+
export interface AnyWithProps
|
|
24
|
+
extends Impl<Api.AnyWithProps, FinalizationStatus> {}
|
|
25
|
+
|
|
26
|
+
export const Impl = <
|
|
27
|
+
Api_ extends Api.AnyWithProps,
|
|
28
|
+
FinalizationStatus_ extends FinalizationStatus,
|
|
29
|
+
>() =>
|
|
30
|
+
Context.GenericTag<Impl<Api_, FinalizationStatus_>>(`@confect/server/Impl`);
|
|
31
|
+
|
|
32
|
+
export const make = <Api_ extends Api.AnyWithProps>(
|
|
33
|
+
api: Api_,
|
|
34
|
+
): Layer.Layer<
|
|
35
|
+
Impl<Api_, "Unfinalized">,
|
|
36
|
+
never,
|
|
37
|
+
GroupImpl.FromGroups<ApiGroups<Api_>>
|
|
38
|
+
> =>
|
|
39
|
+
Layer.effect(
|
|
40
|
+
Impl<Api_, "Unfinalized">(),
|
|
41
|
+
Effect.succeed({
|
|
42
|
+
[TypeId]: TypeId,
|
|
43
|
+
api,
|
|
44
|
+
finalizationStatus: "Unfinalized" as const,
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
export const finalize = <Api_ extends Api.AnyWithProps>(
|
|
49
|
+
impl: Layer.Layer<Impl<Api_, "Unfinalized">>,
|
|
50
|
+
): Layer.Layer<Impl<Api_, "Finalized">> =>
|
|
51
|
+
Layer.map(impl, (context) =>
|
|
52
|
+
Context.make(Impl<Api_, "Finalized">(), {
|
|
53
|
+
[TypeId]: TypeId,
|
|
54
|
+
api: Context.get(context, Impl<Api_, "Unfinalized">()).api,
|
|
55
|
+
finalizationStatus: "Finalized",
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GenericDataModel, GenericMutationCtx } from "convex/server";
|
|
2
|
+
import { Context } from "effect";
|
|
3
|
+
|
|
4
|
+
export const MutationCtx = <DataModel extends GenericDataModel>() =>
|
|
5
|
+
Context.GenericTag<GenericMutationCtx<DataModel>>(
|
|
6
|
+
"@confect/server/MutationCtx",
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
export type MutationCtx<DataModel extends GenericDataModel> = ReturnType<
|
|
10
|
+
typeof MutationCtx<DataModel>
|
|
11
|
+
>["Identifier"];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as Ref from "@confect/core/Ref";
|
|
2
|
+
import { type GenericMutationCtx } from "convex/server";
|
|
3
|
+
import { Context, Effect, Layer, Schema } from "effect";
|
|
4
|
+
|
|
5
|
+
const makeMutationRunner =
|
|
6
|
+
(runMutation: GenericMutationCtx<any>["runMutation"]) =>
|
|
7
|
+
<Mutation extends Ref.AnyMutation>(
|
|
8
|
+
mutation: Mutation,
|
|
9
|
+
args: Ref.Args<Mutation>["Type"],
|
|
10
|
+
) =>
|
|
11
|
+
Effect.gen(function* () {
|
|
12
|
+
const function_ = Ref.getFunction(mutation);
|
|
13
|
+
const functionName = Ref.getConvexFunctionName(mutation);
|
|
14
|
+
|
|
15
|
+
const encodedArgs = yield* Schema.encode(function_.args)(args);
|
|
16
|
+
const encodedReturns = yield* Effect.promise(() =>
|
|
17
|
+
runMutation(functionName as any, encodedArgs),
|
|
18
|
+
);
|
|
19
|
+
return yield* Schema.decode(function_.returns)(encodedReturns);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const MutationRunner = Context.GenericTag<
|
|
23
|
+
ReturnType<typeof makeMutationRunner>
|
|
24
|
+
>("@confect/server/MutationRunner");
|
|
25
|
+
export type MutationRunner = typeof MutationRunner.Identifier;
|
|
26
|
+
|
|
27
|
+
export const layer = (runMutation: GenericMutationCtx<any>["runMutation"]) =>
|
|
28
|
+
Layer.succeed(MutationRunner, makeMutationRunner(runMutation));
|
|
29
|
+
|
|
30
|
+
export class MutationRollback extends Schema.TaggedError<MutationRollback>(
|
|
31
|
+
"MutationRollback",
|
|
32
|
+
)("MutationRollback", {
|
|
33
|
+
mutationName: Schema.String,
|
|
34
|
+
error: Schema.Unknown,
|
|
35
|
+
}) {
|
|
36
|
+
/* v8 ignore start */
|
|
37
|
+
override get message(): string {
|
|
38
|
+
return `Mutation ${this.mutationName} failed and was rolled back.\n\n${this.error}`;
|
|
39
|
+
}
|
|
40
|
+
/* v8 ignore stop */
|
|
41
|
+
}
|