@gaganref/confect-core 10.3.1-fork.5 → 10.3.1-fork.50
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 +13 -2
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +6 -3
- package/dist/App.js.map +1 -1
- package/dist/Auth.d.ts +31 -6
- package/dist/Auth.d.ts.map +1 -1
- package/dist/Auth.js +15 -1
- package/dist/Auth.js.map +1 -1
- package/dist/Callback.d.ts.map +1 -1
- package/dist/Callback.js +2 -2
- package/dist/Callback.js.map +1 -1
- package/dist/Component.d.ts.map +1 -1
- package/dist/Component.js +1 -1
- package/dist/Component.js.map +1 -1
- package/dist/FunctionSpec.d.ts +365 -2
- package/dist/FunctionSpec.d.ts.map +1 -1
- package/dist/FunctionSpec.js +66 -3
- package/dist/FunctionSpec.js.map +1 -1
- package/dist/GroupSpec.js +1 -1
- package/dist/Http.d.ts.map +1 -1
- package/dist/Http.js +2 -2
- package/dist/Http.js.map +1 -1
- package/dist/ManifestSection.d.ts +24 -0
- package/dist/ManifestSection.d.ts.map +1 -0
- package/dist/ManifestSection.js +7 -0
- package/dist/ManifestSection.js.map +1 -0
- 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 -2
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Ref.js +8 -4
- package/dist/Ref.js.map +1 -1
- package/dist/SchemaToValidator.d.ts +10 -1
- package/dist/SchemaToValidator.d.ts.map +1 -1
- package/dist/SchemaToValidator.js +19 -4
- package/dist/SchemaToValidator.js.map +1 -1
- package/dist/SystemFields.js +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -6
- 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 +19 -3
- package/src/Auth.ts +48 -6
- package/src/Callback.ts +1 -0
- package/src/Component.ts +2 -0
- package/src/FunctionSpec.ts +570 -5
- package/src/Http.ts +2 -5
- package/src/ManifestSection.ts +29 -0
- package/src/Profile.ts +141 -0
- package/src/Ref.ts +17 -4
- package/src/SchemaToValidator.ts +22 -1
- package/src/index.ts +3 -0
- package/src/internal/scalarDocs.ts +72 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type * as FunctionSpec from "./FunctionSpec.js";
|
|
2
|
+
import type * as MiddlewareSpec from "./MiddlewareSpec.js";
|
|
3
|
+
|
|
4
|
+
export interface Data<Value = unknown> {
|
|
5
|
+
readonly format: number;
|
|
6
|
+
readonly functions: Readonly<Record<string, Value>>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ManifestSection<Value = unknown> {
|
|
10
|
+
readonly owner: string;
|
|
11
|
+
readonly format: number;
|
|
12
|
+
describe(input: {
|
|
13
|
+
readonly path: string;
|
|
14
|
+
readonly spec: FunctionSpec.AnyWithProps;
|
|
15
|
+
readonly middleware: ReadonlyArray<MiddlewareSpec.AnyMiddlewareSpec>;
|
|
16
|
+
}): Value;
|
|
17
|
+
check?(
|
|
18
|
+
next: Data<Value>,
|
|
19
|
+
previous: unknown,
|
|
20
|
+
): {
|
|
21
|
+
readonly errors: ReadonlyArray<string>;
|
|
22
|
+
readonly notes: ReadonlyArray<string>;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface Entry {
|
|
27
|
+
readonly key: string;
|
|
28
|
+
readonly section: ManifestSection;
|
|
29
|
+
}
|
package/src/Profile.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type * as Schema from "effect/Schema";
|
|
2
|
+
import type * as FunctionProvenance from "./FunctionProvenance.js";
|
|
3
|
+
import type * as MiddlewareSpec from "./MiddlewareSpec.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A type-level function from a function's name and args fields to the fields a
|
|
7
|
+
* profile's builders require. Read `this["Name"]` and `this["Args"]` directly
|
|
8
|
+
* in `Type`, passing them to a type alias; a nested object type cannot name
|
|
9
|
+
* `this`.
|
|
10
|
+
*/
|
|
11
|
+
export interface Fields {
|
|
12
|
+
readonly Name: string;
|
|
13
|
+
// `unknown`, not `ArgsFields`: an index signature here would leak into
|
|
14
|
+
// `keyof this["Args"]`.
|
|
15
|
+
readonly Args: unknown;
|
|
16
|
+
readonly Type: object;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface NoFields extends Fields {
|
|
20
|
+
readonly Type: {};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type Apply<
|
|
24
|
+
Fields_ extends Fields,
|
|
25
|
+
Name_ extends string,
|
|
26
|
+
Args_,
|
|
27
|
+
> = (Fields_ & { readonly Name: Name_; readonly Args: Args_ })["Type"];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A base profile's fields and its extension's, for one function.
|
|
31
|
+
*/
|
|
32
|
+
export interface Both<
|
|
33
|
+
Base extends Fields,
|
|
34
|
+
Extension extends Fields,
|
|
35
|
+
> extends Fields {
|
|
36
|
+
readonly Type: Apply<Base, this["Name"], this["Args"]> &
|
|
37
|
+
Apply<Extension, this["Name"], this["Args"]>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* What a profile callback sees. `args` stays a thunk.
|
|
42
|
+
*/
|
|
43
|
+
export interface Info<FieldsType> {
|
|
44
|
+
readonly name: string;
|
|
45
|
+
readonly description?: string;
|
|
46
|
+
readonly args: () => FunctionProvenance.ArgsFields;
|
|
47
|
+
readonly fields: "description" extends keyof FieldsType
|
|
48
|
+
? Omit<FieldsType, "description">
|
|
49
|
+
: FieldsType;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface Attachment<
|
|
53
|
+
MiddlewareSpec_ extends MiddlewareSpec.AnyMiddlewareSpec,
|
|
54
|
+
FieldsType,
|
|
55
|
+
> {
|
|
56
|
+
readonly spec: MiddlewareSpec_;
|
|
57
|
+
readonly options: (
|
|
58
|
+
info: Info<FieldsType>,
|
|
59
|
+
) => MiddlewareSpec.Options<MiddlewareSpec_>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A middleware without options has none to compute and is attached at most
|
|
64
|
+
* once, so it joins a profile's list directly.
|
|
65
|
+
*/
|
|
66
|
+
type TakesOptions<MiddlewareSpec_ extends MiddlewareSpec.AnyMiddlewareSpec> = [
|
|
67
|
+
MiddlewareSpec.WithoutOptions<MiddlewareSpec_>,
|
|
68
|
+
] extends [never]
|
|
69
|
+
? unknown
|
|
70
|
+
: MiddlewareSpec.AttachmentError<`Middleware "${MiddlewareSpec.Key<MiddlewareSpec_>}" takes no options, so list it without Profile.attach`>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Attach a middleware that takes options to every function a profile builds,
|
|
74
|
+
* with options computed from each function's fields.
|
|
75
|
+
*/
|
|
76
|
+
export const attach = <
|
|
77
|
+
MiddlewareSpec_ extends MiddlewareSpec.AnyMiddlewareSpec,
|
|
78
|
+
FieldsType,
|
|
79
|
+
>(
|
|
80
|
+
spec: MiddlewareSpec_ & TakesOptions<MiddlewareSpec_>,
|
|
81
|
+
options: (
|
|
82
|
+
info: Info<FieldsType>,
|
|
83
|
+
) => MiddlewareSpec.Options<NoInfer<MiddlewareSpec_>>,
|
|
84
|
+
): Attachment<MiddlewareSpec_, FieldsType> => ({ spec, options });
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A type function for a schema wrapper, applied to each declared codec.
|
|
88
|
+
*/
|
|
89
|
+
export interface SchemaTransform {
|
|
90
|
+
readonly Input: Schema.Codec<unknown, unknown>;
|
|
91
|
+
readonly Type: Schema.Codec<any, any>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Args wrappers transform the declared field map, before Struct composition.
|
|
96
|
+
*/
|
|
97
|
+
export interface ArgsTransform {
|
|
98
|
+
readonly Input: unknown;
|
|
99
|
+
readonly Type: FunctionProvenance.ArgsFields;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface Transforms {
|
|
103
|
+
readonly args?: ArgsTransform;
|
|
104
|
+
readonly returns?: SchemaTransform;
|
|
105
|
+
readonly item?: SchemaTransform;
|
|
106
|
+
readonly error?: SchemaTransform;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export type Transform<T, Input> = (T & { readonly Input: Input })["Type" &
|
|
110
|
+
keyof T];
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Error wrappers opt into Schema.Never when no error thunk was declared.
|
|
114
|
+
*/
|
|
115
|
+
export type Wrappers<T extends Transforms, FieldsType> = {
|
|
116
|
+
readonly [K in keyof T]-?: K extends keyof Transforms
|
|
117
|
+
? <
|
|
118
|
+
Input extends (K extends "args"
|
|
119
|
+
? FunctionProvenance.ArgsFields
|
|
120
|
+
: Schema.Codec<any, any>),
|
|
121
|
+
>(
|
|
122
|
+
thunk: () => Input,
|
|
123
|
+
info: Info<FieldsType>,
|
|
124
|
+
) => () => Transform<T[K], Input>
|
|
125
|
+
: never;
|
|
126
|
+
} & { readonly [K in Exclude<keyof Transforms, keyof T>]?: never };
|
|
127
|
+
|
|
128
|
+
type NonemptyError<T extends Transforms> = T extends {
|
|
129
|
+
readonly error: infer E extends SchemaTransform;
|
|
130
|
+
}
|
|
131
|
+
? [Transform<E, typeof Schema.Never>["Type"]] extends [never]
|
|
132
|
+
? MiddlewareSpec.AttachmentError<"Profile error wrapper must add an error to Schema.Never">
|
|
133
|
+
: unknown
|
|
134
|
+
: unknown;
|
|
135
|
+
|
|
136
|
+
export type SchemaConfig<T extends Transforms, FieldsType> = ([
|
|
137
|
+
keyof T,
|
|
138
|
+
] extends [never]
|
|
139
|
+
? { readonly schemas?: never }
|
|
140
|
+
: { readonly schemas: Wrappers<T, FieldsType> }) &
|
|
141
|
+
NonemptyError<T>;
|
package/src/Ref.ts
CHANGED
|
@@ -41,7 +41,9 @@ export interface Base<
|
|
|
41
41
|
: (args: Args_) => void;
|
|
42
42
|
readonly "~Returns": Returns_;
|
|
43
43
|
readonly "~Error": Error_;
|
|
44
|
+
readonly functionType?: RuntimeAndFunctionType_["functionType"];
|
|
44
45
|
readonly convexFunctionName: string;
|
|
46
|
+
readonly reservedArgument?: string;
|
|
45
47
|
/**
|
|
46
48
|
* Preserved for component references and function handles, which have no
|
|
47
49
|
* local name.
|
|
@@ -447,14 +449,19 @@ export const make = <
|
|
|
447
449
|
({
|
|
448
450
|
[TypeId]: TypeId,
|
|
449
451
|
_tag: "Convex",
|
|
452
|
+
functionType: functionSpec.runtimeAndFunctionType.functionType,
|
|
450
453
|
convexFunctionName,
|
|
451
454
|
}) as Any,
|
|
452
455
|
),
|
|
453
456
|
Match.tag("Confect", (provenance): Any =>
|
|
454
|
-
fromProvenance(
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
457
|
+
fromProvenance(
|
|
458
|
+
convexFunctionName,
|
|
459
|
+
provenance,
|
|
460
|
+
[...groupMiddlewareAttachments, ...functionSpec.middlewareAttachments],
|
|
461
|
+
undefined,
|
|
462
|
+
functionSpec.runtimeAndFunctionType.functionType,
|
|
463
|
+
functionSpec.reservedArgument,
|
|
464
|
+
),
|
|
458
465
|
),
|
|
459
466
|
Match.exhaustive,
|
|
460
467
|
) as FromFunctionSpec<
|
|
@@ -476,11 +483,15 @@ export const fromProvenance = (
|
|
|
476
483
|
provenance: FunctionProvenance.AnyConfect,
|
|
477
484
|
middlewareAttachments: ReadonlyArray<MiddlewareAttachment.MiddlewareAttachment>,
|
|
478
485
|
functionReference?: ConvexFunctionReference<any, any>,
|
|
486
|
+
functionType?: "query" | "mutation" | "action",
|
|
487
|
+
reservedArgument?: string,
|
|
479
488
|
): AnyConfect => {
|
|
480
489
|
const ref = {
|
|
481
490
|
[TypeId]: TypeId as TypeId,
|
|
482
491
|
_tag: "Confect" as const,
|
|
492
|
+
...(functionType === undefined ? {} : { functionType }),
|
|
483
493
|
convexFunctionName,
|
|
494
|
+
...(reservedArgument === undefined ? {} : { reservedArgument }),
|
|
484
495
|
...(functionReference === undefined ? {} : { functionReference }),
|
|
485
496
|
kind: provenance.kind,
|
|
486
497
|
middlewareAttachments,
|
|
@@ -532,6 +543,7 @@ export const fromFunctionReference = <
|
|
|
532
543
|
Returns_,
|
|
533
544
|
>(
|
|
534
545
|
functionReference: ConvexFunctionReference<Type, Visibility, Args_, Returns_>,
|
|
546
|
+
functionType?: NoInfer<Type>,
|
|
535
547
|
): ConvexRef<
|
|
536
548
|
Extract<
|
|
537
549
|
RuntimeAndFunctionType.RuntimeAndFunctionType,
|
|
@@ -545,6 +557,7 @@ export const fromFunctionReference = <
|
|
|
545
557
|
return {
|
|
546
558
|
[TypeId]: TypeId,
|
|
547
559
|
_tag: "Convex",
|
|
560
|
+
...(functionType === undefined ? {} : { functionType }),
|
|
548
561
|
convexFunctionName:
|
|
549
562
|
address.name ??
|
|
550
563
|
address.reference ??
|
package/src/SchemaToValidator.ts
CHANGED
|
@@ -46,10 +46,12 @@ import type {
|
|
|
46
46
|
export const compileArgsSchema = <ConfectValue, ConvexValue>(
|
|
47
47
|
argsSchema: Schema.Codec<ConfectValue, ConvexValue>,
|
|
48
48
|
scope: IdScope.IdScope = IdScope.app,
|
|
49
|
+
reservedArgument?: string,
|
|
50
|
+
functionName?: string,
|
|
49
51
|
): PropertyValidators => {
|
|
50
52
|
const ast = Schema.toEncoded(argsSchema).ast;
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
const validators = pipe(
|
|
53
55
|
ast,
|
|
54
56
|
Match.value,
|
|
55
57
|
Match.tag("Objects", (objectsAst) =>
|
|
@@ -60,8 +62,27 @@ export const compileArgsSchema = <ConfectValue, ConvexValue>(
|
|
|
60
62
|
Match.orElse(() => Effect.fail(new TopLevelMustBeObjectError())),
|
|
61
63
|
Effect.runSync,
|
|
62
64
|
);
|
|
65
|
+
if (reservedArgument === undefined) return validators;
|
|
66
|
+
if (Object.hasOwn(validators, reservedArgument)) {
|
|
67
|
+
throw new ReservedArgumentCollision({
|
|
68
|
+
functionName,
|
|
69
|
+
argument: reservedArgument,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return { ...validators, [reservedArgument]: v.optional(v.any()) };
|
|
63
73
|
};
|
|
64
74
|
|
|
75
|
+
export class ReservedArgumentCollision extends Data.TaggedError(
|
|
76
|
+
"ReservedArgumentCollision",
|
|
77
|
+
)<{
|
|
78
|
+
readonly functionName: string | undefined;
|
|
79
|
+
readonly argument: string;
|
|
80
|
+
}> {
|
|
81
|
+
override get message() {
|
|
82
|
+
return `${this.functionName} declares the argument "${this.argument}", which its profile reserves. Rename the argument.`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
65
86
|
// Returns
|
|
66
87
|
|
|
67
88
|
export const compileReturnsSchema = <ConfectValue, ConvexValue>(
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * as ActionCall from "./ActionCall.js";
|
|
1
2
|
export * as Callback from "./Callback.js";
|
|
2
3
|
export * as FunctionProvenance from "./FunctionProvenance.js";
|
|
3
4
|
export * as FunctionSpec from "./FunctionSpec.js";
|
|
@@ -13,11 +14,13 @@ export * as GroupSpec from "./GroupSpec.js";
|
|
|
13
14
|
export * as Identifier from "./Identifier.js";
|
|
14
15
|
export * as Lazy from "./Lazy.js";
|
|
15
16
|
export * as Manifest from "./Manifest.js";
|
|
17
|
+
export * as ManifestSection from "./ManifestSection.js";
|
|
16
18
|
export * as MiddlewareAttachment from "./MiddlewareAttachment.js";
|
|
17
19
|
export * as MiddlewareSpec from "./MiddlewareSpec.js";
|
|
18
20
|
export * as PaginationError from "./PaginationError.js";
|
|
19
21
|
export * as PaginationOptions from "./PaginationOptions.js";
|
|
20
22
|
export * as PaginationResult from "./PaginationResult.js";
|
|
23
|
+
export * as Profile from "./Profile.js";
|
|
21
24
|
export * as Ref from "./Ref.js";
|
|
22
25
|
export * as Refs from "./Refs.js";
|
|
23
26
|
export * as RuntimeAndFunctionType from "./RuntimeAndFunctionType.js";
|
|
@@ -0,0 +1,72 @@
|
|
|
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 type * as HttpApi from "effect/http-api/HttpApi";
|
|
5
|
+
import type * as HttpApiGroup from "effect/http-api/HttpApiGroup";
|
|
6
|
+
import * as OpenApi from "effect/http-api/OpenApi";
|
|
7
|
+
|
|
8
|
+
const escape = (value: string) =>
|
|
9
|
+
value
|
|
10
|
+
.replaceAll("&", "&")
|
|
11
|
+
.replaceAll("<", "<")
|
|
12
|
+
.replaceAll(">", ">");
|
|
13
|
+
|
|
14
|
+
const escapeAttribute = (value: string) =>
|
|
15
|
+
escape(value).replaceAll('"', """).replaceAll("'", "'");
|
|
16
|
+
|
|
17
|
+
const escapeJson = (value: unknown) =>
|
|
18
|
+
JSON.stringify(value)
|
|
19
|
+
.replaceAll("<", "\\u003c")
|
|
20
|
+
.replaceAll("\u2028", "\\u2028")
|
|
21
|
+
.replaceAll("\u2029", "\\u2029");
|
|
22
|
+
|
|
23
|
+
// WORKAROUND: Effect 4.0.6's HttpApiScalar module imports its inline Scalar
|
|
24
|
+
// script dynamically, and Convex's bundler then splits a schema that reaches it
|
|
25
|
+
// into an imported chunk, which Convex refuses. This copies `layerCdn`'s page
|
|
26
|
+
// byte for byte. Remove when `checkSchemaBundle.mjs` passes with
|
|
27
|
+
// `HttpApiScalar.layerCdn` restored.
|
|
28
|
+
export const scalarDocs = <
|
|
29
|
+
Id extends string,
|
|
30
|
+
Groups extends HttpApiGroup.Constraint,
|
|
31
|
+
>(
|
|
32
|
+
api: HttpApi.HttpApi<Id, Groups>,
|
|
33
|
+
path: `/${string}`,
|
|
34
|
+
) =>
|
|
35
|
+
HttpRouter.use((router) => {
|
|
36
|
+
let response: HttpServerResponse.HttpServerResponse | undefined;
|
|
37
|
+
return router.add(
|
|
38
|
+
"GET",
|
|
39
|
+
path,
|
|
40
|
+
Effect.sync(() => {
|
|
41
|
+
if (response !== undefined) return response;
|
|
42
|
+
const spec = OpenApi.fromApi(api);
|
|
43
|
+
const description = (tag: string) =>
|
|
44
|
+
!spec.info.description
|
|
45
|
+
? ""
|
|
46
|
+
: `<meta name="${tag}" content="${escapeAttribute(spec.info.description)}"/>`;
|
|
47
|
+
response = HttpServerResponse.html(`<!doctype html>
|
|
48
|
+
<html>
|
|
49
|
+
<head>
|
|
50
|
+
<meta charset="utf-8" />
|
|
51
|
+
<title>${escape(spec.info.title)}</title>
|
|
52
|
+
${description("description")}
|
|
53
|
+
${description("og:description")}
|
|
54
|
+
<meta
|
|
55
|
+
name="viewport"
|
|
56
|
+
content="width=device-width, initial-scale=1" />
|
|
57
|
+
</head>
|
|
58
|
+
<body>
|
|
59
|
+
<div id="api-reference-container"></div>
|
|
60
|
+
<script src="${escapeAttribute("https://cdn.jsdelivr.net/npm/@scalar/api-reference@latest/dist/browser/standalone.min.js")}" crossorigin></script>
|
|
61
|
+
<script>
|
|
62
|
+
window.Scalar.createApiReference(document.getElementById('api-reference-container'), {
|
|
63
|
+
...${escapeJson({ _integration: "html" })},
|
|
64
|
+
content: ${escapeJson(spec)}
|
|
65
|
+
})
|
|
66
|
+
</script>
|
|
67
|
+
</body>
|
|
68
|
+
</html>`);
|
|
69
|
+
return response;
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
});
|