x402-surface-check 0.2.21 → 0.2.22

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 CHANGED
@@ -11,6 +11,7 @@ npx --yes x402-surface-check https://api.example.com/.well-known/x402
11
11
  npx --yes x402-surface-check https://api.example.com/openapi.json report.md
12
12
  npx --yes x402-surface-check --endpoint --method POST https://x402.rpc.ankr.com/eth
13
13
  npx --yes x402-surface-check --endpoint --method POST --body '{"prompt":"price CPI"}' https://api.example.com/paid-post
14
+ npx --yes x402-surface-check --strict-cache https://api.example.com/openapi.json
14
15
  ```
15
16
 
16
17
  ## What It Checks
@@ -30,7 +31,7 @@ npx --yes x402-surface-check --endpoint --method POST --body '{"prompt":"price C
30
31
  - Testnet or staging rails such as Base Sepolia and Solana devnet
31
32
  - HTTPS resource URLs and stable resource metadata
32
33
  - Browser CORS allowance for the requesting origin and `X-PAYMENT`, including the actual 402 challenge response
33
- - Cache-Control posture on no-payment challenge responses, with warnings for explicitly cacheable payment gates
34
+ - Cache-Control posture on no-payment challenge responses, with warnings for explicitly cacheable payment gates and optional strict-cache findings for missing policy headers
34
35
  - Grouped finding summaries for repeated route-wide issues, so large manifests keep the patch order readable
35
36
  - Contextual reference guides for CORS, cache policy, Worker gates, resource echo, validation/auth ordering, and launch controls
36
37
  - Over-broad public method surfaces
@@ -66,6 +67,7 @@ x402-surface-check --endpoint --method POST <paid-endpoint-url> [output.md]
66
67
  --body-file <p> Read JSON request body for direct endpoint mode from a file
67
68
  --origin <url> Origin to use for browser-style CORS preflight
68
69
  --limit <n> Maximum endpoints to probe, default 6
70
+ --strict-cache Flag missing Cache-Control on no-payment 402 responses
69
71
  --json Print JSON instead of Markdown
70
72
  --help Show usage
71
73
  --version Show package version
@@ -76,6 +78,7 @@ Environment variables are also supported:
76
78
  ```bash
77
79
  X402_CHECK_ORIGIN=https://example.com x402-surface-check https://api.example.com/openapi.json
78
80
  X402_CHECK_LIMIT=12 x402-surface-check https://api.example.com/.well-known/x402
81
+ X402_STRICT_CACHE=1 x402-surface-check https://api.example.com/.well-known/x402
79
82
  ```
80
83
 
81
84
  ## Scope
@@ -22,6 +22,7 @@ Options:
22
22
  --body-file <p> Read JSON request body for direct endpoint mode from a file
23
23
  --origin <url> Origin to use for browser-style CORS preflight
24
24
  --limit <n> Maximum endpoints to probe, default ${defaultLimit}
25
+ --strict-cache Flag missing Cache-Control on no-payment 402 responses
25
26
  --json Print JSON instead of Markdown
26
27
  --help Show this help
27
28
  --version Show package version
@@ -38,6 +39,7 @@ function parseArgs(argv) {
38
39
  body: process.env.X402_CHECK_BODY,
39
40
  bodyFile: process.env.X402_CHECK_BODY_FILE,
40
41
  outputPath: '',
42
+ strictCache: process.env.X402_STRICT_CACHE === '1',
41
43
  url: '',
42
44
  }
43
45
 
@@ -55,6 +57,9 @@ function parseArgs(argv) {
55
57
  else if (arg === '--endpoint') {
56
58
  args.endpoint = true
57
59
  }
60
+ else if (arg === '--strict-cache') {
61
+ args.strictCache = true
62
+ }
58
63
  else if (arg === '--method') {
59
64
  args.method = String(argv[index + 1] ?? '').toUpperCase()
60
65
  index += 1
@@ -721,7 +726,7 @@ function looksLikeOperationalHealthEndpoint(result) {
721
726
  return /(^|[/_\s-])(health|healthz|ready|readiness|live|liveness|status)([/_\s-]|$)/.test(value)
722
727
  }
723
728
 
724
- function findingList(documentResult, challengeResults, preflightResults, entries) {
729
+ function findingList(documentResult, challengeResults, preflightResults, entries, options = {}) {
725
730
  const document = documentResult.body.json ?? {}
726
731
  const findings = []
727
732
  const networks = valueList(document.networks)
@@ -795,6 +800,9 @@ function findingList(documentResult, challengeResults, preflightResults, entries
795
800
  if (looksExplicitlyCacheable(result.headers)) {
796
801
  findings.push(`P2 - ${result.name} payment challenge response is explicitly cacheable (${cachePolicy(result.headers)}); paid routes should use no-store/private cache policy or bypass shared caches.`)
797
802
  }
803
+ else if (options.strictCache && !cachePolicy(result.headers)) {
804
+ findings.push(`P3 - ${result.name} payment challenge response did not expose Cache-Control; for payment-gated routes, document or send no-store/private cache policy and confirm paid 200 responses are never shared-cacheable.`)
805
+ }
798
806
  }
799
807
 
800
808
  for (const result of preflightResults) {
@@ -853,6 +861,9 @@ function groupedFindingLabel(finding) {
853
861
  if (/challenge advertises placeholder-looking payTo/.test(finding)) {
854
862
  return 'P1 - Challenges advertise placeholder-looking payTo recipients.'
855
863
  }
864
+ if (/payment challenge response did not expose Cache-Control/.test(finding)) {
865
+ return 'P3 - Payment challenge responses do not expose Cache-Control in strict cache mode.'
866
+ }
856
867
  return null
857
868
  }
858
869
 
@@ -1013,7 +1024,9 @@ async function runCheck(options) {
1013
1024
  preflights,
1014
1025
  sourceDocument,
1015
1026
  }
1016
- report.findings = findingList(document, challenges, preflights, entries)
1027
+ report.findings = findingList(document, challenges, preflights, entries, {
1028
+ strictCache: options.strictCache,
1029
+ })
1017
1030
  return report
1018
1031
  }
1019
1032
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-surface-check",
3
- "version": "0.2.21",
3
+ "version": "0.2.22",
4
4
  "description": "No-payment x402 public-surface checker for manifests, OpenAPI specs, and HTTP 402 challenges.",
5
5
  "type": "module",
6
6
  "bin": {