@confect/core 10.0.0-next.21 → 10.0.0-next.23
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 +168 -81
- package/dist/FunctionProvenance.d.ts +34 -26
- package/dist/FunctionProvenance.d.ts.map +1 -1
- package/dist/FunctionProvenance.js +14 -13
- package/dist/FunctionProvenance.js.map +1 -1
- package/dist/FunctionSpec.d.ts +15 -9
- package/dist/FunctionSpec.d.ts.map +1 -1
- package/dist/FunctionSpec.js +12 -6
- package/dist/FunctionSpec.js.map +1 -1
- package/dist/GroupPath.d.ts +5 -6
- package/dist/GroupPath.d.ts.map +1 -1
- package/dist/GroupPath.js.map +1 -1
- package/dist/GroupSpec.d.ts +10 -3
- package/dist/GroupSpec.d.ts.map +1 -1
- package/dist/GroupSpec.js +33 -19
- package/dist/GroupSpec.js.map +1 -1
- package/dist/Identifier.d.ts +6 -5
- package/dist/Identifier.d.ts.map +1 -1
- package/dist/Identifier.js +6 -5
- package/dist/Identifier.js.map +1 -1
- package/dist/Lazy.d.ts +11 -13
- package/dist/Lazy.d.ts.map +1 -1
- package/dist/Lazy.js +11 -13
- package/dist/Lazy.js.map +1 -1
- package/dist/MiddlewareAttachment.d.ts +171 -0
- package/dist/MiddlewareAttachment.d.ts.map +1 -0
- package/dist/MiddlewareAttachment.js +48 -0
- package/dist/MiddlewareAttachment.js.map +1 -0
- package/dist/MiddlewareSpec.d.ts +59 -45
- package/dist/MiddlewareSpec.d.ts.map +1 -1
- package/dist/MiddlewareSpec.js +9 -4
- package/dist/MiddlewareSpec.js.map +1 -1
- package/dist/PaginationError.d.ts +9 -3
- package/dist/PaginationError.d.ts.map +1 -1
- package/dist/PaginationError.js +9 -3
- package/dist/PaginationError.js.map +1 -1
- package/dist/PaginationOptions.d.ts +3 -3
- package/dist/PaginationOptions.js +3 -3
- package/dist/PaginationOptions.js.map +1 -1
- package/dist/Ref.d.ts +42 -35
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Ref.js +32 -30
- package/dist/Ref.js.map +1 -1
- package/dist/Refs.d.ts +1 -1
- package/dist/Refs.d.ts.map +1 -1
- package/dist/Refs.js +3 -2
- package/dist/Refs.js.map +1 -1
- package/dist/SchemaToValidator.d.ts.map +1 -1
- package/dist/SchemaToValidator.js +4 -2
- package/dist/SchemaToValidator.js.map +1 -1
- package/dist/Spec.d.ts +15 -12
- package/dist/Spec.d.ts.map +1 -1
- package/dist/Spec.js +13 -8
- package/dist/Spec.js.map +1 -1
- package/dist/SystemFields.d.ts +15 -14
- package/dist/SystemFields.d.ts.map +1 -1
- package/dist/SystemFields.js +11 -10
- package/dist/SystemFields.js.map +1 -1
- package/dist/Table.d.ts +1 -0
- package/dist/Table.d.ts.map +1 -1
- package/dist/Table.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/package.json +8 -7
- package/src/FunctionProvenance.ts +35 -27
- package/src/FunctionSpec.ts +33 -15
- package/src/GroupPath.ts +5 -6
- package/src/GroupSpec.ts +83 -31
- package/src/Identifier.ts +6 -5
- package/src/Lazy.ts +11 -13
- package/src/MiddlewareAttachment.ts +106 -0
- package/src/MiddlewareSpec.ts +79 -43
- package/src/PaginationError.ts +9 -3
- package/src/PaginationOptions.ts +3 -3
- package/src/Ref.ts +76 -65
- package/src/Refs.ts +3 -3
- package/src/SchemaToValidator.ts +53 -44
- package/src/Spec.ts +50 -39
- package/src/SystemFields.ts +18 -17
- package/src/Table.ts +3 -2
- package/src/index.ts +1 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as Data from "effect/Data";
|
|
2
|
+
import * as Result from "effect/Result";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import type * as MiddlewareSpec from "./MiddlewareSpec";
|
|
5
|
+
|
|
6
|
+
export type MiddlewareAttachment<
|
|
7
|
+
MiddlewareSpec_ extends MiddlewareSpec.AnyMiddlewareSpec =
|
|
8
|
+
MiddlewareSpec.AnyMiddlewareSpec,
|
|
9
|
+
> = MiddlewareSpec_ extends MiddlewareSpec.AnyMiddlewareSpec
|
|
10
|
+
? {
|
|
11
|
+
readonly spec: MiddlewareSpec_;
|
|
12
|
+
readonly options: [MiddlewareSpec_["~Options"]] extends [never]
|
|
13
|
+
? undefined
|
|
14
|
+
: MiddlewareSpec.Options<MiddlewareSpec_>;
|
|
15
|
+
}
|
|
16
|
+
: never;
|
|
17
|
+
|
|
18
|
+
export type Args<MiddlewareSpec_ extends MiddlewareSpec.AnyMiddlewareSpec> = [
|
|
19
|
+
MiddlewareSpec_["~Options"],
|
|
20
|
+
] extends [never]
|
|
21
|
+
? []
|
|
22
|
+
: [options: MiddlewareSpec.Options<MiddlewareSpec_>];
|
|
23
|
+
|
|
24
|
+
export type ValidationError = Data.TaggedEnum<{
|
|
25
|
+
InvalidOptions: {
|
|
26
|
+
readonly middlewareKey: string;
|
|
27
|
+
readonly location: string;
|
|
28
|
+
readonly attachmentIndex: number;
|
|
29
|
+
};
|
|
30
|
+
ConflictingSpecs: {
|
|
31
|
+
readonly middlewareKey: string;
|
|
32
|
+
readonly location: string;
|
|
33
|
+
readonly attachmentIndex: number;
|
|
34
|
+
readonly previousIndex: number;
|
|
35
|
+
};
|
|
36
|
+
EquivalentOptions: {
|
|
37
|
+
readonly middlewareKey: string;
|
|
38
|
+
readonly location: string;
|
|
39
|
+
readonly attachmentIndex: number;
|
|
40
|
+
readonly previousIndex: number;
|
|
41
|
+
};
|
|
42
|
+
}>;
|
|
43
|
+
|
|
44
|
+
export const ValidationError = Data.taggedEnum<ValidationError>();
|
|
45
|
+
|
|
46
|
+
export const formatValidationError = ValidationError.$match({
|
|
47
|
+
InvalidOptions: ({ middlewareKey, location, attachmentIndex }) =>
|
|
48
|
+
`Middleware "${middlewareKey}" has invalid options at attachment ${attachmentIndex + 1} on ${location}`,
|
|
49
|
+
ConflictingSpecs: ({ middlewareKey, location }) =>
|
|
50
|
+
`Different middleware specs share key "${middlewareKey}" on ${location}`,
|
|
51
|
+
EquivalentOptions: ({
|
|
52
|
+
middlewareKey,
|
|
53
|
+
location,
|
|
54
|
+
attachmentIndex,
|
|
55
|
+
previousIndex,
|
|
56
|
+
}) =>
|
|
57
|
+
`Middleware "${middlewareKey}" has equivalent options at attachments ${previousIndex + 1} and ${attachmentIndex + 1} on ${location}`,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export const validateAll = (
|
|
61
|
+
attachments: ReadonlyArray<MiddlewareAttachment>,
|
|
62
|
+
location: string,
|
|
63
|
+
): Result.Result<void, ValidationError> => {
|
|
64
|
+
for (const [index, attachment] of attachments.entries()) {
|
|
65
|
+
const schema = attachment.spec.options;
|
|
66
|
+
if (schema !== undefined && !Schema.is(schema)(attachment.options)) {
|
|
67
|
+
return Result.fail(
|
|
68
|
+
ValidationError.InvalidOptions({
|
|
69
|
+
middlewareKey: attachment.spec.key,
|
|
70
|
+
location,
|
|
71
|
+
attachmentIndex: index,
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
const equivalent =
|
|
76
|
+
schema === undefined ? undefined : Schema.toEquivalence(schema);
|
|
77
|
+
for (const [previousIndex, previous] of attachments.entries()) {
|
|
78
|
+
if (previousIndex === index) break;
|
|
79
|
+
if (previous.spec.key !== attachment.spec.key) continue;
|
|
80
|
+
if (previous.spec !== attachment.spec) {
|
|
81
|
+
return Result.fail(
|
|
82
|
+
ValidationError.ConflictingSpecs({
|
|
83
|
+
middlewareKey: attachment.spec.key,
|
|
84
|
+
location,
|
|
85
|
+
attachmentIndex: index,
|
|
86
|
+
previousIndex,
|
|
87
|
+
}),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
if (
|
|
91
|
+
equivalent === undefined ||
|
|
92
|
+
equivalent(previous.options, attachment.options)
|
|
93
|
+
) {
|
|
94
|
+
return Result.fail(
|
|
95
|
+
ValidationError.EquivalentOptions({
|
|
96
|
+
middlewareKey: attachment.spec.key,
|
|
97
|
+
location,
|
|
98
|
+
attachmentIndex: index,
|
|
99
|
+
previousIndex,
|
|
100
|
+
}),
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return Result.void;
|
|
106
|
+
};
|
package/src/MiddlewareSpec.ts
CHANGED
|
@@ -38,31 +38,37 @@ export interface SuccessValue {
|
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* The wrap-style middleware implementation shape: receives the downstream
|
|
41
|
-
* effect (the remaining middleware plus the function handler) and the
|
|
42
|
-
*
|
|
43
|
-
* place.
|
|
41
|
+
* effect (the remaining middleware plus the function handler) and the covered
|
|
42
|
+
* invocation's metadata, and returns the effect that runs in its place.
|
|
44
43
|
*
|
|
45
44
|
* Mirrors `RpcMiddleware.RpcMiddleware` in Effect.
|
|
46
45
|
*/
|
|
47
|
-
export interface MiddlewareImpl<Provides_, E, R> {
|
|
46
|
+
export interface MiddlewareImpl<Provides_, E, R, Options_ = never> {
|
|
48
47
|
(
|
|
49
48
|
effect: Effect.Effect<SuccessValue, E | unhandled, Provides_>,
|
|
50
|
-
|
|
49
|
+
context: MiddlewareOptions<Options_>,
|
|
51
50
|
): Effect.Effect<SuccessValue, E | unhandled, R>;
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
export
|
|
55
|
-
readonly
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
export type MiddlewareOptions<Options_ = never> = {
|
|
54
|
+
readonly invocation: {
|
|
55
|
+
readonly name: string;
|
|
56
|
+
readonly functionType: FunctionType;
|
|
57
|
+
readonly functionVisibility: FunctionVisibility;
|
|
58
|
+
readonly args: unknown;
|
|
59
|
+
};
|
|
60
|
+
} & ([Options_] extends [never] ? unknown : { readonly options: Options_ });
|
|
60
61
|
|
|
61
|
-
export interface AnyMiddlewareImpl
|
|
62
|
+
export interface AnyMiddlewareImpl {
|
|
63
|
+
(
|
|
64
|
+
effect: Effect.Effect<SuccessValue, any, any>,
|
|
65
|
+
context: MiddlewareOptions | MiddlewareOptions<unknown>,
|
|
66
|
+
): Effect.Effect<SuccessValue, any, any>;
|
|
67
|
+
}
|
|
62
68
|
|
|
63
69
|
/**
|
|
64
|
-
* The class shape produced by {@link MiddlewareSpec}. Only the static side is
|
|
65
|
-
* used
|
|
70
|
+
* The class shape produced by {@link MiddlewareSpec}. Only the static side is
|
|
71
|
+
* ever used—the class is a value-level carrier for the middleware's key, its
|
|
66
72
|
* declared functionTypes, and its (lazily-evaluated) error schema, plus the
|
|
67
73
|
* type-level `Provides`/`Error` metadata. It is deliberately not a
|
|
68
74
|
* `Context.Tag`: implementations are registered through the group `Registry`
|
|
@@ -75,6 +81,7 @@ export interface MiddlewareSpec<
|
|
|
75
81
|
Requires_,
|
|
76
82
|
ErrorSchema_ extends Schema.Codec<any, any>,
|
|
77
83
|
FunctionTypes_ extends FunctionType,
|
|
84
|
+
OptionsSchema_ extends Schema.Schema<any> = never,
|
|
78
85
|
> {
|
|
79
86
|
new (_: never): {
|
|
80
87
|
readonly [TypeId]: TypeId;
|
|
@@ -84,11 +91,13 @@ export interface MiddlewareSpec<
|
|
|
84
91
|
readonly key: Key_;
|
|
85
92
|
readonly functionTypes: SupportedFunctionTypes;
|
|
86
93
|
readonly error?: ErrorSchema_;
|
|
94
|
+
readonly options?: OptionsSchema_;
|
|
87
95
|
readonly "~Provides": Provides_;
|
|
88
96
|
readonly "~Requires": Requires_;
|
|
89
97
|
readonly "~Error": ErrorSchema_;
|
|
90
98
|
readonly "~FunctionTypes": FunctionTypes_;
|
|
91
99
|
readonly "~Self": Self;
|
|
100
|
+
readonly "~Options": OptionsSchema_;
|
|
92
101
|
}
|
|
93
102
|
|
|
94
103
|
export interface AnyMiddlewareSpec {
|
|
@@ -96,12 +105,24 @@ export interface AnyMiddlewareSpec {
|
|
|
96
105
|
readonly key: string;
|
|
97
106
|
readonly functionTypes: SupportedFunctionTypes;
|
|
98
107
|
readonly error?: Schema.Codec<any, any>;
|
|
108
|
+
readonly options?: Schema.Schema<any>;
|
|
99
109
|
readonly "~Provides": any;
|
|
100
110
|
readonly "~Requires": any;
|
|
101
111
|
readonly "~Error": any;
|
|
102
112
|
readonly "~FunctionTypes": FunctionType;
|
|
113
|
+
readonly "~Options": any;
|
|
103
114
|
}
|
|
104
115
|
|
|
116
|
+
export type Options<MiddlewareSpec_ extends AnyMiddlewareSpec> =
|
|
117
|
+
MiddlewareSpec_["~Options"]["Type"];
|
|
118
|
+
|
|
119
|
+
export type WithoutOptions<MiddlewareSpec_ extends AnyMiddlewareSpec> =
|
|
120
|
+
MiddlewareSpec_ extends AnyMiddlewareSpec
|
|
121
|
+
? [MiddlewareSpec_["~Options"]] extends [never]
|
|
122
|
+
? MiddlewareSpec_
|
|
123
|
+
: never
|
|
124
|
+
: never;
|
|
125
|
+
|
|
105
126
|
export type Key<MiddlewareSpec_ extends AnyMiddlewareSpec> =
|
|
106
127
|
MiddlewareSpec_["key"];
|
|
107
128
|
|
|
@@ -111,8 +132,8 @@ export type Provides<MiddlewareSpec_ extends AnyMiddlewareSpec> =
|
|
|
111
132
|
: never;
|
|
112
133
|
|
|
113
134
|
/**
|
|
114
|
-
* The services a middleware's implementation may consume from middleware
|
|
115
|
-
*
|
|
135
|
+
* The services a middleware's implementation may consume from middleware that
|
|
136
|
+
* runs earlier in the same chain (type-level only, like `provides`).
|
|
116
137
|
*/
|
|
117
138
|
export type Requires<MiddlewareSpec_ extends AnyMiddlewareSpec> =
|
|
118
139
|
MiddlewareSpec_ extends AnyMiddlewareSpec
|
|
@@ -143,16 +164,20 @@ export type FunctionTypes<MiddlewareSpec_ extends AnyMiddlewareSpec> =
|
|
|
143
164
|
* encode through, and the function types it may attach to.
|
|
144
165
|
*
|
|
145
166
|
* ```ts
|
|
146
|
-
* class RequireUser extends MiddlewareSpec.MiddlewareSpec<
|
|
147
|
-
*
|
|
148
|
-
*
|
|
167
|
+
* class RequireUser extends MiddlewareSpec.MiddlewareSpec<
|
|
168
|
+
* RequireUser,
|
|
169
|
+
* {
|
|
170
|
+
* provides: CurrentUser;
|
|
171
|
+
* }
|
|
172
|
+
* >()("RequireUser", {
|
|
149
173
|
* error: () => NotSignedIn,
|
|
150
174
|
* functionTypes: { query: true, mutation: true, action: false },
|
|
151
175
|
* }) {}
|
|
152
176
|
* ```
|
|
153
177
|
*
|
|
154
178
|
* The implementation is server-only and supplied separately via
|
|
155
|
-
* `MiddlewareImpl.make` (or `makeByFunctionType`/`provides`) in
|
|
179
|
+
* `MiddlewareImpl.make` (or `makeByFunctionType`/`provides`) in
|
|
180
|
+
* `@confect/server`.
|
|
156
181
|
*/
|
|
157
182
|
export const MiddlewareSpec =
|
|
158
183
|
<Self, Config extends { provides?: any; requires?: any } = {}>() =>
|
|
@@ -160,10 +185,12 @@ export const MiddlewareSpec =
|
|
|
160
185
|
const Key_ extends string,
|
|
161
186
|
const FunctionTypesConfig_ extends SupportedFunctionTypes,
|
|
162
187
|
ErrorSchema_ extends Schema.Codec<any, any> = never,
|
|
188
|
+
OptionsSchema_ extends Schema.Schema<any> = never,
|
|
163
189
|
>(
|
|
164
190
|
key: Key_,
|
|
165
191
|
options: {
|
|
166
192
|
readonly error?: () => ErrorSchema_;
|
|
193
|
+
readonly options?: () => OptionsSchema_;
|
|
167
194
|
readonly functionTypes: FunctionTypesConfig_ &
|
|
168
195
|
ValidateFunctionTypesConfig<FunctionTypesConfig_>;
|
|
169
196
|
},
|
|
@@ -173,7 +200,8 @@ export const MiddlewareSpec =
|
|
|
173
200
|
"provides" extends keyof Config ? Config["provides"] : never,
|
|
174
201
|
"requires" extends keyof Config ? Config["requires"] : never,
|
|
175
202
|
ErrorSchema_,
|
|
176
|
-
FunctionTypesFromConfig<FunctionTypesConfig_
|
|
203
|
+
FunctionTypesFromConfig<FunctionTypesConfig_>,
|
|
204
|
+
OptionsSchema_
|
|
177
205
|
> => {
|
|
178
206
|
const { query, mutation, action } = options.functionTypes;
|
|
179
207
|
if (!query && !mutation && !action) {
|
|
@@ -194,6 +222,9 @@ export const MiddlewareSpec =
|
|
|
194
222
|
if (options.error !== undefined) {
|
|
195
223
|
Lazy.defineProperty(class_, "error", options.error);
|
|
196
224
|
}
|
|
225
|
+
if (options.options !== undefined) {
|
|
226
|
+
Lazy.defineProperty(class_, "options", options.options);
|
|
227
|
+
}
|
|
197
228
|
return class_;
|
|
198
229
|
};
|
|
199
230
|
|
|
@@ -225,7 +256,7 @@ export const errorSchemas = (
|
|
|
225
256
|
/**
|
|
226
257
|
* A branded, unconstructible type carrying a spec-authoring error message.
|
|
227
258
|
* Surfaced as (part of) a parameter type so the diagnostic names the exact
|
|
228
|
-
* problem at the `.middleware()
|
|
259
|
+
* problem at the `.middleware()`/`.addFunction()` call site.
|
|
229
260
|
*/
|
|
230
261
|
export interface AttachmentError<Message extends string> {
|
|
231
262
|
readonly "~@confect/core/MiddlewareSpec/AttachmentError": Message;
|
|
@@ -237,10 +268,9 @@ type FunctionTypeOf<FunctionSpec_ extends FunctionSpec.AnyWithProps> =
|
|
|
237
268
|
type ValidationResult<Errors> = [Errors] extends [never] ? unknown : Errors;
|
|
238
269
|
|
|
239
270
|
/**
|
|
240
|
-
* A matching-type Convex-provenance function is rejected rather than
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
* policy hole.
|
|
271
|
+
* A matching-type Convex-provenance function is rejected rather than silently
|
|
272
|
+
* skipped: its raw handler passes through Confect untouched, so the middleware
|
|
273
|
+
* could not actually cover it, and skipping it would be a policy hole.
|
|
244
274
|
*/
|
|
245
275
|
export type ValidateFunction<
|
|
246
276
|
FunctionSpec_ extends FunctionSpec.AnyWithProps,
|
|
@@ -251,12 +281,12 @@ export type ValidateFunction<
|
|
|
251
281
|
readonly functionProvenance: { readonly _tag: "Convex" };
|
|
252
282
|
}
|
|
253
283
|
? FunctionTypeOf<FunctionSpec_> extends FunctionTypes<MiddlewareSpec_>
|
|
254
|
-
? AttachmentError<`Convex-provenance function "${FunctionSpec_["name"]}" cannot be covered by middleware "${Key<MiddlewareSpec_>}"
|
|
284
|
+
? AttachmentError<`Convex-provenance function "${FunctionSpec_["name"]}" cannot be covered by middleware "${Key<MiddlewareSpec_>}"—attach middleware only to groups whose matching-type functions are all Confect-provenance`>
|
|
255
285
|
: never
|
|
256
286
|
: [
|
|
257
287
|
Extract<
|
|
258
288
|
FunctionSpec.MiddlewareSpecs<FunctionSpec_>,
|
|
259
|
-
{ readonly key: Key<MiddlewareSpec_
|
|
289
|
+
{ readonly key: Key<WithoutOptions<MiddlewareSpec_>> }
|
|
260
290
|
>,
|
|
261
291
|
] extends [never]
|
|
262
292
|
? FunctionTypeOf<FunctionSpec_> extends FunctionTypes<MiddlewareSpec_>
|
|
@@ -267,8 +297,8 @@ export type ValidateFunction<
|
|
|
267
297
|
: never;
|
|
268
298
|
|
|
269
299
|
/**
|
|
270
|
-
* Attachment order is chain order, so requiring `requires` to be satisfied
|
|
271
|
-
*
|
|
300
|
+
* Attachment order is chain order, so requiring `requires` to be satisfied by
|
|
301
|
+
* already-attached middleware is exactly requiring the provider to run
|
|
272
302
|
* earlier.
|
|
273
303
|
*/
|
|
274
304
|
export type ValidateAttach<
|
|
@@ -276,13 +306,16 @@ export type ValidateAttach<
|
|
|
276
306
|
Functions_ extends FunctionSpec.AnyWithProps,
|
|
277
307
|
MiddlewareSpecs_ extends AnyMiddlewareSpec,
|
|
278
308
|
> = [
|
|
279
|
-
Extract<
|
|
309
|
+
Extract<
|
|
310
|
+
MiddlewareSpecs_,
|
|
311
|
+
{ readonly key: Key<WithoutOptions<MiddlewareSpec_>> }
|
|
312
|
+
>,
|
|
280
313
|
] extends [never]
|
|
281
314
|
? [Exclude<Requires<MiddlewareSpec_>, Provides<MiddlewareSpecs_>>] extends [
|
|
282
315
|
never,
|
|
283
316
|
]
|
|
284
317
|
? ValidationResult<ValidateFunction<Functions_, MiddlewareSpec_>>
|
|
285
|
-
: AttachmentError<`Middleware "${Key<MiddlewareSpec_>}" requires services that no middleware attached earlier to this group provides
|
|
318
|
+
: AttachmentError<`Middleware "${Key<MiddlewareSpec_>}" requires services that no middleware attached earlier to this group provides—attach the providing middleware first`>
|
|
286
319
|
: AttachmentError<`Middleware "${Key<MiddlewareSpec_>}" is already attached to this group`>;
|
|
287
320
|
|
|
288
321
|
export type ValidateAddedFunction<
|
|
@@ -304,7 +337,7 @@ type GroupOverlap<
|
|
|
304
337
|
? [
|
|
305
338
|
Extract<
|
|
306
339
|
MiddlewareSpecs_,
|
|
307
|
-
{ readonly key: Key<FunctionMiddlewareSpec
|
|
340
|
+
{ readonly key: Key<WithoutOptions<FunctionMiddlewareSpec>> }
|
|
308
341
|
>,
|
|
309
342
|
] extends [never]
|
|
310
343
|
? never
|
|
@@ -313,14 +346,14 @@ type GroupOverlap<
|
|
|
313
346
|
: never;
|
|
314
347
|
|
|
315
348
|
/**
|
|
316
|
-
* The parameter-type validation applied to the group spec at
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
349
|
+
* The parameter-type validation applied to the group spec at `GroupImpl.make`:
|
|
350
|
+
* every function's attached middleware must have its `requires` services
|
|
351
|
+
* provided by some middleware covering that function (the group's or the
|
|
352
|
+
* function's own). Checked here—with the group fully assembled—rather than at
|
|
353
|
+
* the spec builders, because a function-level middleware's `requires` may
|
|
354
|
+
* legitimately be satisfied by a group middleware the function spec never sees,
|
|
355
|
+
* and group attachment is declaratively order-independent with respect to
|
|
356
|
+
* `addFunction`.
|
|
324
357
|
*/
|
|
325
358
|
export type ValidateImplRequires<
|
|
326
359
|
Functions_ extends FunctionSpec.AnyWithProps,
|
|
@@ -346,9 +379,12 @@ export type ValidateFunctionAttach<
|
|
|
346
379
|
FunctionProvenance_ extends FunctionProvenance.FunctionProvenance,
|
|
347
380
|
MiddlewareSpecs_ extends AnyMiddlewareSpec,
|
|
348
381
|
> = FunctionProvenance_ extends { readonly _tag: "Convex" }
|
|
349
|
-
? AttachmentError<`Plain Convex functions cannot have middleware
|
|
382
|
+
? AttachmentError<`Plain Convex functions cannot have middleware—their raw handlers are passed through untouched`>
|
|
350
383
|
: [
|
|
351
|
-
Extract<
|
|
384
|
+
Extract<
|
|
385
|
+
MiddlewareSpecs_,
|
|
386
|
+
{ readonly key: Key<WithoutOptions<MiddlewareSpec_>> }
|
|
387
|
+
>,
|
|
352
388
|
] extends [never]
|
|
353
389
|
? RuntimeAndFunctionType_["functionType"] extends FunctionTypes<MiddlewareSpec_>
|
|
354
390
|
? unknown
|
package/src/PaginationError.ts
CHANGED
|
@@ -4,7 +4,9 @@ import * as Match from "effect/Match";
|
|
|
4
4
|
import * as Option from "effect/Option";
|
|
5
5
|
import * as Schema from "effect/Schema";
|
|
6
6
|
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* A Convex pagination cursor that no longer describes the current query.
|
|
9
|
+
*/
|
|
8
10
|
export class InvalidCursor extends Schema.TaggedError<InvalidCursor>()(
|
|
9
11
|
"InvalidCursor",
|
|
10
12
|
{
|
|
@@ -40,7 +42,9 @@ const fromErrorMessage = (
|
|
|
40
42
|
? Option.some(new InvalidCursor({ cause: error }))
|
|
41
43
|
: Option.none();
|
|
42
44
|
|
|
43
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* Recognizes an invalid-cursor error emitted by a Convex query.
|
|
47
|
+
*/
|
|
44
48
|
export const fromConvexQueryError = (
|
|
45
49
|
error: unknown,
|
|
46
50
|
): Option.Option<InvalidCursor> =>
|
|
@@ -59,7 +63,9 @@ export const fromConvexQueryError = (
|
|
|
59
63
|
Match.exhaustive,
|
|
60
64
|
);
|
|
61
65
|
|
|
62
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Recognizes the error data attached to Convex's invalid-cursor error.
|
|
68
|
+
*/
|
|
63
69
|
export const fromConvexErrorData = (
|
|
64
70
|
errorData: unknown,
|
|
65
71
|
): Option.Option<InvalidCursor> =>
|
package/src/PaginationOptions.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as Schema from "effect/Schema";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Schema for the `paginationOpts` argument that every paginated query
|
|
5
|
-
*
|
|
4
|
+
* Schema for the `paginationOpts` argument that every paginated query receives.
|
|
5
|
+
* Mirrors `paginationOptsValidator` from `convex/server`.
|
|
6
6
|
*
|
|
7
7
|
* Use this as the `paginationOpts` field of a paginated query's args schema.
|
|
8
8
|
* Beyond `numItems` and `cursor`, Convex's pagination protocol sends the
|
|
9
9
|
* optional fields (`endCursor`, `id`, `maximumRowsRead`, `maximumBytesRead`)
|
|
10
|
-
* with real requests
|
|
10
|
+
* with real requests—most notably `usePaginatedQuery` from `convex/react`
|
|
11
11
|
* always includes `id`, and includes `endCursor` when splitting pages.
|
|
12
12
|
* Declaring them is required for the generated Convex argument validator to
|
|
13
13
|
* accept those requests and for the fields to survive decoding and reach
|