@nxgt/graphql-validation 0.6.0 → 0.7.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/README.md +28 -9
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +160 -43
- package/dist/index.js.map +8 -5
- package/dist/limits/cost-context.d.ts +26 -0
- package/dist/limits/cost-context.d.ts.map +1 -0
- package/dist/limits/list-size.d.ts +13 -5
- package/dist/limits/list-size.d.ts.map +1 -1
- package/dist/limits/max-fields.d.ts +35 -0
- package/dist/limits/max-fields.d.ts.map +1 -0
- package/dist/limits/max-list-cost.d.ts +17 -2
- package/dist/limits/max-list-cost.d.ts.map +1 -1
- package/dist/limits/pending-size.d.ts +13 -0
- package/dist/limits/pending-size.d.ts.map +1 -0
- package/docs/README.md +1 -1
- package/docs/guide/query-limits.md +110 -5
- package/docs/roadmap.md +9 -4
- package/docs/troubleshooting.md +23 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -241,19 +241,24 @@ The codes, and `fieldsError`, are in
|
|
|
241
241
|
A schema with list cycles (`Folder.items` returns items, `Item.folder` returns
|
|
242
242
|
its folder) lets a client nest a query whose cost grows exponentially.
|
|
243
243
|
`maxDepth` and `maxListCost` are graphql-js validation rules that refuse such a
|
|
244
|
-
query before any resolver runs
|
|
244
|
+
query before any resolver runs; `maxFields` bounds the breadth they leave open
|
|
245
|
+
(thousands of aliases of a cheap field).
|
|
245
246
|
|
|
246
247
|
```ts
|
|
247
|
-
import { maxDepth, maxListCost } from '@nxgt/graphql-validation';
|
|
248
|
+
import { maxDepth, maxFields, maxListCost } from '@nxgt/graphql-validation';
|
|
248
249
|
import { parse, specifiedRules, validate } from 'graphql';
|
|
249
250
|
|
|
250
|
-
const rules = [
|
|
251
|
+
const rules = [
|
|
252
|
+
maxDepth({ depth: 8 }),
|
|
253
|
+
maxListCost({ budget: 10_000, defaultFirst: 50 }),
|
|
254
|
+
maxFields({ limit: 500 }),
|
|
255
|
+
];
|
|
251
256
|
const errors = validate(schema, parse(query), [...specifiedRules, ...rules]);
|
|
252
257
|
```
|
|
253
258
|
|
|
254
259
|
```ts
|
|
255
260
|
// graphql-yoga
|
|
256
|
-
import { maxDepth, maxListCost } from '@nxgt/graphql-validation';
|
|
261
|
+
import { maxDepth, maxFields, maxListCost } from '@nxgt/graphql-validation';
|
|
257
262
|
import { createYoga } from 'graphql-yoga';
|
|
258
263
|
|
|
259
264
|
const yoga = createYoga({
|
|
@@ -263,6 +268,7 @@ const yoga = createYoga({
|
|
|
263
268
|
onValidate: ({ addValidationRule }) => {
|
|
264
269
|
addValidationRule(maxDepth({ depth: 8 }));
|
|
265
270
|
addValidationRule(maxListCost({ budget: 10_000, defaultFirst: 50 }));
|
|
271
|
+
addValidationRule(maxFields({ limit: 500 }));
|
|
266
272
|
},
|
|
267
273
|
},
|
|
268
274
|
],
|
|
@@ -270,13 +276,25 @@ const yoga = createYoga({
|
|
|
270
276
|
```
|
|
271
277
|
|
|
272
278
|
One `GraphQLError` per operation: `extensions: { code: 'QUERY_TOO_DEEP', depth,
|
|
273
|
-
limit }
|
|
279
|
+
limit }`, `{ code: 'QUERY_TOO_COSTLY', cost, limit }` or `{ code: 'QUERY_TOO_WIDE',
|
|
280
|
+
fields, limit }`. `maxFields` counts every field selection in the document, aliases and
|
|
281
|
+
`__typename` included, at each spread of a fragment. A list field is sized by
|
|
274
282
|
its `first`, `last` or `limit` argument; a variable, a negative number or no
|
|
275
283
|
argument uses the argument's SDL default, else `defaultFirst`. A size is an
|
|
276
284
|
Int, a canonical-integer string or an integral Float; the largest of several
|
|
277
|
-
size arguments wins.
|
|
278
|
-
|
|
279
|
-
|
|
285
|
+
size arguments wins. On a Relay connection the `first` on the object field
|
|
286
|
+
sizes the `edges` and `nodes` lists directly under it (not lists further down,
|
|
287
|
+
nor lists declaring their own size argument):
|
|
288
|
+
|
|
289
|
+
```graphql
|
|
290
|
+
{ items(first: 100) { edges { node { id } } } }
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Trap: any non-list field stating a size sizes the lists declaring none directly
|
|
294
|
+
under it, so an argument that means something else (`limit`, say) and is named in
|
|
295
|
+
`sizeArguments` now sizes them: leave it out of `sizeArguments`.
|
|
296
|
+
Introspection is counted too; add `ignoreIntrospection: true` where it is
|
|
297
|
+
trusted (GraphiQL in development). See
|
|
280
298
|
[Limiting the depth and cost of a query](docs/guide/query-limits.md).
|
|
281
299
|
|
|
282
300
|
## IDE support
|
|
@@ -332,7 +350,8 @@ the directive declared is this package's. Both at once throw
|
|
|
332
350
|
| `ValidationIssue`, `ConstraintValue`, `BadUserInputExtensions` | the types of `extensions.issues`, of an issue's `value`, and of `extensions` |
|
|
333
351
|
| `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` |
|
|
334
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` |
|
|
335
|
-
| `
|
|
353
|
+
| `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
|
+
| `MaxDepthOptions`, `MaxListCostOptions`, `MaxFieldsOptions` | their options |
|
|
336
355
|
| `ConstraintArgument` | the type of `issues[].constraint`: `'minLength' \| 'format' \| ...` |
|
|
337
356
|
| `ArgsSchema`, `ArgsSchemaFor`, `SchemaOf` | the types `validated` accepts: the schema or shape, and that or the function building it from the context |
|
|
338
357
|
| `WithValidationOptions`, `FormatSchemas`, `OwnFormats`, `StringSchema`, `FormatName` | the types of `withValidation`'s options: a record of string schemas, with no built-in format name (`FormatName`) |
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export type { StringSchema } from './formats/format.js';
|
|
|
6
6
|
export type { FormatSchemas, OwnFormats } from './formats/registry.js';
|
|
7
7
|
export { type FieldError, type FieldIssue, type FieldsErrorOptions, fieldsError, INVALID_INPUT, type InvalidInputOptions, type IssueParams, inputPath, invalidInputError, type Translate, } from './invalid-input.js';
|
|
8
8
|
export { type MaxDepthOptions, maxDepth } from './limits/max-depth.js';
|
|
9
|
+
export { type MaxFieldsOptions, maxFields } from './limits/max-fields.js';
|
|
9
10
|
export { type MaxListCostOptions, maxListCost } from './limits/max-list-cost.js';
|
|
10
11
|
export type { ConstraintArgument } from './rules/index.js';
|
|
11
12
|
export { type ArgsSchema, type ArgsSchemaFor, type SchemaOf, validated, } from './validated.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,sBAAsB,EAC3B,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,eAAe,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACN,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,WAAW,EACX,aAAa,EACb,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,SAAS,EACT,iBAAiB,EACjB,KAAK,SAAS,GACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,KAAK,kBAAkB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC9E,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EACN,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,SAAS,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,KAAK,qBAAqB,EAC1B,cAAc,GACd,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,sBAAsB,EAC3B,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,eAAe,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACN,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,WAAW,EACX,aAAa,EACb,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,SAAS,EACT,iBAAiB,EACjB,KAAK,SAAS,GACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,KAAK,kBAAkB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC9E,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EACN,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,SAAS,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,KAAK,qBAAqB,EAC1B,cAAc,GACd,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -266,30 +266,119 @@ function maxDepth(options) {
|
|
|
266
266
|
};
|
|
267
267
|
};
|
|
268
268
|
}
|
|
269
|
+
// src/limits/max-fields.ts
|
|
270
|
+
import {
|
|
271
|
+
GraphQLError as GraphQLError4
|
|
272
|
+
} from "graphql";
|
|
273
|
+
function add(a, b) {
|
|
274
|
+
return Math.min(a + b, Number.MAX_SAFE_INTEGER);
|
|
275
|
+
}
|
|
276
|
+
function countOf(walk, selectionSet) {
|
|
277
|
+
let total = 0;
|
|
278
|
+
for (const selection of selectionSet.selections) {
|
|
279
|
+
if (selection.kind === "Field") {
|
|
280
|
+
if (walk.ignoreIntrospection && isIntrospectionRoot(selection.name.value))
|
|
281
|
+
continue;
|
|
282
|
+
total = add(total, 1);
|
|
283
|
+
if (selection.selectionSet)
|
|
284
|
+
total = add(total, countOf(walk, selection.selectionSet));
|
|
285
|
+
} else if (selection.kind === "InlineFragment") {
|
|
286
|
+
total = add(total, countOf(walk, selection.selectionSet));
|
|
287
|
+
} else {
|
|
288
|
+
total = add(total, fragmentCount(walk, selection.name.value));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return total;
|
|
292
|
+
}
|
|
293
|
+
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;
|
|
305
|
+
}
|
|
306
|
+
function maxFields(options) {
|
|
307
|
+
const limit = options.limit;
|
|
308
|
+
assertInteger("maxFields: limit", limit, 1);
|
|
309
|
+
return (context) => {
|
|
310
|
+
const walk = {
|
|
311
|
+
getFragment: (name) => context.getFragment(name),
|
|
312
|
+
fragmentCounts: new Map,
|
|
313
|
+
counting: new Set,
|
|
314
|
+
ignoreIntrospection: options.ignoreIntrospection ?? false
|
|
315
|
+
};
|
|
316
|
+
return {
|
|
317
|
+
OperationDefinition(operation) {
|
|
318
|
+
const fields = countOf(walk, operation.selectionSet);
|
|
319
|
+
if (fields > limit) {
|
|
320
|
+
context.reportError(new GraphQLError4(`${operationLabel(operation)} selects ${fields} fields, more than the ${limit} allowed`, {
|
|
321
|
+
nodes: [operation],
|
|
322
|
+
extensions: { code: "QUERY_TOO_WIDE", fields, limit }
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
};
|
|
329
|
+
}
|
|
269
330
|
// src/limits/max-list-cost.ts
|
|
270
331
|
import {
|
|
271
|
-
GraphQLError as
|
|
332
|
+
GraphQLError as GraphQLError5,
|
|
272
333
|
getNamedType,
|
|
273
334
|
getNullableType,
|
|
335
|
+
isListType
|
|
336
|
+
} from "graphql";
|
|
337
|
+
|
|
338
|
+
// src/limits/cost-context.ts
|
|
339
|
+
import {
|
|
274
340
|
isInterfaceType as isInterfaceType2,
|
|
275
|
-
isListType,
|
|
276
341
|
isObjectType as isObjectType2
|
|
277
342
|
} from "graphql";
|
|
343
|
+
var CEILING = Number.MAX_SAFE_INTEGER;
|
|
344
|
+
var add2 = (a, b) => Math.min(CEILING, a + b);
|
|
345
|
+
var multiply = (a, b) => Math.min(CEILING, a * b);
|
|
346
|
+
function fieldOf(cost, parent, name) {
|
|
347
|
+
if (parent === cost.schema.getQueryType() && isIntrospectionRoot(name)) {
|
|
348
|
+
return introspectionRoot(name);
|
|
349
|
+
}
|
|
350
|
+
return isObjectType2(parent) || isInterfaceType2(parent) ? parent.getFields()[name] : undefined;
|
|
351
|
+
}
|
|
352
|
+
function rootType(schema, operation) {
|
|
353
|
+
const type = operation.operation === "query" ? schema.getQueryType() : operation.operation === "mutation" ? schema.getMutationType() : schema.getSubscriptionType();
|
|
354
|
+
return type ?? undefined;
|
|
355
|
+
}
|
|
356
|
+
var EXACT_SIZES = 8;
|
|
357
|
+
var NO_PENDING = -1;
|
|
358
|
+
function memoSize(known, pending) {
|
|
359
|
+
if (pending === undefined || known.has(pending) || known.size < EXACT_SIZES) {
|
|
360
|
+
return pending;
|
|
361
|
+
}
|
|
362
|
+
let rounded = 2 ** Math.ceil(Math.log2(Math.max(pending, 1)));
|
|
363
|
+
if (rounded < pending)
|
|
364
|
+
rounded *= 2;
|
|
365
|
+
return Math.min(CEILING, rounded);
|
|
366
|
+
}
|
|
278
367
|
|
|
279
368
|
// src/limits/list-size.ts
|
|
280
369
|
import {
|
|
281
370
|
isAbstractType
|
|
282
371
|
} from "graphql";
|
|
283
|
-
var
|
|
372
|
+
var CEILING2 = Number.MAX_SAFE_INTEGER;
|
|
284
373
|
var CANONICAL_INTEGER = /^(0|[1-9]\d*)$/;
|
|
285
374
|
function sizeOf(value) {
|
|
286
375
|
if (typeof value === "string") {
|
|
287
|
-
return CANONICAL_INTEGER.test(value) ? Math.min(Number(value),
|
|
376
|
+
return CANONICAL_INTEGER.test(value) ? Math.min(Number(value), CEILING2) : undefined;
|
|
288
377
|
}
|
|
289
378
|
if (typeof value === "bigint") {
|
|
290
|
-
return value >= 0n ? Math.min(Number(value),
|
|
379
|
+
return value >= 0n ? Math.min(Number(value), CEILING2) : undefined;
|
|
291
380
|
}
|
|
292
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? Math.min(value,
|
|
381
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? Math.min(value, CEILING2) : undefined;
|
|
293
382
|
}
|
|
294
383
|
function literalSize(value) {
|
|
295
384
|
if (value.kind === "IntValue" || value.kind === "FloatValue") {
|
|
@@ -347,7 +436,9 @@ function profileOf(cost, parent, definition) {
|
|
|
347
436
|
return;
|
|
348
437
|
}),
|
|
349
438
|
someLack: cost.sizeArguments.map(() => false),
|
|
350
|
-
someBare: false
|
|
439
|
+
someBare: false,
|
|
440
|
+
declares: false,
|
|
441
|
+
someUndeclared: false
|
|
351
442
|
};
|
|
352
443
|
for (const field of definitions) {
|
|
353
444
|
let any = false;
|
|
@@ -362,6 +453,11 @@ function profileOf(cost, parent, definition) {
|
|
|
362
453
|
});
|
|
363
454
|
if (!any)
|
|
364
455
|
profile.someBare = true;
|
|
456
|
+
if (field.args.some((arg) => cost.sizeArguments.includes(arg.name))) {
|
|
457
|
+
profile.declares = true;
|
|
458
|
+
} else {
|
|
459
|
+
profile.someUndeclared = true;
|
|
460
|
+
}
|
|
365
461
|
}
|
|
366
462
|
byField.set(key, profile);
|
|
367
463
|
return profile;
|
|
@@ -375,7 +471,7 @@ function argumentSize(cost, profile, index, node) {
|
|
|
375
471
|
return literal;
|
|
376
472
|
return profile.someLack[index] ? Math.max(largest ?? 0, cost.defaultFirst) : largest;
|
|
377
473
|
}
|
|
378
|
-
function
|
|
474
|
+
function statedSize(cost, parent, definition, args) {
|
|
379
475
|
const profile = profileOf(cost, parent, definition);
|
|
380
476
|
let size;
|
|
381
477
|
let given = false;
|
|
@@ -387,23 +483,48 @@ function listSize(cost, parent, definition, args) {
|
|
|
387
483
|
if (said !== undefined)
|
|
388
484
|
size = Math.max(size ?? 0, said);
|
|
389
485
|
});
|
|
390
|
-
if (!given && profile.someBare)
|
|
391
|
-
|
|
392
|
-
|
|
486
|
+
if (size !== undefined && !given && profile.someBare) {
|
|
487
|
+
return Math.max(size, cost.defaultFirst);
|
|
488
|
+
}
|
|
489
|
+
return size;
|
|
490
|
+
}
|
|
491
|
+
function declaration(cost, parent, definition) {
|
|
492
|
+
const { declares, someUndeclared } = profileOf(cost, parent, definition);
|
|
493
|
+
if (!declares)
|
|
494
|
+
return "none";
|
|
495
|
+
return someUndeclared ? "some" : "all";
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// src/limits/pending-size.ts
|
|
499
|
+
function listSizeUnder(cost, parent, definition, args, pending) {
|
|
500
|
+
const own = () => statedSize(cost, parent, definition, args) ?? cost.defaultFirst;
|
|
501
|
+
if (pending === undefined)
|
|
502
|
+
return own();
|
|
503
|
+
const declared = declaration(cost, parent, definition);
|
|
504
|
+
if (declared === "none")
|
|
505
|
+
return pending;
|
|
506
|
+
if (declared === "all")
|
|
507
|
+
return own();
|
|
508
|
+
return Math.max(pending, own());
|
|
393
509
|
}
|
|
394
510
|
|
|
395
511
|
// src/limits/max-list-cost.ts
|
|
396
512
|
var DEFAULT_SIZE_ARGUMENTS = ["first", "last", "limit"];
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
513
|
+
function fieldCost(cost, parent, selection, definition, pending) {
|
|
514
|
+
if (!selection.selectionSet)
|
|
515
|
+
return 1;
|
|
516
|
+
const name = selection.name.value;
|
|
517
|
+
const type = getNamedType(definition.type);
|
|
518
|
+
if (!isListType(getNullableType(definition.type))) {
|
|
519
|
+
const stated = statedSize(cost, parent, definition, selection.arguments);
|
|
520
|
+
const inner = costOf(cost, selection.selectionSet, type, stated);
|
|
521
|
+
return add2(1, inner);
|
|
403
522
|
}
|
|
404
|
-
|
|
523
|
+
const inner = costOf(cost, selection.selectionSet, type, undefined);
|
|
524
|
+
const size = parent?.name.startsWith("__") ? introspectionSize(cost.schema, name) : listSizeUnder(cost, parent, definition, selection.arguments, pending);
|
|
525
|
+
return add2(1, multiply(inner, size));
|
|
405
526
|
}
|
|
406
|
-
function costOf(cost, selectionSet, parent) {
|
|
527
|
+
function costOf(cost, selectionSet, parent, pending) {
|
|
407
528
|
let total = 0;
|
|
408
529
|
for (const selection of selectionSet.selections) {
|
|
409
530
|
if (selection.kind === "Field") {
|
|
@@ -415,41 +536,36 @@ function costOf(cost, selectionSet, parent) {
|
|
|
415
536
|
const definition = fieldOf(cost, parent, name);
|
|
416
537
|
if (!definition)
|
|
417
538
|
continue;
|
|
418
|
-
|
|
419
|
-
if (selection.selectionSet) {
|
|
420
|
-
inner = costOf(cost, selection.selectionSet, getNamedType(definition.type));
|
|
421
|
-
if (isListType(getNullableType(definition.type))) {
|
|
422
|
-
const size = parent?.name.startsWith("__") ? introspectionSize(cost.schema, name) : listSize(cost, parent, definition, selection.arguments);
|
|
423
|
-
inner = multiply(inner, size);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
total = add(total, add(1, inner));
|
|
539
|
+
total = add2(total, fieldCost(cost, parent, selection, definition, pending));
|
|
427
540
|
} else if (selection.kind === "InlineFragment") {
|
|
428
541
|
const condition = selection.typeCondition ? cost.schema.getType(selection.typeCondition.name.value) : parent;
|
|
429
|
-
total =
|
|
542
|
+
total = add2(total, costOf(cost, selection.selectionSet, condition, pending));
|
|
430
543
|
} else {
|
|
431
|
-
total =
|
|
544
|
+
total = add2(total, fragmentCost(cost, selection.name.value, pending));
|
|
432
545
|
}
|
|
433
546
|
}
|
|
434
547
|
return total;
|
|
435
548
|
}
|
|
436
|
-
function fragmentCost(cost, name) {
|
|
437
|
-
|
|
438
|
-
if (known
|
|
439
|
-
|
|
549
|
+
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;
|
|
440
560
|
const fragment = cost.getFragment(name);
|
|
441
561
|
if (!fragment || cost.costing.has(name))
|
|
442
562
|
return 0;
|
|
443
563
|
cost.costing.add(name);
|
|
444
|
-
const result = costOf(cost, fragment.selectionSet, cost.schema.getType(fragment.typeCondition.name.value));
|
|
564
|
+
const result = costOf(cost, fragment.selectionSet, cost.schema.getType(fragment.typeCondition.name.value), size);
|
|
445
565
|
cost.costing.delete(name);
|
|
446
|
-
|
|
566
|
+
known.set(key, result);
|
|
447
567
|
return result;
|
|
448
568
|
}
|
|
449
|
-
function rootType(schema, operation) {
|
|
450
|
-
const type = operation.operation === "query" ? schema.getQueryType() : operation.operation === "mutation" ? schema.getMutationType() : schema.getSubscriptionType();
|
|
451
|
-
return type ?? undefined;
|
|
452
|
-
}
|
|
453
569
|
function maxListCost(options) {
|
|
454
570
|
const { budget, defaultFirst } = options;
|
|
455
571
|
const sizeArguments = Object.freeze([
|
|
@@ -470,9 +586,9 @@ function maxListCost(options) {
|
|
|
470
586
|
};
|
|
471
587
|
return {
|
|
472
588
|
OperationDefinition(operation) {
|
|
473
|
-
const total = costOf(cost, operation.selectionSet, rootType(schema, operation));
|
|
589
|
+
const total = costOf(cost, operation.selectionSet, rootType(schema, operation), undefined);
|
|
474
590
|
if (total > budget) {
|
|
475
|
-
context.reportError(new
|
|
591
|
+
context.reportError(new GraphQLError5(`${operationLabel(operation)} costs ${total}, more than the ${budget} allowed`, {
|
|
476
592
|
nodes: [operation],
|
|
477
593
|
extensions: {
|
|
478
594
|
code: "QUERY_TOO_COSTLY",
|
|
@@ -561,10 +677,11 @@ export {
|
|
|
561
677
|
inputPath,
|
|
562
678
|
invalidInputError,
|
|
563
679
|
maxDepth,
|
|
680
|
+
maxFields,
|
|
564
681
|
maxListCost,
|
|
565
682
|
validated,
|
|
566
683
|
withValidation
|
|
567
684
|
};
|
|
568
685
|
|
|
569
|
-
//# debugId=
|
|
686
|
+
//# debugId=3B937DADAE820B8964756E2164756E21
|
|
570
687
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/bad-user-input.ts", "../src/invalid-input.ts", "../src/field-issue-of.ts", "../src/limits/max-depth.ts", "../src/limits/describe.ts", "../src/limits/introspection.ts", "../src/limits/max-list-cost.ts", "../src/limits/list-size.ts", "../src/validated.ts", "../src/with-validation.ts"],
|
|
3
|
+
"sources": ["../src/bad-user-input.ts", "../src/invalid-input.ts", "../src/field-issue-of.ts", "../src/limits/max-depth.ts", "../src/limits/describe.ts", "../src/limits/introspection.ts", "../src/limits/max-fields.ts", "../src/limits/max-list-cost.ts", "../src/limits/cost-context.ts", "../src/limits/list-size.ts", "../src/limits/pending-size.ts", "../src/validated.ts", "../src/with-validation.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"import { GraphQLError } from 'graphql';\nimport type { z } from 'zod';\nimport type { ConstraintArgument } from './rules';\n\n/** One reason an input was refused, at its path inside the arguments. */\nexport interface ValidationIssue {\n\t/** `['input', 'address', 'zip']`: the argument, then the input fields. */\n\treadonly path: readonly (string | number)[];\n\treadonly message: string;\n\t/** Zod's issue code: `too_small`, `invalid_format`, `custom`, ... */\n\treadonly code: string;\n\t/**\n\t * The `@constraint` argument that refused (`minLength`, `format`), when a\n\t * directive did: stable across Zod versions, unlike `code`. Absent for a\n\t * refusal of `validated()`'s own schema.\n\t */\n\treadonly constraint?: ConstraintArgument;\n\t/**\n\t * What that `@constraint` argument was declared with, exactly as written\n\t * (`100` for `maxLength: 100`, `\"email\"` for `format: \"email\"`), so a\n\t * client can say \"at most 100 characters\" without parsing `message`.\n\t * Present exactly when `constraint` is.\n\t */\n\treadonly value?: ConstraintValue;\n}\n\n/** What a `@constraint` argument is declared with: a number or a string. */\nexport type ConstraintValue = string | number;\n\n/** The `extensions` of the error an invalid input becomes. */\nexport type BadUserInputExtensions = {\n\treadonly code: 'BAD_USER_INPUT';\n\treadonly issues: readonly ValidationIssue[];\n};\n\n/**\n * Names the `@constraint` argument behind an issue, and what it was declared\n * with, when there is one.\n */\nexport type ConstraintOf = (\n\tissue: z.core.$ZodIssue,\n) => { argument: ConstraintArgument; value: ConstraintValue } | undefined;\n\nfunction issuesOf(\n\terror: z.ZodError,\n\tconstraintOf?: ConstraintOf,\n): ValidationIssue[] {\n\treturn error.issues.map((issue) => {\n\t\tconst path = issue.path.map((key) =>\n\t\t\ttypeof key === 'number' ? key : String(key),\n\t\t);\n\t\tconst constraint = constraintOf?.(issue);\n\t\treturn constraint\n\t\t\t? {\n\t\t\t\t\tpath,\n\t\t\t\t\tmessage: issue.message,\n\t\t\t\t\tcode: issue.code,\n\t\t\t\t\tconstraint: constraint.argument,\n\t\t\t\t\tvalue: constraint.value,\n\t\t\t\t}\n\t\t\t: { path, message: issue.message, code: issue.code };\n\t});\n}\n\nfunction errorOf(where: string, issues: ValidationIssue[]): GraphQLError {\n\tconst [first] = issues;\n\tconst reason = first\n\t\t? `${first.path.join('.') || 'arguments'}: ${first.message}`\n\t\t: 'refused';\n\tconst extensions: BadUserInputExtensions = { code: 'BAD_USER_INPUT', issues };\n\treturn new GraphQLError(`Invalid arguments for ${where}. ${reason}`, {\n\t\textensions,\n\t});\n}\n\n/**\n * The one error an invalid input becomes: `extensions.code` is\n * `BAD_USER_INPUT`, the code Apollo and most clients already read, and\n * `extensions.issues` lists every reason with its path, so a form can show\n * each one beside its field. The message names the field and the first\n * reason, for a log line.\n */\nexport function badUserInput(where: string, error: z.ZodError): GraphQLError {\n\treturn errorOf(where, issuesOf(error));\n}\n\n/** The parsed arguments, or the error above, its issues named by `constraintOf`. */\nexport async function parseArgs(\n\tschema: z.ZodType,\n\targs: unknown,\n\twhere: string,\n\tconstraintOf?: ConstraintOf,\n): Promise<unknown> {\n\tconst result = await schema.safeParseAsync(args);\n\tif (!result.success)\n\t\tthrow errorOf(where, issuesOf(result.error, constraintOf));\n\treturn result.data;\n}\n",
|
|
6
6
|
"import { GraphQLError, type GraphQLErrorOptions } from 'graphql';\n\n/** The code of the error `invalidInputError` builds, and its default message. */\nexport const INVALID_INPUT = 'validation.errors.invalid-input';\n\n/** Values a message is built from, such as `{ min: 2 }`. */\nexport type IssueParams = Record<string, string | number>;\n\n/** One field at fault: where it is, why, and what the reason's message needs. */\nexport interface FieldIssue {\n\t/** The field inside the input, dotted: `person.firstName`, `tags.1`. */\n\treadonly path: string;\n\t/** A code your client and your translations know: `validation.errors.too-short`. */\n\treadonly code: string;\n\t/** Values the message needs; an object with no key counts as none. */\n\treadonly params?: IssueParams;\n}\n\n/** One entry of `extensions.fields`: a `FieldIssue` with its message. */\nexport interface FieldError {\n\treadonly path: string;\n\treadonly code: string;\n\t/** `translate(code, params)`, or the code itself without a translator. */\n\treadonly message: string;\n\t/** Present only when the issue had params with at least one key. */\n\treadonly params?: IssueParams;\n}\n\n/** Turns a code (and its params) into the text a person reads. */\nexport type Translate = (code: string, params?: IssueParams) => string;\n\n/** The options of `invalidInputError`: GraphQL's own, and a translator. */\nexport type InvalidInputOptions = GraphQLErrorOptions & {\n\treadonly translate?: Translate;\n};\n\n/** The options of `fieldsError`: also an HTTP status and the error's own params. */\nexport type FieldsErrorOptions = InvalidInputOptions & {\n\t/** `extensions.http.status`, for a server that reads it (409, ...). */\n\treadonly status?: number;\n\treadonly params?: IssueParams;\n};\n\n/** `params` itself, or `undefined` when it holds no key: never `{}`. */\nfunction paramsOf(params: IssueParams | undefined): IssueParams | undefined {\n\treturn params && Object.keys(params).length > 0 ? params : undefined;\n}\n\nfunction messageOf(\n\tcode: string,\n\tparams: IssueParams | undefined,\n\ttranslate: Translate | undefined,\n): string {\n\treturn translate?.(code, params) ?? code;\n}\n\nfunction fieldsOf(\n\tissues: readonly FieldIssue[],\n\ttranslate: Translate | undefined,\n): FieldError[] {\n\treturn issues.map(({ path, code, params: given }) => {\n\t\tconst params = paramsOf(given);\n\t\treturn {\n\t\t\tpath,\n\t\t\tcode,\n\t\t\tmessage: messageOf(code, params, translate),\n\t\t\t...(params && { params }),\n\t\t};\n\t});\n}\n\n/**\n * One 400 error listing every field at fault, for an API that answers invalid\n * input this way: `extensions` is `{ code: 'validation.errors.invalid-input',\n * http: { status: 400 }, fields }`, each field with its translated message\n * (the code itself without `translate`), in the order given. GraphQL's\n * options (`originalError`, `path`, `nodes`, ...) are kept; an `extensions`\n * among them is replaced by this one.\n */\nexport function invalidInputError(\n\tissues: readonly FieldIssue[],\n\toptions: InvalidInputOptions = {},\n): GraphQLError {\n\tconst { translate, ...graphql } = options;\n\treturn new GraphQLError(messageOf(INVALID_INPUT, undefined, translate), {\n\t\t...graphql,\n\t\textensions: {\n\t\t\tcode: INVALID_INPUT,\n\t\t\thttp: { status: 400 },\n\t\t\tfields: fieldsOf(issues, translate),\n\t\t},\n\t});\n}\n\n/**\n * A refusal of your own (a 409 conflict, say) that names the fields at\n * fault: `extensions` is `{ code, params?, http?: { status }, fields }`, the\n * fields worded as `invalidInputError` words them, the message\n * `translate(code, params)` or the code. An `extensions` among the options\n * is replaced by this one.\n */\nexport function fieldsError(\n\tcode: string,\n\tissues: readonly FieldIssue[],\n\toptions: FieldsErrorOptions = {},\n): GraphQLError {\n\tconst { translate, status, params: given, ...graphql } = options;\n\tconst params = paramsOf(given);\n\treturn new GraphQLError(messageOf(code, params, translate), {\n\t\t...graphql,\n\t\textensions: {\n\t\t\tcode,\n\t\t\t...(params && { params }),\n\t\t\t...(status && { http: { status } }),\n\t\t\tfields: fieldsOf(issues, translate),\n\t\t},\n\t});\n}\n\n/**\n * A GraphQL or Zod path as a `FieldIssue` path: dotted, without the leading\n * `input` argument when a field follows it, a symbol written as\n * `String(key)`. `['input', 'person', 'firstName']` is `person.firstName`,\n * `['input', 'tags', 1]` is `tags.1`, `['first']` and `['input']` stay as\n * they are.\n */\nexport function inputPath(path: readonly PropertyKey[]): string {\n\tconst [first, ...rest] = path;\n\treturn (first === 'input' && rest.length > 0 ? rest : path)\n\t\t.map((key) => String(key))\n\t\t.join('.');\n}\n",
|
|
@@ -8,12 +8,15 @@
|
|
|
8
8
|
"import {\n\ttype FragmentDefinitionNode,\n\tGraphQLError,\n\ttype SelectionSetNode,\n\ttype ValidationContext,\n\ttype ValidationRule,\n} from 'graphql';\nimport { assertInteger, operationLabel } from './describe';\nimport { isIntrospectionRoot } from './introspection';\n\n/** Options of {@link maxDepth}. */\nexport interface MaxDepthOptions {\n\t/** The deepest nesting of field selections an operation may have (at least 1). */\n\tdepth: number;\n\t/**\n\t * Do not count `__schema` and `__type` (default `false`). Only where\n\t * introspection is disabled or the client is trusted, e.g. GraphiQL in\n\t * development: the standard introspection query (`getIntrospectionQuery()`) is 15 levels deep.\n\t */\n\tignoreIntrospection?: boolean;\n}\n\n/** What a walk of one document needs: what it has measured so far. */\ninterface DepthContext {\n\tgetFragment: (name: string) => FragmentDefinitionNode | null | undefined;\n\tfragmentDepths: Map<string, number>;\n\tmeasuring: Set<string>;\n\tignoreIntrospection: boolean;\n}\n\n/** The depth of `selectionSet`: 0 when it selects no field. */\nfunction depthOf(depth: DepthContext, selectionSet: SelectionSetNode): number {\n\tlet deepest = 0;\n\tfor (const selection of selectionSet.selections) {\n\t\tlet here = 0;\n\t\tif (selection.kind === 'Field') {\n\t\t\tconst name = selection.name.value;\n\t\t\tif (name === '__typename') continue;\n\t\t\tif (depth.ignoreIntrospection && isIntrospectionRoot(name)) continue;\n\t\t\there =\n\t\t\t\t1 +\n\t\t\t\t(selection.selectionSet ? depthOf(depth, selection.selectionSet) : 0);\n\t\t} else if (selection.kind === 'InlineFragment') {\n\t\t\there = depthOf(depth, selection.selectionSet);\n\t\t} else {\n\t\t\there = fragmentDepth(depth, selection.name.value);\n\t\t}\n\t\tif (here > deepest) deepest = here;\n\t}\n\treturn deepest;\n}\n\n/** The depth of the named fragment, measured once. */\nfunction fragmentDepth(depth: DepthContext, name: string): number {\n\tconst known = depth.fragmentDepths.get(name);\n\tif (known !== undefined) return known;\n\tconst fragment = depth.getFragment(name);\n\t// A cycle is NoFragmentCyclesRule's to report; here it adds nothing.\n\tif (!fragment || depth.measuring.has(name)) return 0;\n\tdepth.measuring.add(name);\n\tconst result = depthOf(depth, fragment.selectionSet);\n\tdepth.measuring.delete(name);\n\tdepth.fragmentDepths.set(name, result);\n\treturn result;\n}\n\n/**\n * A graphql-js validation rule refusing an operation nested deeper than\n * `depth` fields: a top-level field is depth 1.\n *\n * Named fragments are followed (each measured once), inline fragments add no\n * depth, and `__typename` does not count. One `GraphQLError` per\n * operation, with `extensions: { code: 'QUERY_TOO_DEEP', depth, limit }`,\n * `depth` being the operation's real depth.\n *\n * ```ts\n * validate(schema, document, [...specifiedRules, maxDepth({ depth: 8 })]);\n * // graphql-yoga: onValidate: ({ addValidationRule }) => addValidationRule(maxDepth({ depth: 8 }))\n * ```\n */\nexport function maxDepth(options: MaxDepthOptions): ValidationRule {\n\tconst limit = options.depth;\n\tassertInteger('maxDepth: depth', limit, 1);\n\treturn (context: ValidationContext) => {\n\t\tconst walk: DepthContext = {\n\t\t\tgetFragment: (name) => context.getFragment(name),\n\t\t\tfragmentDepths: new Map(),\n\t\t\tmeasuring: new Set(),\n\t\t\tignoreIntrospection: options.ignoreIntrospection ?? false,\n\t\t};\n\t\treturn {\n\t\t\tOperationDefinition(operation) {\n\t\t\t\tconst depth = depthOf(walk, operation.selectionSet);\n\t\t\t\tif (depth > limit) {\n\t\t\t\t\tcontext.reportError(\n\t\t\t\t\t\tnew GraphQLError(\n\t\t\t\t\t\t\t`${operationLabel(operation)} is ${depth} levels deep, more than the ${limit} allowed`,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnodes: [operation],\n\t\t\t\t\t\t\t\textensions: { code: 'QUERY_TOO_DEEP', depth, limit },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t};\n\t};\n}\n",
|
|
9
9
|
"import type { OperationDefinitionNode } from 'graphql';\n\n/** `Operation \"Name\"`, or `Operation` for an anonymous one. */\nexport function operationLabel(operation: OperationDefinitionNode): string {\n\treturn operation.name ? `Operation \"${operation.name.value}\"` : 'Operation';\n}\n\n/**\n * Throws a `RangeError` unless `value` is an integer from `min` up to, and\n * excluding, `max` (default: `Number.MAX_SAFE_INTEGER`, where a cost is clamped).\n */\nexport function assertInteger(\n\toption: string,\n\tvalue: number,\n\tmin: number,\n\tmax = Number.MAX_SAFE_INTEGER,\n): void {\n\tif (!Number.isInteger(value) || value < min || value >= max) {\n\t\tthrow new RangeError(\n\t\t\t`${option} must be an integer from ${min} to ${max - 1}.`,\n\t\t);\n\t}\n}\n",
|
|
10
10
|
"import {\n\ttype GraphQLField,\n\ttype GraphQLNamedType,\n\ttype GraphQLSchema,\n\tisEnumType,\n\tisInputObjectType,\n\tisInterfaceType,\n\tisObjectType,\n\tisUnionType,\n\tSchemaMetaFieldDef,\n\tTypeMetaFieldDef,\n} from 'graphql';\n\n/** The meta-fields that read the schema; `__typename` is not one. */\nexport function isIntrospectionRoot(name: string): boolean {\n\treturn name === '__schema' || name === '__type';\n}\n\n/** The definition of `__schema` or `__type`, selected on the query root. */\nexport function introspectionRoot(\n\tname: string,\n): GraphQLField<unknown, unknown> | undefined {\n\tif (name === '__schema') return SchemaMetaFieldDef;\n\tif (name === '__type') return TypeMetaFieldDef;\n\treturn undefined;\n}\n\n/** The largest list the introspection types can return for `schema`, by schema. */\nconst largest = new WeakMap<GraphQLSchema, number>();\n\nconst typeCounts = new WeakMap<GraphQLSchema, number>();\n\nfunction typeCount(schema: GraphQLSchema): number {\n\tlet count = typeCounts.get(schema);\n\tif (count === undefined) {\n\t\tcount = Object.keys(schema.getTypeMap()).length;\n\t\ttypeCounts.set(schema, count);\n\t}\n\treturn count;\n}\n\nfunction largestCount(schema: GraphQLSchema): number {\n\tconst known = largest.get(schema);\n\tif (known !== undefined) return known;\n\tlet max = schema.getDirectives().length;\n\tfor (const directive of schema.getDirectives()) {\n\t\tmax = Math.max(max, directive.args.length, directive.locations.length);\n\t}\n\tfor (const type of Object.values(schema.getTypeMap())) {\n\t\tmax = Math.max(max, countsOf(schema, type));\n\t}\n\tlargest.set(schema, max);\n\treturn max;\n}\n\n/** The longest of a type's fields, input fields, enum values, interfaces, possible types and arguments. */\nfunction countsOf(schema: GraphQLSchema, type: GraphQLNamedType): number {\n\tif (isObjectType(type) || isInterfaceType(type)) {\n\t\tconst fields = Object.values(type.getFields());\n\t\treturn Math.max(\n\t\t\tfields.length,\n\t\t\ttype.getInterfaces().length,\n\t\t\tisInterfaceType(type) ? schema.getPossibleTypes(type).length : 0,\n\t\t\t...fields.map((field) => field.args.length),\n\t\t);\n\t}\n\tif (isInputObjectType(type)) return Object.keys(type.getFields()).length;\n\tif (isEnumType(type)) return type.getValues().length;\n\tif (isUnionType(type)) return type.getTypes().length;\n\treturn 0;\n}\n\n/**\n * The most items the introspection list `parent.field` can hold in `schema`:\n * the number of types for `__Schema.types`, else the largest list anywhere in\n * the schema. Not `defaultFirst`: a query asks no size of them.\n */\nexport function introspectionSize(\n\tschema: GraphQLSchema,\n\tfield: string,\n): number {\n\treturn field === 'types' ? typeCount(schema) : largestCount(schema);\n}\n",
|
|
11
|
-
"import {\n\ttype FragmentDefinitionNode,\n\tGraphQLError,\n\ttype
|
|
12
|
-
"import {\n\ttype
|
|
11
|
+
"import {\n\ttype FragmentDefinitionNode,\n\tGraphQLError,\n\ttype SelectionSetNode,\n\ttype ValidationContext,\n\ttype ValidationRule,\n} from 'graphql';\nimport { assertInteger, operationLabel } from './describe';\nimport { isIntrospectionRoot } from './introspection';\n\n/** Options of {@link maxFields}. */\nexport interface MaxFieldsOptions {\n\t/** The most field selections an operation may have (at least 1). */\n\tlimit: number;\n\t/**\n\t * Do not count `__schema` and `__type` (default `false`). Only where\n\t * introspection is disabled or the client is trusted, e.g. GraphiQL in\n\t * development: the standard introspection query (`getIntrospectionQuery()`)\n\t * selects 220 fields.\n\t */\n\tignoreIntrospection?: boolean;\n}\n\n/** What a walk of one document needs: what it has counted so far. */\ninterface FieldsContext {\n\tgetFragment: (name: string) => FragmentDefinitionNode | null | undefined;\n\tfragmentCounts: Map<string, number>;\n\tcounting: Set<string>;\n\tignoreIntrospection: boolean;\n}\n\n/** `a + b`, clamped where a count stops being exact. */\nfunction add(a: number, b: number): number {\n\treturn Math.min(a + b, Number.MAX_SAFE_INTEGER);\n}\n\n/** The field selections of `selectionSet`, nested ones included. */\nfunction countOf(walk: FieldsContext, selectionSet: SelectionSetNode): number {\n\tlet total = 0;\n\tfor (const selection of selectionSet.selections) {\n\t\tif (selection.kind === 'Field') {\n\t\t\tif (walk.ignoreIntrospection && isIntrospectionRoot(selection.name.value))\n\t\t\t\tcontinue;\n\t\t\ttotal = add(total, 1);\n\t\t\tif (selection.selectionSet)\n\t\t\t\ttotal = add(total, countOf(walk, selection.selectionSet));\n\t\t} else if (selection.kind === 'InlineFragment') {\n\t\t\ttotal = add(total, countOf(walk, selection.selectionSet));\n\t\t} else {\n\t\t\ttotal = add(total, fragmentCount(walk, selection.name.value));\n\t\t}\n\t}\n\treturn total;\n}\n\n/** The count of the named fragment, walked once. */\nfunction fragmentCount(walk: FieldsContext, name: string): number {\n\tconst known = walk.fragmentCounts.get(name);\n\tif (known !== undefined) return known;\n\tconst fragment = walk.getFragment(name);\n\t// A cycle is NoFragmentCyclesRule's to report; here it adds nothing.\n\tif (!fragment || walk.counting.has(name)) return 0;\n\twalk.counting.add(name);\n\tconst result = countOf(walk, fragment.selectionSet);\n\twalk.counting.delete(name);\n\twalk.fragmentCounts.set(name, result);\n\treturn result;\n}\n\n/**\n * A graphql-js validation rule refusing an operation that selects more than\n * `limit` fields: neither `maxDepth` nor `maxListCost` bounds breadth, so\n * thousands of aliases of a cheap field (or of `__typename`) pass both.\n *\n * Every field node counts 1, aliases and `__typename` included. A named\n * fragment counts at each spread (walked once), an inline fragment counts its\n * contents, and every branch of a union counts: nothing is pruned by type.\n * `@skip` and `@include` are not evaluated, so the count can be over the\n * document's field count. It counts the document, spreads expanded, not what the\n * executor runs: how often a field runs inside a list is `maxListCost`'s.\n * One `GraphQLError` per operation, with\n * `extensions: { code: 'QUERY_TOO_WIDE', fields, limit }`, `fields` being the\n * operation's real count (clamped at `Number.MAX_SAFE_INTEGER`).\n *\n * ```ts\n * validate(schema, document, [...specifiedRules, maxFields({ limit: 500 })]);\n * // graphql-yoga: onValidate: ({ addValidationRule }) => addValidationRule(maxFields({ limit: 500 }))\n * ```\n */\nexport function maxFields(options: MaxFieldsOptions): ValidationRule {\n\tconst limit = options.limit;\n\tassertInteger('maxFields: limit', limit, 1);\n\treturn (context: ValidationContext) => {\n\t\tconst walk: FieldsContext = {\n\t\t\tgetFragment: (name) => context.getFragment(name),\n\t\t\tfragmentCounts: new Map(),\n\t\t\tcounting: new Set(),\n\t\t\tignoreIntrospection: options.ignoreIntrospection ?? false,\n\t\t};\n\t\treturn {\n\t\t\tOperationDefinition(operation) {\n\t\t\t\tconst fields = countOf(walk, operation.selectionSet);\n\t\t\t\tif (fields > limit) {\n\t\t\t\t\tcontext.reportError(\n\t\t\t\t\t\tnew GraphQLError(\n\t\t\t\t\t\t\t`${operationLabel(operation)} selects ${fields} fields, more than the ${limit} allowed`,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnodes: [operation],\n\t\t\t\t\t\t\t\textensions: { code: 'QUERY_TOO_WIDE', fields, limit },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t};\n\t};\n}\n",
|
|
12
|
+
"import {\n\ttype FieldNode,\n\tGraphQLError,\n\ttype GraphQLField,\n\ttype GraphQLNamedType,\n\tgetNamedType,\n\tgetNullableType,\n\tisListType,\n\ttype SelectionSetNode,\n\ttype ValidationContext,\n\ttype ValidationRule,\n} from 'graphql';\nimport {\n\tadd,\n\ttype CostContext,\n\tfieldOf,\n\tmemoSize,\n\tmultiply,\n\tNO_PENDING,\n\trootType,\n} from './cost-context';\nimport { assertInteger, operationLabel } from './describe';\nimport { introspectionSize, isIntrospectionRoot } from './introspection';\nimport { statedSize } from './list-size';\nimport { listSizeUnder } from './pending-size';\n\n/** Options of {@link maxListCost}. */\nexport interface MaxListCostOptions {\n\t/** The most an operation may cost (at least 0). */\n\tbudget: number;\n\t/** The size of a list field whose size cannot be read (an integer of at least 0). */\n\tdefaultFirst: number;\n\t/**\n\t * The argument names that size a list. Each one given, or defaulted in the\n\t * SDL, says a size (an Int, a canonical-integer string or an integral Float)\n\t * and the largest wins. Default `['first', 'last', 'limit']`. One on a\n\t * non-list field also sizes the lists declaring none directly on its return\n\t * type (a Relay connection's `edges` and `nodes`).\n\t */\n\tsizeArguments?: readonly string[];\n\t/**\n\t * Do not cost `__schema` and `__type` (default `false`). Only where\n\t * introspection is disabled or the client is trusted, e.g. GraphiQL in\n\t * development: the standard introspection query is costly (on the order of\n\t * 200,000 on a one-field schema).\n\t */\n\tignoreIntrospection?: boolean;\n}\n\nconst DEFAULT_SIZE_ARGUMENTS = ['first', 'last', 'limit'] as const;\n\n/**\n * The cost of one selected field. `pending` is the size of the field whose\n * return type this selection is on: only a list declaring no size argument\n * takes it, and no field passes it on.\n */\nfunction fieldCost(\n\tcost: CostContext,\n\tparent: GraphQLNamedType | undefined,\n\tselection: FieldNode,\n\tdefinition: GraphQLField<unknown, unknown>,\n\tpending: number | undefined,\n): number {\n\tif (!selection.selectionSet) return 1;\n\tconst name = selection.name.value;\n\tconst type = getNamedType(definition.type);\n\tif (!isListType(getNullableType(definition.type))) {\n\t\t// An object field hands its own size, if it states one, to the lists\n\t\t// selected directly on it; the pending size stops here.\n\t\tconst stated = statedSize(cost, parent, definition, selection.arguments);\n\t\tconst inner = costOf(cost, selection.selectionSet, type, stated);\n\t\treturn add(1, inner);\n\t}\n\tconst inner = costOf(cost, selection.selectionSet, type, undefined);\n\tconst size = parent?.name.startsWith('__')\n\t\t? introspectionSize(cost.schema, name)\n\t\t: listSizeUnder(cost, parent, definition, selection.arguments, pending);\n\treturn add(1, multiply(inner, size));\n}\n\n/** The cost of `selectionSet` selected on `parent`, under the `pending` size of the field they are selected on. */\nfunction costOf(\n\tcost: CostContext,\n\tselectionSet: SelectionSetNode,\n\tparent: GraphQLNamedType | undefined,\n\tpending: number | undefined,\n): number {\n\tlet total = 0;\n\tfor (const selection of selectionSet.selections) {\n\t\tif (selection.kind === 'Field') {\n\t\t\tconst name = selection.name.value;\n\t\t\tif (name === '__typename') continue;\n\t\t\tif (isIntrospectionRoot(name) && cost.ignoreIntrospection) continue;\n\t\t\tconst definition = fieldOf(cost, parent, name);\n\t\t\t// An unknown field is another rule's to report.\n\t\t\tif (!definition) continue;\n\t\t\ttotal = add(\n\t\t\t\ttotal,\n\t\t\t\tfieldCost(cost, parent, selection, definition, pending),\n\t\t\t);\n\t\t} else if (selection.kind === 'InlineFragment') {\n\t\t\tconst condition = selection.typeCondition\n\t\t\t\t? cost.schema.getType(selection.typeCondition.name.value)\n\t\t\t\t: parent;\n\t\t\ttotal = add(\n\t\t\t\ttotal,\n\t\t\t\tcostOf(cost, selection.selectionSet, condition, pending),\n\t\t\t);\n\t\t} else {\n\t\t\ttotal = add(total, fragmentCost(cost, selection.name.value, pending));\n\t\t}\n\t}\n\treturn total;\n}\n\n/** The cost of the named fragment spread under `pending`, computed once per size. */\nfunction fragmentCost(\n\tcost: CostContext,\n\tname: string,\n\tpending: number | undefined,\n): number {\n\tlet known = cost.fragmentCosts.get(name);\n\tif (!known) {\n\t\tknown = new Map();\n\t\tcost.fragmentCosts.set(name, known);\n\t}\n\tconst size = memoSize(known, pending);\n\tconst key = size ?? NO_PENDING;\n\tconst memo = known.get(key);\n\tif (memo !== undefined) return memo;\n\tconst fragment = cost.getFragment(name);\n\t// A cycle is NoFragmentCyclesRule's to report; here it adds nothing.\n\tif (!fragment || cost.costing.has(name)) return 0;\n\tcost.costing.add(name);\n\tconst result = costOf(\n\t\tcost,\n\t\tfragment.selectionSet,\n\t\tcost.schema.getType(fragment.typeCondition.name.value),\n\t\tsize,\n\t);\n\tcost.costing.delete(name);\n\tknown.set(key, result);\n\treturn result;\n}\n\n/**\n * A graphql-js validation rule refusing an operation whose cost is more than\n * `budget`, to stop a client from exploiting list cycles (`Folder.items`,\n * `Item.folder`, `Folder.items`, …) for a cost growing exponentially.\n *\n * The cost of an operation is the sum, over every selected field, of the\n * product of the sizes of the list fields enclosing it: a field costs 1, and a\n * list field multiplies the cost of its sub-selection by its size.\n * `__typename` costs nothing. `__schema` and `__type` are costed like any\n * field, their lists sized by the schema itself (`__Schema.types` is the number\n * of types, the other lists the longest list anywhere in the schema), unless\n * `ignoreIntrospection` is set.\n *\n * The size of a list field is the largest size its `sizeArguments` (default\n * `first`, `last`, `limit`) say. A literal Int, a String holding a canonical\n * integer (`\"1000\"`) or an integral Float (`1e3`) of at least 0 says that\n * number. Anything else (a negative literal, a variable, since validation has\n * no variable values) says the argument's SDL default when it has a usable one,\n * `defaultFirst` otherwise; an argument not given says its SDL default, or\n * nothing. When nothing is said the size is `defaultFirst`. On an interface the\n * largest default over its possible types is used. Hence no subtree ever costs\n * less than nothing: a negative `first` on one field cannot cancel the cost of\n * its sibling. A field whose type (once unwrapped from non-null) is a list is\n * one list, nested `[[X]]` included.\n *\n * A Relay connection puts the size on a field returning an object, with the\n * list below it (`items(first: 100) { edges { node { id } } }`). A field that\n * is not a list and states a size (by the same reading) hands it to the lists\n * selected directly on its return type, through inline fragments and fragment\n * spreads on that same selection set, and only to those declaring none of the\n * size arguments (`edges`, `nodes`): such a list takes it instead of\n * `defaultFirst`. A list declaring a size argument (`recent(first: Int)`)\n * reads its own, never the pending size. Crossing any other field (an object\n * field, `pageInfo`, a wrapper) ends it. A connection stating nothing hands\n * down nothing: its lists are sized `defaultFirst`.\n *\n * Named fragments are followed, each costed once per pending size (past eight\n * distinct sizes under one fragment a size is rounded up to a power of two, so\n * the work stays linear in the document and a cost only over-counts). Inline fragments and\n * fragments on an abstract type are summed branch by branch, so the cost of a\n * query on an interface or a union is overestimated, never underestimated.\n *\n * One `GraphQLError` per operation, with\n * `extensions: { code: 'QUERY_TOO_COSTLY', cost, limit }`. `cost` is exact up\n * to `Number.MAX_SAFE_INTEGER`, which it never exceeds.\n *\n * ```ts\n * const rule = maxListCost({ budget: 10_000, defaultFirst: 50 });\n * validate(schema, document, [...specifiedRules, rule]);\n * // graphql-yoga: onValidate: ({ addValidationRule }) => addValidationRule(rule)\n * ```\n */\nexport function maxListCost(options: MaxListCostOptions): ValidationRule {\n\tconst { budget, defaultFirst } = options;\n\t// A copy: a caller changing its array later must not desync the schema\n\t// cache keyed by it.\n\tconst sizeArguments = Object.freeze([\n\t\t...(options.sizeArguments ?? DEFAULT_SIZE_ARGUMENTS),\n\t]);\n\tassertInteger('maxListCost: budget', budget, 0);\n\tassertInteger('maxListCost: defaultFirst', defaultFirst, 0);\n\n\treturn (context: ValidationContext) => {\n\t\tconst schema = context.getSchema();\n\t\tconst cost: CostContext = {\n\t\t\tschema,\n\t\t\tsizeArguments,\n\t\t\tdefaultFirst,\n\t\t\tignoreIntrospection: options.ignoreIntrospection ?? false,\n\t\t\tgetFragment: (name) => context.getFragment(name),\n\t\t\tfragmentCosts: new Map(),\n\t\t\tcosting: new Set(),\n\t\t};\n\t\treturn {\n\t\t\tOperationDefinition(operation) {\n\t\t\t\tconst total = costOf(\n\t\t\t\t\tcost,\n\t\t\t\t\toperation.selectionSet,\n\t\t\t\t\trootType(schema, operation),\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t\tif (total > budget) {\n\t\t\t\t\tcontext.reportError(\n\t\t\t\t\t\tnew GraphQLError(\n\t\t\t\t\t\t\t`${operationLabel(operation)} costs ${total}, more than the ${budget} allowed`,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnodes: [operation],\n\t\t\t\t\t\t\t\textensions: {\n\t\t\t\t\t\t\t\t\tcode: 'QUERY_TOO_COSTLY',\n\t\t\t\t\t\t\t\t\tcost: total,\n\t\t\t\t\t\t\t\t\tlimit: budget,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t};\n\t};\n}\n",
|
|
13
|
+
"import {\n\ttype FragmentDefinitionNode,\n\ttype GraphQLField,\n\ttype GraphQLNamedType,\n\ttype GraphQLSchema,\n\tisInterfaceType,\n\tisObjectType,\n\ttype OperationDefinitionNode,\n} from 'graphql';\nimport { introspectionRoot, isIntrospectionRoot } from './introspection';\nimport type { SizeContext } from './list-size';\n\n/** Costs are plain numbers, held below this so a hostile query never reaches `Infinity`. */\nconst CEILING = Number.MAX_SAFE_INTEGER;\n\nexport const add = (a: number, b: number) => Math.min(CEILING, a + b);\nexport const multiply = (a: number, b: number) => Math.min(CEILING, a * b);\n\n/** What a walk of one document needs: the options, and what it has measured so far. */\nexport interface CostContext extends SizeContext {\n\tignoreIntrospection: boolean;\n\tgetFragment: (name: string) => FragmentDefinitionNode | null | undefined;\n\tfragmentCosts: Map<string, Map<number, number>>;\n\tcosting: Set<string>;\n}\n\n/** The definition of the field `name` on `parent`, meta-fields of the query root included. */\nexport function fieldOf(\n\tcost: CostContext,\n\tparent: GraphQLNamedType | undefined,\n\tname: string,\n): GraphQLField<unknown, unknown> | undefined {\n\tif (parent === cost.schema.getQueryType() && isIntrospectionRoot(name)) {\n\t\treturn introspectionRoot(name);\n\t}\n\treturn isObjectType(parent) || isInterfaceType(parent)\n\t\t? parent.getFields()[name]\n\t\t: undefined;\n}\n\n/** The type an operation selects on. */\nexport function rootType(\n\tschema: GraphQLSchema,\n\toperation: OperationDefinitionNode,\n) {\n\tconst type =\n\t\toperation.operation === 'query'\n\t\t\t? schema.getQueryType()\n\t\t\t: operation.operation === 'mutation'\n\t\t\t\t? schema.getMutationType()\n\t\t\t\t: schema.getSubscriptionType();\n\treturn type ?? undefined;\n}\n\n/** Distinct pending sizes costed exactly per fragment; further ones are rounded up. */\nconst EXACT_SIZES = 8;\n\n/** The key a fragment is memoized under: `-1` for no pending size. */\nexport const NO_PENDING = -1;\n\n/**\n * The pending size a fragment is costed under. A fragment spread under many\n * distinct sizes would be costed once per size, quadratic in a hostile\n * document; past `EXACT_SIZES` of them a new size is rounded up to a power of\n * two (a cost never lowers as a size grows, so it only over-counts, by less\n * than twice), which leaves at most `EXACT_SIZES` + 53 costings per fragment.\n */\nexport function memoSize(\n\tknown: ReadonlyMap<number, number>,\n\tpending: number | undefined,\n): number | undefined {\n\tif (pending === undefined || known.has(pending) || known.size < EXACT_SIZES) {\n\t\treturn pending;\n\t}\n\t// Math.log2 rounds near 2^k + d, so the power is checked, not trusted.\n\tlet rounded = 2 ** Math.ceil(Math.log2(Math.max(pending, 1)));\n\tif (rounded < pending) rounded *= 2;\n\treturn Math.min(CEILING, rounded);\n}\n",
|
|
14
|
+
"import {\n\ttype ArgumentNode,\n\ttype GraphQLField,\n\ttype GraphQLNamedType,\n\ttype GraphQLSchema,\n\tisAbstractType,\n\ttype ValueNode,\n} from 'graphql';\n\n/** Sizes are plain numbers, held below this so a hostile query never reaches `Infinity`. */\nconst CEILING = Number.MAX_SAFE_INTEGER;\n\n/** What sizing a list needs: the schema and the options of the rule. */\nexport interface SizeContext {\n\tschema: GraphQLSchema;\n\tsizeArguments: readonly string[];\n\tdefaultFirst: number;\n}\n\nconst CANONICAL_INTEGER = /^(0|[1-9]\\d*)$/;\n\n/**\n * The one reading of a size, wherever it comes from (a literal, a default): a\n * non-negative integral number or bigint, or a canonical-integer string,\n * clamped to the ceiling. Anything else says nothing.\n */\nfunction sizeOf(value: unknown): number | undefined {\n\tif (typeof value === 'string') {\n\t\treturn CANONICAL_INTEGER.test(value)\n\t\t\t? Math.min(Number(value), CEILING)\n\t\t\t: undefined;\n\t}\n\t// A bigint is how a Long scalar's default is held once its real scalar is\n\t// swapped in.\n\tif (typeof value === 'bigint') {\n\t\treturn value >= 0n ? Math.min(Number(value), CEILING) : undefined;\n\t}\n\treturn typeof value === 'number' && Number.isInteger(value) && value >= 0\n\t\t? Math.min(value, CEILING)\n\t\t: undefined;\n}\n\n/** The size a literal gives: an Int, a canonical-integer String or an integral Float (`1e3`). */\nfunction literalSize(value: ValueNode): number | undefined {\n\tif (value.kind === 'IntValue' || value.kind === 'FloatValue') {\n\t\treturn sizeOf(Number(value.value));\n\t}\n\treturn value.kind === 'StringValue' ? sizeOf(value.value) : undefined;\n}\n\n/**\n * An argument's SDL default as a size. graphql 16 holds it as `defaultValue`;\n * graphql 17 as `default`, `{ value }` or `{ literal }`.\n */\nfunction defaultSizeOf(argument: object | undefined): number | undefined {\n\tif (!argument) return undefined;\n\tif ('defaultValue' in argument) {\n\t\tconst size = sizeOf(argument.defaultValue);\n\t\tif (size !== undefined) return size;\n\t}\n\tif (!('default' in argument)) return undefined;\n\tconst fallback = argument.default;\n\tif (typeof fallback !== 'object' || fallback === null) return undefined;\n\tif ('value' in fallback) return sizeOf(fallback.value);\n\tif ('literal' in fallback && typeof fallback.literal === 'object') {\n\t\tconst literal = fallback.literal;\n\t\treturn literal !== null && 'kind' in literal\n\t\t\t? literalSize(literal as ValueNode)\n\t\t\t: undefined;\n\t}\n\treturn undefined;\n}\n\n/**\n * What the schema alone says of one list field and the fields implementing it,\n * per size argument (in `sizeArguments` order): the largest default, whether\n * some definition has none, and whether some definition has no default at all.\n */\ninterface Profile {\n\tlargest: (number | undefined)[];\n\tsomeLack: boolean[];\n\tsomeBare: boolean;\n\t/** Whether some definition declares any of the size arguments. */\n\tdeclares: boolean;\n\t/** Whether some definition declares none of them. */\n\tsomeUndeclared: boolean;\n}\n\nconst profiles = new WeakMap<\n\tGraphQLSchema,\n\tWeakMap<readonly string[], Map<string, Profile>>\n>();\n\nfunction profileOf(\n\tcost: SizeContext,\n\tparent: GraphQLNamedType | undefined,\n\tdefinition: GraphQLField<unknown, unknown>,\n): Profile {\n\tlet bySizes = profiles.get(cost.schema);\n\tif (!bySizes) {\n\t\tbySizes = new WeakMap();\n\t\tprofiles.set(cost.schema, bySizes);\n\t}\n\tlet byField = bySizes.get(cost.sizeArguments);\n\tif (!byField) {\n\t\tbyField = new Map();\n\t\tbySizes.set(cost.sizeArguments, byField);\n\t}\n\tconst key = `${parent?.name}.${definition.name}`;\n\tconst known = byField.get(key);\n\tif (known) return known;\n\n\t// On an interface the object types' own fields count too: each may\n\t// declare another default, and the query cannot say which comes back.\n\tconst definitions = [definition];\n\tif (isAbstractType(parent)) {\n\t\tfor (const type of cost.schema.getPossibleTypes(parent)) {\n\t\t\tconst implemented = type.getFields()[definition.name];\n\t\t\tif (implemented) definitions.push(implemented);\n\t\t}\n\t}\n\tconst profile: Profile = {\n\t\tlargest: cost.sizeArguments.map(() => undefined),\n\t\tsomeLack: cost.sizeArguments.map(() => false),\n\t\tsomeBare: false,\n\t\tdeclares: false,\n\t\tsomeUndeclared: false,\n\t};\n\tfor (const field of definitions) {\n\t\tlet any = false;\n\t\tcost.sizeArguments.forEach((name, index) => {\n\t\t\tconst size = defaultSizeOf(field.args.find((arg) => arg.name === name));\n\t\t\tif (size === undefined) {\n\t\t\t\tprofile.someLack[index] = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tany = true;\n\t\t\tprofile.largest[index] = Math.max(profile.largest[index] ?? 0, size);\n\t\t});\n\t\tif (!any) profile.someBare = true;\n\t\tif (field.args.some((arg) => cost.sizeArguments.includes(arg.name))) {\n\t\t\tprofile.declares = true;\n\t\t} else {\n\t\t\tprofile.someUndeclared = true;\n\t\t}\n\t}\n\tbyField.set(key, profile);\n\treturn profile;\n}\n\n/** The size a size argument says, `undefined` when it says nothing. */\nfunction argumentSize(\n\tcost: SizeContext,\n\tprofile: Profile,\n\tindex: number,\n\tnode: ArgumentNode | undefined,\n): number | undefined {\n\tconst largest = profile.largest[index];\n\tif (!node) return largest;\n\tconst literal = literalSize(node.value);\n\tif (literal !== undefined) return literal;\n\t// Given but unusable (a variable, a negative number): the argument's own\n\t// default, else defaultFirst.\n\treturn profile.someLack[index]\n\t\t? Math.max(largest ?? 0, cost.defaultFirst)\n\t\t: largest;\n}\n\n/**\n * The size `definition` states on `parent`, as selected by `args`: the largest\n * its size arguments say, `undefined` when none says anything (none given, and\n * none declared with a default). The schema's part is memoized, so a selection\n * costs `sizeArguments.length` steps whatever the number of possible types.\n * A list uses it, and a field returning an object (a Relay connection) hands it\n * to the lists below it.\n */\nexport function statedSize(\n\tcost: SizeContext,\n\tparent: GraphQLNamedType | undefined,\n\tdefinition: GraphQLField<unknown, unknown>,\n\targs: readonly ArgumentNode[] | undefined,\n): number | undefined {\n\tconst profile = profileOf(cost, parent, definition);\n\tlet size: number | undefined;\n\tlet given = false;\n\tcost.sizeArguments.forEach((name, index) => {\n\t\tconst node = args?.find((arg) => arg.name.value === name);\n\t\tif (node) given = true;\n\t\tconst said = argumentSize(cost, profile, index, node);\n\t\tif (said !== undefined) size = Math.max(size ?? 0, said);\n\t});\n\t// Nothing given: a definition without any default is sized defaultFirst.\n\tif (size !== undefined && !given && profile.someBare) {\n\t\treturn Math.max(size, cost.defaultFirst);\n\t}\n\treturn size;\n}\n\n/**\n * Whether `definition` and the fields implementing it declare a size argument:\n * `'all'` of them, `'none'` of them, or `'some'` (an abstract parent whose\n * possible types differ).\n */\nexport function declaration(\n\tcost: SizeContext,\n\tparent: GraphQLNamedType | undefined,\n\tdefinition: GraphQLField<unknown, unknown>,\n): 'all' | 'none' | 'some' {\n\tconst { declares, someUndeclared } = profileOf(cost, parent, definition);\n\tif (!declares) return 'none';\n\treturn someUndeclared ? 'some' : 'all';\n}\n",
|
|
15
|
+
"import type { ArgumentNode, GraphQLField, GraphQLNamedType } from 'graphql';\nimport { declaration, type SizeContext, statedSize } from './list-size';\n\n/**\n * The size of the list `definition` on `parent`. `pending` is the size of the\n * field whose return type this list is selected on (a connection's `first`):\n * a list that declares none of the size arguments takes it, since the size\n * cannot be stated on the list itself. A list that declares one reads its own\n * arguments, else `defaultFirst`, and never the pending size. On an abstract\n * parent some possible types may declare one and others not: the largest of\n * both readings, since the query cannot say which comes back.\n */\nexport function listSizeUnder(\n\tcost: SizeContext,\n\tparent: GraphQLNamedType | undefined,\n\tdefinition: GraphQLField<unknown, unknown>,\n\targs: readonly ArgumentNode[] | undefined,\n\tpending: number | undefined,\n): number {\n\tconst own = () =>\n\t\tstatedSize(cost, parent, definition, args) ?? cost.defaultFirst;\n\tif (pending === undefined) return own();\n\tconst declared = declaration(cost, parent, definition);\n\tif (declared === 'none') return pending;\n\tif (declared === 'all') return own();\n\t// Mixed: a possible type declaring none takes the pending size, another reads its own.\n\treturn Math.max(pending, own());\n}\n",
|
|
13
16
|
"import type { GraphQLFieldResolver, GraphQLResolveInfo } from 'graphql';\nimport { z } from 'zod';\nimport { parseArgs } from './bad-user-input';\n\n/** An object schema of the arguments, or its shape. */\nexport type ArgsSchema = z.ZodType<Record<string, unknown>> | z.ZodRawShape;\n\n/** The schema `ArgsSchema` stands for. */\nexport type SchemaOf<S extends ArgsSchema> = S extends z.ZodType\n\t? S\n\t: S extends z.ZodRawShape\n\t\t? // Mapped, not `S & z.ZodRawShape`: the intersection's index signature\n\t\t\t// would type every argument `unknown`.\n\t\t\tz.ZodObject<{ [K in keyof S]: S[K] }>\n\t\t: never;\n\n/**\n * What `validated` takes: the schema, or a function that builds it for each\n * call from the request's context and the field's `info`, for checks that\n * need them (a uniqueness query in the request's database, a rule that\n * depends on the viewer).\n */\nexport type ArgsSchemaFor<S extends ArgsSchema, TContext = unknown> =\n\t| S\n\t| SchemaFactory<S, TContext>;\n\ntype SchemaFactory<S extends ArgsSchema, TContext> = (\n\tcontext: TContext,\n\tinfo: GraphQLResolveInfo,\n) => S | Promise<S>;\n\n/**\n * A resolver whose arguments are checked by `schema` before it runs, for what\n * a `@constraint` cannot say: a rule across arguments, a business refinement,\n * an async check. It receives the parsed arguments (`z.output`), defaults and\n * transforms applied; an invalid input is the same `BAD_USER_INPUT` error as\n * the directives'.\n *\n * ```ts\n * signUp: validated(\n * z.object({ input: signUpSchema }).refine(({ input }) => input.password !== input.email),\n * (_, { input }) => users.create(input),\n * )\n * ```\n *\n * A check that needs the request takes a function in place of the schema:\n * it is called on each call, with the context and `info`, and returns the\n * schema (or a promise of it). What it throws reaches the client as it is,\n * not as `BAD_USER_INPUT`.\n *\n * ```ts\n * rename: validated(\n * (ctx: Context) => ({\n * name: z.string().refine(async (name) => !(await ctx.db.users.exists({ name })), 'taken'),\n * }),\n * (_, { name }, ctx) => ctx.db.users.rename(ctx.viewer, name),\n * )\n * ```\n */\nexport function validated<\n\tS extends ArgsSchema,\n\tTSource = unknown,\n\tTContext = unknown,\n\tTResult = unknown,\n>(\n\tschema: SchemaFactory<S, TContext>,\n\tresolve: (\n\t\tsource: TSource,\n\t\targs: z.output<SchemaOf<S>>,\n\t\tcontext: TContext,\n\t\tinfo: GraphQLResolveInfo,\n\t) => TResult,\n): GraphQLFieldResolver<\n\tTSource,\n\tTContext,\n\tz.input<SchemaOf<S>>,\n\tPromise<Awaited<TResult>>\n>;\nexport function validated<\n\tS extends ArgsSchema,\n\tTSource = unknown,\n\tTContext = unknown,\n\tTResult = unknown,\n>(\n\tschema: S,\n\tresolve: (\n\t\tsource: TSource,\n\t\targs: z.output<SchemaOf<S>>,\n\t\tcontext: TContext,\n\t\tinfo: GraphQLResolveInfo,\n\t) => TResult,\n): GraphQLFieldResolver<\n\tTSource,\n\tTContext,\n\tz.input<SchemaOf<S>>,\n\tPromise<Awaited<TResult>>\n>;\nexport function validated<\n\tS extends ArgsSchema,\n\tTSource = unknown,\n\tTContext = unknown,\n\tTResult = unknown,\n>(\n\tschema: ArgsSchemaFor<S, TContext>,\n\tresolve: (\n\t\tsource: TSource,\n\t\targs: z.output<SchemaOf<S>>,\n\t\tcontext: TContext,\n\t\tinfo: GraphQLResolveInfo,\n\t) => TResult,\n): GraphQLFieldResolver<\n\tTSource,\n\tTContext,\n\tz.input<SchemaOf<S>>,\n\tPromise<Awaited<TResult>>\n>;\nexport function validated<\n\tS extends ArgsSchema,\n\tTSource = unknown,\n\tTContext = unknown,\n\tTResult = unknown,\n>(\n\tschema: ArgsSchemaFor<S, TContext>,\n\tresolve: (\n\t\tsource: TSource,\n\t\targs: z.output<SchemaOf<S>>,\n\t\tcontext: TContext,\n\t\tinfo: GraphQLResolveInfo,\n\t) => TResult,\n): GraphQLFieldResolver<\n\tTSource,\n\tTContext,\n\tz.input<SchemaOf<S>>,\n\tPromise<Awaited<TResult>>\n> {\n\tconst fixed = typeof schema === 'function' ? undefined : zodOf(schema);\n\treturn async (source, args, context, info): Promise<Awaited<TResult>> => {\n\t\tconst where = `${info.parentType.name}.${info.fieldName}`;\n\t\tconst checked =\n\t\t\tfixed ??\n\t\t\tzodOf(await (schema as SchemaFactory<S, TContext>)(context, info));\n\t\tconst parsed = (await parseArgs(checked, args, where)) as z.output<\n\t\t\tSchemaOf<S>\n\t\t>;\n\t\treturn await resolve(source, parsed, context, info);\n\t};\n}\n\n/** The schema itself, or the object schema of a shape. */\nfunction zodOf(schema: ArgsSchema): z.ZodType {\n\t// `_zod`, not `instanceof`: a schema from another copy of zod is still one.\n\treturn (\n\t\t'_zod' in schema ? schema : z.object(schema as z.ZodRawShape)\n\t) as z.ZodType;\n}\n",
|
|
14
17
|
"import {\n\tdefaultFieldResolver,\n\ttype GraphQLField,\n\ttype GraphQLFieldResolver,\n\ttype GraphQLSchema,\n} from 'graphql';\nimport type { z } from 'zod';\nimport { type ConstraintOf, parseArgs } from './bad-user-input';\nimport { checkConstraints } from './builder/check-constraints';\nimport type { FormatSchemas, OwnFormats } from './formats/registry';\nimport { constraintOf } from './rules';\n\n// Symbol.for: two copies of the package in one tree still wrap a field once.\nconst wrapped = Symbol.for('@nxgt/graphql-validation/wrapped');\n// The formats a schema was wrapped with, kept on the schema itself.\nconst wrappedWith = Symbol.for('@nxgt/graphql-validation/formats');\n\n/** What `withValidation` takes besides the schema. */\nexport interface WithValidationOptions<\n\tF extends FormatSchemas = FormatSchemas,\n> {\n\t/**\n\t * The application's own formats, which `@constraint(format: \"...\")` may\n\t * name beside the built-in ones: one Zod string schema each, keyed by its\n\t * name (lowercase letters, digits and hyphens). A built-in name is a type\n\t * error, and refused at startup.\n\t */\n\treadonly formats?: OwnFormats<F>;\n}\n\ntype Resolver = GraphQLFieldResolver<unknown, unknown> & { [wrapped]?: true };\n\nfunction checking(\n\tschema: z.ZodType,\n\twhere: string,\n\tresolve: Resolver,\n\tconstraintOf: ConstraintOf,\n): Resolver {\n\tconst check: Resolver = async (source, args, context, info) =>\n\t\tawait resolve(\n\t\t\tsource,\n\t\t\tawait parseArgs(schema, args, where, constraintOf),\n\t\t\tcontext,\n\t\t\tinfo,\n\t\t);\n\tcheck[wrapped] = true;\n\treturn check;\n}\n\n/**\n * Wraps a field once. A subscription field is checked in `subscribe`, which\n * runs once per subscription — graphql's default one when the field has none\n * — and its `resolve` runs once per event, with the same arguments, already\n * checked.\n */\nfunction wrap(\n\tfield: GraphQLField<unknown, unknown>,\n\targs: z.ZodType,\n\twhere: string,\n\tsubscription: boolean,\n\tconstraintOf: ConstraintOf,\n): void {\n\tconst subscribe = (field.subscribe ??\n\t\t(subscription ? defaultFieldResolver : undefined)) as Resolver | undefined;\n\tif (subscribe) {\n\t\tif (!subscribe[wrapped])\n\t\t\tfield.subscribe = checking(args, where, subscribe, constraintOf);\n\t\treturn;\n\t}\n\tconst resolve = (field.resolve ?? defaultFieldResolver) as Resolver;\n\tif (!resolve[wrapped])\n\t\tfield.resolve = checking(args, where, resolve, constraintOf);\n}\n\n/**\n * Checks every `@constraint` of `schema` before the resolvers run. Each\n * field with a constrained argument — directly, or anywhere inside an input\n * type it takes — gets its resolver (and its `subscribe`) wrapped: the\n * arguments are parsed by the Zod schema the directives describe, the\n * resolver receives the parsed value, and an invalid input becomes one\n * `BAD_USER_INPUT` error. Fields with nothing to check are left untouched.\n *\n * The schema is built here, once: a constraint that cannot apply (a\n * `minLength` on an `Int`, an unknown format, a bad pattern) throws now, not\n * on the first request. The resolvers are wrapped in place and the same\n * schema is returned, so it goes wherever it went before; calling it twice\n * wraps nothing twice. Call it last, once every resolver is attached: a\n * resolver set on a field afterwards replaces the check.\n *\n * A `@constraint` on an interface's argument must be repeated on each\n * object's field, which is the one that resolves; a field that drops it\n * fails here.\n *\n * The directives are read from the SDL (`astNode`), so a schema built from\n * type definitions — `buildSchema`, `makeExecutableSchema`, Yoga, Apollo —\n * is checked; a code-first schema with no SDL has no `@constraint` to read.\n *\n * `options.formats` adds the application's own formats; wrapping a schema\n * again throws unless the record has the same names, each the very same\n * schema (no formats after some, or some after none, throws too), since its\n * fields are already checked against the first ones.\n */\nexport function withValidation<\n\tS extends GraphQLSchema,\n\t// biome-ignore lint/complexity/noBannedTypes: no formats of its own by default\n\tconst F extends FormatSchemas = {},\n>(schema: S, options: WithValidationOptions<F> = {}): S {\n\tconst formats: FormatSchemas = options.formats ?? {};\n\tconst holder = schema as unknown as { [wrappedWith]?: FormatSchemas };\n\tconst before = holder[wrappedWith];\n\tif (before && !sameFormats(before, formats)) {\n\t\tthrow new Error(\n\t\t\t'withValidation: this schema is already wrapped with other formats. Call withValidation once, with every format.',\n\t\t);\n\t}\n\tconst directive = checkConstraints(\n\t\tschema,\n\t\t(type, field, args, declared) => {\n\t\t\tconst subscription = type === schema.getSubscriptionType();\n\t\t\t// The rule that refused, with the value this field's SDL declares at the path.\n\t\t\tconst named: ConstraintOf = (issue) => {\n\t\t\t\tconst argument = constraintOf(issue);\n\t\t\t\tif (!argument) return undefined;\n\t\t\t\t// Found: the SDL carries the constraints (interfaces repeat theirs,\n\t\t\t\t// assertInterfaceConstraintsKept), so a miss drops `constraint` by design.\n\t\t\t\tconst found = declared(issue.path).find(\n\t\t\t\t\t({ rule }) => rule.argument === argument,\n\t\t\t\t);\n\t\t\t\treturn found && { argument, value: found.value };\n\t\t\t};\n\t\t\twrap(field, args, `${type.name}.${field.name}`, subscription, named);\n\t\t},\n\t\tformats,\n\t);\n\tif (!directive) {\n\t\tthrow new Error(\n\t\t\t'withValidation: this schema declares no @constraint directive. Add constraintTypeDefs to its type definitions.',\n\t\t);\n\t}\n\tif (!before) Object.defineProperty(schema, wrappedWith, { value: formats });\n\treturn schema;\n}\n\n/** The same names, each the very same schema. */\nfunction sameFormats(a: FormatSchemas, b: FormatSchemas): boolean {\n\tconst names = Object.keys(a);\n\treturn (\n\t\tnames.length === Object.keys(b).length &&\n\t\tnames.every((name) => Object.hasOwn(b, name) && a[name] === b[name])\n\t);\n}\n"
|
|
15
18
|
],
|
|
16
|
-
"mappings": "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",
|
|
17
|
-
"debugId": "
|
|
19
|
+
"mappings": ";;;;;;;;;AAAA;AA2CA,SAAS,QAAQ,CAChB,OACA,cACoB;AAAA,EACpB,OAAO,MAAM,OAAO,IAAI,CAAC,UAAU;AAAA,IAClC,MAAM,OAAO,MAAM,KAAK,IAAI,CAAC,QAC5B,OAAO,QAAQ,WAAW,MAAM,OAAO,GAAG,CAC3C;AAAA,IACA,MAAM,aAAa,eAAe,KAAK;AAAA,IACvC,OAAO,aACJ;AAAA,MACA;AAAA,MACA,SAAS,MAAM;AAAA,MACf,MAAM,MAAM;AAAA,MACZ,YAAY,WAAW;AAAA,MACvB,OAAO,WAAW;AAAA,IACnB,IACC,EAAE,MAAM,SAAS,MAAM,SAAS,MAAM,MAAM,KAAK;AAAA,GACpD;AAAA;AAGF,SAAS,OAAO,CAAC,OAAe,QAAyC;AAAA,EACxE,OAAO,SAAS;AAAA,EAChB,MAAM,SAAS,QACZ,GAAG,MAAM,KAAK,KAAK,GAAG,KAAK,gBAAgB,MAAM,YACjD;AAAA,EACH,MAAM,aAAqC,EAAE,MAAM,kBAAkB,OAAO;AAAA,EAC5E,OAAO,IAAI,aAAa,yBAAyB,UAAU,UAAU;AAAA,IACpE;AAAA,EACD,CAAC;AAAA;AAUK,SAAS,YAAY,CAAC,OAAe,OAAiC;AAAA,EAC5E,OAAO,QAAQ,OAAO,SAAS,KAAK,CAAC;AAAA;AAItC,eAAsB,SAAS,CAC9B,QACA,MACA,OACA,cACmB;AAAA,EACnB,MAAM,SAAS,MAAM,OAAO,eAAe,IAAI;AAAA,EAC/C,IAAI,CAAC,OAAO;AAAA,IACX,MAAM,QAAQ,OAAO,SAAS,OAAO,OAAO,YAAY,CAAC;AAAA,EAC1D,OAAO,OAAO;AAAA;;AChGf,yBAAS;AAGF,IAAM,gBAAgB;AAyC7B,SAAS,QAAQ,CAAC,QAA0D;AAAA,EAC3E,OAAO,UAAU,OAAO,KAAK,MAAM,EAAE,SAAS,IAAI,SAAS;AAAA;AAG5D,SAAS,SAAS,CACjB,MACA,QACA,WACS;AAAA,EACT,OAAO,YAAY,MAAM,MAAM,KAAK;AAAA;AAGrC,SAAS,QAAQ,CAChB,QACA,WACe;AAAA,EACf,OAAO,OAAO,IAAI,GAAG,MAAM,MAAM,QAAQ,YAAY;AAAA,IACpD,MAAM,SAAS,SAAS,KAAK;AAAA,IAC7B,OAAO;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS,UAAU,MAAM,QAAQ,SAAS;AAAA,SACtC,UAAU,EAAE,OAAO;AAAA,IACxB;AAAA,GACA;AAAA;AAWK,SAAS,iBAAiB,CAChC,QACA,UAA+B,CAAC,GACjB;AAAA,EACf,QAAQ,cAAc,YAAY;AAAA,EAClC,OAAO,IAAI,cAAa,UAAU,eAAe,WAAW,SAAS,GAAG;AAAA,OACpE;AAAA,IACH,YAAY;AAAA,MACX,MAAM;AAAA,MACN,MAAM,EAAE,QAAQ,IAAI;AAAA,MACpB,QAAQ,SAAS,QAAQ,SAAS;AAAA,IACnC;AAAA,EACD,CAAC;AAAA;AAUK,SAAS,WAAW,CAC1B,MACA,QACA,UAA8B,CAAC,GAChB;AAAA,EACf,QAAQ,WAAW,QAAQ,QAAQ,UAAU,YAAY;AAAA,EACzD,MAAM,SAAS,SAAS,KAAK;AAAA,EAC7B,OAAO,IAAI,cAAa,UAAU,MAAM,QAAQ,SAAS,GAAG;AAAA,OACxD;AAAA,IACH,YAAY;AAAA,MACX;AAAA,SACI,UAAU,EAAE,OAAO;AAAA,SACnB,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE;AAAA,MACjC,QAAQ,SAAS,QAAQ,SAAS;AAAA,IACnC;AAAA,EACD,CAAC;AAAA;AAUK,SAAS,SAAS,CAAC,MAAsC;AAAA,EAC/D,OAAO,UAAU,QAAQ;AAAA,EACzB,QAAQ,UAAU,WAAW,KAAK,SAAS,IAAI,OAAO,MACpD,IAAI,CAAC,QAAQ,OAAO,GAAG,CAAC,EACxB,KAAK,GAAG;AAAA;;;ACzHJ,IAAM,cAAc;AAAA,EAC1B,UAAU;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,eAAe;AAAA,EACf,SAAS;AACV;AAGA,IAAM,cAAmC,IAAI,IAAI;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAWM,SAAS,YAAY,CAAC,OAAqC;AAAA,EACjE,OAAO,EAAE,MAAM,UAAU,MAAM,IAAI,GAAG,MAAM,OAAO,KAAK,EAAE;AAAA;AAG3D,SAAS,MAAM,CAAC,OAAiC;AAAA,EAChD,QAAQ,MAAM;AAAA,SACR;AAAA,SACA,WAAW;AAAA,MACf,MAAM,QAAQ,MAAM,SAAS;AAAA,MAC7B,QAAQ,MAAM;AAAA,aACR;AAAA,UACJ,OAAO,QAAQ,YAAY,WAAW,YAAY;AAAA,aAC9C;AAAA,aACA;AAAA,UACJ,OAAO,YAAY;AAAA,aACf;AAAA,aACA;AAAA,UACJ,OAAO,QAAQ,YAAY,SAAS,YAAY;AAAA;AAAA,UAEhD,OAAO,YAAY;AAAA;AAAA,IAEtB;AAAA,SACK;AAAA,MACJ,OAAO,YAAY;AAAA,SACf;AAAA,MAGJ,OAAO,YAAY,IAAI,MAAM,MAAM,IAChC,YAAY,UACZ,YAAY;AAAA;AAAA,MAEf,OAAO,YAAY;AAAA;AAAA;;AClEtB;AAAA,kBAEC;AAAA;;;ACCM,SAAS,cAAc,CAAC,WAA4C;AAAA,EAC1E,OAAO,UAAU,OAAO,cAAc,UAAU,KAAK,WAAW;AAAA;AAO1D,SAAS,aAAa,CAC5B,QACA,OACA,KACA,MAAM,OAAO,kBACN;AAAA,EACP,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,OAAO,SAAS,KAAK;AAAA,IAC5D,MAAM,IAAI,WACT,GAAG,kCAAkC,UAAU,MAAM,IACtD;AAAA,EACD;AAAA;;;ACrBD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcO,SAAS,mBAAmB,CAAC,MAAuB;AAAA,EAC1D,OAAO,SAAS,cAAc,SAAS;AAAA;AAIjC,SAAS,iBAAiB,CAChC,MAC6C;AAAA,EAC7C,IAAI,SAAS;AAAA,IAAY,OAAO;AAAA,EAChC,IAAI,SAAS;AAAA,IAAU,OAAO;AAAA,EAC9B;AAAA;AAID,IAAM,UAAU,IAAI;AAEpB,IAAM,aAAa,IAAI;AAEvB,SAAS,SAAS,CAAC,QAA+B;AAAA,EACjD,IAAI,QAAQ,WAAW,IAAI,MAAM;AAAA,EACjC,IAAI,UAAU,WAAW;AAAA,IACxB,QAAQ,OAAO,KAAK,OAAO,WAAW,CAAC,EAAE;AAAA,IACzC,WAAW,IAAI,QAAQ,KAAK;AAAA,EAC7B;AAAA,EACA,OAAO;AAAA;AAGR,SAAS,YAAY,CAAC,QAA+B;AAAA,EACpD,MAAM,QAAQ,QAAQ,IAAI,MAAM;AAAA,EAChC,IAAI,UAAU;AAAA,IAAW,OAAO;AAAA,EAChC,IAAI,MAAM,OAAO,cAAc,EAAE;AAAA,EACjC,WAAW,aAAa,OAAO,cAAc,GAAG;AAAA,IAC/C,MAAM,KAAK,IAAI,KAAK,UAAU,KAAK,QAAQ,UAAU,UAAU,MAAM;AAAA,EACtE;AAAA,EACA,WAAW,QAAQ,OAAO,OAAO,OAAO,WAAW,CAAC,GAAG;AAAA,IACtD,MAAM,KAAK,IAAI,KAAK,SAAS,QAAQ,IAAI,CAAC;AAAA,EAC3C;AAAA,EACA,QAAQ,IAAI,QAAQ,GAAG;AAAA,EACvB,OAAO;AAAA;AAIR,SAAS,QAAQ,CAAC,QAAuB,MAAgC;AAAA,EACxE,IAAI,aAAa,IAAI,KAAK,gBAAgB,IAAI,GAAG;AAAA,IAChD,MAAM,SAAS,OAAO,OAAO,KAAK,UAAU,CAAC;AAAA,IAC7C,OAAO,KAAK,IACX,OAAO,QACP,KAAK,cAAc,EAAE,QACrB,gBAAgB,IAAI,IAAI,OAAO,iBAAiB,IAAI,EAAE,SAAS,GAC/D,GAAG,OAAO,IAAI,CAAC,UAAU,MAAM,KAAK,MAAM,CAC3C;AAAA,EACD;AAAA,EACA,IAAI,kBAAkB,IAAI;AAAA,IAAG,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,EAAE;AAAA,EAClE,IAAI,WAAW,IAAI;AAAA,IAAG,OAAO,KAAK,UAAU,EAAE;AAAA,EAC9C,IAAI,YAAY,IAAI;AAAA,IAAG,OAAO,KAAK,SAAS,EAAE;AAAA,EAC9C,OAAO;AAAA;AAQD,SAAS,iBAAiB,CAChC,QACA,OACS;AAAA,EACT,OAAO,UAAU,UAAU,UAAU,MAAM,IAAI,aAAa,MAAM;AAAA;;;AFlDnE,SAAS,OAAO,CAAC,OAAqB,cAAwC;AAAA,EAC7E,IAAI,UAAU;AAAA,EACd,WAAW,aAAa,aAAa,YAAY;AAAA,IAChD,IAAI,OAAO;AAAA,IACX,IAAI,UAAU,SAAS,SAAS;AAAA,MAC/B,MAAM,OAAO,UAAU,KAAK;AAAA,MAC5B,IAAI,SAAS;AAAA,QAAc;AAAA,MAC3B,IAAI,MAAM,uBAAuB,oBAAoB,IAAI;AAAA,QAAG;AAAA,MAC5D,OACC,KACC,UAAU,eAAe,QAAQ,OAAO,UAAU,YAAY,IAAI;AAAA,IACrE,EAAO,SAAI,UAAU,SAAS,kBAAkB;AAAA,MAC/C,OAAO,QAAQ,OAAO,UAAU,YAAY;AAAA,IAC7C,EAAO;AAAA,MACN,OAAO,cAAc,OAAO,UAAU,KAAK,KAAK;AAAA;AAAA,IAEjD,IAAI,OAAO;AAAA,MAAS,UAAU;AAAA,EAC/B;AAAA,EACA,OAAO;AAAA;AAIR,SAAS,aAAa,CAAC,OAAqB,MAAsB;AAAA,EACjE,MAAM,QAAQ,MAAM,eAAe,IAAI,IAAI;AAAA,EAC3C,IAAI,UAAU;AAAA,IAAW,OAAO;AAAA,EAChC,MAAM,WAAW,MAAM,YAAY,IAAI;AAAA,EAEvC,IAAI,CAAC,YAAY,MAAM,UAAU,IAAI,IAAI;AAAA,IAAG,OAAO;AAAA,EACnD,MAAM,UAAU,IAAI,IAAI;AAAA,EACxB,MAAM,SAAS,QAAQ,OAAO,SAAS,YAAY;AAAA,EACnD,MAAM,UAAU,OAAO,IAAI;AAAA,EAC3B,MAAM,eAAe,IAAI,MAAM,MAAM;AAAA,EACrC,OAAO;AAAA;AAiBD,SAAS,QAAQ,CAAC,SAA0C;AAAA,EAClE,MAAM,QAAQ,QAAQ;AAAA,EACtB,cAAc,mBAAmB,OAAO,CAAC;AAAA,EACzC,OAAO,CAAC,YAA+B;AAAA,IACtC,MAAM,OAAqB;AAAA,MAC1B,aAAa,CAAC,SAAS,QAAQ,YAAY,IAAI;AAAA,MAC/C,gBAAgB,IAAI;AAAA,MACpB,WAAW,IAAI;AAAA,MACf,qBAAqB,QAAQ,uBAAuB;AAAA,IACrD;AAAA,IACA,OAAO;AAAA,MACN,mBAAmB,CAAC,WAAW;AAAA,QAC9B,MAAM,QAAQ,QAAQ,MAAM,UAAU,YAAY;AAAA,QAClD,IAAI,QAAQ,OAAO;AAAA,UAClB,QAAQ,YACP,IAAI,cACH,GAAG,eAAe,SAAS,QAAQ,oCAAoC,iBACvE;AAAA,YACC,OAAO,CAAC,SAAS;AAAA,YACjB,YAAY,EAAE,MAAM,kBAAkB,OAAO,MAAM;AAAA,UACpD,CACD,CACD;AAAA,QACD;AAAA,QACA,OAAO;AAAA;AAAA,IAET;AAAA;AAAA;;AG1GF;AAAA,kBAEC;AAAA;AA8BD,SAAS,GAAG,CAAC,GAAW,GAAmB;AAAA,EAC1C,OAAO,KAAK,IAAI,IAAI,GAAG,OAAO,gBAAgB;AAAA;AAI/C,SAAS,OAAO,CAAC,MAAqB,cAAwC;AAAA,EAC7E,IAAI,QAAQ;AAAA,EACZ,WAAW,aAAa,aAAa,YAAY;AAAA,IAChD,IAAI,UAAU,SAAS,SAAS;AAAA,MAC/B,IAAI,KAAK,uBAAuB,oBAAoB,UAAU,KAAK,KAAK;AAAA,QACvE;AAAA,MACD,QAAQ,IAAI,OAAO,CAAC;AAAA,MACpB,IAAI,UAAU;AAAA,QACb,QAAQ,IAAI,OAAO,QAAQ,MAAM,UAAU,YAAY,CAAC;AAAA,IAC1D,EAAO,SAAI,UAAU,SAAS,kBAAkB;AAAA,MAC/C,QAAQ,IAAI,OAAO,QAAQ,MAAM,UAAU,YAAY,CAAC;AAAA,IACzD,EAAO;AAAA,MACN,QAAQ,IAAI,OAAO,cAAc,MAAM,UAAU,KAAK,KAAK,CAAC;AAAA;AAAA,EAE9D;AAAA,EACA,OAAO;AAAA;AAIR,SAAS,aAAa,CAAC,MAAqB,MAAsB;AAAA,EACjE,MAAM,QAAQ,KAAK,eAAe,IAAI,IAAI;AAAA,EAC1C,IAAI,UAAU;AAAA,IAAW,OAAO;AAAA,EAChC,MAAM,WAAW,KAAK,YAAY,IAAI;AAAA,EAEtC,IAAI,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI;AAAA,IAAG,OAAO;AAAA,EACjD,KAAK,SAAS,IAAI,IAAI;AAAA,EACtB,MAAM,SAAS,QAAQ,MAAM,SAAS,YAAY;AAAA,EAClD,KAAK,SAAS,OAAO,IAAI;AAAA,EACzB,KAAK,eAAe,IAAI,MAAM,MAAM;AAAA,EACpC,OAAO;AAAA;AAuBD,SAAS,SAAS,CAAC,SAA2C;AAAA,EACpE,MAAM,QAAQ,QAAQ;AAAA,EACtB,cAAc,oBAAoB,OAAO,CAAC;AAAA,EAC1C,OAAO,CAAC,YAA+B;AAAA,IACtC,MAAM,OAAsB;AAAA,MAC3B,aAAa,CAAC,SAAS,QAAQ,YAAY,IAAI;AAAA,MAC/C,gBAAgB,IAAI;AAAA,MACpB,UAAU,IAAI;AAAA,MACd,qBAAqB,QAAQ,uBAAuB;AAAA,IACrD;AAAA,IACA,OAAO;AAAA,MACN,mBAAmB,CAAC,WAAW;AAAA,QAC9B,MAAM,SAAS,QAAQ,MAAM,UAAU,YAAY;AAAA,QACnD,IAAI,SAAS,OAAO;AAAA,UACnB,QAAQ,YACP,IAAI,cACH,GAAG,eAAe,SAAS,aAAa,gCAAgC,iBACxE;AAAA,YACC,OAAO,CAAC,SAAS;AAAA,YACjB,YAAY,EAAE,MAAM,kBAAkB,QAAQ,MAAM;AAAA,UACrD,CACD,CACD;AAAA,QACD;AAAA,QACA,OAAO;AAAA;AAAA,IAET;AAAA;AAAA;;ACnHF;AAAA,kBAEC;AAAA;AAAA;AAAA;AAAA;;;ACFD;AAAA,qBAKC;AAAA,kBACA;AAAA;AAOD,IAAM,UAAU,OAAO;AAEhB,IAAM,OAAM,CAAC,GAAW,MAAc,KAAK,IAAI,SAAS,IAAI,CAAC;AAC7D,IAAM,WAAW,CAAC,GAAW,MAAc,KAAK,IAAI,SAAS,IAAI,CAAC;AAWlE,SAAS,OAAO,CACtB,MACA,QACA,MAC6C;AAAA,EAC7C,IAAI,WAAW,KAAK,OAAO,aAAa,KAAK,oBAAoB,IAAI,GAAG;AAAA,IACvE,OAAO,kBAAkB,IAAI;AAAA,EAC9B;AAAA,EACA,OAAO,cAAa,MAAM,KAAK,iBAAgB,MAAM,IAClD,OAAO,UAAU,EAAE,QACnB;AAAA;AAIG,SAAS,QAAQ,CACvB,QACA,WACC;AAAA,EACD,MAAM,OACL,UAAU,cAAc,UACrB,OAAO,aAAa,IACpB,UAAU,cAAc,aACvB,OAAO,gBAAgB,IACvB,OAAO,oBAAoB;AAAA,EAChC,OAAO,QAAQ;AAAA;AAIhB,IAAM,cAAc;AAGb,IAAM,aAAa;AASnB,SAAS,QAAQ,CACvB,OACA,SACqB;AAAA,EACrB,IAAI,YAAY,aAAa,MAAM,IAAI,OAAO,KAAK,MAAM,OAAO,aAAa;AAAA,IAC5E,OAAO;AAAA,EACR;AAAA,EAEA,IAAI,UAAU,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,SAAS,CAAC,CAAC,CAAC;AAAA,EAC5D,IAAI,UAAU;AAAA,IAAS,WAAW;AAAA,EAClC,OAAO,KAAK,IAAI,SAAS,OAAO;AAAA;;;AC7EjC;AAAA;AAAA;AAUA,IAAM,WAAU,OAAO;AASvB,IAAM,oBAAoB;AAO1B,SAAS,MAAM,CAAC,OAAoC;AAAA,EACnD,IAAI,OAAO,UAAU,UAAU;AAAA,IAC9B,OAAO,kBAAkB,KAAK,KAAK,IAChC,KAAK,IAAI,OAAO,KAAK,GAAG,QAAO,IAC/B;AAAA,EACJ;AAAA,EAGA,IAAI,OAAO,UAAU,UAAU;AAAA,IAC9B,OAAO,SAAS,KAAK,KAAK,IAAI,OAAO,KAAK,GAAG,QAAO,IAAI;AAAA,EACzD;AAAA,EACA,OAAO,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,KAAK,SAAS,IACrE,KAAK,IAAI,OAAO,QAAO,IACvB;AAAA;AAIJ,SAAS,WAAW,CAAC,OAAsC;AAAA,EAC1D,IAAI,MAAM,SAAS,cAAc,MAAM,SAAS,cAAc;AAAA,IAC7D,OAAO,OAAO,OAAO,MAAM,KAAK,CAAC;AAAA,EAClC;AAAA,EACA,OAAO,MAAM,SAAS,gBAAgB,OAAO,MAAM,KAAK,IAAI;AAAA;AAO7D,SAAS,aAAa,CAAC,UAAkD;AAAA,EACxE,IAAI,CAAC;AAAA,IAAU;AAAA,EACf,IAAI,kBAAkB,UAAU;AAAA,IAC/B,MAAM,OAAO,OAAO,SAAS,YAAY;AAAA,IACzC,IAAI,SAAS;AAAA,MAAW,OAAO;AAAA,EAChC;AAAA,EACA,IAAI,EAAE,aAAa;AAAA,IAAW;AAAA,EAC9B,MAAM,WAAW,SAAS;AAAA,EAC1B,IAAI,OAAO,aAAa,YAAY,aAAa;AAAA,IAAM;AAAA,EACvD,IAAI,WAAW;AAAA,IAAU,OAAO,OAAO,SAAS,KAAK;AAAA,EACrD,IAAI,aAAa,YAAY,OAAO,SAAS,YAAY,UAAU;AAAA,IAClE,MAAM,UAAU,SAAS;AAAA,IACzB,OAAO,YAAY,QAAQ,UAAU,UAClC,YAAY,OAAoB,IAChC;AAAA,EACJ;AAAA,EACA;AAAA;AAkBD,IAAM,WAAW,IAAI;AAKrB,SAAS,SAAS,CACjB,MACA,QACA,YACU;AAAA,EACV,IAAI,UAAU,SAAS,IAAI,KAAK,MAAM;AAAA,EACtC,IAAI,CAAC,SAAS;AAAA,IACb,UAAU,IAAI;AAAA,IACd,SAAS,IAAI,KAAK,QAAQ,OAAO;AAAA,EAClC;AAAA,EACA,IAAI,UAAU,QAAQ,IAAI,KAAK,aAAa;AAAA,EAC5C,IAAI,CAAC,SAAS;AAAA,IACb,UAAU,IAAI;AAAA,IACd,QAAQ,IAAI,KAAK,eAAe,OAAO;AAAA,EACxC;AAAA,EACA,MAAM,MAAM,GAAG,QAAQ,QAAQ,WAAW;AAAA,EAC1C,MAAM,QAAQ,QAAQ,IAAI,GAAG;AAAA,EAC7B,IAAI;AAAA,IAAO,OAAO;AAAA,EAIlB,MAAM,cAAc,CAAC,UAAU;AAAA,EAC/B,IAAI,eAAe,MAAM,GAAG;AAAA,IAC3B,WAAW,QAAQ,KAAK,OAAO,iBAAiB,MAAM,GAAG;AAAA,MACxD,MAAM,cAAc,KAAK,UAAU,EAAE,WAAW;AAAA,MAChD,IAAI;AAAA,QAAa,YAAY,KAAK,WAAW;AAAA,IAC9C;AAAA,EACD;AAAA,EACA,MAAM,UAAmB;AAAA,IACxB,SAAS,KAAK,cAAc,IAAI,MAAG;AAAA,MAAG;AAAA,KAAS;AAAA,IAC/C,UAAU,KAAK,cAAc,IAAI,MAAM,KAAK;AAAA,IAC5C,UAAU;AAAA,IACV,UAAU;AAAA,IACV,gBAAgB;AAAA,EACjB;AAAA,EACA,WAAW,SAAS,aAAa;AAAA,IAChC,IAAI,MAAM;AAAA,IACV,KAAK,cAAc,QAAQ,CAAC,MAAM,UAAU;AAAA,MAC3C,MAAM,OAAO,cAAc,MAAM,KAAK,KAAK,CAAC,QAAQ,IAAI,SAAS,IAAI,CAAC;AAAA,MACtE,IAAI,SAAS,WAAW;AAAA,QACvB,QAAQ,SAAS,SAAS;AAAA,QAC1B;AAAA,MACD;AAAA,MACA,MAAM;AAAA,MACN,QAAQ,QAAQ,SAAS,KAAK,IAAI,QAAQ,QAAQ,UAAU,GAAG,IAAI;AAAA,KACnE;AAAA,IACD,IAAI,CAAC;AAAA,MAAK,QAAQ,WAAW;AAAA,IAC7B,IAAI,MAAM,KAAK,KAAK,CAAC,QAAQ,KAAK,cAAc,SAAS,IAAI,IAAI,CAAC,GAAG;AAAA,MACpE,QAAQ,WAAW;AAAA,IACpB,EAAO;AAAA,MACN,QAAQ,iBAAiB;AAAA;AAAA,EAE3B;AAAA,EACA,QAAQ,IAAI,KAAK,OAAO;AAAA,EACxB,OAAO;AAAA;AAIR,SAAS,YAAY,CACpB,MACA,SACA,OACA,MACqB;AAAA,EACrB,MAAM,UAAU,QAAQ,QAAQ;AAAA,EAChC,IAAI,CAAC;AAAA,IAAM,OAAO;AAAA,EAClB,MAAM,UAAU,YAAY,KAAK,KAAK;AAAA,EACtC,IAAI,YAAY;AAAA,IAAW,OAAO;AAAA,EAGlC,OAAO,QAAQ,SAAS,SACrB,KAAK,IAAI,WAAW,GAAG,KAAK,YAAY,IACxC;AAAA;AAWG,SAAS,UAAU,CACzB,MACA,QACA,YACA,MACqB;AAAA,EACrB,MAAM,UAAU,UAAU,MAAM,QAAQ,UAAU;AAAA,EAClD,IAAI;AAAA,EACJ,IAAI,QAAQ;AAAA,EACZ,KAAK,cAAc,QAAQ,CAAC,MAAM,UAAU;AAAA,IAC3C,MAAM,OAAO,MAAM,KAAK,CAAC,QAAQ,IAAI,KAAK,UAAU,IAAI;AAAA,IACxD,IAAI;AAAA,MAAM,QAAQ;AAAA,IAClB,MAAM,OAAO,aAAa,MAAM,SAAS,OAAO,IAAI;AAAA,IACpD,IAAI,SAAS;AAAA,MAAW,OAAO,KAAK,IAAI,QAAQ,GAAG,IAAI;AAAA,GACvD;AAAA,EAED,IAAI,SAAS,aAAa,CAAC,SAAS,QAAQ,UAAU;AAAA,IACrD,OAAO,KAAK,IAAI,MAAM,KAAK,YAAY;AAAA,EACxC;AAAA,EACA,OAAO;AAAA;AAQD,SAAS,WAAW,CAC1B,MACA,QACA,YAC0B;AAAA,EAC1B,QAAQ,UAAU,mBAAmB,UAAU,MAAM,QAAQ,UAAU;AAAA,EACvE,IAAI,CAAC;AAAA,IAAU,OAAO;AAAA,EACtB,OAAO,iBAAiB,SAAS;AAAA;;;ACtM3B,SAAS,aAAa,CAC5B,MACA,QACA,YACA,MACA,SACS;AAAA,EACT,MAAM,MAAM,MACX,WAAW,MAAM,QAAQ,YAAY,IAAI,KAAK,KAAK;AAAA,EACpD,IAAI,YAAY;AAAA,IAAW,OAAO,IAAI;AAAA,EACtC,MAAM,WAAW,YAAY,MAAM,QAAQ,UAAU;AAAA,EACrD,IAAI,aAAa;AAAA,IAAQ,OAAO;AAAA,EAChC,IAAI,aAAa;AAAA,IAAO,OAAO,IAAI;AAAA,EAEnC,OAAO,KAAK,IAAI,SAAS,IAAI,CAAC;AAAA;;;AHuB/B,IAAM,yBAAyB,CAAC,SAAS,QAAQ,OAAO;AAOxD,SAAS,SAAS,CACjB,MACA,QACA,WACA,YACA,SACS;AAAA,EACT,IAAI,CAAC,UAAU;AAAA,IAAc,OAAO;AAAA,EACpC,MAAM,OAAO,UAAU,KAAK;AAAA,EAC5B,MAAM,OAAO,aAAa,WAAW,IAAI;AAAA,EACzC,IAAI,CAAC,WAAW,gBAAgB,WAAW,IAAI,CAAC,GAAG;AAAA,IAGlD,MAAM,SAAS,WAAW,MAAM,QAAQ,YAAY,UAAU,SAAS;AAAA,IACvE,MAAM,QAAQ,OAAO,MAAM,UAAU,cAAc,MAAM,MAAM;AAAA,IAC/D,OAAO,KAAI,GAAG,KAAK;AAAA,EACpB;AAAA,EACA,MAAM,QAAQ,OAAO,MAAM,UAAU,cAAc,MAAM,SAAS;AAAA,EAClE,MAAM,OAAO,QAAQ,KAAK,WAAW,IAAI,IACtC,kBAAkB,KAAK,QAAQ,IAAI,IACnC,cAAc,MAAM,QAAQ,YAAY,UAAU,WAAW,OAAO;AAAA,EACvE,OAAO,KAAI,GAAG,SAAS,OAAO,IAAI,CAAC;AAAA;AAIpC,SAAS,MAAM,CACd,MACA,cACA,QACA,SACS;AAAA,EACT,IAAI,QAAQ;AAAA,EACZ,WAAW,aAAa,aAAa,YAAY;AAAA,IAChD,IAAI,UAAU,SAAS,SAAS;AAAA,MAC/B,MAAM,OAAO,UAAU,KAAK;AAAA,MAC5B,IAAI,SAAS;AAAA,QAAc;AAAA,MAC3B,IAAI,oBAAoB,IAAI,KAAK,KAAK;AAAA,QAAqB;AAAA,MAC3D,MAAM,aAAa,QAAQ,MAAM,QAAQ,IAAI;AAAA,MAE7C,IAAI,CAAC;AAAA,QAAY;AAAA,MACjB,QAAQ,KACP,OACA,UAAU,MAAM,QAAQ,WAAW,YAAY,OAAO,CACvD;AAAA,IACD,EAAO,SAAI,UAAU,SAAS,kBAAkB;AAAA,MAC/C,MAAM,YAAY,UAAU,gBACzB,KAAK,OAAO,QAAQ,UAAU,cAAc,KAAK,KAAK,IACtD;AAAA,MACH,QAAQ,KACP,OACA,OAAO,MAAM,UAAU,cAAc,WAAW,OAAO,CACxD;AAAA,IACD,EAAO;AAAA,MACN,QAAQ,KAAI,OAAO,aAAa,MAAM,UAAU,KAAK,OAAO,OAAO,CAAC;AAAA;AAAA,EAEtE;AAAA,EACA,OAAO;AAAA;AAIR,SAAS,YAAY,CACpB,MACA,MACA,SACS;AAAA,EACT,IAAI,QAAQ,KAAK,cAAc,IAAI,IAAI;AAAA,EACvC,IAAI,CAAC,OAAO;AAAA,IACX,QAAQ,IAAI;AAAA,IACZ,KAAK,cAAc,IAAI,MAAM,KAAK;AAAA,EACnC;AAAA,EACA,MAAM,OAAO,SAAS,OAAO,OAAO;AAAA,EACpC,MAAM,MAAM,QAAQ;AAAA,EACpB,MAAM,OAAO,MAAM,IAAI,GAAG;AAAA,EAC1B,IAAI,SAAS;AAAA,IAAW,OAAO;AAAA,EAC/B,MAAM,WAAW,KAAK,YAAY,IAAI;AAAA,EAEtC,IAAI,CAAC,YAAY,KAAK,QAAQ,IAAI,IAAI;AAAA,IAAG,OAAO;AAAA,EAChD,KAAK,QAAQ,IAAI,IAAI;AAAA,EACrB,MAAM,SAAS,OACd,MACA,SAAS,cACT,KAAK,OAAO,QAAQ,SAAS,cAAc,KAAK,KAAK,GACrD,IACD;AAAA,EACA,KAAK,QAAQ,OAAO,IAAI;AAAA,EACxB,MAAM,IAAI,KAAK,MAAM;AAAA,EACrB,OAAO;AAAA;AAuDD,SAAS,WAAW,CAAC,SAA6C;AAAA,EACxE,QAAQ,QAAQ,iBAAiB;AAAA,EAGjC,MAAM,gBAAgB,OAAO,OAAO;AAAA,IACnC,GAAI,QAAQ,iBAAiB;AAAA,EAC9B,CAAC;AAAA,EACD,cAAc,uBAAuB,QAAQ,CAAC;AAAA,EAC9C,cAAc,6BAA6B,cAAc,CAAC;AAAA,EAE1D,OAAO,CAAC,YAA+B;AAAA,IACtC,MAAM,SAAS,QAAQ,UAAU;AAAA,IACjC,MAAM,OAAoB;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA,qBAAqB,QAAQ,uBAAuB;AAAA,MACpD,aAAa,CAAC,SAAS,QAAQ,YAAY,IAAI;AAAA,MAC/C,eAAe,IAAI;AAAA,MACnB,SAAS,IAAI;AAAA,IACd;AAAA,IACA,OAAO;AAAA,MACN,mBAAmB,CAAC,WAAW;AAAA,QAC9B,MAAM,QAAQ,OACb,MACA,UAAU,cACV,SAAS,QAAQ,SAAS,GAC1B,SACD;AAAA,QACA,IAAI,QAAQ,QAAQ;AAAA,UACnB,QAAQ,YACP,IAAI,cACH,GAAG,eAAe,SAAS,WAAW,wBAAwB,kBAC9D;AAAA,YACC,OAAO,CAAC,SAAS;AAAA,YACjB,YAAY;AAAA,cACX,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,YACR;AAAA,UACD,CACD,CACD;AAAA,QACD;AAAA,QACA,OAAO;AAAA;AAAA,IAET;AAAA;AAAA;;AIlPF;AAmHO,SAAS,SAKf,CACA,QACA,SAWC;AAAA,EACD,MAAM,QAAQ,OAAO,WAAW,aAAa,YAAY,MAAM,MAAM;AAAA,EACrE,OAAO,OAAO,QAAQ,MAAM,SAAS,SAAoC;AAAA,IACxE,MAAM,QAAQ,GAAG,KAAK,WAAW,QAAQ,KAAK;AAAA,IAC9C,MAAM,UACL,SACA,MAAM,MAAO,OAAsC,SAAS,IAAI,CAAC;AAAA,IAClE,MAAM,SAAU,MAAM,UAAU,SAAS,MAAM,KAAK;AAAA,IAGpD,OAAO,MAAM,QAAQ,QAAQ,QAAQ,SAAS,IAAI;AAAA;AAAA;AAKpD,SAAS,KAAK,CAAC,QAA+B;AAAA,EAE7C,OACC,UAAU,SAAS,SAAS,EAAE,OAAO,MAAuB;AAAA;;ACxJ9D;AAAA;AAAA;AAaA,IAAM,UAAU,OAAO,IAAI,kCAAkC;AAE7D,IAAM,cAAc,OAAO,IAAI,kCAAkC;AAiBjE,SAAS,QAAQ,CAChB,QACA,OACA,SACA,cACW;AAAA,EACX,MAAM,QAAkB,OAAO,QAAQ,MAAM,SAAS,SACrD,MAAM,QACL,QACA,MAAM,UAAU,QAAQ,MAAM,OAAO,YAAY,GACjD,SACA,IACD;AAAA,EACD,MAAM,WAAW;AAAA,EACjB,OAAO;AAAA;AASR,SAAS,IAAI,CACZ,OACA,MACA,OACA,cACA,cACO;AAAA,EACP,MAAM,YAAa,MAAM,cACvB,eAAe,uBAAuB;AAAA,EACxC,IAAI,WAAW;AAAA,IACd,IAAI,CAAC,UAAU;AAAA,MACd,MAAM,YAAY,SAAS,MAAM,OAAO,WAAW,YAAY;AAAA,IAChE;AAAA,EACD;AAAA,EACA,MAAM,UAAW,MAAM,WAAW;AAAA,EAClC,IAAI,CAAC,QAAQ;AAAA,IACZ,MAAM,UAAU,SAAS,MAAM,OAAO,SAAS,YAAY;AAAA;AA+BtD,SAAS,cAIf,CAAC,QAAW,UAAoC,CAAC,GAAM;AAAA,EACvD,MAAM,UAAyB,QAAQ,WAAW,CAAC;AAAA,EACnD,MAAM,SAAS;AAAA,EACf,MAAM,SAAS,OAAO;AAAA,EACtB,IAAI,UAAU,CAAC,YAAY,QAAQ,OAAO,GAAG;AAAA,IAC5C,MAAM,IAAI,MACT,iHACD;AAAA,EACD;AAAA,EACA,MAAM,YAAY,kBACjB,QACA,CAAC,MAAM,OAAO,MAAM,aAAa;AAAA,IAChC,MAAM,eAAe,SAAS,OAAO,oBAAoB;AAAA,IAEzD,MAAM,QAAsB,CAAC,UAAU;AAAA,MACtC,MAAM,WAAW,aAAa,KAAK;AAAA,MACnC,IAAI,CAAC;AAAA,QAAU;AAAA,MAGf,MAAM,QAAQ,SAAS,MAAM,IAAI,EAAE,KAClC,GAAG,WAAW,KAAK,aAAa,QACjC;AAAA,MACA,OAAO,SAAS,EAAE,UAAU,OAAO,MAAM,MAAM;AAAA;AAAA,IAEhD,KAAK,OAAO,MAAM,GAAG,KAAK,QAAQ,MAAM,QAAQ,cAAc,KAAK;AAAA,KAEpE,OACD;AAAA,EACA,IAAI,CAAC,WAAW;AAAA,IACf,MAAM,IAAI,MACT,gHACD;AAAA,EACD;AAAA,EACA,IAAI,CAAC;AAAA,IAAQ,OAAO,eAAe,QAAQ,aAAa,EAAE,OAAO,QAAQ,CAAC;AAAA,EAC1E,OAAO;AAAA;AAIR,SAAS,WAAW,CAAC,GAAkB,GAA2B;AAAA,EACjE,MAAM,QAAQ,OAAO,KAAK,CAAC;AAAA,EAC3B,OACC,MAAM,WAAW,OAAO,KAAK,CAAC,EAAE,UAChC,MAAM,MAAM,CAAC,SAAS,OAAO,OAAO,GAAG,IAAI,KAAK,EAAE,UAAU,EAAE,KAAK;AAAA;",
|
|
20
|
+
"debugId": "3B937DADAE820B8964756E2164756E21",
|
|
18
21
|
"names": []
|
|
19
22
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type FragmentDefinitionNode, type GraphQLField, type GraphQLNamedType, type GraphQLSchema, type OperationDefinitionNode } from 'graphql';
|
|
2
|
+
import type { SizeContext } from './list-size.js';
|
|
3
|
+
export declare const add: (a: number, b: number) => number;
|
|
4
|
+
export declare const multiply: (a: number, b: number) => number;
|
|
5
|
+
/** What a walk of one document needs: the options, and what it has measured so far. */
|
|
6
|
+
export interface CostContext extends SizeContext {
|
|
7
|
+
ignoreIntrospection: boolean;
|
|
8
|
+
getFragment: (name: string) => FragmentDefinitionNode | null | undefined;
|
|
9
|
+
fragmentCosts: Map<string, Map<number, number>>;
|
|
10
|
+
costing: Set<string>;
|
|
11
|
+
}
|
|
12
|
+
/** The definition of the field `name` on `parent`, meta-fields of the query root included. */
|
|
13
|
+
export declare function fieldOf(cost: CostContext, parent: GraphQLNamedType | undefined, name: string): GraphQLField<unknown, unknown> | undefined;
|
|
14
|
+
/** The type an operation selects on. */
|
|
15
|
+
export declare function rootType(schema: GraphQLSchema, operation: OperationDefinitionNode): import("graphql").GraphQLObjectType<any, any> | undefined;
|
|
16
|
+
/** The key a fragment is memoized under: `-1` for no pending size. */
|
|
17
|
+
export declare const NO_PENDING = -1;
|
|
18
|
+
/**
|
|
19
|
+
* The pending size a fragment is costed under. A fragment spread under many
|
|
20
|
+
* distinct sizes would be costed once per size, quadratic in a hostile
|
|
21
|
+
* document; past `EXACT_SIZES` of them a new size is rounded up to a power of
|
|
22
|
+
* two (a cost never lowers as a size grows, so it only over-counts, by less
|
|
23
|
+
* than twice), which leaves at most `EXACT_SIZES` + 53 costings per fragment.
|
|
24
|
+
*/
|
|
25
|
+
export declare function memoSize(known: ReadonlyMap<number, number>, pending: number | undefined): number | undefined;
|
|
26
|
+
//# sourceMappingURL=cost-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-context.d.ts","sourceRoot":"","sources":["../../src/limits/cost-context.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,sBAAsB,EAC3B,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAGlB,KAAK,uBAAuB,EAC5B,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK/C,eAAO,MAAM,GAAG,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,WAA6B,CAAC;AACtE,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,WAA6B,CAAC;AAE3E,uFAAuF;AACvF,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,sBAAsB,GAAG,IAAI,GAAG,SAAS,CAAC;IACzE,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACrB;AAED,8FAA8F;AAC9F,wBAAgB,OAAO,CACtB,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,gBAAgB,GAAG,SAAS,EACpC,IAAI,EAAE,MAAM,GACV,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,SAAS,CAO5C;AAED,wCAAwC;AACxC,wBAAgB,QAAQ,CACvB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,uBAAuB,6DASlC;AAKD,sEAAsE;AACtE,eAAO,MAAM,UAAU,KAAK,CAAC;AAE7B;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACvB,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,EAAE,MAAM,GAAG,SAAS,GACzB,MAAM,GAAG,SAAS,CAQpB"}
|
|
@@ -6,10 +6,18 @@ export interface SizeContext {
|
|
|
6
6
|
defaultFirst: number;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
* The size
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `sizeArguments.length` steps whatever the number of possible types.
|
|
9
|
+
* The size `definition` states on `parent`, as selected by `args`: the largest
|
|
10
|
+
* its size arguments say, `undefined` when none says anything (none given, and
|
|
11
|
+
* none declared with a default). The schema's part is memoized, so a selection
|
|
12
|
+
* costs `sizeArguments.length` steps whatever the number of possible types.
|
|
13
|
+
* A list uses it, and a field returning an object (a Relay connection) hands it
|
|
14
|
+
* to the lists below it.
|
|
13
15
|
*/
|
|
14
|
-
export declare function
|
|
16
|
+
export declare function statedSize(cost: SizeContext, parent: GraphQLNamedType | undefined, definition: GraphQLField<unknown, unknown>, args: readonly ArgumentNode[] | undefined): number | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Whether `definition` and the fields implementing it declare a size argument:
|
|
19
|
+
* `'all'` of them, `'none'` of them, or `'some'` (an abstract parent whose
|
|
20
|
+
* possible types differ).
|
|
21
|
+
*/
|
|
22
|
+
export declare function declaration(cost: SizeContext, parent: GraphQLNamedType | undefined, definition: GraphQLField<unknown, unknown>): 'all' | 'none' | 'some';
|
|
15
23
|
//# sourceMappingURL=list-size.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-size.d.ts","sourceRoot":"","sources":["../../src/limits/list-size.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAGlB,MAAM,SAAS,CAAC;AAKjB,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"list-size.d.ts","sourceRoot":"","sources":["../../src/limits/list-size.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAGlB,MAAM,SAAS,CAAC;AAKjB,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;CACrB;AAuJD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACzB,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,gBAAgB,GAAG,SAAS,EACpC,UAAU,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EAC1C,IAAI,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,GACvC,MAAM,GAAG,SAAS,CAepB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAC1B,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,gBAAgB,GAAG,SAAS,EACpC,UAAU,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,GACxC,KAAK,GAAG,MAAM,GAAG,MAAM,CAIzB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ValidationRule } from 'graphql';
|
|
2
|
+
/** Options of {@link maxFields}. */
|
|
3
|
+
export interface MaxFieldsOptions {
|
|
4
|
+
/** The most field selections an operation may have (at least 1). */
|
|
5
|
+
limit: number;
|
|
6
|
+
/**
|
|
7
|
+
* Do not count `__schema` and `__type` (default `false`). Only where
|
|
8
|
+
* introspection is disabled or the client is trusted, e.g. GraphiQL in
|
|
9
|
+
* development: the standard introspection query (`getIntrospectionQuery()`)
|
|
10
|
+
* selects 220 fields.
|
|
11
|
+
*/
|
|
12
|
+
ignoreIntrospection?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A graphql-js validation rule refusing an operation that selects more than
|
|
16
|
+
* `limit` fields: neither `maxDepth` nor `maxListCost` bounds breadth, so
|
|
17
|
+
* thousands of aliases of a cheap field (or of `__typename`) pass both.
|
|
18
|
+
*
|
|
19
|
+
* Every field node counts 1, aliases and `__typename` included. A named
|
|
20
|
+
* fragment counts at each spread (walked once), an inline fragment counts its
|
|
21
|
+
* contents, and every branch of a union counts: nothing is pruned by type.
|
|
22
|
+
* `@skip` and `@include` are not evaluated, so the count can be over the
|
|
23
|
+
* document's field count. It counts the document, spreads expanded, not what the
|
|
24
|
+
* executor runs: how often a field runs inside a list is `maxListCost`'s.
|
|
25
|
+
* One `GraphQLError` per operation, with
|
|
26
|
+
* `extensions: { code: 'QUERY_TOO_WIDE', fields, limit }`, `fields` being the
|
|
27
|
+
* operation's real count (clamped at `Number.MAX_SAFE_INTEGER`).
|
|
28
|
+
*
|
|
29
|
+
* ```ts
|
|
30
|
+
* validate(schema, document, [...specifiedRules, maxFields({ limit: 500 })]);
|
|
31
|
+
* // graphql-yoga: onValidate: ({ addValidationRule }) => addValidationRule(maxFields({ limit: 500 }))
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function maxFields(options: MaxFieldsOptions): ValidationRule;
|
|
35
|
+
//# sourceMappingURL=max-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"max-fields.d.ts","sourceRoot":"","sources":["../../src/limits/max-fields.ts"],"names":[],"mappings":"AAAA,OAAO,EAKN,KAAK,cAAc,EACnB,MAAM,SAAS,CAAC;AAIjB,oCAAoC;AACpC,MAAM,WAAW,gBAAgB;IAChC,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAgDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,cAAc,CA4BnE"}
|
|
@@ -8,7 +8,9 @@ export interface MaxListCostOptions {
|
|
|
8
8
|
/**
|
|
9
9
|
* The argument names that size a list. Each one given, or defaulted in the
|
|
10
10
|
* SDL, says a size (an Int, a canonical-integer string or an integral Float)
|
|
11
|
-
* and the largest wins. Default `['first', 'last', 'limit']`.
|
|
11
|
+
* and the largest wins. Default `['first', 'last', 'limit']`. One on a
|
|
12
|
+
* non-list field also sizes the lists declaring none directly on its return
|
|
13
|
+
* type (a Relay connection's `edges` and `nodes`).
|
|
12
14
|
*/
|
|
13
15
|
sizeArguments?: readonly string[];
|
|
14
16
|
/**
|
|
@@ -44,7 +46,20 @@ export interface MaxListCostOptions {
|
|
|
44
46
|
* its sibling. A field whose type (once unwrapped from non-null) is a list is
|
|
45
47
|
* one list, nested `[[X]]` included.
|
|
46
48
|
*
|
|
47
|
-
*
|
|
49
|
+
* A Relay connection puts the size on a field returning an object, with the
|
|
50
|
+
* list below it (`items(first: 100) { edges { node { id } } }`). A field that
|
|
51
|
+
* is not a list and states a size (by the same reading) hands it to the lists
|
|
52
|
+
* selected directly on its return type, through inline fragments and fragment
|
|
53
|
+
* spreads on that same selection set, and only to those declaring none of the
|
|
54
|
+
* size arguments (`edges`, `nodes`): such a list takes it instead of
|
|
55
|
+
* `defaultFirst`. A list declaring a size argument (`recent(first: Int)`)
|
|
56
|
+
* reads its own, never the pending size. Crossing any other field (an object
|
|
57
|
+
* field, `pageInfo`, a wrapper) ends it. A connection stating nothing hands
|
|
58
|
+
* down nothing: its lists are sized `defaultFirst`.
|
|
59
|
+
*
|
|
60
|
+
* Named fragments are followed, each costed once per pending size (past eight
|
|
61
|
+
* distinct sizes under one fragment a size is rounded up to a power of two, so
|
|
62
|
+
* the work stays linear in the document and a cost only over-counts). Inline fragments and
|
|
48
63
|
* fragments on an abstract type are summed branch by branch, so the cost of a
|
|
49
64
|
* query on an interface or a union is overestimated, never underestimated.
|
|
50
65
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"max-list-cost.d.ts","sourceRoot":"","sources":["../../src/limits/max-list-cost.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"max-list-cost.d.ts","sourceRoot":"","sources":["../../src/limits/max-list-cost.ts"],"names":[],"mappings":"AAAA,OAAO,EAUN,KAAK,cAAc,EACnB,MAAM,SAAS,CAAC;AAejB,sCAAsC;AACtC,MAAM,WAAW,kBAAkB;IAClC,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAkGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,cAAc,CAgDvE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ArgumentNode, GraphQLField, GraphQLNamedType } from 'graphql';
|
|
2
|
+
import { type SizeContext } from './list-size.js';
|
|
3
|
+
/**
|
|
4
|
+
* The size of the list `definition` on `parent`. `pending` is the size of the
|
|
5
|
+
* field whose return type this list is selected on (a connection's `first`):
|
|
6
|
+
* a list that declares none of the size arguments takes it, since the size
|
|
7
|
+
* cannot be stated on the list itself. A list that declares one reads its own
|
|
8
|
+
* arguments, else `defaultFirst`, and never the pending size. On an abstract
|
|
9
|
+
* parent some possible types may declare one and others not: the largest of
|
|
10
|
+
* both readings, since the query cannot say which comes back.
|
|
11
|
+
*/
|
|
12
|
+
export declare function listSizeUnder(cost: SizeContext, parent: GraphQLNamedType | undefined, definition: GraphQLField<unknown, unknown>, args: readonly ArgumentNode[] | undefined, pending: number | undefined): number;
|
|
13
|
+
//# sourceMappingURL=pending-size.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-size.d.ts","sourceRoot":"","sources":["../../src/limits/pending-size.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,EAAe,KAAK,WAAW,EAAc,MAAM,aAAa,CAAC;AAExE;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC5B,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,gBAAgB,GAAG,SAAS,EACpC,UAAU,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EAC1C,IAAI,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,EACzC,OAAO,EAAE,MAAM,GAAG,SAAS,GACzB,MAAM,CASR"}
|
package/docs/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
| --- | --- |
|
|
7
7
|
| [Constraints](guide/constraints.md) | you write `@constraint` in your schema: setup with `withValidation`, every argument and its Zod equivalent, the formats and your own, lists and nested inputs |
|
|
8
8
|
| [Answering invalid input as one error](guide/invalid-input.md) | your API answers invalid input as one 400 error with a list of fields (`invalidInputError`, `fieldIssueOf` for a Zod parse), or a refusal such as a 409 names the fields at fault (`fieldsError`) |
|
|
9
|
-
| [Limiting the depth and cost of a query](guide/query-limits.md) | a schema has list cycles and you want to refuse a query nested too deep or too
|
|
9
|
+
| [Limiting the depth and cost of a query](guide/query-limits.md) | a schema has list cycles and you want to refuse a query nested too deep, too costly or too wide (`maxDepth`, `maxListCost`, `maxFields`), with graphql-js `validate` or graphql-yoga |
|
|
10
10
|
| [Errors](guide/errors.md) | you handle the `BAD_USER_INPUT` error in a client, build it yourself with `badUserInput`, or add rules a directive cannot say with `validated` |
|
|
11
11
|
|
|
12
12
|
## Reference
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Limiting the depth and cost of a query
|
|
2
2
|
|
|
3
|
-
`maxDepth` and `
|
|
3
|
+
`maxDepth`, `maxListCost` and `maxFields` are graphql-js validation rules. They refuse an
|
|
4
4
|
operation before any resolver runs, so a hostile query costs a walk of its
|
|
5
5
|
document and nothing more. For `@constraint`, see
|
|
6
6
|
[Constraints](constraints.md).
|
|
@@ -26,25 +26,31 @@ query {
|
|
|
26
26
|
Four `items` levels of 100 each can ask for 100 million nodes in a query nine
|
|
27
27
|
levels deep (`folder`, four `items`, three `folder`, `id`). `maxDepth` bounds the nesting; `maxListCost` bounds the work.
|
|
28
28
|
|
|
29
|
+
Neither bounds breadth: a query of 2000 aliases of `item(id: "1") { id }` is two
|
|
30
|
+
levels deep and costs 4000, yet selects 4000 fields for the executor to run; so does a
|
|
31
|
+
query of thousands of aliases of `__typename`, which neither rule counts.
|
|
32
|
+
`maxFields` bounds that.
|
|
33
|
+
|
|
29
34
|
## Use
|
|
30
35
|
|
|
31
36
|
With graphql-js, add the rules to the ones `validate` already runs:
|
|
32
37
|
|
|
33
38
|
```ts
|
|
34
|
-
import { maxDepth, maxListCost } from '@nxgt/graphql-validation';
|
|
39
|
+
import { maxDepth, maxFields, maxListCost } from '@nxgt/graphql-validation';
|
|
35
40
|
import { parse, specifiedRules, validate } from 'graphql';
|
|
36
41
|
|
|
37
42
|
const errors = validate(schema, parse(query), [
|
|
38
43
|
...specifiedRules,
|
|
39
44
|
maxDepth({ depth: 8 }),
|
|
40
45
|
maxListCost({ budget: 10_000, defaultFirst: 50 }),
|
|
46
|
+
maxFields({ limit: 500 }),
|
|
41
47
|
]);
|
|
42
48
|
```
|
|
43
49
|
|
|
44
50
|
With graphql-yoga, in a plugin:
|
|
45
51
|
|
|
46
52
|
```ts
|
|
47
|
-
import { maxDepth, maxListCost } from '@nxgt/graphql-validation';
|
|
53
|
+
import { maxDepth, maxFields, maxListCost } from '@nxgt/graphql-validation';
|
|
48
54
|
import { createYoga } from 'graphql-yoga';
|
|
49
55
|
|
|
50
56
|
createYoga({
|
|
@@ -54,6 +60,7 @@ createYoga({
|
|
|
54
60
|
onValidate: ({ addValidationRule }) => {
|
|
55
61
|
addValidationRule(maxDepth({ depth: 8 }));
|
|
56
62
|
addValidationRule(maxListCost({ budget: 10_000, defaultFirst: 50 }));
|
|
63
|
+
addValidationRule(maxFields({ limit: 500 }));
|
|
57
64
|
},
|
|
58
65
|
},
|
|
59
66
|
],
|
|
@@ -61,7 +68,7 @@ createYoga({
|
|
|
61
68
|
```
|
|
62
69
|
|
|
63
70
|
Each rule reports **one** `GraphQLError` per operation, whose `nodes` is the
|
|
64
|
-
operation. An invalid option (`depth: 0`, a fractional `budget`) throws a
|
|
71
|
+
operation. An invalid option (`depth: 0`, a fractional `budget`, `limit: 0`) throws a
|
|
65
72
|
`RangeError` when the rule is created.
|
|
66
73
|
|
|
67
74
|
## `maxDepth({ depth, ignoreIntrospection? })`
|
|
@@ -168,9 +175,59 @@ Pick `defaultFirst` knowing a variable counts for it: a client using
|
|
|
168
175
|
`first: $n` is charged the default whatever it sends. If your server caps a size
|
|
169
176
|
argument, set `defaultFirst` (or the SDL default) at that cap.
|
|
170
177
|
|
|
178
|
+
### Relay connections
|
|
179
|
+
|
|
180
|
+
On a Relay connection the size is on a field that returns an **object**, and the
|
|
181
|
+
list is below it:
|
|
182
|
+
|
|
183
|
+
```graphql
|
|
184
|
+
type Query { items(first: Int): ItemConnection! }
|
|
185
|
+
type ItemConnection { edges: [ItemEdge!]! nodes: [Item!]! pageInfo: PageInfo! }
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
```graphql
|
|
189
|
+
{ items(first: 100) { edges { node { id } } nodes { id } } }
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
A field that is not a list and states a size, read as for a list above (a size
|
|
193
|
+
argument given, or declared with a default; on an abstract parent the largest
|
|
194
|
+
over its possible types), hands it down as a **pending size** to the lists
|
|
195
|
+
selected **directly on its return type**:
|
|
196
|
+
|
|
197
|
+
- Only a list that **declares none of the size arguments** takes it, instead of
|
|
198
|
+
`defaultFirst`: `edges` and `nodes` above are both 100. A list that declares
|
|
199
|
+
one (`recent(first: Int)`) reads its own arguments, else `defaultFirst`,
|
|
200
|
+
never the pending size.
|
|
201
|
+
- On an interface, when some possible types declare a size argument on that
|
|
202
|
+
list and others do not, the larger of the pending size and the list's own
|
|
203
|
+
reading is used, since the query cannot say which comes back.
|
|
204
|
+
- It stops at the first field crossed: an object field (`owner`), `pageInfo` or
|
|
205
|
+
a wrapper object passes nothing on, so the lists below them are sized as
|
|
206
|
+
without a connection. In `items(first: 0) { owner { friends { … } } }` the
|
|
207
|
+
`0` does not reach `friends`. A nested field that states a size hands its own
|
|
208
|
+
to the lists directly on it.
|
|
209
|
+
- A connection field that states nothing (no size argument given, none declared
|
|
210
|
+
with a default) hands down nothing: its lists are sized `defaultFirst`, as
|
|
211
|
+
before. A variable, a negative number or an unusable value on it counts as for
|
|
212
|
+
a list: its SDL default, else `defaultFirst`.
|
|
213
|
+
- The rule is structural: any non-list field stating a size sizes the lists
|
|
214
|
+
declaring no size argument directly on its return type, whether or not it is
|
|
215
|
+
a connection. `user(limit: 0) { friends { … } }` sizes `friends` 0. So an
|
|
216
|
+
argument named in `sizeArguments` must size the lists directly under its
|
|
217
|
+
field: when one of yours means something else, leave its name out of
|
|
218
|
+
`sizeArguments` (or rename the argument).
|
|
219
|
+
- Inline fragments, and fragment spreads, on that same selection set pass the
|
|
220
|
+
pending size through. A named fragment is costed once for each distinct
|
|
221
|
+
pending size it is spread under (`...C` under
|
|
222
|
+
`first: 2` and `first: 5` costs differently). Under more than eight distinct
|
|
223
|
+
sizes in one document a fragment's further sizes are rounded up to the next
|
|
224
|
+
power of two, so the work stays linear in the document and the cost only
|
|
225
|
+
over-counts.
|
|
226
|
+
|
|
171
227
|
### Fragments and abstract types
|
|
172
228
|
|
|
173
|
-
Named fragments are followed, each costed once
|
|
229
|
+
Named fragments are followed, each costed once per pending size (see above;
|
|
230
|
+
a fragment's type condition fixes
|
|
174
231
|
its parent type). A fragment spread twice counts twice. Inline fragments and
|
|
175
232
|
fragments on an interface or a union are **summed branch by branch**: a
|
|
176
233
|
selection `... on A { ... } ... on B { ... }` costs A's plus B's, although an
|
|
@@ -194,6 +251,54 @@ Costs are plain numbers, computed from memoized fragments (no exponential work
|
|
|
194
251
|
on a hostile query) and held at `Number.MAX_SAFE_INTEGER`: `cost` is exact below
|
|
195
252
|
it and never `Infinity`.
|
|
196
253
|
|
|
254
|
+
## `maxFields({ limit, ignoreIntrospection? })`
|
|
255
|
+
|
|
256
|
+
The size of an operation is the number of field selections in its document,
|
|
257
|
+
fragment spreads expanded. It is not what the executor runs: how often a field
|
|
258
|
+
runs inside a list is `maxListCost`'s business, so `maxFields` alone does not
|
|
259
|
+
bound execution.
|
|
260
|
+
|
|
261
|
+
- Every field node counts 1: aliases count (`a1: id a2: id` is 2), and so does
|
|
262
|
+
`__typename`.
|
|
263
|
+
- A named fragment counts **at each spread**: a fragment of 3 fields spread
|
|
264
|
+
twice adds 6. Each fragment is walked once, so the work stays linear in the
|
|
265
|
+
size of the document even when spreads multiply. A fragment cycle counts 0
|
|
266
|
+
(`NoFragmentCyclesRule` reports it).
|
|
267
|
+
- Inline fragments count their contents. No type condition prunes anything:
|
|
268
|
+
every branch of a union or an interface counts, so the figure can only be
|
|
269
|
+
over the document's field count.
|
|
270
|
+
- `@skip` and `@include` are not evaluated (the rules read the document, not its
|
|
271
|
+
variables): a field they would remove is counted anyway.
|
|
272
|
+
- `__schema` and `__type` and everything under them count like any field.
|
|
273
|
+
The standard introspection query (`getIntrospectionQuery()`) selects **220
|
|
274
|
+
fields** on graphql 16 and 17 (the fragments `FullType`, `InputValue` and
|
|
275
|
+
`TypeRef` are counted at each spread), so a limit under 220 refuses it. Where
|
|
276
|
+
introspection is disabled, or the client is trusted (GraphiQL in development),
|
|
277
|
+
pass `ignoreIntrospection: true`.
|
|
278
|
+
|
|
279
|
+
The refusal:
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{
|
|
283
|
+
"message": "Operation \"Wide\" selects 4000 fields, more than the 500 allowed",
|
|
284
|
+
"extensions": { "code": "QUERY_TOO_WIDE", "fields": 4000, "limit": 500 }
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
`fields` is the operation's real count, held at `Number.MAX_SAFE_INTEGER`
|
|
289
|
+
whatever a hostile query multiplies. An anonymous operation reads
|
|
290
|
+
`Operation selects 4000 fields, ...`. `limit` must be an integer from 1 to
|
|
291
|
+
`Number.MAX_SAFE_INTEGER - 1`, else a `RangeError`.
|
|
292
|
+
|
|
293
|
+
### Choosing a limit
|
|
294
|
+
|
|
295
|
+
Count the fields of your largest legitimate query, spreads included (a page
|
|
296
|
+
that spreads a 10-field fragment on 20 list entries reads 200 plus the rest),
|
|
297
|
+
and add headroom: a few hundred covers most screens. Keep the introspection
|
|
298
|
+
query in mind (220) if you leave it counted. `maxFields` complements the other
|
|
299
|
+
two: `maxDepth` bounds nesting, `maxListCost` bounds list multiplication, and
|
|
300
|
+
`maxFields` bounds how many fields one request may name.
|
|
301
|
+
|
|
197
302
|
## Not covered
|
|
198
303
|
|
|
199
304
|
- A size carried inside an input object (`items(page: { first: 1000 })`) is not
|
package/docs/roadmap.md
CHANGED
|
@@ -18,10 +18,15 @@ Nothing planned yet.
|
|
|
18
18
|
|
|
19
19
|
## Shipped
|
|
20
20
|
|
|
21
|
-
- **
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
- **Relay connection sizing** — `maxListCost` sizes the `edges` and `nodes` of
|
|
22
|
+
a connection from the connection field's size argument (`items(first: 100)
|
|
23
|
+
{ edges { … } }`), not `defaultFirst`.
|
|
24
|
+
- **Query depth, cost and breadth limits** — `maxDepth`, `maxListCost` and
|
|
25
|
+
`maxFields` are graphql-js validation rules (also for graphql-yoga's
|
|
26
|
+
`addValidationRule`) that refuse a query nested too deep, too costly for a
|
|
27
|
+
schema with list cycles, or selecting too many fields (aliases of a cheap
|
|
28
|
+
field), with the stable codes `QUERY_TOO_DEEP`, `QUERY_TOO_COSTLY` and
|
|
29
|
+
`QUERY_TOO_WIDE`.
|
|
25
30
|
- **Schemas that read the context** — 0.5.0. `validated((context, info) =>
|
|
26
31
|
schema, resolver)` builds the schema on each call from the request's context
|
|
27
32
|
and the field's `info`, for checks that need the request (a uniqueness query
|
package/docs/troubleshooting.md
CHANGED
|
@@ -427,10 +427,30 @@ reads `Operation is 9 levels deep, ...`.
|
|
|
427
427
|
Each field costs 1, times the sizes of the lists enclosing it. A list without a
|
|
428
428
|
usable `first` (a variable, a negative number, nothing) counts for its SDL
|
|
429
429
|
default, else `defaultFirst`, so a query that is cheap with the variable's real
|
|
430
|
-
value can still be refused.
|
|
430
|
+
value can still be refused. A size argument on a field returning an object (a
|
|
431
|
+
connection's `first`) now sizes its `edges` and `nodes`, and any non-list field
|
|
432
|
+
stating a size sizes the lists declaring none directly under it, see
|
|
433
|
+
[Relay connections](guide/query-limits.md#relay-connections).
|
|
431
434
|
**Fix:** ask for fewer items with a literal `first`, or raise `budget`. A query
|
|
432
435
|
on an interface or a union is overestimated (every branch is summed).
|
|
433
436
|
|
|
437
|
+
### `Operation "Name" selects 4000 fields, more than the 500 allowed`
|
|
438
|
+
|
|
439
|
+
**When:** an operation is validated with `maxFields({ limit: 500 })`.
|
|
440
|
+
**Why:** `extensions` is `{ code: 'QUERY_TOO_WIDE', fields: 4000, limit: 500 }`.
|
|
441
|
+
Every field selection counts 1, aliases and `__typename` included, and a named
|
|
442
|
+
fragment counts at each spread; every branch of an inline fragment counts and
|
|
443
|
+
`@skip`/`@include` are not evaluated, so the figure can be over what runs. An
|
|
444
|
+
anonymous operation reads `Operation selects 4000 fields, ...`.
|
|
445
|
+
**Fix:** ask for fewer fields (a fragment spread many times is many fields), or
|
|
446
|
+
raise `limit`. See [Limiting the depth and cost of a query](guide/query-limits.md).
|
|
447
|
+
|
|
448
|
+
### `maxFields: limit must be an integer from 1 to 9007199254740990.`
|
|
449
|
+
|
|
450
|
+
**When:** `maxFields` is called with `0`, a negative, a fractional or a too
|
|
451
|
+
large `limit`.
|
|
452
|
+
**Fix:** pass an integer in range.
|
|
453
|
+
|
|
434
454
|
### `maxDepth: depth must be an integer from 1 to 9007199254740990.`
|
|
435
455
|
|
|
436
456
|
**When:** `maxDepth` is called with `0`, a negative or a fractional `depth`.
|
|
@@ -450,10 +470,10 @@ budget at or over it would refuse nothing.
|
|
|
450
470
|
|
|
451
471
|
### A query refused although its `first` is small, or an introspection query refused
|
|
452
472
|
|
|
453
|
-
**When:** `QUERY_TOO_COSTLY` or `
|
|
473
|
+
**When:** `QUERY_TOO_COSTLY`, `QUERY_TOO_DEEP` or `QUERY_TOO_WIDE` for GraphiQL's schema fetch or
|
|
454
474
|
a codegen's introspection query.
|
|
455
475
|
**Why:** `__schema` is counted: the standard introspection query is 15 levels
|
|
456
|
-
deep and costs on the order of 200,000 on a one-field schema.
|
|
476
|
+
deep, selects 220 fields and costs on the order of 200,000 on a one-field schema.
|
|
457
477
|
**Fix:** `ignoreIntrospection: true` on the rule where introspection is
|
|
458
478
|
disabled or the client is trusted. A `first: $n` variable counts for the SDL
|
|
459
479
|
default, not for the value sent.
|
package/package.json
CHANGED