zuplo 6.71.21 → 6.71.23

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.
@@ -56,8 +56,8 @@ page for product-focused portals. The previews on this page are presented in a
56
56
  title="Build with our API"
57
57
  description="Everything you need to integrate payments, webhooks, and more — in minutes, not days."
58
58
  actions={[
59
- { label: "Get started", href: "/docs/getting-started" },
60
- { label: "API Reference", href: "/docs", variant: "outline" },
59
+ { label: "Get started", href: "/getting-started" },
60
+ { label: "API Reference", href: "/", variant: "outline" },
61
61
  ]}
62
62
  features={[
63
63
  {
@@ -121,7 +121,7 @@ front.
121
121
  title="Ship anywhere in the whole universe"
122
122
  description="Create and manage shipments, track packages in real-time, and integrate with multiple carriers through a single interface."
123
123
  actions={[
124
- { label: "Get started", href: "/docs/getting-started" },
124
+ { label: "Get started", href: "/getting-started" },
125
125
  { label: "View on GitHub", href: "https://github.com/zuplo/zudoku", variant: "outline" },
126
126
  ]}
127
127
  aside={
@@ -183,25 +183,25 @@ routes visitors to the right section quickly.
183
183
  icon: <RocketIcon />,
184
184
  title: "Getting Started",
185
185
  description: "Set up your account and make your first request.",
186
- href: "/docs/getting-started",
186
+ href: "/getting-started",
187
187
  },
188
188
  {
189
189
  icon: <BookOpenIcon />,
190
190
  title: "Guides",
191
191
  description: "Step-by-step tutorials for common use cases.",
192
- href: "/docs",
192
+ href: "/",
193
193
  },
194
194
  {
195
195
  icon: <CodeIcon />,
196
196
  title: "API Reference",
197
197
  description: "Complete reference for every endpoint and type.",
198
- href: "/docs",
198
+ href: "/",
199
199
  },
200
200
  {
201
201
  icon: <WebhookIcon />,
202
202
  title: "Webhooks",
203
203
  description: "Listen to events and build real-time integrations.",
204
- href: "/docs",
204
+ href: "/",
205
205
  },
206
206
  ]}
207
207
  />
@@ -17,7 +17,7 @@ import { Link } from "zudoku/components";
17
17
  ### Basic Internal Link
18
18
 
19
19
  ```tsx
20
- <Link to="/docs/getting-started">Get Started</Link>
20
+ <Link to="/getting-started">Get Started</Link>
21
21
  ```
22
22
 
23
23
  ### Link with State
@@ -39,7 +39,7 @@ import { Link } from "zudoku/components";
39
39
  ### External Link Behavior
40
40
 
41
41
  ```tsx
42
- <Link to="/docs" reloadDocument>
42
+ <Link to="/" reloadDocument>
43
43
  Full Page Reload
44
44
  </Link>
45
45
  ```
@@ -53,7 +53,7 @@ function Navigation() {
53
53
  return (
54
54
  <nav>
55
55
  <Link to="/">Home</Link>
56
- <Link to="/docs">Documentation</Link>
56
+ <Link to="/">Documentation</Link>
57
57
  <Link to="/api">API Reference</Link>
58
58
  <Link to="/blog">Blog</Link>
59
59
  </nav>
@@ -69,7 +69,7 @@ function Breadcrumbs({ path }) {
69
69
  <div className="breadcrumbs">
70
70
  <Link to="/">Home</Link>
71
71
  <span>/</span>
72
- <Link to="/docs">Docs</Link>
72
+ <Link to="/">Docs</Link>
73
73
  <span>/</span>
74
74
  <span>{path}</span>
75
75
  </div>
@@ -134,7 +134,7 @@ function ConditionalLink({ to, disabled, children }) {
134
134
  ### Hash Links
135
135
 
136
136
  ```tsx
137
- <Link to="/docs/api#authentication">Authentication Section</Link>
137
+ <Link to="/api#authentication">Authentication Section</Link>
138
138
  ```
139
139
 
140
140
  ## Advanced Usage
@@ -59,7 +59,7 @@ footer: {
59
59
  links: [
60
60
  { label: "Features", href: "/features" },
61
61
  { label: "Pricing", href: "/pricing" },
62
- { label: "Documentation", href: "/docs" },
62
+ { label: "Documentation", href: "/" },
63
63
  { label: "GitHub", href: "https://github.com/org/repo" }, // Auto-detected as external
64
64
  ],
65
65
  },
@@ -184,7 +184,7 @@ footer: {
184
184
  links: [
185
185
  { label: "Features", href: "/features" },
186
186
  { label: "Pricing", href: "/pricing" },
187
- { label: "Documentation", href: "/docs" }
187
+ { label: "Documentation", href: "/" }
188
188
  ]
189
189
  },
190
190
  {
@@ -46,7 +46,7 @@ const config: ZudokuConfig = {
46
46
  },
47
47
  { type: "link", to: "api", label: "API Reference" },
48
48
  ],
49
- redirects: [{ from: "/", to: "/docs/introduction" }],
49
+ redirects: [{ from: "/", to: "/introduction" }],
50
50
  apis: {
51
51
  type: "file",
52
52
  input: "./apis/openapi.yaml",
@@ -85,7 +85,7 @@ signal a permanent move; the JavaScript redirect used on generic static hosts is
85
85
  The most common use of redirects is setting a landing page for the root path of your portal:
86
86
 
87
87
  ```ts
88
- redirects: [{ from: "/", to: "/docs/introduction" }];
88
+ redirects: [{ from: "/", to: "/introduction" }];
89
89
  ```
90
90
 
91
91
  This sends visitors who arrive at your portal's root URL to your introduction page.
@@ -98,7 +98,7 @@ external links continue to work:
98
98
  ```ts
99
99
  redirects: [
100
100
  { from: "/api/authentication", to: "/guides/auth-overview" },
101
- { from: "/api/getting-started", to: "/docs/quickstart" },
101
+ { from: "/api/getting-started", to: "/quickstart" },
102
102
  { from: "/reference", to: "/api" },
103
103
  ];
104
104
  ```
@@ -2,9 +2,8 @@
2
2
  title: Proxying Between Zuplo Gateways
3
3
  sidebar_label: Proxying Between Gateways
4
4
  description:
5
- Learn how to proxy requests from one Zuplo project to another using the URL
6
- Forward Handler or a custom fetch handler, propagate authentication, surface
7
- upstream errors, and troubleshoot 522 timeouts.
5
+ Learn how to proxy requests from one Zuplo gateway to another, propagate
6
+ authentication, handle upstream errors, and fix 522 timeouts.
8
7
  tags:
9
8
  - backends
10
9
  - deployment
@@ -43,7 +43,8 @@
43
43
  | formdata-to-json-inbound | Form Data to JSON | Converts form data in the incoming request to JSON. | api-gateway |
44
44
  | galileo-tracing-inbound | Galileo Tracing | Galileo Tracing Inbound Policy | ai-gateway |
45
45
  | geo-filter-inbound | Geo-location filtering | Block requests based on geo-location parameters: country, region code, and ASN | api-gateway |
46
- | graphql-analytics-outbound | GraphQL Analytics | Reports GraphQL errors returned in response bodies to Zuplo's GraphQL analytics. GraphQL servers following the standard Apollo / graphql-yoga pattern return `200 OK` with an `errors[]` array in the body when an operation fails, which HTTP-level analytics alone report as a success — add this policy to a GraphQL route and failed operations show up as failures on the GraphQL dashboard, classified by error type. Each error in `errors[]` is classified from its `extensions.code` following the Apollo Server conventions (`GRAPHQL_PARSE_FAILED` → `syntax`, `GRAPHQL_VALIDATION_FAILED` → `validation`, `UNAUTHENTICATED` / `FORBIDDEN` → `auth`, timeout codes → `timeout`); custom codes can be mapped with `errorCodeClassification`, and anything unrecognized falls back to `defaultErrorClass` (`resolver`). Optionally set `logErrors` to also write a structured warning per errored response. Bodies larger than `maxResponseBytes` (default 5 MiB) are not inspected. The response always passes through unchanged — the body is read from a clone, and any internal failure is swallowed so reporting can never break the request. The route must be marked `x-graphql: true` in `routes.oas.json` (which enables GraphQL analytics for the route); without the marker the policy logs a warning and does nothing. | api-gateway |
46
+ | graphql-analytics-outbound | GraphQL Analytics | Reports GraphQL errors returned in response bodies to Zuplo's GraphQL analytics. GraphQL servers following the standard Apollo / graphql-yoga pattern return `200 OK` with an `errors[]` array in the body when an operation fails, which HTTP-level analytics alone report as a success — add this policy to a GraphQL route and failed operations show up as failures on the GraphQL dashboard, classified by error type. Each error in `errors[]` is classified from its `extensions.code` following the Apollo Server conventions (`GRAPHQL_PARSE_FAILED` → `syntax`, `GRAPHQL_VALIDATION_FAILED` → `validation`, `UNAUTHENTICATED` / `FORBIDDEN` → `auth`, timeout codes → `timeout`); custom codes can be mapped with `errorCodeClassification`, and anything unrecognized falls back to `defaultErrorClass` (`resolver`). Optionally set `logErrors` to also write a structured warning per errored response. The policy reads up to `maxScanBytes` of the body (128 KiB by default, 5 MiB maximum), scanning it for the `errors` token; a response larger than that is treated as error-free. When the token is found and the body fits, it is parsed and its errors reported. The response always passes through unchanged — the body is read from a clone, and any internal failure is swallowed so reporting can never break the request. The route must be marked `x-graphql: true` in `routes.oas.json` (which enables GraphQL analytics for the route); without the marker the policy logs a warning and does nothing. | api-gateway |
47
+ | graphql-cache-inbound | GraphQL Cache | Caches GraphQL query responses at the edge so identical queries are served without a round-trip to the origin. Unlike CDN caching that keys on the raw request body, this policy parses the GraphQL document and normalizes it before hashing: insignificant whitespace, field formatting, and fragment layout are collapsed, and variable object keys are sorted. Two requests that are semantically identical therefore share a cache entry even when their bodies differ byte-for-byte. There is no query size or nesting-depth limit. Only `query` operations are cached. Mutations, subscriptions, malformed documents, and non-JSON bodies are forwarded to the origin untouched. Cache hits and misses are reported on the `x-cache` response header, with a short key fingerprint on `x-cache-key`. To avoid serving one user's data to another, requests carrying an `authorization` or `cookie` header are not cached by default. Use `cacheKeyHeaders` to opt into caching them: each listed header's value is included in the cache key, so distinct credentials get distinct cache entries. | api-gateway |
47
48
  | graphql-complexity-limit-inbound | GraphQL Complexity Limit | Policy that limits the complexity and depth of GraphQL queries to prevent abuse. Protects your GraphQL API from expensive queries that could cause performance issues or denial of service attacks. | api-gateway |
48
49
  | graphql-disable-introspection-inbound | GraphQL Disable Introspection | Policy that disables GraphQL introspection queries in production. Introspection allows clients to discover the schema, which can be a security risk as it exposes your entire API structure. | api-gateway |
49
50
  | graphql-introspection-filter-outbound | GraphQL Introspection Filter | Filters GraphQL introspection responses to exclude specific types and fields. This policy intercepts GraphQL introspection query responses and removes configured types and fields from the schema. Useful for hiding internal types or sensitive fields from the public schema. | api-gateway |
@@ -41,10 +41,13 @@ result in the batch.
41
41
  ## What is inspected
42
42
 
43
43
  Only responses with a JSON content type (`application/json` or any `+json` type
44
- such as `application/graphql-response+json`) are read, and bodies larger than
45
- `maxResponseBytes` (5 MiB by default) are skipped by `Content-Length` when the
46
- header is present, or measured while reading when it is absent. Everything else
47
- passes through without the body being touched.
44
+ such as `application/graphql-response+json`) are read. The policy reads up to
45
+ `maxScanBytes` of the body (128 KiB by default, 5 MiB maximum) and scans it for
46
+ the `errors` token; a response larger than that by `Content-Length` when the
47
+ header is present, or measured while reading when it is absent — is treated as
48
+ error-free, so any errors it carries go unreported. Raise `maxScanBytes` if your
49
+ GraphQL responses are larger. Everything else passes through without the body
50
+ being touched.
48
51
 
49
52
  ## Logging
50
53
 
@@ -63,8 +66,9 @@ alert on it.
63
66
  `resolver`
64
67
  - `logErrors`: Also log a structured warning per errored response. **Default:**
65
68
  `false`
66
- - `maxResponseBytes`: Maximum response body size in bytes to inspect.
67
- **Default:** `5242880` (5 MiB)
69
+ - `maxScanBytes`: How many bytes of the response body to read and scan for the
70
+ `errors` token. A larger response is treated as error-free. Capped at 5 MiB.
71
+ **Default:** `131072` (128 KiB)
68
72
 
69
73
  ## Usage
70
74
 
@@ -11,7 +11,7 @@
11
11
  "isHidden": false,
12
12
  "requiresAI": false,
13
13
  "products": ["api-gateway"],
14
- "description": "Reports GraphQL errors returned in response bodies to Zuplo's GraphQL analytics. GraphQL servers following the standard Apollo / graphql-yoga pattern return `200 OK` with an `errors[]` array in the body when an operation fails, which HTTP-level analytics alone report as a success — add this policy to a GraphQL route and failed operations show up as failures on the GraphQL dashboard, classified by error type.\n\nEach error in `errors[]` is classified from its `extensions.code` following the Apollo Server conventions (`GRAPHQL_PARSE_FAILED` → `syntax`, `GRAPHQL_VALIDATION_FAILED` → `validation`, `UNAUTHENTICATED` / `FORBIDDEN` → `auth`, timeout codes → `timeout`); custom codes can be mapped with `errorCodeClassification`, and anything unrecognized falls back to `defaultErrorClass` (`resolver`). Optionally set `logErrors` to also write a structured warning per errored response. Bodies larger than `maxResponseBytes` (default 5 MiB) are not inspected.\n\nThe response always passes through unchanged — the body is read from a clone, and any internal failure is swallowed so reporting can never break the request. The route must be marked `x-graphql: true` in `routes.oas.json` (which enables GraphQL analytics for the route); without the marker the policy logs a warning and does nothing.",
14
+ "description": "Reports GraphQL errors returned in response bodies to Zuplo's GraphQL analytics. GraphQL servers following the standard Apollo / graphql-yoga pattern return `200 OK` with an `errors[]` array in the body when an operation fails, which HTTP-level analytics alone report as a success — add this policy to a GraphQL route and failed operations show up as failures on the GraphQL dashboard, classified by error type.\n\nEach error in `errors[]` is classified from its `extensions.code` following the Apollo Server conventions (`GRAPHQL_PARSE_FAILED` → `syntax`, `GRAPHQL_VALIDATION_FAILED` → `validation`, `UNAUTHENTICATED` / `FORBIDDEN` → `auth`, timeout codes → `timeout`); custom codes can be mapped with `errorCodeClassification`, and anything unrecognized falls back to `defaultErrorClass` (`resolver`). Optionally set `logErrors` to also write a structured warning per errored response. The policy reads up to `maxScanBytes` of the body (128 KiB by default, 5 MiB maximum), scanning it for the `errors` token; a response larger than that is treated as error-free. When the token is found and the body fits, it is parsed and its errors reported.\n\nThe response always passes through unchanged — the body is read from a clone, and any internal failure is swallowed so reporting can never break the request. The route must be marked `x-graphql: true` in `routes.oas.json` (which enables GraphQL analytics for the route); without the marker the policy logs a warning and does nothing.",
15
15
  "deprecatedMessage": "",
16
16
  "required": ["handler"],
17
17
  "properties": {
@@ -64,12 +64,13 @@
64
64
  "default": false,
65
65
  "description": "When `true`, also write a structured warning to the request log (message, `extensions.code`, and path of each error — capped at the first 10) whenever a response contains GraphQL errors."
66
66
  },
67
- "maxResponseBytes": {
67
+ "maxScanBytes": {
68
68
  "type": "integer",
69
69
  "minimum": 1,
70
- "default": 5242880,
70
+ "maximum": 5242880,
71
+ "default": 131072,
71
72
  "x-show-example": false,
72
- "description": "Maximum response body size in bytes the policy will inspect. Larger bodies — by `Content-Length`, or measured while reading when the header is absent — pass through without being scanned, so their GraphQL errors (if any) go unreported. The default is 5 MiB."
73
+ "description": "How many bytes of the response body the policy reads to look for GraphQL errors. The body is read and scanned for the `errors` token up to this limit; a body larger than the limit — by `Content-Length`, or measured while reading when the header is absent — is treated as error-free, so any errors it carries go unreported. The default of 128 KiB suits the common case, where servers emit `errors` near the front of the body. Raise it (up to the 5 MiB maximum) to detect errors in larger responses, at the cost of reading more of every response. When the token is found and the body fits within the limit, the body is parsed and its errors are reported."
73
74
  }
74
75
  }
75
76
  }
@@ -0,0 +1,137 @@
1
+ The GraphQL Cache policy stores successful GraphQL query responses in a
2
+ [ZoneCache](https://zuplo.com/docs/articles/zonecache) and serves later,
3
+ identical queries directly from the edge.
4
+
5
+ ### How caching works
6
+
7
+ For every inbound request the policy:
8
+
9
+ 1. Reads the request body and parses it as GraphQL JSON
10
+ (`{ "query": "...", "variables": { ... }, "operationName": "..." }`).
11
+ 2. Parses the query and re-prints it, producing a canonical form that ignores
12
+ insignificant whitespace, field formatting, and fragment layout.
13
+ 3. Canonicalizes the `variables` by recursively sorting object keys.
14
+ 4. Hashes the normalized query, canonicalized variables, and `operationName`
15
+ (SHA-256) into a cache key. `operationName` is included because a document
16
+ with multiple operations returns a different response depending on which
17
+ operation the client selects.
18
+
19
+ On a **hit**, the cached response is returned immediately. On a **miss**, the
20
+ request is forwarded to the origin and a successful response is stored for
21
+ future requests.
22
+
23
+ Every response served or stored by the policy carries two headers:
24
+
25
+ - **`x-cache`** — `HIT` when served from cache, `MISS` when fetched from the
26
+ origin.
27
+ - **`x-cache-key`** — the first 8 characters of the cache key, useful for
28
+ confirming that two requests resolve to the same entry.
29
+
30
+ Both headers are added to `access-control-expose-headers` so browsers can read
31
+ them, without overwriting any value an upstream CORS policy already set.
32
+
33
+ ### What is and isn't cached
34
+
35
+ - Only `query` operations are cached. **Mutations** and **subscriptions** are
36
+ forwarded to the origin and never cached. In a multi-operation document the
37
+ operation selected by `operationName` is the one that decides this.
38
+ - **Malformed** GraphQL and **non-JSON** bodies are forwarded untouched so the
39
+ origin can return a proper error. Documents with multiple operations but no
40
+ `operationName` (or an `operationName` that matches none) are also forwarded.
41
+ - Only `200` responses are cached, and only when the body is a successful
42
+ GraphQL result. Because GraphQL returns execution errors with a `200` status
43
+ and an `errors` array, responses carrying a non-empty `errors` array — and
44
+ non-JSON `200` bodies — are **not** cached.
45
+
46
+ ### Options
47
+
48
+ - **`cacheName`** - The name of the cache used to store responses. Defaults to
49
+ `graphql-responses`. Routes that share a name share a cache; use distinct
50
+ names to isolate caches per route or per upstream.
51
+ - **`ttlSeconds`** - How long, in seconds, a cached response is served before it
52
+ is considered stale and the next request is forwarded to the origin to refresh
53
+ the entry. Defaults to `60`.
54
+ - **`cacheKeyHeaders`** - Request header names whose values are included in the
55
+ cache key (matched case-insensitively), and the control for how credentialed
56
+ requests are cached. See
57
+ [Authentication and per-user caching](#authentication-and-per-user-caching)
58
+ below. Defaults to omitted.
59
+
60
+ ### Authentication and per-user caching
61
+
62
+ A response cache keyed only on the query would serve the first user's response
63
+ to everyone. To prevent that, the policy **does not cache requests that carry an
64
+ `authorization` or `cookie` header** by default — those requests are forwarded
65
+ to the origin every time.
66
+
67
+ To cache authenticated traffic safely, list the headers that make a response
68
+ user-specific in `cacheKeyHeaders`. Each listed header's value becomes part of
69
+ the cache key, so every distinct value (for example, every bearer token) gets
70
+ its own cache entry:
71
+
72
+ ```json
73
+ {
74
+ "name": "graphql-cache",
75
+ "policyType": "graphql-cache-inbound",
76
+ "handler": {
77
+ "export": "GraphQLCacheInboundPolicy",
78
+ "module": "$import(@zuplo/graphql)",
79
+ "options": {
80
+ "ttlSeconds": 30,
81
+ "cacheKeyHeaders": ["authorization"]
82
+ }
83
+ }
84
+ }
85
+ ```
86
+
87
+ If a request still carries an `authorization` or `cookie` header that is **not**
88
+ in `cacheKeyHeaders`, it is left uncached — so partially configuring the
89
+ allowlist fails safe rather than leaking across users.
90
+
91
+ #### Caching credentialed requests as a single shared entry
92
+
93
+ Sometimes a request must carry `authorization` (or `cookie`) to be authorized,
94
+ but the response is identical for everyone allowed through — the credential
95
+ gates access without changing the data. In that case, set `cacheKeyHeaders` to
96
+ an **empty array** to cache one response and share it across all callers:
97
+
98
+ ```json
99
+ {
100
+ "name": "graphql-cache",
101
+ "policyType": "graphql-cache-inbound",
102
+ "handler": {
103
+ "export": "GraphQLCacheInboundPolicy",
104
+ "module": "$import(@zuplo/graphql)",
105
+ "options": {
106
+ "cacheKeyHeaders": []
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ This is distinct from omitting the option: omitting it keeps the safe default
113
+ (credentialed requests are not cached), whereas `[]` is an explicit assertion
114
+ that the response does not depend on the caller. **Only use `[]` when that is
115
+ true** — otherwise one caller's response will be served to others.
116
+
117
+ Response cookies are never shared. `Set-Cookie` (along with `Set-Cookie2` and
118
+ `Clear-Site-Data`) is stripped from the stored entry, so a cookie an origin sets
119
+ on one caller's response is never replayed to another from cache. The caller
120
+ whose request reached the origin still receives the original `Set-Cookie`.
121
+
122
+ ### Example
123
+
124
+ ```json
125
+ {
126
+ "name": "graphql-cache",
127
+ "policyType": "graphql-cache-inbound",
128
+ "handler": {
129
+ "export": "GraphQLCacheInboundPolicy",
130
+ "module": "$import(@zuplo/graphql)",
131
+ "options": {
132
+ "cacheName": "graphql-responses",
133
+ "ttlSeconds": 60
134
+ }
135
+ }
136
+ }
137
+ ```
@@ -0,0 +1,15 @@
1
+ This policy caches GraphQL query responses at the edge so identical queries are
2
+ served without a round-trip to your origin.
3
+
4
+ Unlike CDN caching that keys on the raw request body, this policy parses each
5
+ GraphQL document and normalizes it before building a cache key. Insignificant
6
+ whitespace, field formatting, and fragment layout are collapsed, and variable
7
+ object keys are sorted. As a result, two requests that are semantically
8
+ identical share a cache entry even when their bodies differ byte-for-byte — and
9
+ there is no query size or nesting-depth limit.
10
+
11
+ Only `query` operations are cached. Mutations, subscriptions, malformed
12
+ documents, and non-GraphQL bodies are always forwarded to the origin untouched.
13
+ To avoid serving one user's data to another, requests carrying an
14
+ `authorization` or `cookie` header are not cached unless you opt in with the
15
+ `cacheKeyHeaders` option.
@@ -0,0 +1,74 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft-07/schema",
3
+ "$id": "https://cdn.zuplo.com/policies/graphql/schemas/graphql-cache-inbound.json",
4
+ "type": "object",
5
+ "title": "GraphQL Cache",
6
+ "isDeprecated": false,
7
+ "isPaidAddOn": false,
8
+ "isEnterprise": false,
9
+ "isInternal": false,
10
+ "isBeta": false,
11
+ "isHidden": false,
12
+ "requiresAI": false,
13
+ "products": ["api-gateway"],
14
+ "description": "Caches GraphQL query responses at the edge so identical queries are served without a round-trip to the origin.\n\nUnlike CDN caching that keys on the raw request body, this policy parses the GraphQL document and normalizes it before hashing: insignificant whitespace, field formatting, and fragment layout are collapsed, and variable object keys are sorted. Two requests that are semantically identical therefore share a cache entry even when their bodies differ byte-for-byte. There is no query size or nesting-depth limit.\n\nOnly `query` operations are cached. Mutations, subscriptions, malformed documents, and non-JSON bodies are forwarded to the origin untouched. Cache hits and misses are reported on the `x-cache` response header, with a short key fingerprint on `x-cache-key`.\n\nTo avoid serving one user's data to another, requests carrying an `authorization` or `cookie` header are not cached by default. Use `cacheKeyHeaders` to opt into caching them: each listed header's value is included in the cache key, so distinct credentials get distinct cache entries.",
15
+ "deprecatedMessage": "",
16
+ "required": ["handler"],
17
+ "properties": {
18
+ "handler": {
19
+ "type": "object",
20
+ "default": {},
21
+ "required": ["export", "module", "options"],
22
+ "properties": {
23
+ "export": {
24
+ "const": "GraphQLCacheInboundPolicy",
25
+ "description": "The name of the exported type"
26
+ },
27
+ "module": {
28
+ "const": "$import(@zuplo/graphql)",
29
+ "description": "The module containing the policy"
30
+ },
31
+ "options": {
32
+ "title": "GraphQLCacheInboundPolicyOptions",
33
+ "type": "object",
34
+ "description": "The options for this policy.",
35
+ "required": [],
36
+ "additionalProperties": false,
37
+ "properties": {
38
+ "cacheName": {
39
+ "type": "string",
40
+ "default": "graphql-responses",
41
+ "examples": ["graphql-responses"],
42
+ "description": "The name of the cache used to store responses. Routes that share a name share a cache; use distinct names to isolate caches per route or per upstream."
43
+ },
44
+ "ttlSeconds": {
45
+ "type": "number",
46
+ "default": 60,
47
+ "examples": [60],
48
+ "description": "How long, in seconds, a cached response is served before it is considered stale and the next request is forwarded to the origin to refresh the entry."
49
+ },
50
+ "cacheKeyHeaders": {
51
+ "type": "array",
52
+ "items": {
53
+ "type": "string"
54
+ },
55
+ "examples": [["authorization"]],
56
+ "description": "Request header names whose values are included in the cache key (matched case-insensitively), and the control for how credentialed requests are cached. Omit this option (the default) and requests carrying an `authorization` or `cookie` header are not cached, to avoid serving one user's response to another. List those headers to cache such requests keyed per value, so each distinct value gets its own entry (a credential header you don't list still blocks caching, so a partial list fails safe). Set it to an empty array `[]` to cache a single response shared across all callers — only do this when the response does not depend on who is calling, as it disables the per-user safety check."
57
+ }
58
+ }
59
+ }
60
+ },
61
+ "examples": [
62
+ {
63
+ "export": "GraphQLCacheInboundPolicy",
64
+ "module": "$import(@zuplo/graphql)",
65
+ "options": {
66
+ "cacheKeyHeaders": ["authorization"],
67
+ "cacheName": "graphql-responses",
68
+ "ttlSeconds": 60
69
+ }
70
+ }
71
+ ]
72
+ }
73
+ }
74
+ }