@nxgt/graphql-validation 0.7.0 → 0.8.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.
Files changed (49) hide show
  1. package/README.md +8 -3
  2. package/dist/chunks/{index-w9pw7fsk.js → index-5x1yd76p.js} +2 -2
  3. package/dist/chunks/{index-atwkcfg3.js → index-sq3exxg2.js} +25 -4
  4. package/dist/chunks/index-sq3exxg2.js.map +27 -0
  5. package/dist/cli.js +1 -1
  6. package/dist/codegen.js +2 -2
  7. package/dist/constraint-directive.d.ts.map +1 -1
  8. package/dist/index.js +102 -71
  9. package/dist/index.js.map +12 -9
  10. package/dist/limits/cost-context.d.ts +7 -7
  11. package/dist/limits/cost-context.d.ts.map +1 -1
  12. package/dist/limits/describe.d.ts +4 -0
  13. package/dist/limits/describe.d.ts.map +1 -1
  14. package/dist/limits/fragments.d.ts +19 -0
  15. package/dist/limits/fragments.d.ts.map +1 -0
  16. package/dist/limits/list-size.d.ts +2 -0
  17. package/dist/limits/list-size.d.ts.map +1 -1
  18. package/dist/limits/max-depth.d.ts.map +1 -1
  19. package/dist/limits/max-fields.d.ts.map +1 -1
  20. package/dist/limits/max-list-cost-options.d.ts +38 -0
  21. package/dist/limits/max-list-cost-options.d.ts.map +1 -0
  22. package/dist/limits/max-list-cost.d.ts +11 -29
  23. package/dist/limits/max-list-cost.d.ts.map +1 -1
  24. package/dist/limits/size-reading.d.ts +22 -0
  25. package/dist/limits/size-reading.d.ts.map +1 -0
  26. package/dist/rules/contains.d.ts.map +1 -1
  27. package/dist/rules/ends-with.d.ts.map +1 -1
  28. package/dist/rules/exclusive-max.d.ts.map +1 -1
  29. package/dist/rules/exclusive-min.d.ts.map +1 -1
  30. package/dist/rules/format.d.ts.map +1 -1
  31. package/dist/rules/max-items.d.ts.map +1 -1
  32. package/dist/rules/max-length.d.ts.map +1 -1
  33. package/dist/rules/max.d.ts.map +1 -1
  34. package/dist/rules/min-items.d.ts.map +1 -1
  35. package/dist/rules/min-length.d.ts.map +1 -1
  36. package/dist/rules/min.d.ts.map +1 -1
  37. package/dist/rules/multiple-of.d.ts.map +1 -1
  38. package/dist/rules/not-contains.d.ts.map +1 -1
  39. package/dist/rules/pattern.d.ts.map +1 -1
  40. package/dist/rules/rule.d.ts +5 -0
  41. package/dist/rules/rule.d.ts.map +1 -1
  42. package/dist/rules/starts-with.d.ts.map +1 -1
  43. package/docs/guide/query-limits.md +46 -13
  44. package/docs/roadmap.md +6 -0
  45. package/docs/troubleshooting.md +26 -9
  46. package/graphql/constraint.graphqls +48 -0
  47. package/package.json +1 -1
  48. package/dist/chunks/index-atwkcfg3.js.map +0 -27
  49. /package/dist/chunks/{index-w9pw7fsk.js.map → index-5x1yd76p.js.map} +0 -0
package/README.md CHANGED
@@ -279,8 +279,13 @@ One `GraphQLError` per operation: `extensions: { code: 'QUERY_TOO_DEEP', depth,
279
279
  limit }`, `{ code: 'QUERY_TOO_COSTLY', cost, limit }` or `{ code: 'QUERY_TOO_WIDE',
280
280
  fields, limit }`. `maxFields` counts every field selection in the document, aliases and
281
281
  `__typename` included, at each spread of a fragment. A list field is sized by
282
- its `first`, `last` or `limit` argument; a variable, a negative number or no
283
- argument uses the argument's SDL default, else `defaultFirst`. A size is an
282
+ its `first`, `last` or `limit` argument. An argument not given says its SDL
283
+ default; with no argument and no default the size is `defaultFirst`. A variable
284
+ or an unusable literal (a negative number) counts as the largest of that
285
+ default (else `defaultFirst`), the argument's declared `@constraint(max)` or
286
+ `exclusiveMax`, and `variableSize` where some definition declares no bound; the
287
+ operation's own variable default is ignored. A code-first argument has no SDL
288
+ node, so only `variableSize` applies to it. A size is an
284
289
  Int, a canonical-integer string or an integral Float; the largest of several
285
290
  size arguments wins. On a Relay connection the `first` on the object field
286
291
  sizes the `edges` and `nodes` lists directly under it (not lists further down,
@@ -349,7 +354,7 @@ the directive declared is this package's. Both at once throw
349
354
  | `FieldIssue`, `FieldError`, `IssueParams`, `Translate`, `InvalidInputOptions`, `FieldsErrorOptions` | their types: an issue you write, a `fields` entry, its params, your translator, the options |
350
355
  | `ValidationIssue`, `ConstraintValue`, `BadUserInputExtensions` | the types of `extensions.issues`, of an issue's `value`, and of `extensions` |
351
356
  | `maxDepth({ depth, ignoreIntrospection? })` | a graphql-js validation rule refusing an operation nested deeper than `depth` fields, `extensions.code` `QUERY_TOO_DEEP`; introspection counts (the standard query is 15 levels) unless `ignoreIntrospection` |
352
- | `maxListCost({ budget, defaultFirst, sizeArguments?, ignoreIntrospection? })` | a graphql-js validation rule refusing an operation whose list-weighted cost is over `budget`, `extensions.code` `QUERY_TOO_COSTLY`; `sizeArguments` names the arguments sizing a list (default `first`, `last`, `limit`, the largest wins); `ignoreIntrospection` skips `__schema` and `__type` |
357
+ | `maxListCost({ budget, defaultFirst, sizeArguments?, ignoreIntrospection?, variableSize? })` | a graphql-js validation rule refusing an operation whose list-weighted cost is over `budget`, `extensions.code` `QUERY_TOO_COSTLY`; `sizeArguments` names the arguments sizing a list (default `first`, `last`, `limit`, the largest wins); `ignoreIntrospection` skips `__schema` and `__type`; `variableSize` is the size assumed for any size argument (`first`, `last`, `limit`, custom `sizeArguments`) sent as a variable or an unusable literal; see [Variables](docs/guide/query-limits.md#variables) for how a declared bound and `variableSize` combine |
353
358
  | `maxFields({ limit, ignoreIntrospection? })` | a graphql-js validation rule refusing an operation that selects more than `limit` fields (aliases, `__typename` and every fragment spread counted, `@skip`/`@include` not evaluated), `extensions.code` `QUERY_TOO_WIDE`; introspection counts (the standard query selects 220 fields) unless `ignoreIntrospection` |
354
359
  | `MaxDepthOptions`, `MaxListCostOptions`, `MaxFieldsOptions` | their options |
355
360
  | `ConstraintArgument` | the type of `issues[].constraint`: `'minLength' \| 'format' \| ...` |
@@ -4,7 +4,7 @@ import {
4
4
  rules,
5
5
  applyRule,
6
6
  assertOwnConstraint
7
- } from "./index-atwkcfg3.js";
7
+ } from "./index-sq3exxg2.js";
8
8
 
9
9
  // src/formats/all.ts
10
10
  var exports_all = {};
@@ -558,4 +558,4 @@ function assertNoDirectiveArgumentConstrained(inputs, schema) {
558
558
  export { registryOf, constraintsOn2, assertLeafTargets, assertObjectTargets, baseCode, checkConstraints2 };
559
559
 
560
560
  //# debugId=418E0FAAA9B9E68E64756E2164756E21
561
- //# sourceMappingURL=index-w9pw7fsk.js.map
561
+ //# sourceMappingURL=index-5x1yd76p.js.map
@@ -48,6 +48,7 @@ var containsRule = defineRule({
48
48
  argument: "contains",
49
49
  type: "String",
50
50
  target: "string",
51
+ description: "The string must contain this text (case-sensitive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.",
51
52
  toZod: (schema, value) => schema.includes(value),
52
53
  toCode: (schema, value) => `${schema}.includes(${literal(value)})`,
53
54
  owns: (issue) => issue.format === "includes"
@@ -57,6 +58,7 @@ var endsWithRule = defineRule({
57
58
  argument: "endsWith",
58
59
  type: "String",
59
60
  target: "string",
61
+ description: "The string must end with this text (case-sensitive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.",
60
62
  toZod: (schema, value) => schema.endsWith(value),
61
63
  toCode: (schema, value) => `${schema}.endsWith(${literal(value)})`,
62
64
  owns: (issue) => issue.format === "ends_with"
@@ -66,6 +68,7 @@ var exclusiveMaxRule = defineRule({
66
68
  argument: "exclusiveMax",
67
69
  type: "Float",
68
70
  target: "number",
71
+ description: "The number must be strictly less than this value (the value itself is refused). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to Int and Float values.",
69
72
  toZod: (schema, value) => schema.lt(value),
70
73
  toCode: (schema, value) => `${schema}.lt(${value})`,
71
74
  owns: (issue) => issue.code === "too_big" && issue.origin === "number" && issue.inclusive === false
@@ -75,6 +78,7 @@ var exclusiveMinRule = defineRule({
75
78
  argument: "exclusiveMin",
76
79
  type: "Float",
77
80
  target: "number",
81
+ description: "The number must be strictly greater than this value (the value itself is refused). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to Int and Float values.",
78
82
  toZod: (schema, value) => schema.gt(value),
79
83
  toCode: (schema, value) => `${schema}.gt(${value})`,
80
84
  owns: (issue) => issue.code === "too_small" && issue.origin === "number" && issue.inclusive === false
@@ -85,6 +89,7 @@ var formatRule = defineRule({
85
89
  argument: "format",
86
90
  type: "String",
87
91
  target: "string",
92
+ description: "The string must match this named format: byte, date, date-time, email, ipv4, ipv6, uri or uuid, or a format the server registered. An unknown name fails at server startup. Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.",
88
93
  base: true,
89
94
  toZod: (_schema, value, { formats }) => formats.named(value).toZod(),
90
95
  toCode: (_schema, value, { formats, formatCode }) => {
@@ -102,6 +107,7 @@ var maxRule = defineRule({
102
107
  argument: "max",
103
108
  type: "Float",
104
109
  target: "number",
110
+ description: "The number must be less than or equal to this value (inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to Int and Float values.",
105
111
  toZod: (schema, value) => schema.lte(value),
106
112
  toCode: (schema, value) => `${schema}.lte(${value})`,
107
113
  owns: (issue) => issue.code === "too_big" && issue.origin === "number" && issue.inclusive === true
@@ -111,6 +117,7 @@ var maxItemsRule = defineRule({
111
117
  argument: "maxItems",
112
118
  type: "Int",
113
119
  target: "list",
120
+ description: "The list must hold at most this many items (inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to list values.",
114
121
  toZod: (schema, value) => schema.max(value),
115
122
  toCode: (schema, value) => `${schema}.max(${value})`,
116
123
  owns: (issue) => issue.code === "too_big" && issue.origin === "array"
@@ -120,6 +127,7 @@ var maxLengthRule = defineRule({
120
127
  argument: "maxLength",
121
128
  type: "Int",
122
129
  target: "string",
130
+ description: "The string must be at most this many characters long (UTF-16 code units, inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.",
123
131
  toZod: (schema, value) => schema.max(value),
124
132
  toCode: (schema, value) => `${schema}.max(${value})`,
125
133
  owns: (issue) => issue.code === "too_big" && issue.origin === "string"
@@ -129,6 +137,7 @@ var minRule = defineRule({
129
137
  argument: "min",
130
138
  type: "Float",
131
139
  target: "number",
140
+ description: "The number must be greater than or equal to this value (inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to Int and Float values.",
132
141
  toZod: (schema, value) => schema.gte(value),
133
142
  toCode: (schema, value) => `${schema}.gte(${value})`,
134
143
  owns: (issue) => issue.code === "too_small" && issue.origin === "number" && issue.inclusive === true
@@ -138,6 +147,7 @@ var minItemsRule = defineRule({
138
147
  argument: "minItems",
139
148
  type: "Int",
140
149
  target: "list",
150
+ description: "The list must hold at least this many items (inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to list values.",
141
151
  toZod: (schema, value) => schema.min(value),
142
152
  toCode: (schema, value) => `${schema}.min(${value})`,
143
153
  owns: (issue) => issue.code === "too_small" && issue.origin === "array"
@@ -147,6 +157,7 @@ var minLengthRule = defineRule({
147
157
  argument: "minLength",
148
158
  type: "Int",
149
159
  target: "string",
160
+ description: "The string must be at least this many characters long (UTF-16 code units, inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.",
150
161
  toZod: (schema, value) => schema.min(value),
151
162
  toCode: (schema, value) => `${schema}.min(${value})`,
152
163
  owns: (issue) => issue.code === "too_small" && issue.origin === "string"
@@ -156,6 +167,7 @@ var multipleOfRule = defineRule({
156
167
  argument: "multipleOf",
157
168
  type: "Float",
158
169
  target: "number",
170
+ description: "The number must be a whole multiple of this value (for example 5 accepts 0, 5 and 10). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to Int and Float values.",
159
171
  toZod: (schema, value) => schema.multipleOf(value),
160
172
  toCode: (schema, value) => `${schema}.multipleOf(${value})`,
161
173
  owns: (issue) => issue.code === "not_multiple_of"
@@ -166,6 +178,7 @@ var notContainsRule = defineRule({
166
178
  argument: "notContains",
167
179
  type: "String",
168
180
  target: "string",
181
+ description: "The string must not contain this text (case-sensitive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.",
169
182
  toZod: (schema, value) => schema.refine((input) => !input.includes(value), message(value)),
170
183
  toCode: (schema, value) => `${schema}.refine((input) => !input.includes(${literal(value)}), ${literal(message(value))})`,
171
184
  owns: (issue) => issue.code === "custom"
@@ -182,6 +195,7 @@ var patternRule = defineRule({
182
195
  argument: "pattern",
183
196
  type: "String",
184
197
  target: "string",
198
+ description: "The string must match this regular expression (JavaScript syntax, not anchored unless it uses ^ and $). An invalid expression fails at server startup. Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.",
185
199
  toZod: (schema, value) => schema.regex(compile(value)),
186
200
  toCode: (schema, value) => `${schema}.regex(new RegExp(${literal(compile(value).source)}))`,
187
201
  owns: (issue) => issue.format === "regex"
@@ -191,6 +205,7 @@ var startsWithRule = defineRule({
191
205
  argument: "startsWith",
192
206
  type: "String",
193
207
  target: "string",
208
+ description: "The string must start with this text (case-sensitive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.",
194
209
  toZod: (schema, value) => schema.startsWith(value),
195
210
  toCode: (schema, value) => `${schema}.startsWith(${literal(value)})`,
196
211
  owns: (issue) => issue.format === "starts_with"
@@ -214,8 +229,14 @@ function constraintOf(issue) {
214
229
  }
215
230
 
216
231
  // src/constraint-directive.ts
217
- var constraintTypeDefs2 = `directive @constraint(
218
- ${Object.values(rules).map((rule) => ` ${rule.argument}: ${rule.type}`).join(`
232
+ var constraintTypeDefs2 = `"""
233
+ Validates an argument or an input field when the request arrives, before the resolver runs. A value that breaks a constraint is refused with a BAD_USER_INPUT error whose extensions list each issue with its path and the constraint that refused it; null and omitted values are not checked. Each argument below is one constraint, and they combine on one field.
234
+ """
235
+ directive @constraint(
236
+ ${Object.values(rules).map((rule) => ` """
237
+ ${rule.description}
238
+ """
239
+ ${rule.argument}: ${rule.type}`).join(`
219
240
  `)}
220
241
  ) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
221
242
  `;
@@ -242,5 +263,5 @@ function assertOwnConstraint(directive) {
242
263
 
243
264
  export { __export, RULE_PARAM, rules, applyRule, applyRuleCode, constraintOf, constraintTypeDefs2, assertOwnConstraint };
244
265
 
245
- //# debugId=02497C6067AC4D4564756E2164756E21
246
- //# sourceMappingURL=index-atwkcfg3.js.map
266
+ //# debugId=81ADC34E6A09C39064756E2164756E21
267
+ //# sourceMappingURL=index-sq3exxg2.js.map
@@ -0,0 +1,27 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/constraint-directive.ts", "../src/rules/rule.ts", "../src/rules/contains.ts", "../src/rules/ends-with.ts", "../src/rules/exclusive-max.ts", "../src/rules/exclusive-min.ts", "../src/rules/format.ts", "../src/rules/max.ts", "../src/rules/max-items.ts", "../src/rules/max-length.ts", "../src/rules/min.ts", "../src/rules/min-items.ts", "../src/rules/min-length.ts", "../src/rules/multiple-of.ts", "../src/rules/not-contains.ts", "../src/rules/pattern.ts", "../src/rules/starts-with.ts", "../src/rules/index.ts"],
4
+ "sourcesContent": [
5
+ "import { DirectiveLocation, type GraphQLDirective } from 'graphql';\nimport { rules } from './rules';\n\n/**\n * The SDL of `@constraint`, to add to a schema-first server's `typeDefs`,\n * written from the rules: an argument is declared once its rule exists.\n *\n * Its arguments are graphql-constraint-directive's, minus `uniqueTypeName`\n * (a detail of that package's scalar wrapping). It is allowed on arguments\n * and input fields only, where that package also allows output fields: a\n * resolver's result is the output scalars' job, and a directive that checked\n * nothing there would be a promise broken in silence.\n */\nexport const constraintTypeDefs: string = `\"\"\"\nValidates an argument or an input field when the request arrives, before the resolver runs. A value that breaks a constraint is refused with a BAD_USER_INPUT error whose extensions list each issue with its path and the constraint that refused it; null and omitted values are not checked. Each argument below is one constraint, and they combine on one field.\n\"\"\"\ndirective @constraint(\n${Object.values(rules)\n\t.map(\n\t\t(rule) =>\n\t\t\t`\\t\"\"\"\\n\\t${rule.description}\\n\\t\"\"\"\\n\\t${rule.argument}: ${rule.type}`,\n\t)\n\t.join('\\n')}\n) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION\n`;\n\nconst allowed = new Set<string>([\n\tDirectiveLocation.ARGUMENT_DEFINITION,\n\tDirectiveLocation.INPUT_FIELD_DEFINITION,\n]);\n\n/**\n * Fails when the schema's `@constraint` is not the one\n * {@link constraintTypeDefs} declares — graphql-constraint-directive's, say,\n * kept from a migration. Its extra locations would be accepted and checked\n * by nothing, its extra arguments mean nothing here, and an argument of\n * another type would reach a rule as the wrong kind of value.\n */\nexport function assertOwnConstraint(directive: GraphQLDirective): void {\n\tconst problems = [\n\t\t...(directive.isRepeatable\n\t\t\t? ['repeatable, and only its first use is read']\n\t\t\t: []),\n\t\t...directive.locations\n\t\t\t.filter((location) => !allowed.has(location))\n\t\t\t.map((location) => `allowed on ${location}`),\n\t\t...directive.args.flatMap((arg) => {\n\t\t\tconst rule = (rules as Record<string, { type: string } | undefined>)[\n\t\t\t\targ.name\n\t\t\t];\n\t\t\tif (!rule) return [`declares ${arg.name}, which no rule reads`];\n\t\t\tconst type = String(arg.type);\n\t\t\treturn type === rule.type\n\t\t\t\t? []\n\t\t\t\t: [`declares ${arg.name}: ${type}, not ${rule.type}`];\n\t\t}),\n\t];\n\tif (problems.length > 0) {\n\t\tthrow new Error(\n\t\t\t`This schema's @constraint is not constraintTypeDefs': it is ${problems.join('; ')}. Declare it with constraintTypeDefs.`,\n\t\t);\n\t}\n}\n",
6
+ "import type { z } from 'zod';\nimport type { StringSchema } from '../formats/format';\nimport type { FormatRegistry } from '../formats/registry';\n\n/** The schema each kind of rule narrows. */\nexport interface Targets {\n\tstring: StringSchema;\n\tnumber: z.ZodNumber;\n\tlist: z.ZodArray<z.ZodType>;\n}\n\nexport type Target = keyof Targets;\n\n/**\n * What a rule may read besides its value: the formats `format` resolves\n * against, the built-in ones and the application's own, and, when writing\n * source, how to write one of the application's (`InputCodeOptions.format`).\n */\nexport interface RuleContext {\n\treadonly formats: FormatRegistry;\n\treadonly formatCode?: ((name: string) => string) | undefined;\n}\n\n/** What a `@constraint` argument's value can be. */\ninterface ValueOf {\n\tInt: number;\n\tFloat: number;\n\tString: string;\n}\n\n/**\n * One `@constraint` argument: its GraphQL type in the directive's SDL, the\n * kind of value it narrows, and the same narrowing twice — `toZod` applied to\n * a schema at startup, `toCode` written as source by a code generator. The\n * spec beside each rule proves the two accept and refuse the same values.\n *\n * A `base` rule (only `format`) replaces the schema instead of narrowing it,\n * so a builder applies it before every other rule of its target.\n */\nexport interface Rule<\n\tA extends string = string,\n\tT extends keyof ValueOf = keyof ValueOf,\n\tK extends Target = Target,\n> {\n\treadonly argument: A;\n\treadonly type: T;\n\treadonly target: K;\n\t/**\n\t * The argument's description in the shipped SDL: what it enforces, its\n\t * bounds, the values it applies to and how a refusal reaches the client.\n\t */\n\treadonly description: string;\n\treadonly base?: true;\n\treadonly toZod: (\n\t\tschema: Targets[K],\n\t\tvalue: ValueOf[T],\n\t\tcontext: RuleContext,\n\t) => Targets[K];\n\t/**\n\t * `schema` is the source of the schema this rule narrows. The source names\n\t * zod as a free `z`: the generated file imports it.\n\t */\n\treadonly toCode: (\n\t\tschema: string,\n\t\tvalue: ValueOf[T],\n\t\tcontext: RuleContext,\n\t) => string;\n\t/**\n\t * Whether a Zod issue is this rule's refusal, so the error a client gets\n\t * names the rule (`constraint: 'minLength'`), which does not change with\n\t * Zod's own issue codes.\n\t */\n\treadonly owns: (issue: IssueFields) => boolean;\n}\n\n/** The fields of a Zod issue a rule recognises its refusal by. */\nexport interface IssueFields {\n\treadonly code: string;\n\treadonly origin?: string;\n\treadonly format?: string;\n\treadonly inclusive?: boolean;\n\treadonly params?: Readonly<Record<string, unknown>>;\n}\n\n/**\n * The `params` key that marks an issue as one argument's whatever its code:\n * an application format's issues carry `format` there, so a `.regex()` or a\n * `.refine()` inside one is not read as `pattern` or `notContains`.\n */\nexport const RULE_PARAM = 'nxgtConstraint';\n\n/** Declares a rule, with its argument name kept literal. */\nexport function defineRule<\n\tconst A extends string,\n\tT extends keyof ValueOf,\n\tK extends Target,\n>(rule: Rule<A, T, K>): Rule<A, T, K> {\n\treturn rule;\n}\n\n/** A string literal as source: quotes and escapes included. */\nexport const literal = (value: string): string => JSON.stringify(value);\n",
7
+ "import { defineRule, literal } from './rule';\n\nexport const containsRule = defineRule({\n\targument: 'contains',\n\ttype: 'String',\n\ttarget: 'string',\n\tdescription:\n\t\t'The string must contain this text (case-sensitive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.',\n\ttoZod: (schema, value) => schema.includes(value),\n\ttoCode: (schema, value) => `${schema}.includes(${literal(value)})`,\n\towns: (issue) => issue.format === 'includes',\n});\n",
8
+ "import { defineRule, literal } from './rule';\n\nexport const endsWithRule = defineRule({\n\targument: 'endsWith',\n\ttype: 'String',\n\ttarget: 'string',\n\tdescription:\n\t\t'The string must end with this text (case-sensitive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.',\n\ttoZod: (schema, value) => schema.endsWith(value),\n\ttoCode: (schema, value) => `${schema}.endsWith(${literal(value)})`,\n\towns: (issue) => issue.format === 'ends_with',\n});\n",
9
+ "import { defineRule } from './rule';\n\nexport const exclusiveMaxRule = defineRule({\n\targument: 'exclusiveMax',\n\ttype: 'Float',\n\ttarget: 'number',\n\tdescription:\n\t\t'The number must be strictly less than this value (the value itself is refused). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to Int and Float values.',\n\ttoZod: (schema, value) => schema.lt(value),\n\ttoCode: (schema, value) => `${schema}.lt(${value})`,\n\towns: (issue) =>\n\t\tissue.code === 'too_big' &&\n\t\tissue.origin === 'number' &&\n\t\tissue.inclusive === false,\n});\n",
10
+ "import { defineRule } from './rule';\n\nexport const exclusiveMinRule = defineRule({\n\targument: 'exclusiveMin',\n\ttype: 'Float',\n\ttarget: 'number',\n\tdescription:\n\t\t'The number must be strictly greater than this value (the value itself is refused). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to Int and Float values.',\n\ttoZod: (schema, value) => schema.gt(value),\n\ttoCode: (schema, value) => `${schema}.gt(${value})`,\n\towns: (issue) =>\n\t\tissue.code === 'too_small' &&\n\t\tissue.origin === 'number' &&\n\t\tissue.inclusive === false,\n});\n",
11
+ "import { defineRule, RULE_PARAM } from './rule';\n\n// The string rules' own formats; every other invalid_format is a format's.\nconst NARROWING = new Set(['starts_with', 'ends_with', 'includes', 'regex']);\n\nexport const formatRule = defineRule({\n\targument: 'format',\n\ttype: 'String',\n\ttarget: 'string',\n\tdescription:\n\t\t'The string must match this named format: byte, date, date-time, email, ipv4, ipv6, uri or uuid, or a format the server registered. An unknown name fails at server startup. Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.',\n\tbase: true,\n\ttoZod: (_schema, value, { formats }) => formats.named(value).toZod(),\n\ttoCode: (_schema, value, { formats, formatCode }) => {\n\t\tconst format = formats.named(value);\n\t\tif (format.toCode) return format.toCode();\n\t\tif (formatCode) return formatCode(value);\n\t\tthrow new Error(\n\t\t\t`@constraint(format: \"${value}\") is one of the application's formats: its source is the code generator's to write, through inputCode's format option.`,\n\t\t);\n\t},\n\t// An application format's issues are marked, whatever their code\n\t// (`custom` for a `.refine()`): see FormatRegistry.\n\towns: (issue) =>\n\t\tissue.params?.[RULE_PARAM] === 'format' ||\n\t\t(issue.code === 'invalid_format' && !NARROWING.has(issue.format ?? '')),\n});\n",
12
+ "import { defineRule } from './rule';\n\nexport const maxRule = defineRule({\n\targument: 'max',\n\ttype: 'Float',\n\ttarget: 'number',\n\tdescription:\n\t\t'The number must be less than or equal to this value (inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to Int and Float values.',\n\ttoZod: (schema, value) => schema.lte(value),\n\ttoCode: (schema, value) => `${schema}.lte(${value})`,\n\towns: (issue) =>\n\t\tissue.code === 'too_big' &&\n\t\tissue.origin === 'number' &&\n\t\tissue.inclusive === true,\n});\n",
13
+ "import { defineRule } from './rule';\n\nexport const maxItemsRule = defineRule({\n\targument: 'maxItems',\n\ttype: 'Int',\n\ttarget: 'list',\n\tdescription:\n\t\t'The list must hold at most this many items (inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to list values.',\n\ttoZod: (schema, value) => schema.max(value),\n\ttoCode: (schema, value) => `${schema}.max(${value})`,\n\towns: (issue) => issue.code === 'too_big' && issue.origin === 'array',\n});\n",
14
+ "import { defineRule } from './rule';\n\nexport const maxLengthRule = defineRule({\n\targument: 'maxLength',\n\ttype: 'Int',\n\ttarget: 'string',\n\tdescription:\n\t\t'The string must be at most this many characters long (UTF-16 code units, inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.',\n\ttoZod: (schema, value) => schema.max(value),\n\ttoCode: (schema, value) => `${schema}.max(${value})`,\n\towns: (issue) => issue.code === 'too_big' && issue.origin === 'string',\n});\n",
15
+ "import { defineRule } from './rule';\n\nexport const minRule = defineRule({\n\targument: 'min',\n\ttype: 'Float',\n\ttarget: 'number',\n\tdescription:\n\t\t'The number must be greater than or equal to this value (inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to Int and Float values.',\n\ttoZod: (schema, value) => schema.gte(value),\n\ttoCode: (schema, value) => `${schema}.gte(${value})`,\n\towns: (issue) =>\n\t\tissue.code === 'too_small' &&\n\t\tissue.origin === 'number' &&\n\t\tissue.inclusive === true,\n});\n",
16
+ "import { defineRule } from './rule';\n\nexport const minItemsRule = defineRule({\n\targument: 'minItems',\n\ttype: 'Int',\n\ttarget: 'list',\n\tdescription:\n\t\t'The list must hold at least this many items (inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to list values.',\n\ttoZod: (schema, value) => schema.min(value),\n\ttoCode: (schema, value) => `${schema}.min(${value})`,\n\towns: (issue) => issue.code === 'too_small' && issue.origin === 'array',\n});\n",
17
+ "import { defineRule } from './rule';\n\nexport const minLengthRule = defineRule({\n\targument: 'minLength',\n\ttype: 'Int',\n\ttarget: 'string',\n\tdescription:\n\t\t'The string must be at least this many characters long (UTF-16 code units, inclusive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.',\n\ttoZod: (schema, value) => schema.min(value),\n\ttoCode: (schema, value) => `${schema}.min(${value})`,\n\towns: (issue) => issue.code === 'too_small' && issue.origin === 'string',\n});\n",
18
+ "import { defineRule } from './rule';\n\nexport const multipleOfRule = defineRule({\n\targument: 'multipleOf',\n\ttype: 'Float',\n\ttarget: 'number',\n\tdescription:\n\t\t'The number must be a whole multiple of this value (for example 5 accepts 0, 5 and 10). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to Int and Float values.',\n\ttoZod: (schema, value) => schema.multipleOf(value),\n\ttoCode: (schema, value) => `${schema}.multipleOf(${value})`,\n\towns: (issue) => issue.code === 'not_multiple_of',\n});\n",
19
+ "import { defineRule, literal } from './rule';\n\nconst message = (value: string) => `Must not contain ${literal(value)}`;\n\nexport const notContainsRule = defineRule({\n\targument: 'notContains',\n\ttype: 'String',\n\ttarget: 'string',\n\tdescription:\n\t\t'The string must not contain this text (case-sensitive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.',\n\t// `refine` keeps the schema's own type, so later rules still chain.\n\ttoZod: (schema, value) =>\n\t\tschema.refine((input) => !input.includes(value), message(value)),\n\ttoCode: (schema, value) =>\n\t\t`${schema}.refine((input) => !input.includes(${literal(value)}), ${literal(message(value))})`,\n\towns: (issue) => issue.code === 'custom',\n});\n",
20
+ "import { defineRule, literal } from './rule';\n\n/** The pattern as a RegExp, or an error that names the argument. */\nfunction compile(value: string): RegExp {\n\ttry {\n\t\treturn new RegExp(value);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Invalid @constraint pattern ${literal(value)}: ${(error as Error).message}`,\n\t\t);\n\t}\n}\n\nexport const patternRule = defineRule({\n\targument: 'pattern',\n\ttype: 'String',\n\ttarget: 'string',\n\tdescription:\n\t\t'The string must match this regular expression (JavaScript syntax, not anchored unless it uses ^ and $). An invalid expression fails at server startup. Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.',\n\ttoZod: (schema, value) => schema.regex(compile(value)),\n\ttoCode: (schema, value) =>\n\t\t`${schema}.regex(new RegExp(${literal(compile(value).source)}))`,\n\towns: (issue) => issue.format === 'regex',\n});\n",
21
+ "import { defineRule, literal } from './rule';\n\nexport const startsWithRule = defineRule({\n\targument: 'startsWith',\n\ttype: 'String',\n\ttarget: 'string',\n\tdescription:\n\t\t'The string must start with this text (case-sensitive). Refused otherwise with a BAD_USER_INPUT error naming the constraint. Applies to String and ID values.',\n\ttoZod: (schema, value) => schema.startsWith(value),\n\ttoCode: (schema, value) => `${schema}.startsWith(${literal(value)})`,\n\towns: (issue) => issue.format === 'starts_with',\n});\n",
22
+ "import type { z } from 'zod';\nimport * as all from './all';\nimport { type IssueFields, RULE_PARAM, type RuleContext } from './rule';\n\n/**\n * One of the rules, as its own type: a builder narrows it on `target`, so a\n * number schema never reaches a string rule.\n */\nexport type RegisteredRule = (typeof all)[keyof typeof all];\n\n/** An argument `@constraint` takes. */\nexport type ConstraintArgument = RegisteredRule['argument'];\n\n/**\n * Every rule, keyed by its `@constraint` argument. Derived from what\n * `./all` exports, so a new rule is one file and one line there, and the\n * directive's SDL follows.\n */\nexport const rules = Object.fromEntries(\n\tObject.values(all).map((rule) => [rule.argument, rule]),\n) as {\n\treadonly [A in ConstraintArgument]: Extract<RegisteredRule, { argument: A }>;\n};\n\n/**\n * Applies a rule to a schema its caller has already matched to the rule's\n * target: the one place the rule's typed `toZod` meets a schema built from\n * GraphQL types, which the compiler cannot relate.\n */\nexport function applyRule(\n\trule: RegisteredRule,\n\tschema: z.ZodType,\n\tvalue: string | number,\n\tcontext: RuleContext,\n): z.ZodType {\n\tconst toZod = rule.toZod as unknown as (\n\t\tschema: z.ZodType,\n\t\tvalue: string | number,\n\t\tcontext: RuleContext,\n\t) => z.ZodType;\n\treturn toZod(schema, value, context);\n}\n\n/** `applyRule` for source: the rule's typed `toCode` on a schema's source. */\nexport function applyRuleCode(\n\trule: RegisteredRule,\n\tsource: string,\n\tvalue: string | number,\n\tcontext: RuleContext,\n): string {\n\tconst toCode = rule.toCode as (\n\t\tschema: string,\n\t\tvalue: string | number,\n\t\tcontext: RuleContext,\n\t) => string;\n\treturn toCode(source, value, context);\n}\n\n/**\n * The `@constraint` argument whose rule refused with this issue, if any: the\n * one the issue is marked with (an application format's), else the one rule\n * that owns its shape.\n */\nexport function constraintOf(\n\tissue: z.core.$ZodIssue,\n): ConstraintArgument | undefined {\n\tconst fields = issue as unknown as IssueFields;\n\tconst marked = fields.params?.[RULE_PARAM];\n\tif (typeof marked === 'string' && Object.hasOwn(rules, marked))\n\t\treturn marked as ConstraintArgument;\n\treturn Object.values(rules).find((rule) => rule.owns(fields))?.argument;\n}\n"
23
+ ],
24
+ "mappings": "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",
25
+ "debugId": "81ADC34E6A09C39064756E2164756E21",
26
+ "names": []
27
+ }
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  constraintTypeDefs2
4
- } from "./chunks/index-atwkcfg3.js";
4
+ } from "./chunks/index-sq3exxg2.js";
5
5
 
6
6
  // src/typedefs-command.ts
7
7
  import { mkdir, writeFile } from "node:fs/promises";
package/dist/codegen.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  applyRuleCode
3
- } from "./chunks/index-atwkcfg3.js";
3
+ } from "./chunks/index-sq3exxg2.js";
4
4
  import {
5
5
  registryOf,
6
6
  constraintsOn2,
@@ -8,7 +8,7 @@ import {
8
8
  assertObjectTargets,
9
9
  baseCode,
10
10
  checkConstraints2
11
- } from "./chunks/index-w9pw7fsk.js";
11
+ } from "./chunks/index-5x1yd76p.js";
12
12
  // src/builder/input-code.ts
13
13
  import {
14
14
  getNamedType,
@@ -1 +1 @@
1
- {"version":3,"file":"constraint-directive.d.ts","sourceRoot":"","sources":["../src/constraint-directive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGnE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAKhC,CAAC;AAOF;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAwBrE"}
1
+ {"version":3,"file":"constraint-directive.d.ts","sourceRoot":"","sources":["../src/constraint-directive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGnE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAWhC,CAAC;AAOF;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAwBrE"}
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  constraintOf,
3
3
  constraintTypeDefs2
4
- } from "./chunks/index-atwkcfg3.js";
4
+ } from "./chunks/index-sq3exxg2.js";
5
5
  import {
6
6
  checkConstraints2
7
- } from "./chunks/index-w9pw7fsk.js";
7
+ } from "./chunks/index-5x1yd76p.js";
8
8
 
9
9
  // src/bad-user-input.ts
10
10
  import { GraphQLError } from "graphql";
@@ -137,15 +137,42 @@ import {
137
137
  } from "graphql";
138
138
 
139
139
  // src/limits/describe.ts
140
+ var CEILING = Number.MAX_SAFE_INTEGER;
141
+ var add = (a, b) => Math.min(CEILING, a + b);
140
142
  function operationLabel(operation) {
141
143
  return operation.name ? `Operation "${operation.name.value}"` : "Operation";
142
144
  }
143
- function assertInteger(option, value, min, max = Number.MAX_SAFE_INTEGER) {
145
+ function assertInteger(option, value, min, max = CEILING) {
144
146
  if (!Number.isInteger(value) || value < min || value >= max) {
145
147
  throw new RangeError(`${option} must be an integer from ${min} to ${max - 1}.`);
146
148
  }
147
149
  }
148
150
 
151
+ // src/limits/fragments.ts
152
+ var NO_KEY = -1;
153
+ function newFragmentWalk(getFragment) {
154
+ return { getFragment, values: new Map, visiting: new Set };
155
+ }
156
+ function fragmentValue(walk, name, key, compute) {
157
+ let known = walk.values.get(name);
158
+ if (!known) {
159
+ known = new Map;
160
+ walk.values.set(name, known);
161
+ }
162
+ const at = typeof key === "number" ? key : key(known);
163
+ const memo = known.get(at);
164
+ if (memo !== undefined)
165
+ return memo;
166
+ const fragment = walk.getFragment(name);
167
+ if (!fragment || walk.visiting.has(name))
168
+ return 0;
169
+ walk.visiting.add(name);
170
+ const result = compute(fragment, at);
171
+ walk.visiting.delete(name);
172
+ known.set(at, result);
173
+ return result;
174
+ }
175
+
149
176
  // src/limits/introspection.ts
150
177
  import {
151
178
  isEnumType,
@@ -230,26 +257,14 @@ function depthOf(depth, selectionSet) {
230
257
  return deepest;
231
258
  }
232
259
  function fragmentDepth(depth, name) {
233
- const known = depth.fragmentDepths.get(name);
234
- if (known !== undefined)
235
- return known;
236
- const fragment = depth.getFragment(name);
237
- if (!fragment || depth.measuring.has(name))
238
- return 0;
239
- depth.measuring.add(name);
240
- const result = depthOf(depth, fragment.selectionSet);
241
- depth.measuring.delete(name);
242
- depth.fragmentDepths.set(name, result);
243
- return result;
260
+ return fragmentValue(depth, name, NO_KEY, (fragment) => depthOf(depth, fragment.selectionSet));
244
261
  }
245
262
  function maxDepth(options) {
246
263
  const limit = options.depth;
247
264
  assertInteger("maxDepth: depth", limit, 1);
248
265
  return (context) => {
249
266
  const walk = {
250
- getFragment: (name) => context.getFragment(name),
251
- fragmentDepths: new Map,
252
- measuring: new Set,
267
+ ...newFragmentWalk((name) => context.getFragment(name)),
253
268
  ignoreIntrospection: options.ignoreIntrospection ?? false
254
269
  };
255
270
  return {
@@ -270,9 +285,6 @@ function maxDepth(options) {
270
285
  import {
271
286
  GraphQLError as GraphQLError4
272
287
  } from "graphql";
273
- function add(a, b) {
274
- return Math.min(a + b, Number.MAX_SAFE_INTEGER);
275
- }
276
288
  function countOf(walk, selectionSet) {
277
289
  let total = 0;
278
290
  for (const selection of selectionSet.selections) {
@@ -291,26 +303,14 @@ function countOf(walk, selectionSet) {
291
303
  return total;
292
304
  }
293
305
  function fragmentCount(walk, name) {
294
- const known = walk.fragmentCounts.get(name);
295
- if (known !== undefined)
296
- return known;
297
- const fragment = walk.getFragment(name);
298
- if (!fragment || walk.counting.has(name))
299
- return 0;
300
- walk.counting.add(name);
301
- const result = countOf(walk, fragment.selectionSet);
302
- walk.counting.delete(name);
303
- walk.fragmentCounts.set(name, result);
304
- return result;
306
+ return fragmentValue(walk, name, NO_KEY, (fragment) => countOf(walk, fragment.selectionSet));
305
307
  }
306
308
  function maxFields(options) {
307
309
  const limit = options.limit;
308
310
  assertInteger("maxFields: limit", limit, 1);
309
311
  return (context) => {
310
312
  const walk = {
311
- getFragment: (name) => context.getFragment(name),
312
- fragmentCounts: new Map,
313
- counting: new Set,
313
+ ...newFragmentWalk((name) => context.getFragment(name)),
314
314
  ignoreIntrospection: options.ignoreIntrospection ?? false
315
315
  };
316
316
  return {
@@ -340,8 +340,6 @@ import {
340
340
  isInterfaceType as isInterfaceType2,
341
341
  isObjectType as isObjectType2
342
342
  } from "graphql";
343
- var CEILING = Number.MAX_SAFE_INTEGER;
344
- var add2 = (a, b) => Math.min(CEILING, a + b);
345
343
  var multiply = (a, b) => Math.min(CEILING, a * b);
346
344
  function fieldOf(cost, parent, name) {
347
345
  if (parent === cost.schema.getQueryType() && isIntrospectionRoot(name)) {
@@ -354,7 +352,7 @@ function rootType(schema, operation) {
354
352
  return type ?? undefined;
355
353
  }
356
354
  var EXACT_SIZES = 8;
357
- var NO_PENDING = -1;
355
+ var NO_PENDING = NO_KEY;
358
356
  function memoSize(known, pending) {
359
357
  if (pending === undefined || known.has(pending) || known.size < EXACT_SIZES) {
360
358
  return pending;
@@ -369,16 +367,17 @@ function memoSize(known, pending) {
369
367
  import {
370
368
  isAbstractType
371
369
  } from "graphql";
372
- var CEILING2 = Number.MAX_SAFE_INTEGER;
370
+
371
+ // src/limits/size-reading.ts
373
372
  var CANONICAL_INTEGER = /^(0|[1-9]\d*)$/;
374
373
  function sizeOf(value) {
375
374
  if (typeof value === "string") {
376
- return CANONICAL_INTEGER.test(value) ? Math.min(Number(value), CEILING2) : undefined;
375
+ return CANONICAL_INTEGER.test(value) ? Math.min(Number(value), CEILING) : undefined;
377
376
  }
378
377
  if (typeof value === "bigint") {
379
- return value >= 0n ? Math.min(Number(value), CEILING2) : undefined;
378
+ return value >= 0n ? Math.min(Number(value), CEILING) : undefined;
380
379
  }
381
- return typeof value === "number" && Number.isInteger(value) && value >= 0 ? Math.min(value, CEILING2) : undefined;
380
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 ? Math.min(value, CEILING) : undefined;
382
381
  }
383
382
  function literalSize(value) {
384
383
  if (value.kind === "IntValue" || value.kind === "FloatValue") {
@@ -407,6 +406,30 @@ function defaultSizeOf(argument) {
407
406
  }
408
407
  return;
409
408
  }
409
+ function boundOf(value) {
410
+ if (value.kind === "StringValue")
411
+ return literalSize(value);
412
+ if (value.kind !== "IntValue" && value.kind !== "FloatValue")
413
+ return;
414
+ const number = Number(value.value);
415
+ return Number.isFinite(number) && number >= 0 ? Math.min(Math.ceil(number), CEILING) : undefined;
416
+ }
417
+ function constraintMaxOf(argument) {
418
+ const directive = argument?.astNode?.directives?.find((node) => node.name.value === "constraint");
419
+ let largest;
420
+ for (const node of directive?.arguments ?? []) {
421
+ if (node.name.value !== "max" && node.name.value !== "exclusiveMax") {
422
+ continue;
423
+ }
424
+ const bound = boundOf(node.value);
425
+ if (bound !== undefined && (largest === undefined || bound > largest)) {
426
+ largest = bound;
427
+ }
428
+ }
429
+ return largest;
430
+ }
431
+
432
+ // src/limits/list-size.ts
410
433
  var profiles = new WeakMap;
411
434
  function profileOf(cost, parent, definition) {
412
435
  let bySizes = profiles.get(cost.schema);
@@ -435,6 +458,10 @@ function profileOf(cost, parent, definition) {
435
458
  largest: cost.sizeArguments.map(() => {
436
459
  return;
437
460
  }),
461
+ maxima: cost.sizeArguments.map(() => {
462
+ return;
463
+ }),
464
+ someNoMax: cost.sizeArguments.map(() => false),
438
465
  someLack: cost.sizeArguments.map(() => false),
439
466
  someBare: false,
440
467
  declares: false,
@@ -443,7 +470,13 @@ function profileOf(cost, parent, definition) {
443
470
  for (const field of definitions) {
444
471
  let any = false;
445
472
  cost.sizeArguments.forEach((name, index) => {
446
- const size = defaultSizeOf(field.args.find((arg) => arg.name === name));
473
+ const argument = field.args.find((arg) => arg.name === name);
474
+ const max = constraintMaxOf(argument);
475
+ if (max === undefined)
476
+ profile.someNoMax[index] = true;
477
+ else
478
+ profile.maxima[index] = Math.max(profile.maxima[index] ?? 0, max);
479
+ const size = defaultSizeOf(argument);
447
480
  if (size === undefined) {
448
481
  profile.someLack[index] = true;
449
482
  return;
@@ -469,7 +502,16 @@ function argumentSize(cost, profile, index, node) {
469
502
  const literal = literalSize(node.value);
470
503
  if (literal !== undefined)
471
504
  return literal;
472
- return profile.someLack[index] ? Math.max(largest ?? 0, cost.defaultFirst) : largest;
505
+ const today = profile.someLack[index] ? Math.max(largest ?? 0, cost.defaultFirst) : largest;
506
+ const bound = unusableBound(cost, profile, index);
507
+ return bound === undefined ? today : Math.max(today ?? 0, bound);
508
+ }
509
+ function unusableBound(cost, profile, index) {
510
+ const assumed = profile.someNoMax[index] ? cost.variableSize : undefined;
511
+ const declared = profile.maxima[index];
512
+ if (assumed === undefined)
513
+ return declared;
514
+ return Math.max(declared ?? 0, assumed);
473
515
  }
474
516
  function statedSize(cost, parent, definition, args) {
475
517
  const profile = profileOf(cost, parent, definition);
@@ -495,6 +537,9 @@ function declaration(cost, parent, definition) {
495
537
  return someUndeclared ? "some" : "all";
496
538
  }
497
539
 
540
+ // src/limits/max-list-cost-options.ts
541
+ var DEFAULT_SIZE_ARGUMENTS = ["first", "last", "limit"];
542
+
498
543
  // src/limits/pending-size.ts
499
544
  function listSizeUnder(cost, parent, definition, args, pending) {
500
545
  const own = () => statedSize(cost, parent, definition, args) ?? cost.defaultFirst;
@@ -509,7 +554,6 @@ function listSizeUnder(cost, parent, definition, args, pending) {
509
554
  }
510
555
 
511
556
  // src/limits/max-list-cost.ts
512
- var DEFAULT_SIZE_ARGUMENTS = ["first", "last", "limit"];
513
557
  function fieldCost(cost, parent, selection, definition, pending) {
514
558
  if (!selection.selectionSet)
515
559
  return 1;
@@ -518,11 +562,11 @@ function fieldCost(cost, parent, selection, definition, pending) {
518
562
  if (!isListType(getNullableType(definition.type))) {
519
563
  const stated = statedSize(cost, parent, definition, selection.arguments);
520
564
  const inner = costOf(cost, selection.selectionSet, type, stated);
521
- return add2(1, inner);
565
+ return add(1, inner);
522
566
  }
523
567
  const inner = costOf(cost, selection.selectionSet, type, undefined);
524
568
  const size = parent?.name.startsWith("__") ? introspectionSize(cost.schema, name) : listSizeUnder(cost, parent, definition, selection.arguments, pending);
525
- return add2(1, multiply(inner, size));
569
+ return add(1, multiply(inner, size));
526
570
  }
527
571
  function costOf(cost, selectionSet, parent, pending) {
528
572
  let total = 0;
@@ -536,35 +580,19 @@ function costOf(cost, selectionSet, parent, pending) {
536
580
  const definition = fieldOf(cost, parent, name);
537
581
  if (!definition)
538
582
  continue;
539
- total = add2(total, fieldCost(cost, parent, selection, definition, pending));
583
+ total = add(total, fieldCost(cost, parent, selection, definition, pending));
540
584
  } else if (selection.kind === "InlineFragment") {
541
585
  const condition = selection.typeCondition ? cost.schema.getType(selection.typeCondition.name.value) : parent;
542
- total = add2(total, costOf(cost, selection.selectionSet, condition, pending));
586
+ total = add(total, costOf(cost, selection.selectionSet, condition, pending));
543
587
  } else {
544
- total = add2(total, fragmentCost(cost, selection.name.value, pending));
588
+ total = add(total, fragmentCost(cost, selection.name.value, pending));
545
589
  }
546
590
  }
547
591
  return total;
548
592
  }
549
593
  function fragmentCost(cost, name, pending) {
550
- let known = cost.fragmentCosts.get(name);
551
- if (!known) {
552
- known = new Map;
553
- cost.fragmentCosts.set(name, known);
554
- }
555
- const size = memoSize(known, pending);
556
- const key = size ?? NO_PENDING;
557
- const memo = known.get(key);
558
- if (memo !== undefined)
559
- return memo;
560
- const fragment = cost.getFragment(name);
561
- if (!fragment || cost.costing.has(name))
562
- return 0;
563
- cost.costing.add(name);
564
- const result = costOf(cost, fragment.selectionSet, cost.schema.getType(fragment.typeCondition.name.value), size);
565
- cost.costing.delete(name);
566
- known.set(key, result);
567
- return result;
594
+ const key = (known) => memoSize(known, pending) ?? NO_PENDING;
595
+ return fragmentValue(cost, name, key, (fragment, at) => costOf(cost, fragment.selectionSet, cost.schema.getType(fragment.typeCondition.name.value), at === NO_PENDING ? undefined : at));
568
596
  }
569
597
  function maxListCost(options) {
570
598
  const { budget, defaultFirst } = options;
@@ -573,16 +601,19 @@ function maxListCost(options) {
573
601
  ]);
574
602
  assertInteger("maxListCost: budget", budget, 0);
575
603
  assertInteger("maxListCost: defaultFirst", defaultFirst, 0);
604
+ const { variableSize } = options;
605
+ if (variableSize !== undefined) {
606
+ assertInteger("maxListCost: variableSize", variableSize, 0);
607
+ }
576
608
  return (context) => {
577
609
  const schema = context.getSchema();
578
610
  const cost = {
579
611
  schema,
580
612
  sizeArguments,
581
613
  defaultFirst,
614
+ variableSize,
582
615
  ignoreIntrospection: options.ignoreIntrospection ?? false,
583
- getFragment: (name) => context.getFragment(name),
584
- fragmentCosts: new Map,
585
- costing: new Set
616
+ ...newFragmentWalk((name) => context.getFragment(name))
586
617
  };
587
618
  return {
588
619
  OperationDefinition(operation) {
@@ -683,5 +714,5 @@ export {
683
714
  withValidation
684
715
  };
685
716
 
686
- //# debugId=3B937DADAE820B8964756E2164756E21
717
+ //# debugId=B1856E23719B140164756E2164756E21
687
718
  //# sourceMappingURL=index.js.map