@gaganref/confect-core 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 +18 -0
- package/dist/ActionCall.d.ts.map +1 -0
- package/dist/ActionCall.js +21 -0
- package/dist/ActionCall.js.map +1 -0
- package/dist/App.d.ts +38 -93
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +30 -38
- package/dist/App.js.map +1 -1
- package/dist/Auth.d.ts +33 -9
- package/dist/Auth.d.ts.map +1 -1
- package/dist/Auth.js +17 -2
- package/dist/Auth.js.map +1 -1
- package/dist/Callback.d.ts +7 -2
- package/dist/Callback.d.ts.map +1 -1
- package/dist/Callback.js +11 -6
- package/dist/Callback.js.map +1 -1
- package/dist/CommitTs.d.ts +18 -0
- package/dist/CommitTs.d.ts.map +1 -0
- package/dist/CommitTs.js +20 -0
- package/dist/CommitTs.js.map +1 -0
- package/dist/Component.d.ts +106 -2
- package/dist/Component.d.ts.map +1 -1
- package/dist/Component.js +44 -18
- package/dist/Component.js.map +1 -1
- package/dist/FunctionSpec.d.ts +361 -2
- package/dist/FunctionSpec.d.ts.map +1 -1
- package/dist/FunctionSpec.js +68 -3
- package/dist/FunctionSpec.js.map +1 -1
- package/dist/GenericId.js +2 -2
- package/dist/GroupSpec.js +1 -1
- package/dist/Http.d.ts +4 -8
- package/dist/Http.d.ts.map +1 -1
- package/dist/Http.js +15 -22
- package/dist/Http.js.map +1 -1
- package/dist/ManifestSection.d.ts +101 -0
- package/dist/ManifestSection.d.ts.map +1 -0
- package/dist/ManifestSection.js +7 -0
- package/dist/ManifestSection.js.map +1 -0
- package/dist/Mount.d.ts +200 -0
- package/dist/Mount.d.ts.map +1 -0
- package/dist/Mount.js +116 -0
- package/dist/Mount.js.map +1 -0
- package/dist/PaginationError.js +1 -1
- package/dist/Profile.d.ts +95 -0
- package/dist/Profile.d.ts.map +1 -0
- package/dist/Profile.js +15 -0
- package/dist/Profile.js.map +1 -0
- package/dist/Ref.d.ts +4 -3
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Ref.js +13 -19
- package/dist/Ref.js.map +1 -1
- package/dist/RefInternal.d.ts +3 -0
- package/dist/RefInternal.d.ts.map +1 -0
- package/dist/RefInternal.js +16 -0
- package/dist/RefInternal.js.map +1 -0
- package/dist/SchemaToValidator.d.ts +20 -6
- package/dist/SchemaToValidator.d.ts.map +1 -1
- package/dist/SchemaToValidator.js +45 -14
- package/dist/SchemaToValidator.js.map +1 -1
- package/dist/SystemFields.js +3 -3
- package/dist/Table.d.ts +48 -9
- package/dist/Table.d.ts.map +1 -1
- package/dist/Table.js +41 -13
- package/dist/Table.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -6
- package/dist/internal/annotations.d.ts +2 -0
- package/dist/internal/annotations.d.ts.map +1 -0
- package/dist/internal/annotations.js +6 -0
- package/dist/internal/annotations.js.map +1 -0
- package/dist/internal/scalarDocs.d.ts +5 -0
- package/dist/internal/scalarDocs.d.ts.map +1 -0
- package/dist/internal/scalarDocs.js +43 -0
- package/dist/internal/scalarDocs.js.map +1 -0
- package/package.json +3 -3
- package/src/ActionCall.ts +25 -0
- package/src/App.ts +45 -136
- package/src/Auth.ts +54 -11
- package/src/Callback.ts +17 -4
- package/src/CommitTs.ts +26 -0
- package/src/Component.ts +204 -11
- package/src/FunctionSpec.ts +562 -5
- package/src/Http.ts +15 -37
- package/src/ManifestSection.ts +108 -0
- package/src/Mount.ts +401 -0
- package/src/Profile.ts +141 -0
- package/src/Ref.ts +19 -26
- package/src/RefInternal.ts +26 -0
- package/src/SchemaToValidator.ts +97 -22
- package/src/Table.ts +157 -23
- package/src/index.ts +5 -0
- package/src/internal/annotations.ts +1 -0
- package/src/internal/scalarDocs.ts +72 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as HttpRouter from "effect/http/HttpRouter";
|
|
3
|
+
import * as HttpServerResponse from "effect/http/HttpServerResponse";
|
|
4
|
+
import * as OpenApi from "effect/http-api/OpenApi";
|
|
5
|
+
//#region src/internal/scalarDocs.ts
|
|
6
|
+
const escape = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
7
|
+
const escapeAttribute = (value) => escape(value).replaceAll("\"", """).replaceAll("'", "'");
|
|
8
|
+
const escapeJson = (value) => JSON.stringify(value).replaceAll("<", "\\u003c").replaceAll("\u2028", "\\u2028").replaceAll("\u2029", "\\u2029");
|
|
9
|
+
const scalarDocs = (api, path) => HttpRouter.use((router) => {
|
|
10
|
+
let response;
|
|
11
|
+
return router.add("GET", path, Effect.sync(() => {
|
|
12
|
+
if (response !== void 0) return response;
|
|
13
|
+
const spec = OpenApi.fromApi(api);
|
|
14
|
+
const description = (tag) => !spec.info.description ? "" : `<meta name="${tag}" content="${escapeAttribute(spec.info.description)}"/>`;
|
|
15
|
+
response = HttpServerResponse.html(`<!doctype html>
|
|
16
|
+
<html>
|
|
17
|
+
<head>
|
|
18
|
+
<meta charset="utf-8" />
|
|
19
|
+
<title>${escape(spec.info.title)}</title>
|
|
20
|
+
${description("description")}
|
|
21
|
+
${description("og:description")}
|
|
22
|
+
<meta
|
|
23
|
+
name="viewport"
|
|
24
|
+
content="width=device-width, initial-scale=1" />
|
|
25
|
+
</head>
|
|
26
|
+
<body>
|
|
27
|
+
<div id="api-reference-container"></div>
|
|
28
|
+
<script src="${escapeAttribute("https://cdn.jsdelivr.net/npm/@scalar/api-reference@latest/dist/browser/standalone.min.js")}" crossorigin><\/script>
|
|
29
|
+
<script>
|
|
30
|
+
window.Scalar.createApiReference(document.getElementById('api-reference-container'), {
|
|
31
|
+
...${escapeJson({ _integration: "html" })},
|
|
32
|
+
content: ${escapeJson(spec)}
|
|
33
|
+
})
|
|
34
|
+
<\/script>
|
|
35
|
+
</body>
|
|
36
|
+
</html>`);
|
|
37
|
+
return response;
|
|
38
|
+
}));
|
|
39
|
+
});
|
|
40
|
+
//#endregion
|
|
41
|
+
export { scalarDocs };
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=scalarDocs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scalarDocs.js","names":[],"sources":["../../src/internal/scalarDocs.ts"],"sourcesContent":["import * as Effect from \"effect/Effect\";\nimport * as HttpRouter from \"effect/http/HttpRouter\";\nimport * as HttpServerResponse from \"effect/http/HttpServerResponse\";\nimport type * as HttpApi from \"effect/http-api/HttpApi\";\nimport type * as HttpApiGroup from \"effect/http-api/HttpApiGroup\";\nimport * as OpenApi from \"effect/http-api/OpenApi\";\n\nconst escape = (value: string) =>\n value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\");\n\nconst escapeAttribute = (value: string) =>\n escape(value).replaceAll('\"', \""\").replaceAll(\"'\", \"'\");\n\nconst escapeJson = (value: unknown) =>\n JSON.stringify(value)\n .replaceAll(\"<\", \"\\\\u003c\")\n .replaceAll(\"\\u2028\", \"\\\\u2028\")\n .replaceAll(\"\\u2029\", \"\\\\u2029\");\n\n// WORKAROUND: Effect 4.0.6's HttpApiScalar module imports its inline Scalar\n// script dynamically, and Convex's bundler then splits a schema that reaches it\n// into an imported chunk, which Convex refuses. This copies `layerCdn`'s page\n// byte for byte. Remove when `checkSchemaBundle.mjs` passes with\n// `HttpApiScalar.layerCdn` restored.\nexport const scalarDocs = <\n Id extends string,\n Groups extends HttpApiGroup.Constraint,\n>(\n api: HttpApi.HttpApi<Id, Groups>,\n path: `/${string}`,\n) =>\n HttpRouter.use((router) => {\n let response: HttpServerResponse.HttpServerResponse | undefined;\n return router.add(\n \"GET\",\n path,\n Effect.sync(() => {\n if (response !== undefined) return response;\n const spec = OpenApi.fromApi(api);\n const description = (tag: string) =>\n !spec.info.description\n ? \"\"\n : `<meta name=\"${tag}\" content=\"${escapeAttribute(spec.info.description)}\"/>`;\n response = HttpServerResponse.html(`<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <title>${escape(spec.info.title)}</title>\n ${description(\"description\")}\n ${description(\"og:description\")}\n <meta\n name=\"viewport\"\n content=\"width=device-width, initial-scale=1\" />\n </head>\n <body>\n <div id=\"api-reference-container\"></div>\n <script src=\"${escapeAttribute(\"https://cdn.jsdelivr.net/npm/@scalar/api-reference@latest/dist/browser/standalone.min.js\")}\" crossorigin></script>\n <script>\n window.Scalar.createApiReference(document.getElementById('api-reference-container'), {\n ...${escapeJson({ _integration: \"html\" })},\n content: ${escapeJson(spec)}\n })\n </script>\n </body>\n</html>`);\n return response;\n }),\n );\n });\n"],"mappings":";;;;;AAOA,MAAM,UAAU,UACd,MACG,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,KAAK,MAAM;AAE3B,MAAM,mBAAmB,UACvB,OAAO,KAAK,CAAC,CAAC,WAAW,MAAK,QAAQ,CAAC,CAAC,WAAW,KAAK,OAAO;AAEjE,MAAM,cAAc,UAClB,KAAK,UAAU,KAAK,CAAC,CAClB,WAAW,KAAK,SAAS,CAAC,CAC1B,WAAW,UAAU,SAAS,CAAC,CAC/B,WAAW,UAAU,SAAS;AAOnC,MAAa,cAIX,KACA,SAEA,WAAW,KAAK,WAAW;CACzB,IAAI;CACJ,OAAO,OAAO,IACZ,OACA,MACA,OAAO,WAAW;EAChB,IAAI,aAAa,KAAA,GAAW,OAAO;EACnC,MAAM,OAAO,QAAQ,QAAQ,GAAG;EAChC,MAAM,eAAe,QACnB,CAAC,KAAK,KAAK,cACP,KACA,eAAe,IAAI,aAAa,gBAAgB,KAAK,KAAK,WAAW,EAAE;EAC7E,WAAW,mBAAmB,KAAK;;;;aAI9B,OAAO,KAAK,KAAK,KAAK,EAAE;MAC/B,YAAY,aAAa,EAAE;MAC3B,YAAY,gBAAgB,EAAE;;;;;;;mBAOjB,gBAAgB,0FAA0F,EAAE;;;aAGlH,WAAW,EAAE,cAAc,OAAO,CAAC,EAAE;mBAC/B,WAAW,IAAI,EAAE;;;;QAI5B;EACA,OAAO;CACT,CAAC,CACH;AACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaganref/confect-core",
|
|
3
|
-
"version": "10.3.1-fork.
|
|
3
|
+
"version": "10.3.1-fork.90",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"convex": "^1.
|
|
6
|
-
"effect": "
|
|
5
|
+
"convex": "^1.49.0",
|
|
6
|
+
"effect": ">=4.0.0 <4.1.0"
|
|
7
7
|
},
|
|
8
8
|
"description": "Shared specs and schemas used by all Confect packages",
|
|
9
9
|
"author": "RJ Dellecese",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as Context from "effect/Context";
|
|
2
|
+
import type * as Effect from "effect/Effect";
|
|
3
|
+
import type * as Schema from "effect/Schema";
|
|
4
|
+
import * as FunctionSpec from "./FunctionSpec.js";
|
|
5
|
+
import * as MiddlewareSpec from "./MiddlewareSpec.js";
|
|
6
|
+
import type * as Ref from "./Ref.js";
|
|
7
|
+
|
|
8
|
+
export interface Call {
|
|
9
|
+
<Target extends Ref.AnyQuery | Ref.AnyMutation>(
|
|
10
|
+
target: Target,
|
|
11
|
+
...args: Ref.OptionalArgs<NoInfer<Target>>
|
|
12
|
+
): Effect.Effect<Ref.Returns<Target>, Ref.Error<Target> | Schema.SchemaError>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class ActionCall extends Context.Service<ActionCall, Call>()(
|
|
16
|
+
"@confect/core/ActionCall",
|
|
17
|
+
) {}
|
|
18
|
+
export class Middleware extends MiddlewareSpec.MiddlewareSpec<
|
|
19
|
+
Middleware,
|
|
20
|
+
{ provides: ActionCall }
|
|
21
|
+
>()("@confect/core/ActionCall/Middleware", {
|
|
22
|
+
functionTypes: { query: false, mutation: false, action: true },
|
|
23
|
+
}) {}
|
|
24
|
+
|
|
25
|
+
export const profile = FunctionSpec.extend()({ middleware: [Middleware] });
|
package/src/App.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import type { ComponentDefinition
|
|
2
|
-
import type { Infer, Validator } from "convex/values";
|
|
1
|
+
import type { ComponentDefinition } from "convex/server";
|
|
3
2
|
import type * as HttpApi from "effect/http-api/HttpApi";
|
|
4
3
|
import * as Predicate from "effect/Predicate";
|
|
5
4
|
import type * as Env from "./Env.js";
|
|
5
|
+
import type * as ManifestSection from "./ManifestSection.js";
|
|
6
|
+
import type * as MiddlewareSpec from "./MiddlewareSpec.js";
|
|
7
|
+
import * as Mount from "./Mount.js";
|
|
6
8
|
|
|
7
9
|
const TypeId = "~@confect/core/App";
|
|
8
|
-
const MountTypeId = "~@confect/core/App/Mount";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* The default export of a Convex component's `convex.config` module.
|
|
@@ -19,112 +20,11 @@ export type HttpPrefix = `/${string}`;
|
|
|
19
20
|
*/
|
|
20
21
|
export type Api = HttpApi.HttpApi<string, any>;
|
|
21
22
|
|
|
22
|
-
type EnvOf<D extends Definition> = D["__env"];
|
|
23
|
-
|
|
24
|
-
type IsOptional<V> = V extends Validator<any, "optional", any> ? true : false;
|
|
25
|
-
|
|
26
|
-
type RequiredKeys<E extends EnvDefinition> = {
|
|
27
|
-
[K in keyof E]: IsOptional<E[K]> extends true ? never : K;
|
|
28
|
-
}[keyof E];
|
|
29
|
-
|
|
30
|
-
type SlotValue<V extends Validator<any, any, any>> = Extract<Infer<V>, string>;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* What one component env slot accepts: a constant, or an entry whose Convex
|
|
34
|
-
* value fits. A required slot takes only a required entry.
|
|
35
|
-
*/
|
|
36
|
-
type Slot<V extends Validator<any, any, any>> =
|
|
37
|
-
IsOptional<V> extends true
|
|
38
|
-
? SlotValue<V> | undefined | Env.Entry<string, any, SlotValue<V>, boolean>
|
|
39
|
-
: SlotValue<V> | Env.Entry<string, any, SlotValue<V>, false>;
|
|
40
|
-
|
|
41
|
-
export type Bindings<E extends EnvDefinition> = {
|
|
42
|
-
readonly [K in RequiredKeys<E>]: Slot<E[K]>;
|
|
43
|
-
} & {
|
|
44
|
-
readonly [K in Exclude<keyof E, RequiredKeys<E>>]?: Slot<E[K]>;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
type HttpOptions =
|
|
48
|
-
| { readonly httpPrefix?: never; readonly api?: never }
|
|
49
|
-
| { readonly httpPrefix: HttpPrefix; readonly api?: Api };
|
|
50
|
-
|
|
51
|
-
export type Options<D extends Definition> = HttpOptions &
|
|
52
|
-
([RequiredKeys<EnvOf<D>>] extends [never]
|
|
53
|
-
? { readonly env?: Bindings<EnvOf<D>> }
|
|
54
|
-
: { readonly env: Bindings<EnvOf<D>> });
|
|
55
|
-
|
|
56
|
-
type Exact<D extends Definition, O> = {
|
|
57
|
-
readonly [K in Exclude<keyof O, "env" | "httpPrefix" | "api">]: never;
|
|
58
|
-
} & (O extends { readonly env: infer B }
|
|
59
|
-
? {
|
|
60
|
-
readonly env: { readonly [K in Exclude<keyof B, keyof EnvOf<D>>]: never };
|
|
61
|
-
}
|
|
62
|
-
: unknown);
|
|
63
|
-
|
|
64
|
-
export interface MountData {
|
|
65
|
-
readonly definition: Definition;
|
|
66
|
-
readonly httpPrefix: HttpPrefix | undefined;
|
|
67
|
-
readonly api: Api | undefined;
|
|
68
|
-
readonly env: Readonly<Record<string, string | Env.AnyEntry | undefined>>;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* A mounted Convex component. `O` keeps the options as written, so {@link make}
|
|
73
|
-
* can see which backends the bound entries come from.
|
|
74
|
-
*/
|
|
75
|
-
export interface Mount<out D extends Definition, out O> extends MountData {
|
|
76
|
-
readonly [MountTypeId]: { readonly definition: D; readonly options: O };
|
|
77
|
-
readonly httpPrefix: O extends {
|
|
78
|
-
readonly httpPrefix: infer P extends HttpPrefix;
|
|
79
|
-
}
|
|
80
|
-
? P
|
|
81
|
-
: undefined;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export type AnyMount = Mount<Definition, unknown>;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Mount a Convex component: the default export of its `convex.config` module,
|
|
88
|
-
* official or Confect-authored. `env` is typed against the component's own
|
|
89
|
-
* `defineComponent({ env })` declaration, so a missing required binding, an
|
|
90
|
-
* optional entry in a required slot, a wrong literal and an unknown slot fail
|
|
91
|
-
* to typecheck. `api` is the component's `HttpApi`, for route checks.
|
|
92
|
-
*/
|
|
93
|
-
export function mount<const D extends Definition>(
|
|
94
|
-
definition: D &
|
|
95
|
-
([RequiredKeys<EnvOf<D>>] extends [never]
|
|
96
|
-
? unknown
|
|
97
|
-
: "App.mount: this component declares required env; pass { env }"),
|
|
98
|
-
): Mount<D, {}>;
|
|
99
|
-
export function mount<const D extends Definition, const O extends Options<D>>(
|
|
100
|
-
definition: D,
|
|
101
|
-
options: O & Exact<NoInfer<D>, NoInfer<O>>,
|
|
102
|
-
): Mount<D, O>;
|
|
103
|
-
export function mount(
|
|
104
|
-
definition: Definition,
|
|
105
|
-
options?: {
|
|
106
|
-
readonly httpPrefix?: HttpPrefix;
|
|
107
|
-
readonly api?: Api;
|
|
108
|
-
readonly env?: MountData["env"];
|
|
109
|
-
},
|
|
110
|
-
): AnyMount {
|
|
111
|
-
return {
|
|
112
|
-
[MountTypeId]: { definition, options },
|
|
113
|
-
definition,
|
|
114
|
-
httpPrefix: options?.httpPrefix,
|
|
115
|
-
api: options?.api,
|
|
116
|
-
env: options?.env ?? {},
|
|
117
|
-
// The overloads above carry the precise types; this body serves both.
|
|
118
|
-
} as AnyMount;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
23
|
type OwnerOf<V> = V extends Env.Entry<infer N, any, any, any> ? N : never;
|
|
122
24
|
|
|
123
25
|
type Owners<M> =
|
|
124
|
-
M extends Mount<
|
|
125
|
-
?
|
|
126
|
-
? { [K in keyof B]: OwnerOf<B[K]> }[keyof B]
|
|
127
|
-
: never
|
|
26
|
+
M extends Mount.Mount<any, any, Mount.Declared<any, infer B>>
|
|
27
|
+
? { [K in keyof B]: OwnerOf<B[K]> }[keyof B]
|
|
128
28
|
: never;
|
|
129
29
|
|
|
130
30
|
type OwnedBy<N extends string, M> = {
|
|
@@ -137,51 +37,65 @@ export type Kind = "app" | "component";
|
|
|
137
37
|
|
|
138
38
|
export interface App<
|
|
139
39
|
E extends Env.Any,
|
|
140
|
-
M extends
|
|
40
|
+
M extends ReadonlyArray<Mount.Any>,
|
|
141
41
|
K extends Kind = Kind,
|
|
142
42
|
> {
|
|
143
43
|
readonly [TypeId]: typeof TypeId;
|
|
144
44
|
readonly kind: K;
|
|
145
45
|
readonly env: E;
|
|
46
|
+
readonly components: ReadonlyArray<Definition>;
|
|
146
47
|
readonly mounts: M;
|
|
48
|
+
readonly requiresMiddleware: ReadonlyArray<MiddlewareSpec.AnyMiddlewareSpec>;
|
|
49
|
+
readonly manifestSections: ReadonlyArray<ManifestSection.Entry>;
|
|
147
50
|
}
|
|
148
51
|
|
|
149
|
-
export type Any = App<Env.Any,
|
|
52
|
+
export type Any = App<Env.Any, ReadonlyArray<Mount.Any>>;
|
|
150
53
|
|
|
151
54
|
/**
|
|
152
|
-
* Declare a backend, in `confect/app.ts`: its env
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
* Codegen
|
|
156
|
-
*
|
|
55
|
+
* Declare a backend, in `confect/app.ts`: its env, the `convex.config`
|
|
56
|
+
* definitions of the Convex components it mounts, its mounts and its manifest
|
|
57
|
+
* sections. Set `kind: "component"` when declaring a component; the default is
|
|
58
|
+
* `"app"`. Codegen rejects a kind that differs from its target, and writes
|
|
59
|
+
* `convex/convex.config.ts` with one `app.use` per mount, in list order, using
|
|
60
|
+
* the definition whose `defineComponent` name is the mount's component name. A
|
|
61
|
+
* mount that binds another backend's env entry fails to typecheck.
|
|
62
|
+
*
|
|
63
|
+
* `manifestSections` is the only place codegen learns a backend's sections.
|
|
64
|
+
* Each section describes every registered function of an app, whatever builder
|
|
65
|
+
* made it, and writes its `_generated` file for an app or a component, even one
|
|
66
|
+
* with no functions.
|
|
157
67
|
*
|
|
158
68
|
* ```ts
|
|
69
|
+
* import email from "@acme/email/convex.config";
|
|
70
|
+
* import workpool from "@convex-dev/workpool/convex.config";
|
|
71
|
+
*
|
|
159
72
|
* export default App.make({
|
|
160
73
|
* env,
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* httpPrefix: "/email",
|
|
164
|
-
* env: { FROM: env.EMAIL_FROM, KEY: env.RESEND_API_KEY },
|
|
165
|
-
* }),
|
|
166
|
-
* importsPool: App.mount(workpool),
|
|
167
|
-
* },
|
|
74
|
+
* components: [email, workpool],
|
|
75
|
+
* mounts: [BulkEmail, TransactionalEmail, ImportsPool],
|
|
168
76
|
* });
|
|
169
77
|
* ```
|
|
170
78
|
*/
|
|
171
79
|
export const make = <
|
|
172
80
|
const E extends Env.Any,
|
|
173
|
-
const M extends
|
|
81
|
+
const M extends ReadonlyArray<Mount.Any> = [],
|
|
174
82
|
const K extends Kind = "app",
|
|
175
83
|
>(
|
|
176
84
|
options: {
|
|
177
85
|
readonly env: E;
|
|
86
|
+
readonly requiresMiddleware?: ReadonlyArray<MiddlewareSpec.AnyMiddlewareSpec>;
|
|
87
|
+
readonly manifestSections?: ReadonlyArray<ManifestSection.Entry>;
|
|
88
|
+
readonly components?: ReadonlyArray<Definition>;
|
|
178
89
|
readonly mounts?: M & OwnedBy<NoInfer<Env.Name<E>>, NoInfer<M>>;
|
|
179
90
|
} & ([K] extends ["app"] ? { readonly kind?: K } : { readonly kind: K }),
|
|
180
91
|
): App<E, M, K> => ({
|
|
181
92
|
[TypeId]: TypeId,
|
|
182
93
|
kind: options.kind ?? ("app" as K),
|
|
183
94
|
env: options.env,
|
|
184
|
-
|
|
95
|
+
components: options.components ?? [],
|
|
96
|
+
mounts: options.mounts ?? ([] as unknown as M),
|
|
97
|
+
requiresMiddleware: options.requiresMiddleware ?? [],
|
|
98
|
+
manifestSections: options.manifestSections ?? [],
|
|
185
99
|
});
|
|
186
100
|
|
|
187
101
|
export const isApp = (u: unknown): u is Any =>
|
|
@@ -190,21 +104,16 @@ export const isApp = (u: unknown): u is Any =>
|
|
|
190
104
|
Predicate.hasProperty(u, "kind") &&
|
|
191
105
|
(u.kind === "app" || u.kind === "component");
|
|
192
106
|
|
|
193
|
-
export const isMount = (u: unknown): u is AnyMount =>
|
|
194
|
-
Predicate.hasProperty(u, MountTypeId);
|
|
195
|
-
|
|
196
107
|
export const env = <A extends Any>(app: A): A["env"] => app.env;
|
|
197
108
|
|
|
198
109
|
/**
|
|
199
|
-
*
|
|
110
|
+
* The `convex.config` definitions the backend lists, in list order.
|
|
111
|
+
*/
|
|
112
|
+
export const components = (app: Any): ReadonlyArray<Definition> =>
|
|
113
|
+
app.components;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* What each mount was declared with, in list order.
|
|
200
117
|
*/
|
|
201
|
-
export const mounts = (
|
|
202
|
-
app
|
|
203
|
-
): ReadonlyArray<MountData & { readonly name: string }> =>
|
|
204
|
-
Object.entries(app.mounts).map(([name, installed]) => ({
|
|
205
|
-
name,
|
|
206
|
-
definition: installed.definition,
|
|
207
|
-
httpPrefix: installed.httpPrefix,
|
|
208
|
-
api: installed.api,
|
|
209
|
-
env: installed.env,
|
|
210
|
-
}));
|
|
118
|
+
export const mounts = (app: Any): ReadonlyArray<Mount.Data> =>
|
|
119
|
+
app.mounts.map(Mount.data);
|
package/src/Auth.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { AuthProvider } from "convex/server";
|
|
2
2
|
import * as Predicate from "effect/Predicate";
|
|
3
3
|
import type * as App from "./App.js";
|
|
4
|
+
import type * as Env from "./Env.js";
|
|
5
|
+
import * as Mount from "./Mount.js";
|
|
4
6
|
import type { TypeError } from "./Types.js";
|
|
5
7
|
|
|
6
8
|
const TypeId = "~@confect/core/Auth";
|
|
9
|
+
const CloudUrlTypeId = "~@confect/core/Auth/CloudUrl";
|
|
7
10
|
const SiteUrlTypeId = "~@confect/core/Auth/SiteUrl";
|
|
8
11
|
|
|
9
12
|
/**
|
|
@@ -15,19 +18,59 @@ export interface SiteUrl {
|
|
|
15
18
|
readonly path: string;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
/**
|
|
22
|
+
* The deployment's cloud URL (`CONVEX_CLOUD_URL`) plus a path.
|
|
23
|
+
*/
|
|
24
|
+
export interface CloudUrl {
|
|
25
|
+
readonly [CloudUrlTypeId]: typeof CloudUrlTypeId;
|
|
26
|
+
readonly path: string;
|
|
27
|
+
}
|
|
19
28
|
|
|
20
|
-
type
|
|
29
|
+
type Url =
|
|
30
|
+
| string
|
|
31
|
+
| SiteUrl
|
|
32
|
+
| CloudUrl
|
|
33
|
+
| Env.Entry<string, string, string, false>;
|
|
34
|
+
|
|
35
|
+
type WithUrls<P> = P extends unknown
|
|
21
36
|
? {
|
|
22
|
-
[K in keyof P]: K extends "domain" | "issuer" | "jwks"
|
|
37
|
+
[K in keyof P]: K extends "domain" | "issuer" | "jwks" | "applicationID"
|
|
38
|
+
? Url
|
|
39
|
+
: P[K];
|
|
23
40
|
}
|
|
24
41
|
: never;
|
|
25
42
|
|
|
26
43
|
/**
|
|
27
|
-
* Convex's
|
|
28
|
-
|
|
44
|
+
* Convex's provider list with deployment URLs and required, public env strings.
|
|
45
|
+
*/
|
|
46
|
+
export type Provider = WithUrls<AuthProvider> & {
|
|
47
|
+
/**
|
|
48
|
+
* Application-defined token family, copied to the runtime provider data.
|
|
49
|
+
*/
|
|
50
|
+
readonly family?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Application-defined issuer name, for example a trusted service.
|
|
53
|
+
*/
|
|
54
|
+
readonly name?: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The cloud URL, or a path under it, resolved when Convex loads auth config.
|
|
29
59
|
*/
|
|
30
|
-
export
|
|
60
|
+
export const cloudUrl = (path: `/${string}` | "" = ""): CloudUrl => ({
|
|
61
|
+
[CloudUrlTypeId]: CloudUrlTypeId,
|
|
62
|
+
path,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The path of a cloud URL placeholder, or `undefined` for another value.
|
|
67
|
+
*/
|
|
68
|
+
export const cloudUrlPath = (u: unknown): string | undefined =>
|
|
69
|
+
Predicate.hasProperty(u, CloudUrlTypeId) &&
|
|
70
|
+
Predicate.hasProperty(u, "path") &&
|
|
71
|
+
typeof u.path === "string"
|
|
72
|
+
? u.path
|
|
73
|
+
: undefined;
|
|
31
74
|
|
|
32
75
|
export interface Auth<A extends App.Any> {
|
|
33
76
|
readonly [TypeId]: typeof TypeId;
|
|
@@ -43,19 +86,19 @@ export type Any = Auth<App.Any>;
|
|
|
43
86
|
*/
|
|
44
87
|
export function siteUrl(path?: `/${string}`): SiteUrl;
|
|
45
88
|
export function siteUrl(
|
|
46
|
-
mount:
|
|
89
|
+
mount: Mount.Mount<any, string, Mount.Declared<App.HttpPrefix>>,
|
|
47
90
|
path?: `/${string}`,
|
|
48
91
|
): SiteUrl;
|
|
49
92
|
export function siteUrl(
|
|
50
|
-
pathOrMount?: `/${string}` |
|
|
93
|
+
pathOrMount?: `/${string}` | Mount.Any,
|
|
51
94
|
path: string = "",
|
|
52
95
|
): SiteUrl {
|
|
53
96
|
return {
|
|
54
97
|
[SiteUrlTypeId]: SiteUrlTypeId,
|
|
55
98
|
path:
|
|
56
|
-
typeof pathOrMount === "
|
|
57
|
-
? pathOrMount
|
|
58
|
-
: (pathOrMount ?? ""),
|
|
99
|
+
typeof pathOrMount === "string" || pathOrMount === undefined
|
|
100
|
+
? (pathOrMount ?? "")
|
|
101
|
+
: (Mount.data(pathOrMount).httpPrefix ?? "").replace(/\/+$/, "") + path,
|
|
59
102
|
};
|
|
60
103
|
}
|
|
61
104
|
|
package/src/Callback.ts
CHANGED
|
@@ -8,6 +8,8 @@ import * as Schema from "effect/Schema";
|
|
|
8
8
|
import * as SchemaGetter from "effect/SchemaGetter";
|
|
9
9
|
import * as FunctionProvenance from "./FunctionProvenance.js";
|
|
10
10
|
import * as Ref from "./Ref.js";
|
|
11
|
+
import { getFunctionReference } from "./RefInternal.js";
|
|
12
|
+
import { CallbackContract } from "./internal/annotations.js";
|
|
11
13
|
import type * as RuntimeAndFunctionType from "./RuntimeAndFunctionType.js";
|
|
12
14
|
|
|
13
15
|
export const TypeId = "~@confect/core/Callback";
|
|
@@ -137,6 +139,7 @@ const isHandleOf =
|
|
|
137
139
|
const fromText = <Contract_ extends Any>(
|
|
138
140
|
contract: Contract_,
|
|
139
141
|
text: string,
|
|
142
|
+
reservedArgument?: string,
|
|
140
143
|
): Handle<Contract_> =>
|
|
141
144
|
Object.assign(
|
|
142
145
|
Ref.fromProvenance(
|
|
@@ -145,25 +148,35 @@ const fromText = <Contract_ extends Any>(
|
|
|
145
148
|
[],
|
|
146
149
|
// Convex types a handle as a string that is also a function reference.
|
|
147
150
|
text as unknown as FunctionReference<any, any>,
|
|
151
|
+
contract.functionType,
|
|
152
|
+
contract.functionType === "query" ? undefined : reservedArgument,
|
|
148
153
|
),
|
|
149
154
|
{ [HandleTypeId]: contract.id },
|
|
150
155
|
) as unknown as Handle<Contract_>;
|
|
151
156
|
|
|
152
157
|
/**
|
|
153
158
|
* The schema of a handle for `contract`: a string on the wire, a runnable ref
|
|
154
|
-
* once decoded. Use it in a component's function args or tables.
|
|
159
|
+
* once decoded. Use it in a component's function args or tables. It lowers to
|
|
160
|
+
* Convex's `v.function` with the contract's encoded args and returns.
|
|
161
|
+
* `reservedArgument` opts mutation and action handles into context forwarding.
|
|
162
|
+
* The host target must reserve the same argument name.
|
|
155
163
|
*/
|
|
156
164
|
export const handle = <Contract_ extends Any>(
|
|
157
165
|
contract: Contract_,
|
|
166
|
+
options?: {
|
|
167
|
+
readonly reservedArgument?: Contract_["functionType"] extends "query"
|
|
168
|
+
? never
|
|
169
|
+
: string;
|
|
170
|
+
},
|
|
158
171
|
): Schema.Codec<Handle<Contract_>, string> =>
|
|
159
|
-
Schema.String.pipe(
|
|
172
|
+
Schema.String.annotate({ [CallbackContract]: contract }).pipe(
|
|
160
173
|
Schema.decodeTo(
|
|
161
174
|
Schema.declare(isHandleOf(contract), {
|
|
162
175
|
identifier: `Callback.Handle<${contract.id}>`,
|
|
163
176
|
}),
|
|
164
177
|
{
|
|
165
178
|
decode: SchemaGetter.transform((text: string) =>
|
|
166
|
-
fromText(contract, text),
|
|
179
|
+
fromText(contract, text, options?.reservedArgument),
|
|
167
180
|
),
|
|
168
181
|
encode: SchemaGetter.transform(
|
|
169
182
|
(ref: Handle<Contract_>) => ref.convexFunctionName,
|
|
@@ -301,4 +314,4 @@ export const toFuture = <Ref_ extends Ref.Any>(
|
|
|
301
314
|
Ref.GetFunctionVisibility<Ref_>,
|
|
302
315
|
EncodedArgs<Ref_>,
|
|
303
316
|
EncodedReturns<Ref_>
|
|
304
|
-
> =>
|
|
317
|
+
> => getFunctionReference(ref) as never;
|
package/src/CommitTs.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { CommitTsPlaceholder } from "convex/values";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import * as SchemaAST from "effect/SchemaAST";
|
|
4
|
+
|
|
5
|
+
const ConvexCommitTs = "~@confect/core/ConvexCommitTs";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A commit timestamp as Convex types it. A mutation writes the database
|
|
9
|
+
* writer's `vars.commitTs` placeholder, which resolves to an int64 when the
|
|
10
|
+
* mutation commits. Reading the field back inside that mutation still yields
|
|
11
|
+
* the placeholder, so a reader narrows with `typeof value === "bigint"` before
|
|
12
|
+
* using it as a number.
|
|
13
|
+
*/
|
|
14
|
+
export type CommitTs = bigint | CommitTsPlaceholder;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A field Convex stores as `v.commitTs()`. An index on it orders documents by
|
|
18
|
+
* commit order.
|
|
19
|
+
*/
|
|
20
|
+
export const CommitTs: Schema.Codec<CommitTs> = Schema.Union([
|
|
21
|
+
Schema.BigInt,
|
|
22
|
+
Schema.instanceOf(CommitTsPlaceholder),
|
|
23
|
+
]).annotate({ [ConvexCommitTs]: true });
|
|
24
|
+
|
|
25
|
+
export const isCommitTs = (ast: SchemaAST.AST): boolean =>
|
|
26
|
+
SchemaAST.resolveAt<boolean>(ConvexCommitTs)(ast) === true;
|