@nxgt/graphql-codegen-zod 0.1.0 → 0.2.1

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.
@@ -1,11 +1,14 @@
1
1
  # Output
2
2
 
3
3
  What the plugin writes from your schema and operations: the schemas, the
4
- types, their names, and how defaults, recursion, `@oneOf` and custom scalars
5
- come out.
4
+ types, their names, and how defaults, recursion, `@oneOf`, custom scalars,
5
+ output types and operation results come out.
6
6
 
7
7
  ## The smallest example
8
8
 
9
+ The SDL files for `@constraint` and the scalars, and how to run codegen, are in
10
+ the README's [Setup](../../README.md#setup).
11
+
9
12
  ```graphql
10
13
  # schema
11
14
  input SignUpInput {
@@ -41,8 +44,11 @@ export default config;
41
44
  ```
42
45
 
43
46
  The plugin writes, in this order: every enum, every input type, the
44
- arguments of every object or interface field that takes any, then the
45
- variables of every named operation. Each is a schema and its type.
47
+ arguments of every object or interface field that takes any, every object
48
+ type, then every interface and union (see [Output types](#output-types)),
49
+ then the variables of every named operation. The results come last: every
50
+ fragment's, then every named operation's (see
51
+ [Operation results](#operation-results)). Each is a schema and its type.
46
52
 
47
53
  ```ts
48
54
  import { z } from "zod";
@@ -65,6 +71,12 @@ export const zMutationSignUpArgs = z.object({
65
71
  });
66
72
  export type MutationSignUpArgs = z.output<typeof zMutationSignUpArgs>;
67
73
 
74
+ export const zMutation = z.object({
75
+ __typename: z.literal("Mutation").optional(),
76
+ signUp: z.boolean().nullish(),
77
+ });
78
+ export type Mutation = z.output<typeof zMutation>;
79
+
68
80
  export const zSignUpMutationVariables = z.object({
69
81
  get input() {
70
82
  return zSignUpInput;
@@ -99,6 +111,9 @@ export const zQueryUserArgs = z.object({
99
111
  | `z<Input>` | an `input` | `z.output` | the value a resolver receives |
100
112
  | `z<Parent><Field>Args` | an object or interface field with arguments | `z.output` | typing the resolver's arguments |
101
113
  | `z<Operation><Kind>Variables` | a named operation in `documents` | `z.input` | checking a form before sending it |
114
+ | `z<Type>` | an object type, interface or union | `z.output` | typing what a resolver returns; `z.encode` checks it |
115
+ | `z<Operation><Kind>` | a named operation in `documents` | `z.output` | parsing the response on the client |
116
+ | `z<Fragment>Fragment` | a fragment in `documents` | `z.output` | parsing the part of a response a fragment selects |
102
117
 
103
118
  `z.output` is what a resolver receives after `withValidation` parsed the
104
119
  arguments; `z.input` is what a client sends. They differ where a default
@@ -139,6 +154,9 @@ and `typescript-operations` give them.
139
154
  | enum | `zRole` | `Role` |
140
155
  | field arguments | `zMutationSignUpArgs` | `MutationSignUpArgs` |
141
156
  | operation variables | `zSignUpMutationVariables` | `SignUpMutationVariables` |
157
+ | object type, interface, union | `zUser` | `User` |
158
+ | operation result | `zSearchQuery` | `SearchQuery` |
159
+ | fragment | `zUserFieldsFragment` | `UserFieldsFragment` |
142
160
 
143
161
  | Option | Type | Default | Effect |
144
162
  | --- | --- | --- | --- |
@@ -147,8 +165,8 @@ and `typescript-operations` give them.
147
165
  | `typesPrefix` | `string` | `''` | before each type's name: `ISignUpInput`; the schema's name follows: `zISignUpInput` |
148
166
  | `typesSuffix` | `string` | `''` | after each type's name |
149
167
  | `addUnderscoreToArgsType` | `boolean` | `false` | `Query_FindUserArgs` instead of `QueryFindUserArgs` |
150
- | `dedupeOperationSuffix` | `boolean` | `false` | `findUserQuery` gives `FindUserQueryVariables`, not `FindUserQueryQueryVariables` |
151
- | `omitOperationSuffix` | `boolean` | `false` | `FindUserVariables`: no `Query`, `Mutation` or `Subscription` |
168
+ | `dedupeOperationSuffix` | `boolean` | `false` | `findUserQuery` gives `FindUserQueryVariables` and `FindUserQuery`, not `FindUserQueryQueryVariables` and `FindUserQueryQuery`; a fragment `UFFragment` gives `UfFragment` |
169
+ | `omitOperationSuffix` | `boolean` | `false` | `FindUserVariables`, `FindUser`: no `Query`, `Mutation`, `Subscription` or `Fragment` |
152
170
 
153
171
  ```ts
154
172
  config: {
@@ -181,7 +199,9 @@ Any other module string (`'my-module#myCase'`) throws, see
181
199
 
182
200
  Generate into a file the typescript plugins do not write to: the names would
183
201
  collide. This plugin's types can replace the typescript plugin's `*Args` and
184
- `*Variables`, so the other plugins can be limited to the output types.
202
+ `*Variables`, and typescript-operations' `*Query`, `*Mutation` and `*Fragment`,
203
+ so the other plugins can be limited to the output types. Or set
204
+ `operations: false`, and keep those from typescript-operations.
185
205
 
186
206
  ## Defaults
187
207
 
@@ -430,6 +450,258 @@ price: moneySchema,
430
450
  - A rule on a custom scalar (`@constraint` on a `DateTime` field) is refused,
431
451
  as `withValidation` refuses it; check the value in the scalar's own schema.
432
452
 
453
+ ## Output types
454
+
455
+ Every object type gets a schema and a type, typed `z.output`: what a
456
+ resolver returns. The root types are written too: a field may return
457
+ `Query` (a mutation payload's `query: Query!`). Then every interface and union, as a `z.union` of its
458
+ object types. `objects: false` writes none of them.
459
+
460
+ ```graphql
461
+ """Someone with an account."""
462
+ type User implements Node {
463
+ id: ID!
464
+ name: String!
465
+ role: Role
466
+ "Who they follow."
467
+ friends: [User!]
468
+ pinned: SearchResult
469
+ joined: DateTime!
470
+ }
471
+ union SearchResult = User | Post
472
+ ```
473
+
474
+ A type outside any cycle is a `z.object`, its type inferred:
475
+
476
+ ```ts
477
+ export const zMutation = z.object({
478
+ __typename: z.literal("Mutation").optional(),
479
+ signUp: z.boolean().nullish(),
480
+ });
481
+ export type Mutation = z.output<typeof zMutation>;
482
+
483
+ export const zSearchResult = z.union([zUser, zPost]);
484
+ export type SearchResult = z.output<typeof zSearchResult>;
485
+ ```
486
+
487
+ An interface no object type implements is `z.never()`; a union of one
488
+ member is that member's schema.
489
+
490
+ A type in a cycle (`User.friends: [User!]`, or `User` → `Org` → `User`) has
491
+ its types written out, as an input type in a cycle has: TypeScript infers a
492
+ looping schema only so deep, and fails with TS2589 on a loop of ten types.
493
+ `User` is what a resolver returns, `UserWire` the wire value (not
494
+ `UserInput`, which an SDL `input UserInput` often already takes), and `zUser`
495
+ is typed by both:
496
+
497
+ ```ts
498
+ /** Someone with an account. */
499
+ export type User = {
500
+ __typename?: "User" | undefined;
501
+ id: string;
502
+ name: string;
503
+ role?: z.output<typeof zRole> | null | undefined;
504
+ /** Who they follow. */
505
+ friends?: Array<User> | null | undefined;
506
+ pinned?: z.output<typeof zSearchResult> | null | undefined;
507
+ joined: z.output<typeof scalarSchemas.DateTime>;
508
+ };
509
+ /** Someone with an account. */
510
+ export type UserWire = {
511
+ /* the same, with z.input for scalars, UserWire, z.input<typeof zSearchResult> */
512
+ };
513
+ /** Someone with an account. */
514
+ export const zUser: z.ZodType<User, UserWire> = z.object({
515
+ __typename: z.literal("User").optional(),
516
+ id: z.string(),
517
+ name: z.string(),
518
+ role: zRole.nullish(),
519
+ /** Who they follow. */
520
+ get friends() {
521
+ return z.array(zUser).nullish();
522
+ },
523
+ get pinned() {
524
+ return zSearchResult.nullish();
525
+ },
526
+ joined: scalarSchemas.DateTime,
527
+ });
528
+ ```
529
+
530
+ `zUser` is then a `z.ZodType`, not a `z.ZodObject`: `.shape`, `.pick` and
531
+ `.extend` are not offered on a type in a cycle.
532
+
533
+ - **`__typename` is optional:** a resolver rarely sets it. When it is set, it
534
+ must be the type's name.
535
+ - **A field the type does not declare is dropped** (`z.object`): a newer
536
+ server's extra field does not fail a parse.
537
+ - **Custom scalars are decoded:** `User['joined']` is a `Date` with
538
+ `@nxgt/graphql-scalars`; `z.input<typeof zUser>` has the wire `string`.
539
+ - **Every field is written**, arguments ignored: `User` is the whole type, as
540
+ `@graphql-codegen/typescript` writes it.
541
+ - **Nesting goes through getters**, so types refer to each other in any
542
+ order. Interfaces and unions are declared after every object type.
543
+ - `Int` is `z.int32()` and `ID` a `z.string()`, as for inputs. A nullable
544
+ field is `.nullish()`.
545
+ - **Every custom scalar needs a schema**, an output-only one included
546
+ (`createdAt: DateTime` on an object type): generation fails naming it,
547
+ as for inputs. 0.1.0 did not read output fields, and nor operations'
548
+ results; 0.1.0's output needs both `objects: false` and `operations: false`.
549
+ - **A name the plugin already writes clashes:** an object type named
550
+ `QueryFindArgs`, or `FilterInput` beside a cyclic input `Filter`, fails
551
+ generation with "would declare … twice". Rename it, set `typesSuffix`, or
552
+ set `objects: false` (or `operations: false`, for a clash with a result
553
+ such as `SearchQuery`).
554
+
555
+ ## Operation results
556
+
557
+ Each fragment and each named operation gets a schema and a type, typed
558
+ `z.output`: the response as it arrives, under the aliases the document gave.
559
+ `operations: false` writes none of them; the variables stay. An anonymous
560
+ operation gets none, as for variables.
561
+
562
+ ```graphql
563
+ query Search($text: String!, $id: ID!, $withTags: Boolean!) {
564
+ search(text: $text) {
565
+ __typename
566
+ ... on User { id who: name joined role }
567
+ ... on Post { id title tags @include(if: $withTags) author { ...UserFields } }
568
+ }
569
+ node(id: $id) { __typename id kind: __typename }
570
+ }
571
+ fragment UserFields on User { id name }
572
+ ```
573
+
574
+ ```ts
575
+ export const zSearchQuery = z.object({
576
+ search: z.array(z.discriminatedUnion("__typename", [
577
+ z.object({
578
+ __typename: z.literal("User"),
579
+ id: z.string(),
580
+ who: z.string(),
581
+ joined: scalarSchemas.DateTime,
582
+ role: zRole.nullable(),
583
+ }),
584
+ z.object({
585
+ __typename: z.literal("Post"),
586
+ id: z.string(),
587
+ title: z.string(),
588
+ tags: z.array(z.array(z.string().nullable()).nullable()).nullable().optional(),
589
+ author: z.object({
590
+ id: z.string(),
591
+ name: z.string(),
592
+ }),
593
+ }),
594
+ ])),
595
+ node: z.object({
596
+ __typename: z.enum(["User", "Post"]),
597
+ id: z.string(),
598
+ kind: z.enum(["User", "Post"]),
599
+ }).nullable(),
600
+ });
601
+ export type SearchQuery = z.output<typeof zSearchQuery>;
602
+
603
+ export const zUserFieldsFragment = z.object({
604
+ id: z.string(),
605
+ name: z.string(),
606
+ });
607
+ export type UserFieldsFragment = z.output<typeof zUserFieldsFragment>;
608
+ ```
609
+
610
+ - **Custom scalars are decoded:** `joined` is a `Date` with
611
+ `@nxgt/graphql-scalars`.
612
+ - **`z.object`:** a field the selection does not name is dropped, so a newer
613
+ server's extra field does not fail a parse.
614
+ - **A fragment spread is inlined** into the operation: `author` holds
615
+ `UserFields`' `id` and `name`. A fragment has its own schema too, and the
616
+ inlined one is not a reference to it.
617
+ - **An abstract type's selection is a `z.discriminatedUnion` on
618
+ `__typename`** when its possible types select different fields, and then
619
+ `__typename` must be selected for every member. Without it generation
620
+ fails, see [Troubleshooting](../troubleshooting.md). A `__typename` under
621
+ `@skip` or `@include` does not count.
622
+ - **Possible types that select the same fields share one member**, with
623
+ `__typename: z.enum([...])`: `node` selects only `id` and `kind`, the same
624
+ for `User` and `Post`. A single group is a plain object, not a union.
625
+ - **When every possible type selects the same fields, `__typename` is not
626
+ needed:** the result is one plain object. `plain: node(id: $id) { id }`
627
+ gives `plain: z.object({ id: z.string() }).nullable()`. Selected there,
628
+ `__typename` is `z.enum([...])`.
629
+ - **An aliased `__typename` is the discriminator under its alias:** the
630
+ union is discriminated on `kind` if the document selects only
631
+ `kind: __typename`. The members must select it under one key; when several
632
+ keys select it, `__typename` is preferred. Otherwise generation fails.
633
+ - **A field under `@skip`, `@include` or `@defer` is `.optional()`:** `tags`
634
+ may be absent. A field selected both with and without the directive is
635
+ required, but a sub-field that only the conditional node selects stays
636
+ optional: with `friends { id } friends @include(if: $v) { name }`, `name`
637
+ is optional. A field selected only under the directive is optional, and
638
+ its own fields are not: `maybe: user(id: $id) @include(if: $v) { id }`
639
+ gives `{ id: string } | null | undefined`.
640
+ - **A nullable field is `.nullable()`**, not `.nullish()`: a response holds
641
+ null, not undefined.
642
+ - `Int` is `z.int32()` and `ID` a `z.string()`, as elsewhere. An enum is its
643
+ schema (`zRole`).
644
+ - **An introspection field** (`__schema`, `__type`) is `z.unknown()`.
645
+
646
+ **Deep selections.** Past five nested levels, a selection is declared apart,
647
+ so TypeScript infers an operation of any depth (it failed with TS2589 at
648
+ fourteen levels). The helpers are not exported; identical deep selections
649
+ share one:
650
+
651
+ ```ts
652
+ const zDeepQuery$1$ = z.object({ /* the selection */ });
653
+ const zDeepQuery$1: z.ZodType<z.output<typeof zDeepQuery$1$>, z.input<typeof zDeepQuery$1$>> = zDeepQuery$1$;
654
+ // zDeepQuery$2 and zDeepQuery$3 the same way, each using the one before.
655
+ export const zDeepQuery = z.object({
656
+ user: z.object({
657
+ friends: z.array(z.object({
658
+ friends: z.array(z.object({
659
+ friends: z.array(z.object({
660
+ friends: z.array(zDeepQuery$3).nullable(),
661
+ })).nullable(),
662
+ })).nullable(),
663
+ })).nullable(),
664
+ }).nullable(),
665
+ });
666
+ ```
667
+
668
+ A fragment's name follows `omitOperationSuffix` and `dedupeOperationSuffix`,
669
+ as typescript-operations names it: `fragment UserFields` is
670
+ `UserFieldsFragment`, and `UserFields` under `omitOperationSuffix`;
671
+ `fragment UFFragment` is `UfFragmentFragment`, and `UfFragment` under either
672
+ option.
673
+
674
+ A fragment on an abstract type, or one that spreads into several places,
675
+ follows the same rules. Here `Pinned` selects `pinned`, a union, whose `User`
676
+ member holds only `__typename`:
677
+
678
+ ```ts
679
+ export const zPinnedFragment = z.object({
680
+ pinned: z.discriminatedUnion("__typename", [
681
+ z.object({
682
+ __typename: z.literal("User"),
683
+ }),
684
+ z.object({
685
+ __typename: z.literal("Post"),
686
+ title: z.string(),
687
+ }),
688
+ ]).nullable(),
689
+ });
690
+ ```
691
+
692
+ On the client, parse the response, then narrow on the discriminator:
693
+
694
+ ```ts
695
+ import { zSearchQuery, type SearchQuery } from './generated/zod';
696
+
697
+ export function names(data: unknown): string[] {
698
+ const { search }: SearchQuery = zSearchQuery.parse(data);
699
+ return search.map((hit) =>
700
+ hit.__typename === 'User' ? hit.who : hit.title,
701
+ );
702
+ }
703
+ ```
704
+
433
705
  ## Errors
434
706
 
435
707
  A schema that declares `@constraint` must be read from its SDL files: an
package/docs/roadmap.md CHANGED
@@ -4,10 +4,10 @@ What `@nxgt/graphql-codegen-zod` is heading for, phrased as what you get.
4
4
 
5
5
  ## Now
6
6
 
7
- - **The first release, 0.1.0.** Zod 4 schemas and types for enums, input
8
- types, field arguments and operation variables, carrying every
9
- `@constraint` of `@nxgt/graphql-validation`, so the client refuses what the
10
- server refuses.
7
+ - **Output types.** Zod schemas and types for the SDL's object types,
8
+ interfaces and unions, and for each named operation's result and each
9
+ fragment, with `__typename` discriminating abstract types. Both parts are
10
+ written; they ship with the next release.
11
11
 
12
12
  ## Next
13
13
 
@@ -32,4 +32,7 @@ Nothing yet.
32
32
 
33
33
  ## Shipped
34
34
 
35
- Nothing yet.
35
+ - **The first release, 0.1.0.** Zod 4 schemas and types for enums, input
36
+ types, field arguments and operation variables, carrying every
37
+ `@constraint` of `@nxgt/graphql-validation`, so the client refuses what the
38
+ server refuses.
@@ -29,10 +29,16 @@ config: { namingConvention: (name) => name.toUpperCase() }
29
29
 
30
30
  ### `@nxgt/graphql-codegen-zod: the scalar Money is not in zodScalars, and no scalarSchemas is set. Map it: zodScalars: { Money: './module#export' }, or set scalarSchemas: '@nxgt/graphql-scalars'.`
31
31
 
32
- **When:** running codegen on a schema with a custom scalar (here `Money`).
32
+ **When:** running codegen on a schema with a custom scalar (here `Money`),
33
+ on an input or, since 0.2.0, on an object type's field or in an operation's
34
+ result only (`createdAt: Money`). 0.1.0 did not read output fields, so such a
35
+ scalar used to need no schema.
33
36
  **Why:** a scalar written as `z.unknown()` would check nothing, in silence, so
34
37
  the plugin refuses instead.
35
- **Fix:** map the scalar, or point `scalarSchemas` at a module that has it.
38
+ **Fix:** map the scalar, or point `scalarSchemas` at a module that has it. If
39
+ the scalar is only on output fields and in operations' results, and you do not
40
+ need those types, `objects: false` and `operations: false` together skip them:
41
+ either alone still reads it, wherever an operation selects the scalar.
36
42
 
37
43
  ```ts
38
44
  config: { zodScalars: { Money: './money#moneySchema' } }
@@ -95,6 +101,38 @@ document.
95
101
  mutation SignUp($input: SignUpInput!) { signUp(input: $input) }
96
102
  ```
97
103
 
104
+ ### `@nxgt/graphql-codegen-zod: Bare.search selects the abstract type SearchResult without __typename for User. Select __typename there, so the result tells its members apart.`
105
+
106
+ **When:** running codegen on a named operation or a fragment. The operation
107
+ (or `fragment <Name>`), the path, the type and the member in the message are
108
+ yours.
109
+ **Why:** when the possible types of an interface or a union select different
110
+ fields, the selection becomes a union discriminated on `__typename`, and
111
+ without it the result cannot tell the members apart. When they all select the
112
+ same fields, no `__typename` is needed. A `__typename` under `@skip` or
113
+ `@include` may be absent, so it counts as missing.
114
+ **Fix:** select `__typename` in that selection, or set `operations: false`.
115
+
116
+ ```graphql
117
+ # fails
118
+ query Bare { search(text: "a") { ... on User { id } } }
119
+ # generates
120
+ query Bare { search(text: "a") { __typename ... on User { id } } }
121
+ ```
122
+
123
+ ### `@nxgt/graphql-codegen-zod: Keys.search selects __typename under a different key for each member of SearchResult (t, k). Select it under one key for every member, so the result tells its members apart.`
124
+
125
+ **When:** running codegen on an operation or a fragment. The path, the type
126
+ and the keys in the message are yours.
127
+ **Why:** the union is discriminated on one key, and the members select
128
+ `__typename` under different aliases. When several keys select it,
129
+ `__typename` itself is preferred.
130
+ **Fix:** select `__typename` under one key for every member.
131
+
132
+ ```graphql
133
+ query Keys { search(text: "a") { ... on User { t: __typename id } ... on Post { k: __typename title } } }
134
+ ```
135
+
98
136
  ### `@nxgt/graphql-codegen-zod: Both($v:) is passed to Query.e(v:) (format: "email") and to Query.u(v:) (format: "uuid"), whose schemas cannot both apply. Use one variable for each.`
99
137
 
100
138
  **When:** running codegen on an operation that passes one variable to two
@@ -109,6 +147,18 @@ query Both($e: String, $u: String) { e(v: $e) u(v: $u) }
109
147
 
110
148
  ## The generated file
111
149
 
150
+ ### `TS2305: Module '"@nxgt/graphql-scalars"' has no exported member 'scalarSchemas'`
151
+
152
+ **When:** type-checking the generated file under `moduleResolution`
153
+ `nodenext` or `node16`, with `scalarSchemas: '@nxgt/graphql-scalars'`.
154
+ **Why:** `@nxgt/graphql-scalars` before 0.4.1 ships declarations that
155
+ `nodenext` does not resolve.
156
+ **Fix:** upgrade it to 0.4.1 or later.
157
+
158
+ ```bash
159
+ bun add @nxgt/graphql-scalars@latest
160
+ ```
161
+
112
162
  ### `Property 'Money' does not exist on type '{ DateTime: ... }'` (or `TS2339`)
113
163
 
114
164
  **When:** type-checking the generated file, with `scalarSchemas` set.
@@ -159,15 +209,24 @@ field. The variables object itself ignores an extra variable, as `graphql` does.
159
209
 
160
210
  ## The schema
161
211
 
162
- ### `@nxgt/graphql-codegen-zod: the file would declare FilterInput twice: two GraphQL names, or an input type in a cycle and its Input type, give the same name. Rename one of the GraphQL types, or set typesSuffix.`
212
+ ### `@nxgt/graphql-codegen-zod: the file would declare FilterInput twice: two GraphQL names, or a type in a cycle and its Input or Wire type, give the same name. Rename one of the GraphQL types or operations, set typesSuffix, or set objects: false or operations: false.`
163
213
 
164
214
  **When:** running codegen on a schema where two declarations of the same kind
165
- get one name: an input type in a cycle (`Filter`) declares `FilterInput`, and
166
- the schema also has an input type `FilterInput`.
215
+ get one name:
216
+ - an input type in a cycle (`Filter`) declares `FilterInput`, or an object
217
+ type in a cycle (`User`) declares `UserWire`, and the schema also has a
218
+ type of that name;
219
+ - an object type is named like a type the plugin already writes, such as
220
+ `QueryFindArgs` beside a field `Query.find(...)`. With 0.1.0 this generated,
221
+ because object types were not written.
222
+
167
223
  **Why:** the file cannot declare one name twice.
168
224
  **Fix:** rename one of the GraphQL types, or set `typesSuffix`: `Filter`
169
225
  then declares `FilterTInput`, apart from `FilterInputT`. A `typesPrefix`
170
- does not part them.
226
+ does not part them. When the clash comes from an object type and you do not
227
+ need the output types, `objects: false` writes none of them. When it comes
228
+ from an operation's or a fragment's result (`SearchQuery`), `operations:
229
+ false` writes none of them.
171
230
 
172
231
  ```graphql
173
232
  input Filter { and: [Filter] }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nxgt/graphql-codegen-zod",
3
- "version": "0.1.0",
4
- "description": "A graphql-codegen plugin that writes Zod schemas from your SDL — inputs, enums, field arguments and operation variables — with the @constraint rules of @nxgt/graphql-validation",
3
+ "version": "0.2.1",
4
+ "description": "A graphql-codegen plugin that writes Zod schemas from your SDL — inputs, enums, field arguments, operation variables, operation results and output types — with the @constraint rules of @nxgt/graphql-validation",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
@@ -46,10 +46,11 @@
46
46
  "generated:write": "bun run test/write-generated.ts"
47
47
  },
48
48
  "dependencies": {
49
- "@nxgt/graphql-validation": "^0.2.0",
49
+ "@nxgt/graphql-validation": "^0.2.1",
50
50
  "change-case": "^5.4.4"
51
51
  },
52
52
  "devDependencies": {
53
+ "@nxgt/graphql-scalars": "^0.4.1",
53
54
  "@types/bun": "^1.4.0",
54
55
  "graphql": "16.11.0",
55
56
  "zod": "4.6.5"