x402-surface-check 0.2.19 → 0.2.21

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
@@ -30,7 +30,9 @@ npx --yes x402-surface-check --endpoint --method POST --body '{"prompt":"price C
30
30
  - Testnet or staging rails such as Base Sepolia and Solana devnet
31
31
  - HTTPS resource URLs and stable resource metadata
32
32
  - 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
33
34
  - Grouped finding summaries for repeated route-wide issues, so large manifests keep the patch order readable
35
+ - Contextual reference guides for CORS, cache policy, Worker gates, resource echo, validation/auth ordering, and launch controls
34
36
  - Over-broad public method surfaces
35
37
  - Auth, validation, and free/trial responses that appear before a payment challenge, without piling on missing-field findings when no challenge was actually returned
36
38
  - Operational health/status endpoints, without treating expected free health checks as paid-route failures
@@ -701,6 +701,17 @@ function looksLikePlaceholderPayTo(payTo) {
701
701
  return false
702
702
  }
703
703
 
704
+ function cachePolicy(headers = {}) {
705
+ return headers['cache-control'] ?? headers.cacheControl ?? ''
706
+ }
707
+
708
+ function looksExplicitlyCacheable(headers = {}) {
709
+ const policy = cachePolicy(headers)
710
+ if (!policy) return false
711
+ if (/\b(no-store|private|no-cache)\b/i.test(policy)) return false
712
+ return /\b(public|s-maxage|max-age\s*=)\b/i.test(policy)
713
+ }
714
+
704
715
  function entryKey(entry) {
705
716
  return `${entry.method ?? 'POST'} ${entry.url}`
706
717
  }
@@ -781,6 +792,9 @@ function findingList(documentResult, challengeResults, preflightResults, entries
781
792
  if (!summary.resourceUrl || !summary.extraResource) {
782
793
  findings.push(`P2 - ${result.name} challenge does not repeat the resource URL in both resource.url and accepts[0].extra.resource/resource.`)
783
794
  }
795
+ if (looksExplicitlyCacheable(result.headers)) {
796
+ 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
+ }
784
798
  }
785
799
 
786
800
  for (const result of preflightResults) {
@@ -853,6 +867,29 @@ function groupedFindingSummary(findings) {
853
867
  .map(([label, count]) => `- ${count} endpoints: ${label}`)
854
868
  }
855
869
 
870
+ function referenceGuides(findings) {
871
+ const guides = []
872
+ const add = (label, url) => {
873
+ if (!guides.some(guide => guide.url === url)) guides.push({ label, url })
874
+ }
875
+ const text = findings.join('\n')
876
+ if (/CORS|402 challenge response does not allow the requesting origin|X-PAYMENT/i.test(text)) {
877
+ add('x402 CORS Fix', 'https://tateprograms.com/x402-cors-fix.html')
878
+ add('Cloudflare x402 Worker Starter', 'https://tateprograms.com/cloudflare-x402-worker.html')
879
+ }
880
+ if (/cacheable|Cache-Control|cache policy|shared caches/i.test(text)) {
881
+ add('Cloudflare x402 Worker Starter', 'https://tateprograms.com/cloudflare-x402-worker.html')
882
+ add('x402 Attack Map 2026', 'https://tateprograms.com/x402-attack-map-2026.html')
883
+ }
884
+ if (/validation HTTP \d+ before a payment challenge|auth HTTP \d+ before a payment challenge|replay|idempotency/i.test(text)) {
885
+ add('x402 Launch Checklist', 'https://tateprograms.com/x402-launch-checklist.html')
886
+ }
887
+ if (/resource URL|resource echo|accepts\[0\]\.extra\.resource/i.test(text)) {
888
+ add('x402 Surface Check notes', 'https://tateprograms.com/x402-surface-check.html')
889
+ }
890
+ return guides.map(guide => `- ${guide.label}: ${guide.url}`)
891
+ }
892
+
856
893
  function formatMarkdown(report) {
857
894
  const document = report.document.body.json ?? {}
858
895
  const challengeRows = report.challenges.map(result => {
@@ -862,7 +899,11 @@ function formatMarkdown(report) {
862
899
  const preflightRows = report.preflights.map(result => {
863
900
  return `| ${result.name} | ${result.method ?? 'POST'} | ${result.status} | ${result.headers['access-control-allow-origin'] ?? '-'} | ${result.headers['access-control-allow-headers'] ?? '-'} | ${result.headers['access-control-allow-methods'] ?? '-'} |`
864
901
  })
902
+ const cacheRows = report.challenges.map(result => {
903
+ return `| ${result.name} | ${result.method ?? 'POST'} | ${result.status} | ${cachePolicy(result.headers) || '-'} |`
904
+ })
865
905
  const findingSummary = groupedFindingSummary(report.findings)
906
+ const guides = referenceGuides(report.findings)
866
907
 
867
908
  return [
868
909
  '# x402 Public Surface Check',
@@ -896,6 +937,12 @@ function formatMarkdown(report) {
896
937
  '| --- | --- | --- | --- | --- | --- |',
897
938
  ...(preflightRows.length ? preflightRows : ['| - | - | - | - | - | - |']),
898
939
  '',
940
+ '## Cache Policy Map',
941
+ '',
942
+ '| Endpoint | Method | HTTP | Cache-Control |',
943
+ '| --- | --- | --- | --- |',
944
+ ...(cacheRows.length ? cacheRows : ['| - | - | - | - |']),
945
+ '',
899
946
  ...(findingSummary.length ? [
900
947
  '## Finding Summary',
901
948
  '',
@@ -906,6 +953,12 @@ function formatMarkdown(report) {
906
953
  '',
907
954
  ...(report.findings.length ? report.findings.map(item => `- ${item}`) : ['- No obvious launch-readiness findings from the public no-payment probes.']),
908
955
  '',
956
+ ...(guides.length ? [
957
+ '## Reference Guides',
958
+ '',
959
+ ...guides,
960
+ '',
961
+ ] : []),
909
962
  ].join('\n')
910
963
  }
911
964
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-surface-check",
3
- "version": "0.2.19",
3
+ "version": "0.2.21",
4
4
  "description": "No-payment x402 public-surface checker for manifests, OpenAPI specs, and HTTP 402 challenges.",
5
5
  "type": "module",
6
6
  "bin": {