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 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
+ ![CI](https://github.com/Mateodiaz401/graphql-safe-guards/actions/workflows/ci.yml/badge.svg)
2
+ ![npm](https://img.shields.io/npm/v/graphql-safe-guards)
3
+ ![downloads](https://img.shields.io/npm/dm/graphql-safe-guards)
4
+ ![license](https://img.shields.io/npm/l/graphql-safe-guards)
5
+ ![typescript](https://img.shields.io/badge/TypeScript-Ready-blue)
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
- return [
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
@@ -4,4 +4,5 @@ export interface GraphQLSafeGuardsOptions {
4
4
  preset?: SafeGuardPreset;
5
5
  depth?: number;
6
6
  complexity?: number;
7
+ ignoreIntrospection?: boolean;
7
8
  }
@@ -0,0 +1,2 @@
1
+ import { ValidationRule } from "graphql";
2
+ export declare function wrapIgnoreIntrospection(rule: ValidationRule): ValidationRule;
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "graphql-safe-guards",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Opinionated GraphQL security guards (depth + complexity) in one import",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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
- });