graphql-safe-guards 1.0.2 → 1.1.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/CHANGELOG.md +40 -0
- package/README.md +48 -1
- package/dist/index.js +13 -2
- package/dist/types.d.ts +1 -0
- package/dist/utils/wrapIgnoreIntrospection.d.ts +2 -0
- package/dist/utils/wrapIgnoreIntrospection.js +21 -0
- package/package.json +1 -1
- package/test/graphqlSafeGuards.test.ts +0 -28
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [1.1.0] – 2026-01-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `ignoreIntrospection` option to allow GraphQL introspection queries
|
|
15
|
+
without applying depth and complexity validation.
|
|
16
|
+
- Documentation explaining how to use `ignoreIntrospection` with
|
|
17
|
+
GraphQL Playground and Apollo Sandbox.
|
|
18
|
+
- Security guidelines for private APIs with introspection enabled.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Improved README clarity around introspection and validation behavior.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Prevented GraphQL introspection queries from being blocked by strict
|
|
27
|
+
depth or complexity limits when `ignoreIntrospection` is enabled.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## [1.0.2]
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- Preset-based configuration (`strict`, `balanced`, `relaxed`)
|
|
36
|
+
- Integration tests validating combined depth and complexity limits
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- Type-safe preset resolution
|
package/README.md
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+

|
|
2
|
+

|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
1
7
|
# graphql-safe-guards
|
|
2
8
|
|
|
3
9
|
Protect your GraphQL API with a single import.
|
|
4
10
|
|
|
5
11
|
A tiny utility that **combines depth limiting and query complexity validation**
|
|
6
|
-
using native GraphQL validation rules
|
|
12
|
+
using **native GraphQL validation rules**.
|
|
7
13
|
|
|
8
14
|
---
|
|
9
15
|
|
|
@@ -38,6 +44,33 @@ const server = new ApolloServer({
|
|
|
38
44
|
createSafeGuards({
|
|
39
45
|
depth?: number; // default: 5
|
|
40
46
|
complexity?: number; // default: 100
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* If true, GraphQL introspection queries are ignored
|
|
50
|
+
* by depth and complexity validation.
|
|
51
|
+
*
|
|
52
|
+
* Useful for GraphQL Playground / Apollo Sandbox.
|
|
53
|
+
*/
|
|
54
|
+
ignoreIntrospection?: boolean; // default: false
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Security Note ⚠️
|
|
59
|
+
|
|
60
|
+
- This library does not enable or disable GraphQL introspection
|
|
61
|
+
|
|
62
|
+
- Introspection is controlled by your GraphQL server (e.g. Apollo Server)
|
|
63
|
+
For private APIs with documentation enabled, the recommended setup is:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const server = new ApolloServer({
|
|
67
|
+
schema,
|
|
68
|
+
introspection: true,
|
|
69
|
+
validationRules: createSafeGuards({
|
|
70
|
+
depth: 3,
|
|
71
|
+
complexity: 10,
|
|
72
|
+
ignoreIntrospection: true,
|
|
73
|
+
}),
|
|
41
74
|
});
|
|
42
75
|
```
|
|
43
76
|
|
|
@@ -57,6 +90,8 @@ Internally, this package composes:
|
|
|
57
90
|
- `graphql-safe-depth`
|
|
58
91
|
- `graphql-complexity-validation`
|
|
59
92
|
|
|
93
|
+
The combination is validated through integration tests using native GraphQL validation.
|
|
94
|
+
|
|
60
95
|
---
|
|
61
96
|
|
|
62
97
|
## Supported Frameworks
|
|
@@ -79,6 +114,18 @@ for GraphQL query safety.
|
|
|
79
114
|
|
|
80
115
|
---
|
|
81
116
|
|
|
117
|
+
## 🗺️ Roadmap
|
|
118
|
+
|
|
119
|
+
### v1.x (current)
|
|
120
|
+
|
|
121
|
+
- ✅ Combine depth + complexity validation
|
|
122
|
+
- ✅ Presets support (`strict`, `balanced`, `relaxed`)
|
|
123
|
+
- ✅ Backward-compatible API
|
|
124
|
+
- ✅ Integration tests with `graphql-js`
|
|
125
|
+
- 🔜 Preset for private APIs (privateApi)
|
|
126
|
+
|
|
127
|
+
> Roadmap items may change based on feedback and real-world usage.
|
|
128
|
+
|
|
82
129
|
## License
|
|
83
130
|
|
|
84
131
|
MIT © Mateo Diaz
|
package/dist/index.js
CHANGED
|
@@ -4,15 +4,26 @@ exports.createSafeGuards = createSafeGuards;
|
|
|
4
4
|
const graphql_safe_depth_1 = require("graphql-safe-depth");
|
|
5
5
|
const graphql_complexity_validation_1 = require("graphql-complexity-validation");
|
|
6
6
|
const presets_1 = require("./presets");
|
|
7
|
+
const wrapIgnoreIntrospection_1 = require("./utils/wrapIgnoreIntrospection");
|
|
7
8
|
function createSafeGuards(options = {}) {
|
|
8
|
-
var _a, _b, _c, _d;
|
|
9
|
+
var _a, _b, _c, _d, _e;
|
|
9
10
|
const presetConfig = options.preset
|
|
10
11
|
? presets_1.SAFE_GUARD_PRESETS[options.preset]
|
|
11
12
|
: undefined;
|
|
12
13
|
const depth = (_b = (_a = options.depth) !== null && _a !== void 0 ? _a : presetConfig === null || presetConfig === void 0 ? void 0 : presetConfig.depth) !== null && _b !== void 0 ? _b : 5;
|
|
13
14
|
const complexity = (_d = (_c = options.complexity) !== null && _c !== void 0 ? _c : presetConfig === null || presetConfig === void 0 ? void 0 : presetConfig.complexity) !== null && _d !== void 0 ? _d : 100;
|
|
14
|
-
|
|
15
|
+
const ignoreIntrospection = (_e = options.ignoreIntrospection) !== null && _e !== void 0 ? _e : false;
|
|
16
|
+
const rules = [
|
|
15
17
|
(0, graphql_safe_depth_1.createDepthLimitRule)({ maxDepth: depth }),
|
|
16
18
|
(0, graphql_complexity_validation_1.createComplexityLimitRule)({ maxComplexity: complexity }),
|
|
17
19
|
];
|
|
20
|
+
if (!ignoreIntrospection) {
|
|
21
|
+
return rules;
|
|
22
|
+
}
|
|
23
|
+
return rules.map((rule) => (0, wrapIgnoreIntrospection_1.wrapIgnoreIntrospection)(rule));
|
|
24
|
+
// el original
|
|
25
|
+
// return [
|
|
26
|
+
// createDepthLimitRule({ maxDepth: depth }),
|
|
27
|
+
// createComplexityLimitRule({ maxComplexity: complexity }),
|
|
28
|
+
// ];
|
|
18
29
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapIgnoreIntrospection = wrapIgnoreIntrospection;
|
|
4
|
+
function wrapIgnoreIntrospection(rule) {
|
|
5
|
+
return (context) => {
|
|
6
|
+
const visitor = rule(context);
|
|
7
|
+
return {
|
|
8
|
+
Field(node) {
|
|
9
|
+
// Detecta introspection (__schema, __type)
|
|
10
|
+
if (node.name.value.startsWith("__")) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
// Delegamos al visitor original si existe
|
|
14
|
+
const fieldVisitor = visitor === null || visitor === void 0 ? void 0 : visitor.Field;
|
|
15
|
+
if (typeof fieldVisitor === "function") {
|
|
16
|
+
return fieldVisitor(node);
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { createSafeGuards } from "../src";
|
|
3
|
-
|
|
4
|
-
describe("createSafeGuards", () => {
|
|
5
|
-
it("uses strict preset", () => {
|
|
6
|
-
const rules = createSafeGuards({ preset: "strict" });
|
|
7
|
-
|
|
8
|
-
expect(rules).toHaveLength(2);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it("allows overriding preset values", () => {
|
|
12
|
-
const rules = createSafeGuards({
|
|
13
|
-
preset: "strict",
|
|
14
|
-
depth: 10,
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
expect(rules).toHaveLength(2);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it("works without preset (backward compatible)", () => {
|
|
21
|
-
const rules = createSafeGuards({
|
|
22
|
-
depth: 4,
|
|
23
|
-
complexity: 20,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
expect(rules).toHaveLength(2);
|
|
27
|
-
});
|
|
28
|
-
});
|