x402-surface-check 0.2.38 → 0.2.40

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
@@ -20,7 +20,7 @@ npx --yes x402-surface-check --strict-proof https://api.example.com/openapi.json
20
20
 
21
21
  ## What It Checks
22
22
 
23
- - Manifest endpoint discovery from `items[]`, `endpoints[]`, object-valued `endpoints`, string-valued endpoint maps, `tools` maps, `resources[]`, `x402Endpoints`, category arrays, raw resource URL strings, method-prefixed resource strings, and OpenAPI paths
23
+ - Manifest endpoint discovery from `items[]`, `endpoints[]`, marketplace `skills[]` / `catalog.skills[]`, `agents[].tools[]` resource URLs, object-valued `endpoints`, string-valued endpoint maps, `tools` maps, `resources[]`, `x402Endpoints`, category arrays, raw resource URL strings, method-prefixed resource strings, and OpenAPI paths
24
24
  - Streamable HTTP MCP tool catalogs via safe JSON-RPC `tools/list` probes with `Accept: application/json, text/event-stream`
25
25
  - Object-valued manifest endpoint query examples, public catalog/discovery GETs, and payment-bearing two-phase operations without treating expected public catalog reads as failed payment gates
26
26
  - Linked discovery documents via `discovery_url`, `discoveryUrl`, `resources_url`, `resourcesUrl`, string `discovery` links, nested `discovery.x402_json` / OpenAPI links, or manifest-level OpenAPI links
@@ -358,6 +358,40 @@ function manifestEndpointBody(endpoint, document) {
358
358
  return exampleValue(body, document)
359
359
  }
360
360
 
361
+ function marketplaceSkillBody(skill) {
362
+ return skill?.example?.input
363
+ ?? skill?.exampleInput
364
+ ?? skill?.input?.example
365
+ ?? skill?.input?.safe_example
366
+ ?? skill?.input?.safeExample
367
+ ?? manifestEndpointBody(skill, {})
368
+ }
369
+
370
+ function marketplaceSkillPriceUsd(skill) {
371
+ const value = skill?.price?.amount
372
+ ?? skill?.price?.usd
373
+ ?? skill?.priceUsd
374
+ ?? skill?.price_usd
375
+ ?? skill?.pricePerCall
376
+ return numberFromDecimal(value)
377
+ }
378
+
379
+ function endpointRawPath(endpoint) {
380
+ if (!endpoint || typeof endpoint !== 'object') return undefined
381
+ const values = [
382
+ endpoint.url,
383
+ endpoint.endpoint,
384
+ endpoint.resourceUrl,
385
+ endpoint.resourceURL,
386
+ endpoint.resource_url,
387
+ endpoint.resource?.url,
388
+ endpoint.resource?.uri,
389
+ endpoint.resource,
390
+ endpoint.path,
391
+ ]
392
+ return values.find(value => typeof value === 'string' && value.trim())
393
+ }
394
+
361
395
  function manifestEndpointUrl(rawPath, endpoint, baseUrl, sourceUrl) {
362
396
  const url = new URL(endpointUrl(rawPath, baseUrl, sourceUrl))
363
397
  const parameters = endpoint?.parameters
@@ -404,9 +438,64 @@ function endpointEntries(document, sourceUrl, limit) {
404
438
  }
405
439
  }
406
440
 
441
+ const marketplaceSkillLists = [
442
+ document.skills,
443
+ document.services,
444
+ document.catalog?.skills,
445
+ document.catalog?.services,
446
+ ].filter(Array.isArray)
447
+
448
+ for (const skillList of marketplaceSkillLists) {
449
+ for (const skill of skillList) {
450
+ if (!skill || typeof skill !== 'object') continue
451
+ const rawPath = endpointRawPath(skill)
452
+ if (!rawPath) continue
453
+ if (redactedCredentialUrl(rawPath)) continue
454
+ entries.push({
455
+ name: skill.slug ?? skill.id ?? skill.name ?? String(rawPath).split('/').filter(Boolean).at(-1) ?? String(rawPath),
456
+ url: endpointUrl(rawPath, baseUrl, sourceUrl),
457
+ method: String(skill.method ?? 'POST').toUpperCase(),
458
+ expectedPriceUsd: marketplaceSkillPriceUsd(skill),
459
+ requestBody: marketplaceSkillBody(skill),
460
+ })
461
+ }
462
+ }
463
+
464
+ const agentCatalogLists = [
465
+ document.agents,
466
+ document.catalog?.agents,
467
+ document.marketplace?.agents,
468
+ ].filter(Array.isArray)
469
+
470
+ for (const agentList of agentCatalogLists) {
471
+ for (const agent of agentList) {
472
+ if (!agent || typeof agent !== 'object' || !Array.isArray(agent.tools)) continue
473
+ const agentName = agent.agentId ?? agent.agent_id ?? agent.slug ?? agent.id ?? agent.name
474
+ for (const tool of agent.tools) {
475
+ if (!tool || typeof tool !== 'object') continue
476
+ const rawPath = endpointRawPath(tool)
477
+ if (!rawPath) continue
478
+ if (redactedCredentialUrl(rawPath)) continue
479
+ const method = String(tool.method ?? 'POST').toUpperCase()
480
+ const paymentSignal = Math.max(manifestEndpointPaymentSignal(agent), manifestEndpointPaymentSignal(tool))
481
+ const hasPathParameters = /\{[^}]+\}/.test(String(rawPath))
482
+ if (paymentSignal === 0 && (method !== 'GET' || hasPathParameters)) continue
483
+ const toolName = tool.slug ?? tool.id ?? tool.name ?? String(rawPath).split('/').filter(Boolean).at(-1)
484
+ entries.push({
485
+ name: agentName && toolName ? `${agentName}/${toolName}` : toolName ?? agentName ?? String(rawPath),
486
+ url: manifestEndpointUrl(rawPath, tool, baseUrl, sourceUrl),
487
+ method,
488
+ expectedPriceUsd: marketplaceSkillPriceUsd(tool) ?? marketplaceSkillPriceUsd(agent),
489
+ requestBody: marketplaceSkillBody(tool) ?? marketplaceSkillBody(agent),
490
+ publicDiscovery: paymentSignal === 0,
491
+ })
492
+ }
493
+ }
494
+ }
495
+
407
496
  if (Array.isArray(document.endpoints)) {
408
497
  for (const endpoint of document.endpoints) {
409
- const rawPath = endpoint?.url ?? endpoint?.endpoint ?? endpoint?.path
498
+ const rawPath = endpointRawPath(endpoint)
410
499
  if (!rawPath) continue
411
500
  entries.push({
412
501
  name: endpoint.id ?? endpoint.name ?? String(rawPath).split('/').filter(Boolean).at(-1) ?? String(rawPath),
@@ -446,7 +535,7 @@ function endpointEntries(document, sourceUrl, limit) {
446
535
  if (Array.isArray(document.tools)) {
447
536
  for (const tool of document.tools) {
448
537
  if (!tool || typeof tool !== 'object') continue
449
- const rawPath = tool.url ?? tool.endpoint ?? tool.path
538
+ const rawPath = endpointRawPath(tool)
450
539
  if (!rawPath) continue
451
540
  const method = String(tool.method ?? 'POST').toUpperCase()
452
541
  const paymentSignal = manifestEndpointPaymentSignal(tool)
@@ -475,7 +564,7 @@ function endpointEntries(document, sourceUrl, limit) {
475
564
  }
476
565
  if (!endpoint || typeof endpoint !== 'object') continue
477
566
  const keyPath = key.match(/^(GET|POST|PUT|PATCH|DELETE)\s+(\S+)/i)?.[2] ?? key
478
- const rawPath = endpoint.url ?? endpoint.endpoint ?? endpoint.path ?? keyPath
567
+ const rawPath = endpointRawPath(endpoint) ?? keyPath
479
568
  if (!rawPath) continue
480
569
  const method = String(endpoint.method ?? 'POST').toUpperCase()
481
570
  const paymentSignal = manifestEndpointPaymentSignal(endpoint)
@@ -494,7 +583,7 @@ function endpointEntries(document, sourceUrl, limit) {
494
583
  if (Array.isArray(document.items)) {
495
584
  for (const item of document.items) {
496
585
  if (item?.type && item.type !== 'http') continue
497
- const rawPath = item?.resource ?? item?.url ?? item?.endpoint ?? item?.path
586
+ const rawPath = endpointRawPath(item)
498
587
  if (!rawPath) continue
499
588
  entries.push({
500
589
  name: item.metadata?.name ?? item.id ?? item.name ?? String(rawPath).split('/').filter(Boolean).at(-1) ?? String(rawPath),
@@ -547,7 +636,7 @@ function endpointEntries(document, sourceUrl, limit) {
547
636
  }
548
637
 
549
638
  if (!resource || typeof resource !== 'object') continue
550
- const rawPath = resource.url ?? resource.endpoint ?? resource.resource ?? resource.path
639
+ const rawPath = endpointRawPath(resource)
551
640
  if (!rawPath) continue
552
641
  entries.push({
553
642
  name: resource.id
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-surface-check",
3
- "version": "0.2.38",
3
+ "version": "0.2.40",
4
4
  "description": "No-payment x402 public-surface checker for manifests, OpenAPI specs, and HTTP 402 challenges.",
5
5
  "type": "module",
6
6
  "bin": {