x402-surface-check 0.2.13 → 0.2.14

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
@@ -14,7 +14,7 @@ npx --yes x402-surface-check --endpoint --method POST https://x402.rpc.ankr.com/
14
14
 
15
15
  ## What It Checks
16
16
 
17
- - Manifest endpoint discovery from `items[]`, `endpoints[]`, `x402Endpoints`, category arrays, resource strings, and OpenAPI paths
17
+ - Manifest endpoint discovery from `items[]`, `endpoints[]`, `resources[]`, `x402Endpoints`, category arrays, resource strings, and OpenAPI paths
18
18
  - Linked discovery documents via `discovery_url`, `discoveryUrl`, `resources_url`, `resourcesUrl`, or manifest-level OpenAPI links
19
19
  - OpenAPI query/path examples and JSON request-body examples for safer no-payment probes
20
20
  - No-payment HTTP 402 challenge shape
@@ -26,7 +26,7 @@ npx --yes x402-surface-check --endpoint --method POST https://x402.rpc.ankr.com/
26
26
  - Placeholder recipients such as zero addresses and Solana system-program values
27
27
  - Testnet or staging rails such as Base Sepolia and Solana devnet
28
28
  - HTTPS resource URLs and stable resource metadata
29
- - Browser CORS allowance for `X-PAYMENT`
29
+ - Browser CORS allowance for the requesting origin and `X-PAYMENT`
30
30
  - Over-broad public method surfaces
31
31
  - Auth, validation, and free/trial responses that appear before a payment challenge, without piling on missing-field findings when no challenge was actually returned
32
32
  - Operational health/status endpoints, without treating expected free health checks as paid-route failures
@@ -44,6 +44,7 @@ Recent public no-payment checks have found and verified real launch fixes:
44
44
  - anchor-x402: multi-rail x402 challenges verified, with browser preflight blockers isolated before merge. https://github.com/solana-foundation/pay-skills/pull/47#issuecomment-4455678163
45
45
  - Agent Trust Bench: linked discovery URL and browser-compatibility notes verified clean for adversarial agent-payment resources. https://github.com/solana-foundation/pay-skills/pull/23#issuecomment-4455722170
46
46
  - Solrouter: private LLM inference route verified with HTTPS resource-binding and price-alignment notes. https://github.com/solana-foundation/pay-skills/pull/39#issuecomment-4455800060
47
+ - Tetrac: Solana market-data payment gates verified, with browser payment-header preflight blocker isolated. https://github.com/solana-foundation/pay-skills/pull/32#issuecomment-4455923744
47
48
 
48
49
  Field notes and browser version: https://tateprograms.com/x402-surface-check.html
49
50
 
@@ -294,17 +294,32 @@ function endpointEntries(document, sourceUrl, limit) {
294
294
  }
295
295
 
296
296
  for (const resource of document.resources ?? []) {
297
- if (typeof resource !== 'string') continue
298
- const match = resource.match(/^(GET|POST|PUT|PATCH|DELETE)\s+(\S+)/i)
299
- if (!match) continue
300
- const [, method, rawPath] = match
301
- const url = rawPath.startsWith('http')
302
- ? rawPath
303
- : new URL(rawPath, document.baseUrl ?? sourceUrl).toString()
297
+ if (typeof resource === 'string') {
298
+ const match = resource.match(/^(GET|POST|PUT|PATCH|DELETE)\s+(\S+)/i)
299
+ if (!match) continue
300
+ const [, method, rawPath] = match
301
+ const url = rawPath.startsWith('http')
302
+ ? rawPath
303
+ : new URL(rawPath, document.baseUrl ?? sourceUrl).toString()
304
+ entries.push({
305
+ name: rawPath.split('/').filter(Boolean).at(-1) ?? rawPath,
306
+ url,
307
+ method: method.toUpperCase(),
308
+ })
309
+ continue
310
+ }
311
+
312
+ if (!resource || typeof resource !== 'object') continue
313
+ const rawPath = resource.url ?? resource.endpoint ?? resource.resource ?? resource.path
314
+ if (!rawPath) continue
304
315
  entries.push({
305
- name: rawPath.split('/').filter(Boolean).at(-1) ?? rawPath,
306
- url,
307
- method: method.toUpperCase(),
316
+ name: resource.id
317
+ ?? resource.name
318
+ ?? resource.title
319
+ ?? String(resource.path ?? rawPath).split('/').filter(Boolean).at(-1)
320
+ ?? String(rawPath),
321
+ url: endpointUrl(rawPath, baseUrl, sourceUrl),
322
+ method: String(resource.method ?? 'GET').toUpperCase(),
308
323
  })
309
324
  }
310
325
 
@@ -669,6 +684,10 @@ function findingList(documentResult, challengeResults, preflightResults, entries
669
684
  for (const result of preflightResults) {
670
685
  const challengeResult = challengesByEntry.get(entryKey(result))
671
686
  if (!challengeResult || !hasPaymentChallenge(challengeResult)) continue
687
+ const allowedOrigin = result.headers['access-control-allow-origin'] ?? ''
688
+ if (!allowedOrigin) {
689
+ findings.push(`P1 - ${result.name} CORS preflight does not allow the requesting origin; observed allow-origin: none.`)
690
+ }
672
691
  const allowed = result.headers['access-control-allow-headers'] ?? ''
673
692
  if (allowed !== '*' && !/x-payment/i.test(allowed)) {
674
693
  const observed = result.status >= 400
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-surface-check",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
4
4
  "description": "No-payment x402 public-surface checker for manifests, OpenAPI specs, and HTTP 402 challenges.",
5
5
  "type": "module",
6
6
  "bin": {