graphql-safe-guards 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -3
- package/README.md +27 -3
- package/dist/index.js +9 -14
- package/dist/presets.d.ts +3 -0
- package/dist/presets.js +3 -0
- package/dist/utils/wrapIgnoreIntrospection.js +6 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
## [1.1.2] – 2026-01-22
|
|
13
|
+
|
|
10
14
|
## [1.1.0] – 2026-01-22
|
|
11
15
|
|
|
12
16
|
### Added
|
|
@@ -19,12 +23,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
19
23
|
|
|
20
24
|
### Changed
|
|
21
25
|
|
|
22
|
-
-
|
|
26
|
+
- `ignoreIntrospection` option to exclude GraphQL introspection queries
|
|
27
|
+
from depth and complexity validation.
|
|
23
28
|
|
|
24
29
|
### Fixed
|
|
25
30
|
|
|
26
|
-
-
|
|
27
|
-
|
|
31
|
+
- Ensured GraphQL introspection queries are excluded from depth and
|
|
32
|
+
complexity validation when `ignoreIntrospection` is enabled.
|
|
28
33
|
|
|
29
34
|
---
|
|
30
35
|
|
package/README.md
CHANGED
|
@@ -42,8 +42,8 @@ const server = new ApolloServer({
|
|
|
42
42
|
|
|
43
43
|
```ts
|
|
44
44
|
createSafeGuards({
|
|
45
|
-
depth?: number; // default:
|
|
46
|
-
complexity?: number; // default:
|
|
45
|
+
depth?: number; // default: 3 (strict preset)
|
|
46
|
+
complexity?: number; // default: 50 (strict preset)
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* If true, GraphQL introspection queries are ignored
|
|
@@ -74,6 +74,22 @@ const server = new ApolloServer({
|
|
|
74
74
|
});
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
## Presets (Recommended)
|
|
78
|
+
|
|
79
|
+
graphql-safe-guards includes opinionated, production-ready presets for common use cases.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
createSafeGuards({ preset: "strict" });
|
|
83
|
+
createSafeGuards({ preset: "balanced" });
|
|
84
|
+
createSafeGuards({ preset: "relaxed" });
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| Preset | Depth | Complexity | Use case |
|
|
88
|
+
| -------- | ----- | ---------- | --------------------------- |
|
|
89
|
+
| strict | 3 | 50 | Public APIs, read-only APIs |
|
|
90
|
+
| balanced | 4 | 100 | Private frontends |
|
|
91
|
+
| relaxed | 6 | 200 | Admin / internal tools |
|
|
92
|
+
|
|
77
93
|
---
|
|
78
94
|
|
|
79
95
|
## What It Does
|
|
@@ -112,6 +128,14 @@ Most GraphQL servers need **both**, but wiring them together is repetitive.
|
|
|
112
128
|
`graphql-safe-guards` provides a **single, predictable entry point**
|
|
113
129
|
for GraphQL query safety.
|
|
114
130
|
|
|
131
|
+
### Environment-based setup
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
createSafeGuards({
|
|
135
|
+
preset: process.env.NODE_ENV === "production" ? "strict" : "balanced",
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
115
139
|
---
|
|
116
140
|
|
|
117
141
|
## 🗺️ Roadmap
|
|
@@ -122,7 +146,7 @@ for GraphQL query safety.
|
|
|
122
146
|
- ✅ Presets support (`strict`, `balanced`, `relaxed`)
|
|
123
147
|
- ✅ Backward-compatible API
|
|
124
148
|
- ✅ Integration tests with `graphql-js`
|
|
125
|
-
- 🔜
|
|
149
|
+
- 🔜 Additional presets based on community feedback
|
|
126
150
|
|
|
127
151
|
> Roadmap items may change based on feedback and real-world usage.
|
|
128
152
|
|
package/dist/index.js
CHANGED
|
@@ -6,24 +6,19 @@ const graphql_complexity_validation_1 = require("graphql-complexity-validation")
|
|
|
6
6
|
const presets_1 = require("./presets");
|
|
7
7
|
const wrapIgnoreIntrospection_1 = require("./utils/wrapIgnoreIntrospection");
|
|
8
8
|
function createSafeGuards(options = {}) {
|
|
9
|
-
var _a, _b, _c
|
|
9
|
+
var _a, _b, _c;
|
|
10
10
|
const presetConfig = options.preset
|
|
11
11
|
? presets_1.SAFE_GUARD_PRESETS[options.preset]
|
|
12
|
-
:
|
|
13
|
-
const depth = (
|
|
14
|
-
const complexity = (
|
|
15
|
-
const ignoreIntrospection = (
|
|
16
|
-
|
|
12
|
+
: presets_1.SAFE_GUARD_PRESETS.strict;
|
|
13
|
+
const depth = (_a = options.depth) !== null && _a !== void 0 ? _a : presetConfig.depth;
|
|
14
|
+
const complexity = (_b = options.complexity) !== null && _b !== void 0 ? _b : presetConfig.complexity;
|
|
15
|
+
const ignoreIntrospection = (_c = options.ignoreIntrospection) !== null && _c !== void 0 ? _c : presetConfig.ignoreIntrospection;
|
|
16
|
+
let rules = [
|
|
17
17
|
(0, graphql_safe_depth_1.createDepthLimitRule)({ maxDepth: depth }),
|
|
18
18
|
(0, graphql_complexity_validation_1.createComplexityLimitRule)({ maxComplexity: complexity }),
|
|
19
19
|
];
|
|
20
|
-
if (
|
|
21
|
-
|
|
20
|
+
if (ignoreIntrospection) {
|
|
21
|
+
rules = rules.map((rule) => (0, wrapIgnoreIntrospection_1.wrapIgnoreIntrospection)(rule));
|
|
22
22
|
}
|
|
23
|
-
return rules
|
|
24
|
-
// el original
|
|
25
|
-
// return [
|
|
26
|
-
// createDepthLimitRule({ maxDepth: depth }),
|
|
27
|
-
// createComplexityLimitRule({ maxComplexity: complexity }),
|
|
28
|
-
// ];
|
|
23
|
+
return rules;
|
|
29
24
|
}
|
package/dist/presets.d.ts
CHANGED
|
@@ -2,13 +2,16 @@ export declare const SAFE_GUARD_PRESETS: {
|
|
|
2
2
|
readonly strict: {
|
|
3
3
|
readonly depth: 3;
|
|
4
4
|
readonly complexity: 50;
|
|
5
|
+
readonly ignoreIntrospection: false;
|
|
5
6
|
};
|
|
6
7
|
readonly balanced: {
|
|
7
8
|
readonly depth: 5;
|
|
8
9
|
readonly complexity: 100;
|
|
10
|
+
readonly ignoreIntrospection: true;
|
|
9
11
|
};
|
|
10
12
|
readonly relaxed: {
|
|
11
13
|
readonly depth: 8;
|
|
12
14
|
readonly complexity: 200;
|
|
15
|
+
readonly ignoreIntrospection: true;
|
|
13
16
|
};
|
|
14
17
|
};
|
package/dist/presets.js
CHANGED
|
@@ -5,13 +5,16 @@ exports.SAFE_GUARD_PRESETS = {
|
|
|
5
5
|
strict: {
|
|
6
6
|
depth: 3,
|
|
7
7
|
complexity: 50,
|
|
8
|
+
ignoreIntrospection: false,
|
|
8
9
|
},
|
|
9
10
|
balanced: {
|
|
10
11
|
depth: 5,
|
|
11
12
|
complexity: 100,
|
|
13
|
+
ignoreIntrospection: true,
|
|
12
14
|
},
|
|
13
15
|
relaxed: {
|
|
14
16
|
depth: 8,
|
|
15
17
|
complexity: 200,
|
|
18
|
+
ignoreIntrospection: true,
|
|
16
19
|
},
|
|
17
20
|
};
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.wrapIgnoreIntrospection = wrapIgnoreIntrospection;
|
|
4
|
+
const INTROSPECTION_FIELDS = new Set(["__schema", "__type"]);
|
|
4
5
|
function wrapIgnoreIntrospection(rule) {
|
|
5
6
|
return (context) => {
|
|
6
7
|
const visitor = rule(context);
|
|
7
8
|
return {
|
|
8
9
|
Field(node) {
|
|
9
|
-
//
|
|
10
|
-
if (node.name.value
|
|
11
|
-
return
|
|
10
|
+
// Ignora introspection sin romper traversal
|
|
11
|
+
if (INTROSPECTION_FIELDS.has(node.name.value)) {
|
|
12
|
+
return null;
|
|
12
13
|
}
|
|
13
|
-
//
|
|
14
|
+
// Delegate safely if Field visitor exists
|
|
14
15
|
const fieldVisitor = visitor === null || visitor === void 0 ? void 0 : visitor.Field;
|
|
15
16
|
if (typeof fieldVisitor === "function") {
|
|
16
17
|
return fieldVisitor(node);
|
|
17
18
|
}
|
|
19
|
+
return undefined;
|
|
18
20
|
},
|
|
19
21
|
};
|
|
20
22
|
};
|