@nxgt/graphql-validation 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +235 -2
- package/dist/bad-user-input.d.ts +35 -0
- package/dist/bad-user-input.d.ts.map +1 -0
- package/dist/builder/args-schema.d.ts +17 -0
- package/dist/builder/args-schema.d.ts.map +1 -0
- package/dist/builder/check-constraints.d.ts +15 -0
- package/dist/builder/check-constraints.d.ts.map +1 -0
- package/dist/builder/constraints.d.ts +16 -0
- package/dist/builder/constraints.d.ts.map +1 -0
- package/dist/builder/input-code.d.ts +29 -0
- package/dist/builder/input-code.d.ts.map +1 -0
- package/dist/builder/input-schema.d.ts +31 -0
- package/dist/builder/input-schema.d.ts.map +1 -0
- package/dist/builder/leaf.d.ts +24 -0
- package/dist/builder/leaf.d.ts.map +1 -0
- package/dist/chunks/index-rbxe5m3y.js +319 -0
- package/dist/chunks/index-rbxe5m3y.js.map +37 -0
- package/dist/chunks/index-s1kkmg35.js +266 -0
- package/dist/chunks/index-s1kkmg35.js.map +14 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +69 -0
- package/dist/cli.js.map +11 -0
- package/dist/codegen.d.ts +4 -0
- package/dist/codegen.d.ts.map +1 -0
- package/dist/codegen.js +56 -0
- package/dist/codegen.js.map +10 -0
- package/dist/constraint-directive.d.ts +21 -0
- package/dist/constraint-directive.d.ts.map +1 -0
- package/dist/formats/all.d.ts +9 -0
- package/dist/formats/all.d.ts.map +1 -0
- package/dist/formats/byte.d.ts +2 -0
- package/dist/formats/byte.d.ts.map +1 -0
- package/dist/formats/date-time.d.ts +2 -0
- package/dist/formats/date-time.d.ts.map +1 -0
- package/dist/formats/date.d.ts +2 -0
- package/dist/formats/date.d.ts.map +1 -0
- package/dist/formats/email.d.ts +2 -0
- package/dist/formats/email.d.ts.map +1 -0
- package/dist/formats/format.d.ts +15 -0
- package/dist/formats/format.d.ts.map +1 -0
- package/dist/formats/index.d.ts +13 -0
- package/dist/formats/index.d.ts.map +1 -0
- package/dist/formats/ipv4.d.ts +2 -0
- package/dist/formats/ipv4.d.ts.map +1 -0
- package/dist/formats/ipv6.d.ts +2 -0
- package/dist/formats/ipv6.d.ts.map +1 -0
- package/dist/formats/uri.d.ts +2 -0
- package/dist/formats/uri.d.ts.map +1 -0
- package/dist/formats/uuid.d.ts +2 -0
- package/dist/formats/uuid.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +12 -0
- package/dist/rules/all.d.ts +16 -0
- package/dist/rules/all.d.ts.map +1 -0
- package/dist/rules/contains.d.ts +2 -0
- package/dist/rules/contains.d.ts.map +1 -0
- package/dist/rules/ends-with.d.ts +2 -0
- package/dist/rules/ends-with.d.ts.map +1 -0
- package/dist/rules/exclusive-max.d.ts +2 -0
- package/dist/rules/exclusive-max.d.ts.map +1 -0
- package/dist/rules/exclusive-min.d.ts +2 -0
- package/dist/rules/exclusive-min.d.ts.map +1 -0
- package/dist/rules/format.d.ts +2 -0
- package/dist/rules/format.d.ts.map +1 -0
- package/dist/rules/index.d.ts +28 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/max-items.d.ts +2 -0
- package/dist/rules/max-items.d.ts.map +1 -0
- package/dist/rules/max-length.d.ts +2 -0
- package/dist/rules/max-length.d.ts.map +1 -0
- package/dist/rules/max.d.ts +2 -0
- package/dist/rules/max.d.ts.map +1 -0
- package/dist/rules/min-items.d.ts +2 -0
- package/dist/rules/min-items.d.ts.map +1 -0
- package/dist/rules/min-length.d.ts +2 -0
- package/dist/rules/min-length.d.ts.map +1 -0
- package/dist/rules/min.d.ts +2 -0
- package/dist/rules/min.d.ts.map +1 -0
- package/dist/rules/multiple-of.d.ts +2 -0
- package/dist/rules/multiple-of.d.ts.map +1 -0
- package/dist/rules/not-contains.d.ts +2 -0
- package/dist/rules/not-contains.d.ts.map +1 -0
- package/dist/rules/pattern.d.ts +2 -0
- package/dist/rules/pattern.d.ts.map +1 -0
- package/dist/rules/rule.d.ts +55 -0
- package/dist/rules/rule.d.ts.map +1 -0
- package/dist/rules/starts-with.d.ts +2 -0
- package/dist/rules/starts-with.d.ts.map +1 -0
- package/dist/typedefs-command.d.ts +10 -0
- package/dist/typedefs-command.d.ts.map +1 -0
- package/dist/validated.d.ts +22 -0
- package/dist/validated.d.ts.map +1 -0
- package/dist/with-validation.d.ts +26 -0
- package/dist/with-validation.d.ts.map +1 -0
- package/docs/README.md +15 -0
- package/docs/guide/constraints.md +291 -0
- package/docs/guide/errors.md +194 -0
- package/docs/roadmap.md +31 -0
- package/docs/troubleshooting.md +260 -0
- package/graphql/constraint.graphqls +20 -0
- package/package.json +73 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Steve Tsala
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,236 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @nxgt/graphql-validation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Validate GraphQL arguments and input fields with `@constraint` directives
|
|
4
|
+
written in your schema. Each directive becomes a Zod schema that checks the
|
|
5
|
+
arguments before your resolver runs; an invalid input is one `BAD_USER_INPUT`
|
|
6
|
+
error that lists every reason with its path, so a form can show each one beside
|
|
7
|
+
its field. For schema-first servers on `graphql` 16 and 17 (`graphql-js`,
|
|
8
|
+
GraphQL Yoga, Apollo Server).
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
bun add @nxgt/graphql-validation graphql zod typescript
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Peers, all **required**:
|
|
17
|
+
|
|
18
|
+
| Peer | Range |
|
|
19
|
+
| --- | --- |
|
|
20
|
+
| `graphql` | `^16.11.0 \|\| ^17.0.0` |
|
|
21
|
+
| `zod` | `>=4.6.5 <5` |
|
|
22
|
+
| `typescript` | `^6.0.3` |
|
|
23
|
+
|
|
24
|
+
Your `tsconfig.json` needs:
|
|
25
|
+
|
|
26
|
+
```jsonc
|
|
27
|
+
{
|
|
28
|
+
"compilerOptions": {
|
|
29
|
+
"moduleResolution": "bundler" // `nodenext` is not supported
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### Constrain arguments and input fields
|
|
37
|
+
|
|
38
|
+
Add `constraintTypeDefs` to your type definitions, write `@constraint(...)`,
|
|
39
|
+
build the schema with any schema-first builder (`buildSchema` from `graphql`,
|
|
40
|
+
or `makeExecutableSchema` from `@graphql-tools/schema` as below), then call
|
|
41
|
+
`withValidation(schema)` **last**, once every resolver is attached.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { makeExecutableSchema } from '@graphql-tools/schema';
|
|
45
|
+
import { constraintTypeDefs, withValidation } from '@nxgt/graphql-validation';
|
|
46
|
+
|
|
47
|
+
const typeDefs = [
|
|
48
|
+
constraintTypeDefs,
|
|
49
|
+
/* GraphQL */ `
|
|
50
|
+
input SignUp {
|
|
51
|
+
email: String! @constraint(format: "email", maxLength: 254)
|
|
52
|
+
age: Int @constraint(min: 18)
|
|
53
|
+
tags: [String!] @constraint(maxItems: 5, maxLength: 20)
|
|
54
|
+
}
|
|
55
|
+
type Query {
|
|
56
|
+
user(id: ID! @constraint(format: "uuid")): String
|
|
57
|
+
}
|
|
58
|
+
type Mutation {
|
|
59
|
+
signUp(input: SignUp!): Boolean
|
|
60
|
+
}
|
|
61
|
+
`,
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const resolvers = {
|
|
65
|
+
Mutation: {
|
|
66
|
+
// `input` is already checked: this only runs for a valid one
|
|
67
|
+
signUp: (_: unknown, { input }: { input: { email: string } }) => {
|
|
68
|
+
console.log(input.email);
|
|
69
|
+
return true;
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const schema = withValidation(makeExecutableSchema({ typeDefs, resolvers }));
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`withValidation` wraps, in place, the resolver of each field that has
|
|
78
|
+
something to check, and returns the same schema. A subscription field is
|
|
79
|
+
checked once, in `subscribe`. Calling it twice wraps nothing twice. A
|
|
80
|
+
constraint that cannot apply throws when you call it, not on the first
|
|
81
|
+
request. The resolver receives the parsed arguments.
|
|
82
|
+
|
|
83
|
+
Every argument, its rule and its Zod equivalent, and the formats, are in
|
|
84
|
+
[Constraints](docs/guide/constraints.md).
|
|
85
|
+
|
|
86
|
+
### Read the error
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"errors": [
|
|
91
|
+
{
|
|
92
|
+
"message": "Invalid arguments for Mutation.signUp. input.email: Invalid email address",
|
|
93
|
+
"path": ["signUp"],
|
|
94
|
+
"extensions": {
|
|
95
|
+
"code": "BAD_USER_INPUT",
|
|
96
|
+
"issues": [
|
|
97
|
+
{ "path": ["input", "email"], "message": "Invalid email address", "code": "invalid_format", "constraint": "format" },
|
|
98
|
+
{ "path": ["input", "age"], "message": "Too small: expected number to be >=18", "code": "too_small", "constraint": "min" }
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`issues[].path` is relative to the arguments, and `issues[].constraint` names the
|
|
107
|
+
`@constraint` argument that refused. Mapping issues to form fields is
|
|
108
|
+
in [Errors](docs/guide/errors.md).
|
|
109
|
+
|
|
110
|
+
### Rules a directive cannot say
|
|
111
|
+
|
|
112
|
+
`validated(schema, resolver)` checks the arguments with a Zod schema you write,
|
|
113
|
+
for rules across fields, refinements and async checks. It raises the same error.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { validated } from '@nxgt/graphql-validation';
|
|
117
|
+
import { z } from 'zod';
|
|
118
|
+
|
|
119
|
+
const resolvers = {
|
|
120
|
+
Query: {
|
|
121
|
+
range: validated(
|
|
122
|
+
z
|
|
123
|
+
.object({ from: z.number(), to: z.number() })
|
|
124
|
+
.refine(({ from, to }) => from <= to, {
|
|
125
|
+
message: 'from must not exceed to',
|
|
126
|
+
path: ['to'],
|
|
127
|
+
}),
|
|
128
|
+
(_, { from, to }) => to - from,
|
|
129
|
+
),
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## IDE support
|
|
135
|
+
|
|
136
|
+
An IDE's GraphQL plugin (JetBrains GraphQL, VS Code GraphQL) reads your `.graphql`
|
|
137
|
+
files, not `constraintTypeDefs`, so it reports `Unknown directive "@constraint"`.
|
|
138
|
+
The package ships the directive as a file; add it to your `graphql.config.yml`:
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
schema:
|
|
142
|
+
- src/**/*.graphql
|
|
143
|
+
- node_modules/@nxgt/graphql-validation/graphql/constraint.graphqls
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
If your IDE does not index `node_modules`, or you want the file committed with
|
|
147
|
+
your schema, write it into the project (Node or Bun), and list that path instead:
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
bunx nxgt-graphql-validation typedefs --out
|
|
151
|
+
# or: npx nxgt-graphql-validation typedefs --out
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`--out` alone writes `generated/graphql/constraint.graphqls`, `--out <file>` writes
|
|
155
|
+
`<file>`, and without `--out` the SDL is printed. Regenerate the file after upgrading the package.
|
|
156
|
+
|
|
157
|
+
The schema must declare `@constraint` once. Pick one source for the server:
|
|
158
|
+
|
|
159
|
+
- **The generated file is part of your schema.** If the server loads its
|
|
160
|
+
type definitions by scanning `*.graphql(s)` files and the copy sits among
|
|
161
|
+
them, it already declares the directive: do not add `constraintTypeDefs`.
|
|
162
|
+
- **`constraintTypeDefs` declares it.** Then the copy is for the IDE only:
|
|
163
|
+
keep it out of the folders the server scans (or exclude it from the glob).
|
|
164
|
+
|
|
165
|
+
Both give the same schema, and `withValidation` accepts either: it checks that
|
|
166
|
+
the directive declared is this package's. Both at once throw
|
|
167
|
+
`There can be only one directive named "@constraint".`
|
|
168
|
+
|
|
169
|
+
## Exports
|
|
170
|
+
|
|
171
|
+
| Export | Is |
|
|
172
|
+
| --- | --- |
|
|
173
|
+
| `constraintTypeDefs` | the SDL of `@constraint`, to add to `typeDefs` |
|
|
174
|
+
| `withValidation(schema)` | checks every `@constraint` of a schema before its resolvers run |
|
|
175
|
+
| `validated(schema \| shape, resolver)` | a resolver whose arguments a Zod schema checks |
|
|
176
|
+
| `badUserInput(where, zodError)` | builds the error above, for code that validates by hand |
|
|
177
|
+
| `ValidationIssue`, `BadUserInputExtensions` | the types of `extensions.issues` and `extensions` |
|
|
178
|
+
| `ConstraintArgument` | the type of `issues[].constraint`: `'minLength' \| 'format' \| ...` |
|
|
179
|
+
| `ArgsSchema`, `SchemaOf` | the types `validated` accepts |
|
|
180
|
+
|
|
181
|
+
`@nxgt/graphql-validation/codegen` is for a code generator, such as
|
|
182
|
+
[`@nxgt/graphql-codegen-zod`](https://www.npmjs.com/package/@nxgt/graphql-codegen-zod): it writes the schemas `withValidation` builds as source, and
|
|
183
|
+
refuses the schemas `withValidation` refuses. A server does not need it.
|
|
184
|
+
|
|
185
|
+
| Export | Is |
|
|
186
|
+
| --- | --- |
|
|
187
|
+
| `checkConstraints(schema, onArgs?)` | runs every startup check of `withValidation` without wrapping anything; returns the `@constraint` directive, or `undefined` when the schema declares none |
|
|
188
|
+
| `constraintsOn(directive, node)` | the `Constraint`s written on an argument or input field (`arg.astNode`), `format` first |
|
|
189
|
+
| `inputCode(type, constraints, where, named, options?)` | the schema of that argument or field as source, `z` a free identifier: built-in scalars and lists written in full, nullable types `.nullish()`; every other named type (enum, input object, custom scalar) is what `named(type)` returns. A constraint that cannot apply throws the startup message, naming `where`. `options` (`InputCodeOptions`): `list({ type, code, single })` returns each list's source, given `code` (the array with every rule) and `single` (the list's named type, non-null, without rules), e.g. to take a single value as graphql does: `single`, wrapped, piped into `code` |
|
|
190
|
+
| `Constraint` | `{ rule, value }`, one `@constraint` argument. Of `rule`, read `argument` (`'minItems'`, `'format'`, …), `target` (`'list'` for `minItems`/`maxItems`, else what the rule narrows) and `base` (`true` for `format`, which picks the schema the others narrow); the rest is internal |
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import { checkConstraints, constraintsOn, inputCode } from '@nxgt/graphql-validation/codegen';
|
|
194
|
+
|
|
195
|
+
const directive = checkConstraints(schema); // throws what withValidation would
|
|
196
|
+
const arg = schema.getMutationType()!.getFields().signUp!.args[0]!;
|
|
197
|
+
const source = inputCode(
|
|
198
|
+
arg.type,
|
|
199
|
+
constraintsOn(directive, arg.astNode),
|
|
200
|
+
'Mutation.signUp(input:)', // named in errors, as at startup
|
|
201
|
+
(type) => `z${type.name}`, // enums, input objects, custom scalars
|
|
202
|
+
);
|
|
203
|
+
// e.g. 'zSignUpInput' — or, for `name: String @constraint(minLength: 2)`,
|
|
204
|
+
// 'z.string().min(2).nullish()'
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Also shipped, outside `exports`:
|
|
208
|
+
|
|
209
|
+
| File | Is |
|
|
210
|
+
| --- | --- |
|
|
211
|
+
| `graphql/constraint.graphqls` | the SDL of `@constraint` for IDEs; reference it by path, it is not importable |
|
|
212
|
+
| `nxgt-graphql-validation` (bin) | `typedefs [--out [<file>]]` prints or writes that SDL; `--help` |
|
|
213
|
+
|
|
214
|
+
## Traps
|
|
215
|
+
|
|
216
|
+
- `@constraint` is read from the SDL. A code-first schema does not declare the
|
|
217
|
+
directive, so `withValidation` throws; one that declares it but whose
|
|
218
|
+
constrained types and fields have no SDL (code-first, or merged pieces) is
|
|
219
|
+
checked for nothing, and no error says so. Use type definitions.
|
|
220
|
+
- Call `withValidation` last: a resolver set on a field afterwards replaces
|
|
221
|
+
the check.
|
|
222
|
+
- A `@constraint` on an interface field's argument must be repeated on each
|
|
223
|
+
implementing object's field, or `withValidation` throws at startup.
|
|
224
|
+
- `@constraint` is refused on an output field:
|
|
225
|
+
`Directive "@constraint" may not be used on FIELD_DEFINITION.`
|
|
226
|
+
- `format: "date-time"` takes the canonical RFC 3339 form only (uppercase `T`
|
|
227
|
+
and `Z`, seconds present).
|
|
228
|
+
|
|
229
|
+
Every startup error and its fix is in [Troubleshooting](docs/troubleshooting.md).
|
|
230
|
+
|
|
231
|
+
## Documentation
|
|
232
|
+
|
|
233
|
+
- [Documentation index](docs/README.md)
|
|
234
|
+
- Guides: [Constraints](docs/guide/constraints.md), [Errors](docs/guide/errors.md)
|
|
235
|
+
- [Troubleshooting](docs/troubleshooting.md)
|
|
236
|
+
- [Roadmap](docs/roadmap.md): a Zod codegen plugin, your own formats, schemas that read the context
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { GraphQLError } from 'graphql';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
import type { ConstraintArgument } from './rules';
|
|
4
|
+
/** One reason an input was refused, at its path inside the arguments. */
|
|
5
|
+
export interface ValidationIssue {
|
|
6
|
+
/** `['input', 'address', 'zip']`: the argument, then the input fields. */
|
|
7
|
+
readonly path: readonly (string | number)[];
|
|
8
|
+
readonly message: string;
|
|
9
|
+
/** Zod's issue code: `too_small`, `invalid_format`, `custom`, ... */
|
|
10
|
+
readonly code: string;
|
|
11
|
+
/**
|
|
12
|
+
* The `@constraint` argument that refused (`minLength`, `format`), when a
|
|
13
|
+
* directive did: stable across Zod versions, unlike `code`. Absent for a
|
|
14
|
+
* refusal of `validated()`'s own schema.
|
|
15
|
+
*/
|
|
16
|
+
readonly constraint?: ConstraintArgument;
|
|
17
|
+
}
|
|
18
|
+
/** The `extensions` of the error an invalid input becomes. */
|
|
19
|
+
export type BadUserInputExtensions = {
|
|
20
|
+
readonly code: 'BAD_USER_INPUT';
|
|
21
|
+
readonly issues: readonly ValidationIssue[];
|
|
22
|
+
};
|
|
23
|
+
/** Names the `@constraint` argument behind an issue, when there is one. */
|
|
24
|
+
export type ConstraintOf = (issue: z.core.$ZodIssue) => ConstraintArgument | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* The one error an invalid input becomes: `extensions.code` is
|
|
27
|
+
* `BAD_USER_INPUT`, the code Apollo and most clients already read, and
|
|
28
|
+
* `extensions.issues` lists every reason with its path, so a form can show
|
|
29
|
+
* each one beside its field. The message names the field and the first
|
|
30
|
+
* reason, for a log line.
|
|
31
|
+
*/
|
|
32
|
+
export declare function badUserInput(where: string, error: z.ZodError): GraphQLError;
|
|
33
|
+
/** The parsed arguments, or the error above, its issues named by `constraintOf`. */
|
|
34
|
+
export declare function parseArgs(schema: z.ZodType, args: unknown, where: string, constraintOf?: ConstraintOf): Promise<unknown>;
|
|
35
|
+
//# sourceMappingURL=bad-user-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bad-user-input.d.ts","sourceRoot":"","sources":["../src/bad-user-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAED,8DAA8D;AAC9D,MAAM,MAAM,sBAAsB,GAAG;IACpC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC;CAC5C,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,CAC1B,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,KACnB,kBAAkB,GAAG,SAAS,CAAC;AA4BpC;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,YAAY,CAE3E;AAED,oFAAoF;AACpF,wBAAsB,SAAS,CAC9B,MAAM,EAAE,CAAC,CAAC,OAAO,EACjB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,YAAY,GACzB,OAAO,CAAC,OAAO,CAAC,CAKlB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GraphQLField, GraphQLObjectType } from 'graphql';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { InputSchemas } from './input-schema';
|
|
4
|
+
/**
|
|
5
|
+
* The schema of a field's arguments, or `undefined` when none of them can
|
|
6
|
+
* break a constraint, so a field with nothing to check is left untouched.
|
|
7
|
+
* `parent` is the type's name, for errors: `Mutation.signUp(input:)`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function argsSchemaOf(inputs: InputSchemas, parent: string, field: GraphQLField<unknown, unknown>): z.ZodType | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Fails when an object type's field does not repeat the `@constraint` its
|
|
12
|
+
* interface writes on an argument. The object's field is the one that
|
|
13
|
+
* resolves, and graphql lets it redeclare the argument bare: the interface's
|
|
14
|
+
* constraint would then check nothing, in silence.
|
|
15
|
+
*/
|
|
16
|
+
export declare function assertInterfaceConstraintsKept(inputs: InputSchemas, type: GraphQLObjectType): void;
|
|
17
|
+
//# sourceMappingURL=args-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args-schema.d.ts","sourceRoot":"","sources":["../../src/builder/args-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,GACnC,CAAC,CAAC,OAAO,GAAG,SAAS,CAUvB;AAcD;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC7C,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,iBAAiB,GACrB,IAAI,CAoBN"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type GraphQLDirective, type GraphQLField, type GraphQLObjectType, type GraphQLSchema } from 'graphql';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* Runs every check `withValidation` makes at startup, so a code generator
|
|
5
|
+
* refuses the same schemas: the declaration is `constraintTypeDefs`', every
|
|
6
|
+
* constraint applies where it is written (in every input type), none sits on
|
|
7
|
+
* a directive's argument, objects keep their interfaces' constraints, and no
|
|
8
|
+
* default value breaks its own. `onArgs` receives each object field's
|
|
9
|
+
* arguments schema, for a field with something to check.
|
|
10
|
+
*
|
|
11
|
+
* Returns the `@constraint` directive, or `undefined` when the schema
|
|
12
|
+
* declares none (and so carries no constraint).
|
|
13
|
+
*/
|
|
14
|
+
export declare function checkConstraints(schema: GraphQLSchema, onArgs?: (type: GraphQLObjectType, field: GraphQLField<unknown, unknown>, args: z.ZodType) => void): GraphQLDirective | undefined;
|
|
15
|
+
//# sourceMappingURL=check-constraints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-constraints.d.ts","sourceRoot":"","sources":["../../src/builder/check-constraints.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAGlB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAM7B;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,aAAa,EACrB,MAAM,CAAC,EAAE,CACR,IAAI,EAAE,iBAAiB,EACvB,KAAK,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EACrC,IAAI,EAAE,CAAC,CAAC,OAAO,KACX,IAAI,GACP,gBAAgB,GAAG,SAAS,CAyB9B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type DirectiveNode, type GraphQLDirective } from 'graphql';
|
|
2
|
+
import { type RegisteredRule } from '../rules';
|
|
3
|
+
/** One `@constraint` argument written on an argument or an input field. */
|
|
4
|
+
export interface Constraint {
|
|
5
|
+
readonly rule: RegisteredRule;
|
|
6
|
+
readonly value: string | number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The constraints written on a node, base rules (`format`) first so the
|
|
10
|
+
* others narrow the schema they produce. Empty when the schema declares no
|
|
11
|
+
* `@constraint` or the node carries none.
|
|
12
|
+
*/
|
|
13
|
+
export declare function constraintsOn(directive: GraphQLDirective | undefined, node: {
|
|
14
|
+
readonly directives?: ReadonlyArray<DirectiveNode> | undefined;
|
|
15
|
+
} | null | undefined): Constraint[];
|
|
16
|
+
//# sourceMappingURL=constraints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraints.d.ts","sourceRoot":"","sources":["../../src/builder/constraints.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,gBAAgB,EAErB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,KAAK,cAAc,EAAS,MAAM,UAAU,CAAC;AAEtD,2EAA2E;AAC3E,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC5B,SAAS,EAAE,gBAAgB,GAAG,SAAS,EACvC,IAAI,EACD;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,SAAS,CAAA;CAAE,GAClE,IAAI,GACJ,SAAS,GACV,UAAU,EAAE,CAad"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type GraphQLInputType, type GraphQLList, type GraphQLNamedInputType } from 'graphql';
|
|
2
|
+
import type { Constraint } from './constraints';
|
|
3
|
+
/**
|
|
4
|
+
* The source of the schema of one argument or input field: what
|
|
5
|
+
* `InputSchemas` builds at startup, written for a code generator. The
|
|
6
|
+
* source names zod as a free `z`.
|
|
7
|
+
*
|
|
8
|
+
* The runtime leaves what graphql already checked to graphql; generated
|
|
9
|
+
* code checks every value, so each named type comes from `named`: an input
|
|
10
|
+
* object's or an enum's schema by name, a custom scalar's from a mapping.
|
|
11
|
+
* The built-in scalars are written here, with their constraints. A
|
|
12
|
+
* constraint that cannot apply fails as it does at startup.
|
|
13
|
+
*/
|
|
14
|
+
export declare function inputCode(type: GraphQLInputType, constraints: readonly Constraint[], where: string, named: (type: GraphQLNamedInputType) => string, options?: InputCodeOptions): string;
|
|
15
|
+
/** How `inputCode` writes what a generator may want written otherwise. */
|
|
16
|
+
export interface InputCodeOptions {
|
|
17
|
+
/**
|
|
18
|
+
* A list's schema, given its `type`, `code` (the array with every rule)
|
|
19
|
+
* and `single` (the list's named type, non-null, without rules): to
|
|
20
|
+
* take a single value for a list, as graphql does, `single` wrapped then
|
|
21
|
+
* piped into `code`. Default: `code`.
|
|
22
|
+
*/
|
|
23
|
+
readonly list?: (list: {
|
|
24
|
+
readonly type: GraphQLList<GraphQLInputType>;
|
|
25
|
+
readonly code: string;
|
|
26
|
+
readonly single: string;
|
|
27
|
+
}) => string;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=input-code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-code.d.ts","sourceRoot":"","sources":["../../src/builder/input-code.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAK1B,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACxB,IAAI,EAAE,gBAAgB,EACtB,WAAW,EAAE,SAAS,UAAU,EAAE,EAClC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,MAAM,EAC9C,OAAO,GAAE,gBAAqB,GAC5B,MAAM,CAGR;AAED,0EAA0E;AAC1E,MAAM,WAAW,gBAAgB;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE;QACtB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;QAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACxB,KAAK,MAAM,CAAC;CACb"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type GraphQLArgument, type GraphQLDirective, type GraphQLInputField, type GraphQLInputType, type GraphQLSchema } from 'graphql';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the schemas of the arguments and input fields of one GraphQL
|
|
5
|
+
* schema, once each: an input type is walked a single time however many
|
|
6
|
+
* fields use it, and a recursive one (`input Filter { and: [Filter!] }`) is
|
|
7
|
+
* reached through `z.lazy`.
|
|
8
|
+
*/
|
|
9
|
+
export declare class InputSchemas {
|
|
10
|
+
#private;
|
|
11
|
+
readonly directive: GraphQLDirective | undefined;
|
|
12
|
+
constructor(schema: GraphQLSchema);
|
|
13
|
+
/** Whether a value of this type can break a constraint anywhere inside. */
|
|
14
|
+
isConstrained(type: GraphQLInputType): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Builds every constrained input type, reached by an argument or not, so
|
|
17
|
+
* a constraint that cannot apply fails at startup wherever it is written.
|
|
18
|
+
*/
|
|
19
|
+
buildAll(schema: GraphQLSchema): void;
|
|
20
|
+
/** Whether an argument or input field needs checking at all. */
|
|
21
|
+
needsCheck(input: GraphQLArgument | GraphQLInputField): boolean;
|
|
22
|
+
/** The schema of one argument or input field, `where` naming it in errors. */
|
|
23
|
+
of(input: GraphQLArgument | GraphQLInputField, where: string): z.ZodType;
|
|
24
|
+
/**
|
|
25
|
+
* Fails when a default value breaks its own constraint: every request that
|
|
26
|
+
* leaves the value out would be refused for something the client never
|
|
27
|
+
* sent. Run once every schema is built, so a recursive type is complete.
|
|
28
|
+
*/
|
|
29
|
+
checkDefaults(): void;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=input-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-schema.d.ts","sourceRoot":"","sources":["../../src/builder/input-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EAEtB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAMlB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;GAKG;AACH,qBAAa,YAAY;;IACxB,QAAQ,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAAC;gBAWrC,MAAM,EAAE,aAAa;IAwBjC,2EAA2E;IAC3E,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO;IAK9C;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAMrC,gEAAgE;IAChE,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,iBAAiB,GAAG,OAAO;IAO/D,8EAA8E;IAC9E,EAAE,CAAC,KAAK,EAAE,eAAe,GAAG,iBAAiB,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO;IAYxE;;;;OAIG;IACH,aAAa,IAAI,IAAI;CAoErB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type GraphQLLeafType } from 'graphql';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { Target } from '../rules/rule';
|
|
4
|
+
import type { Constraint } from './constraints';
|
|
5
|
+
/**
|
|
6
|
+
* Fails unless every constraint applies to a value of `type`: `minLength` on
|
|
7
|
+
* an `Int`, anything on a custom scalar or an enum, fails, naming `where`.
|
|
8
|
+
* The runtime and the code generator refuse the same schemas with the same
|
|
9
|
+
* message.
|
|
10
|
+
*/
|
|
11
|
+
export declare function assertLeafTargets(type: GraphQLLeafType, constraints: readonly Constraint[], where: string): void;
|
|
12
|
+
/** Fails when an input object carries a constraint: none applies to it. */
|
|
13
|
+
export declare function assertObjectTargets(typeName: string, constraints: readonly Constraint[], where: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* The schema of a scalar or enum value with its constraints applied. A leaf
|
|
16
|
+
* without any is left as graphql parsed it. A constraint that cannot apply
|
|
17
|
+
* fails here, at startup.
|
|
18
|
+
*/
|
|
19
|
+
export declare function leafSchema(type: GraphQLLeafType, constraints: readonly Constraint[], where: string): z.ZodType;
|
|
20
|
+
/** The source of a built-in scalar's schema, before its constraints. */
|
|
21
|
+
export declare function baseCode(type: GraphQLLeafType): string | undefined;
|
|
22
|
+
/** What a rule's target reads as in an error. */
|
|
23
|
+
export declare function describeTarget(target: Target): string;
|
|
24
|
+
//# sourceMappingURL=leaf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leaf.d.ts","sourceRoot":"","sources":["../../src/builder/leaf.ts"],"names":[],"mappings":"AAAA,OAAO,EAKN,KAAK,eAAe,EAEpB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAehD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,eAAe,EACrB,WAAW,EAAE,SAAS,UAAU,EAAE,EAClC,KAAK,EAAE,MAAM,GACX,IAAI,CAMN;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAClC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,SAAS,UAAU,EAAE,EAClC,KAAK,EAAE,MAAM,GACX,IAAI,CAIN;AAYD;;;;GAIG;AACH,wBAAgB,UAAU,CACzB,IAAI,EAAE,eAAe,EACrB,WAAW,EAAE,SAAS,UAAU,EAAE,EAClC,KAAK,EAAE,MAAM,GACX,CAAC,CAAC,OAAO,CAQX;AAED,wEAAwE;AACxE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAMlE;AAED,iDAAiD;AACjD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIrD"}
|