You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@x402/extensions

Package Overview
Dependencies
Maintainers
2
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@x402/extensions - npm Package Compare versions

Comparing version
2.3.1
to
2.4.0
+662
dist/cjs/index-G8RNfr6X.d.ts
import { FacilitatorExtension, ResourceServerExtension, PaymentPayload, PaymentRequirements, PaymentRequirementsV1 } from '@x402/core/types';
import { BodyMethods, QueryParamMethods, HTTPFacilitatorClient } from '@x402/core/http';
/**
* Shared type utilities for x402 extensions
*/
/**
* Type utility to merge extensions properly when chaining.
* If T already has extensions, merge them; otherwise add new extensions.
*
* @example
* ```ts
* // Chaining multiple extensions preserves all types:
* const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient()));
* // Type: HTTPFacilitatorClient & { extensions: OtherExtension & BazaarExtension }
* ```
*/
type WithExtensions<T, E> = T extends {
extensions: infer Existing;
} ? Omit<T, "extensions"> & {
extensions: Existing & E;
} : T & {
extensions: E;
};
/**
* HTTP-specific type definitions for the Bazaar Discovery Extension
*/
/**
* Discovery info for query parameter methods (GET, HEAD, DELETE)
*/
interface QueryDiscoveryInfo {
input: {
type: "http";
/** Absent at declaration time; set by bazaarResourceServerExtension.enrichDeclaration */
method?: QueryParamMethods;
queryParams?: Record<string, unknown>;
headers?: Record<string, string>;
};
output?: {
type?: string;
format?: string;
example?: unknown;
};
}
/**
* Discovery info for body methods (POST, PUT, PATCH)
*/
interface BodyDiscoveryInfo {
input: {
type: "http";
/** Absent at declaration time; set by bazaarResourceServerExtension.enrichDeclaration */
method?: BodyMethods;
bodyType: "json" | "form-data" | "text";
body: Record<string, unknown>;
queryParams?: Record<string, unknown>;
headers?: Record<string, string>;
};
output?: {
type?: string;
format?: string;
example?: unknown;
};
}
/**
* Discovery extension for query parameter methods (GET, HEAD, DELETE)
*/
interface QueryDiscoveryExtension {
info: QueryDiscoveryInfo;
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema";
type: "object";
properties: {
input: {
type: "object";
properties: {
type: {
type: "string";
const: "http";
};
method: {
type: "string";
enum: QueryParamMethods[];
};
queryParams?: {
type: "object";
properties?: Record<string, unknown>;
required?: string[];
additionalProperties?: boolean;
};
headers?: {
type: "object";
additionalProperties: {
type: "string";
};
};
};
required: ("type" | "method")[];
additionalProperties?: boolean;
};
output?: {
type: "object";
properties?: Record<string, unknown>;
required?: readonly string[];
additionalProperties?: boolean;
};
};
required: ["input"];
};
}
/**
* Discovery extension for body methods (POST, PUT, PATCH)
*/
interface BodyDiscoveryExtension {
info: BodyDiscoveryInfo;
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema";
type: "object";
properties: {
input: {
type: "object";
properties: {
type: {
type: "string";
const: "http";
};
method: {
type: "string";
enum: BodyMethods[];
};
bodyType: {
type: "string";
enum: ["json", "form-data", "text"];
};
body: Record<string, unknown>;
queryParams?: {
type: "object";
properties?: Record<string, unknown>;
required?: string[];
additionalProperties?: boolean;
};
headers?: {
type: "object";
additionalProperties: {
type: "string";
};
};
};
required: ("type" | "method" | "bodyType" | "body")[];
additionalProperties?: boolean;
};
output?: {
type: "object";
properties?: Record<string, unknown>;
required?: readonly string[];
additionalProperties?: boolean;
};
};
required: ["input"];
};
}
interface DeclareQueryDiscoveryExtensionConfig {
method?: QueryParamMethods;
input?: Record<string, unknown>;
inputSchema?: Record<string, unknown>;
output?: {
example?: unknown;
schema?: Record<string, unknown>;
};
}
interface DeclareBodyDiscoveryExtensionConfig {
method?: BodyMethods;
input?: Record<string, unknown>;
inputSchema?: Record<string, unknown>;
bodyType: "json" | "form-data" | "text";
output?: {
example?: unknown;
schema?: Record<string, unknown>;
};
}
interface DiscoveredHTTPResource {
resourceUrl: string;
description?: string;
mimeType?: string;
/** Present after server extension enrichment; may be absent for pre-enrichment data */
method?: string;
x402Version: number;
discoveryInfo: DiscoveryInfo;
}
declare const isQueryExtensionConfig: (config: DeclareQueryDiscoveryExtensionConfig | DeclareBodyDiscoveryExtensionConfig) => config is DeclareQueryDiscoveryExtensionConfig;
declare const isBodyExtensionConfig: (config: DeclareQueryDiscoveryExtensionConfig | DeclareBodyDiscoveryExtensionConfig) => config is DeclareBodyDiscoveryExtensionConfig;
/**
* MCP-specific type definitions for the Bazaar Discovery Extension
*/
/**
* Discovery info for MCP tools
*/
interface McpDiscoveryInfo {
input: {
type: "mcp";
toolName: string;
description?: string;
transport?: "streamable-http" | "sse";
inputSchema: Record<string, unknown>;
example?: Record<string, unknown>;
};
output?: {
type?: string;
format?: string;
example?: unknown;
};
}
/**
* Discovery extension for MCP tools
*/
interface McpDiscoveryExtension {
info: McpDiscoveryInfo;
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema";
type: "object";
properties: {
input: {
type: "object";
properties: {
type: {
type: "string";
const: "mcp";
};
toolName: {
type: "string";
};
description?: {
type: "string";
};
transport?: {
type: "string";
enum: ["streamable-http", "sse"];
};
inputSchema: Record<string, unknown>;
example?: Record<string, unknown>;
};
required: ("type" | "toolName" | "inputSchema")[];
additionalProperties?: boolean;
};
output?: {
type: "object";
properties?: Record<string, unknown>;
required?: readonly string[];
additionalProperties?: boolean;
};
};
required: ["input"];
};
}
interface DeclareMcpDiscoveryExtensionConfig {
toolName: string;
description?: string;
transport?: "streamable-http" | "sse";
inputSchema: Record<string, unknown>;
example?: Record<string, unknown>;
output?: {
example?: unknown;
schema?: Record<string, unknown>;
};
}
interface DiscoveredMCPResource {
resourceUrl: string;
description?: string;
mimeType?: string;
toolName: string;
x402Version: number;
discoveryInfo: DiscoveryInfo;
}
declare const isMcpExtensionConfig: (config: DeclareMcpDiscoveryExtensionConfig | Record<string, unknown>) => config is DeclareMcpDiscoveryExtensionConfig;
/**
* Shared type definitions for the Bazaar Discovery Extension
*
* Protocol-specific types live in their own directories (http/, mcp/).
* This file defines the shared unions, constants, and utility types,
* and re-exports all protocol-specific types for backwards compatibility.
*/
/**
* Extension identifier for the Bazaar discovery extension.
*/
declare const BAZAAR: FacilitatorExtension;
/**
* Combined discovery info type
*/
type DiscoveryInfo = QueryDiscoveryInfo | BodyDiscoveryInfo | McpDiscoveryInfo;
/**
* Combined discovery extension type
*/
type DiscoveryExtension = QueryDiscoveryExtension | BodyDiscoveryExtension | McpDiscoveryExtension;
type DeclareDiscoveryExtensionConfig = DeclareQueryDiscoveryExtensionConfig | DeclareBodyDiscoveryExtensionConfig | DeclareMcpDiscoveryExtensionConfig;
/**
* Distributive Omit - properly distributes Omit over union types.
*
* Standard `Omit<A | B, K>` collapses to common properties only,
* losing discriminant properties like `bodyType`.
*
* This type uses conditional type distribution to preserve the union:
* `DistributiveOmit<A | B, K>` = `Omit<A, K> | Omit<B, K>`
*/
type DistributiveOmit<T, K extends keyof T> = T extends T ? Omit<T, K> : never;
/**
* Config type for declareDiscoveryExtension function.
* Uses DistributiveOmit to preserve bodyType discriminant in the union for HTTP configs.
* MCP config has no `method` field so it's included directly.
*/
type DeclareDiscoveryExtensionInput = DistributiveOmit<DeclareQueryDiscoveryExtensionConfig, "method"> | DistributiveOmit<DeclareBodyDiscoveryExtensionConfig, "method"> | DeclareMcpDiscoveryExtensionConfig;
/**
* Resource Service entry point for creating Bazaar discovery extensions
*
* This module provides the unified `declareDiscoveryExtension` function that
* routes to protocol-specific builders in http/ and mcp/.
*/
/**
* Create a discovery extension for any HTTP method or MCP tool
*
* This function helps servers declare how their endpoint should be called,
* including the expected input parameters/body and output format.
*
* @param config - Configuration object for the discovery extension
* @returns A discovery extension object with both info and schema
*
* @example
* ```typescript
* // For a GET endpoint with no input
* const getExtension = declareDiscoveryExtension({
* method: "GET",
* output: {
* example: { message: "Success", timestamp: "2024-01-01T00:00:00Z" }
* }
* });
*
* // For a GET endpoint with query params
* const getWithParams = declareDiscoveryExtension({
* method: "GET",
* input: { query: "example" },
* inputSchema: {
* properties: {
* query: { type: "string" }
* },
* required: ["query"]
* }
* });
*
* // For a POST endpoint with JSON body
* const postExtension = declareDiscoveryExtension({
* method: "POST",
* input: { name: "John", age: 30 },
* inputSchema: {
* properties: {
* name: { type: "string" },
* age: { type: "number" }
* },
* required: ["name"]
* },
* bodyType: "json",
* output: {
* example: { success: true, id: "123" }
* }
* });
*
* // For an MCP tool
* const mcpExtension = declareDiscoveryExtension({
* toolName: "financial_analysis",
* description: "Analyze financial data for a given ticker",
* inputSchema: {
* type: "object",
* properties: {
* ticker: { type: "string" },
* },
* required: ["ticker"],
* },
* output: {
* example: { pe_ratio: 28.5, recommendation: "hold" }
* }
* });
* ```
*/
declare function declareDiscoveryExtension(config: DeclareDiscoveryExtensionInput): Record<string, DiscoveryExtension>;
declare const bazaarResourceServerExtension: ResourceServerExtension;
/**
* Facilitator functions for validating and extracting Bazaar discovery extensions
*
* These functions help facilitators validate extension data against schemas
* and extract the discovery information for cataloging in the Bazaar.
*
* Supports both v2 (extensions in PaymentRequired) and v1 (outputSchema in PaymentRequirements).
*/
/**
* Validation result for discovery extensions
*/
interface ValidationResult {
valid: boolean;
errors?: string[];
}
/**
* Validates a discovery extension's info against its schema
*
* @param extension - The discovery extension containing info and schema
* @returns Validation result indicating if the info matches the schema
*
* @example
* ```typescript
* const extension = declareDiscoveryExtension(...);
* const result = validateDiscoveryExtension(extension);
*
* if (result.valid) {
* console.log("Extension is valid");
* } else {
* console.error("Validation errors:", result.errors);
* }
* ```
*/
declare function validateDiscoveryExtension(extension: DiscoveryExtension): ValidationResult;
type DiscoveredResource = DiscoveredHTTPResource | DiscoveredMCPResource;
/**
* Extracts discovery information from payment payload and requirements.
* Combines resource URL, HTTP method, version, and discovery info into a single object.
*
* @param paymentPayload - The payment payload containing extensions and resource info
* @param paymentRequirements - The payment requirements to validate against
* @param validate - Whether to validate the discovery info against the schema (default: true)
* @returns Discovered resource info with URL, method, version and discovery data, or null if not found
*/
declare function extractDiscoveryInfo(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements | PaymentRequirementsV1, validate?: boolean): DiscoveredResource | null;
/**
* Extracts discovery info from a v2 extension directly
*
* This is a lower-level function for when you already have the extension object.
* For general use, prefer the main extractDiscoveryInfo function.
*
* @param extension - The discovery extension to extract info from
* @param validate - Whether to validate before extracting (default: true)
* @returns The discovery info if valid
* @throws Error if validation fails and validate is true
*/
declare function extractDiscoveryInfoFromExtension(extension: DiscoveryExtension, validate?: boolean): DiscoveryInfo;
/**
* Validates and extracts discovery info in one step
*
* This is a convenience function that combines validation and extraction,
* returning both the validation result and the info if valid.
*
* @param extension - The discovery extension to validate and extract
* @returns Object containing validation result and info (if valid)
*
* @example
* ```typescript
* const extension = declareDiscoveryExtension(...);
* const { valid, info, errors } = validateAndExtract(extension);
*
* if (valid && info) {
* // Store info in Bazaar catalog
* } else {
* console.error("Validation errors:", errors);
* }
* ```
*/
declare function validateAndExtract(extension: DiscoveryExtension): {
valid: boolean;
info?: DiscoveryInfo;
errors?: string[];
};
/**
* V1 Facilitator functions for extracting Bazaar discovery information
*
* In v1, discovery information is stored in the `outputSchema` field
* of PaymentRequirements, which has a different structure than v2.
*
* This module transforms v1 data into v2 DiscoveryInfo format.
*/
/**
* Extracts discovery info from v1 PaymentRequirements and transforms to v2 format
*
* In v1, the discovery information is stored in the `outputSchema` field,
* which contains both input (endpoint shape) and output (response schema) information.
*
* This function makes smart assumptions to normalize v1 data into v2 DiscoveryInfo format:
* - For GET/HEAD/DELETE: Looks for queryParams, query, or params fields
* - For POST/PUT/PATCH: Looks for bodyFields, body, or data fields and normalizes bodyType
* - Extracts optional headers if present
*
* @param paymentRequirements - V1 payment requirements
* @returns Discovery info in v2 format if present and valid, or null if not discoverable
*
* @example
* ```typescript
* const requirements: PaymentRequirementsV1 = {
* scheme: "exact",
* network: "eip155:8453",
* maxAmountRequired: "100000",
* resource: "https://api.example.com/data",
* description: "Get data",
* mimeType: "application/json",
* outputSchema: {
* input: {
* type: "http",
* method: "GET",
* discoverable: true,
* queryParams: { query: "string" }
* },
* output: { type: "object" }
* },
* payTo: "0x...",
* maxTimeoutSeconds: 300,
* asset: "0x...",
* extra: {}
* };
*
* const info = extractDiscoveryInfoV1(requirements);
* if (info) {
* console.log("Endpoint method:", info.input.method);
* }
* ```
*/
declare function extractDiscoveryInfoV1(paymentRequirements: PaymentRequirementsV1): DiscoveryInfo | null;
/**
* Checks if v1 PaymentRequirements contains discoverable information
*
* @param paymentRequirements - V1 payment requirements
* @returns True if the requirements contain valid discovery info
*
* @example
* ```typescript
* if (isDiscoverableV1(requirements)) {
* const info = extractDiscoveryInfoV1(requirements);
* // Catalog info in Bazaar
* }
* ```
*/
declare function isDiscoverableV1(paymentRequirements: PaymentRequirementsV1): boolean;
/**
* Extracts resource metadata from v1 PaymentRequirements
*
* In v1, resource information is embedded directly in the payment requirements
* rather than in a separate resource object.
*
* @param paymentRequirements - V1 payment requirements
* @returns Resource metadata
*
* @example
* ```typescript
* const metadata = extractResourceMetadataV1(requirements);
* console.log("Resource URL:", metadata.url);
* console.log("Description:", metadata.description);
* ```
*/
declare function extractResourceMetadataV1(paymentRequirements: PaymentRequirementsV1): {
url: string;
description: string;
mimeType: string;
};
/**
* Client extensions for querying Bazaar discovery resources
*/
/**
* Parameters for listing discovery resources.
* All parameters are optional and used for filtering/pagination.
*/
interface ListDiscoveryResourcesParams {
/**
* Filter by protocol type (e.g., "http", "mcp").
*/
type?: string;
/**
* The number of discovered x402 resources to return per page.
*/
limit?: number;
/**
* The offset of the first discovered x402 resource to return.
*/
offset?: number;
}
/**
* A discovered x402 resource from the bazaar.
*/
interface DiscoveryResource {
/** The URL or identifier of the discovered resource */
resource: string;
/** The protocol type of the resource (e.g., "http") */
type: string;
/** The x402 protocol version supported by this resource */
x402Version: number;
/** Array of accepted payment methods for this resource */
accepts: PaymentRequirements[];
/** ISO 8601 timestamp of when the resource was last updated */
lastUpdated: string;
/** Additional metadata about the resource */
metadata?: Record<string, unknown>;
}
/**
* Response from listing discovery resources.
*/
interface DiscoveryResourcesResponse {
/** The x402 protocol version of this response */
x402Version: number;
/** The list of discovered resources */
items: DiscoveryResource[];
/** Pagination information for the response */
pagination: {
/** Maximum number of results returned */
limit: number;
/** Number of results skipped */
offset: number;
/** Total count of resources matching the query */
total: number;
};
}
/**
* Bazaar client extension interface providing discovery query functionality.
*/
interface BazaarClientExtension {
discovery: {
/**
* List x402 discovery resources from the bazaar.
*
* @param params - Optional filtering and pagination parameters
* @returns A promise resolving to the discovery resources response
*/
listResources(params?: ListDiscoveryResourcesParams): Promise<DiscoveryResourcesResponse>;
};
}
/**
* Extends a facilitator client with Bazaar discovery query functionality.
* Preserves and merges with any existing extensions from prior chaining.
*
* @param client - The facilitator client to extend
* @returns The client extended with bazaar discovery capabilities
*
* @example
* ```ts
* // Basic usage
* const client = withBazaar(new HTTPFacilitatorClient());
* const resources = await client.extensions.discovery.listResources({ type: "http" });
*
* // Chaining with other extensions
* const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient()));
* await client.extensions.other.someMethod();
* await client.extensions.discovery.listResources();
* ```
*/
declare function withBazaar<T extends HTTPFacilitatorClient>(client: T): WithExtensions<T, BazaarClientExtension>;
export { validateAndExtract as A, BAZAAR as B, validateDiscoveryExtension as C, type DeclareBodyDiscoveryExtensionConfig as D, withBazaar as E, type ListDiscoveryResourcesParams as L, type McpDiscoveryExtension as M, type QueryDiscoveryExtension as Q, type ValidationResult as V, type WithExtensions as W, type BazaarClientExtension as a, type BodyDiscoveryExtension as b, type BodyDiscoveryInfo as c, type DeclareDiscoveryExtensionConfig as d, type DeclareDiscoveryExtensionInput as e, type DeclareMcpDiscoveryExtensionConfig as f, type DeclareQueryDiscoveryExtensionConfig as g, type DiscoveredHTTPResource as h, type DiscoveredMCPResource as i, type DiscoveredResource as j, type DiscoveryExtension as k, type DiscoveryInfo as l, type DiscoveryResource as m, type DiscoveryResourcesResponse as n, type McpDiscoveryInfo as o, type QueryDiscoveryInfo as p, bazaarResourceServerExtension as q, declareDiscoveryExtension as r, extractDiscoveryInfo as s, extractDiscoveryInfoFromExtension as t, extractDiscoveryInfoV1 as u, extractResourceMetadataV1 as v, isBodyExtensionConfig as w, isDiscoverableV1 as x, isMcpExtensionConfig as y, isQueryExtensionConfig as z };
// src/bazaar/http/types.ts
var isQueryExtensionConfig = (config) => {
return !("bodyType" in config) && !("toolName" in config);
};
var isBodyExtensionConfig = (config) => {
return "bodyType" in config;
};
// src/bazaar/mcp/types.ts
var isMcpExtensionConfig = (config) => {
return "toolName" in config;
};
// src/bazaar/types.ts
var BAZAAR = { key: "bazaar" };
// src/bazaar/http/resourceService.ts
function createQueryDiscoveryExtension({
method,
input = {},
inputSchema = { properties: {} },
output
}) {
return {
info: {
input: {
type: "http",
...method ? { method } : {},
...input ? { queryParams: input } : {}
},
...output?.example ? {
output: {
type: "json",
example: output.example
}
} : {}
},
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
input: {
type: "object",
properties: {
type: {
type: "string",
const: "http"
},
method: {
type: "string",
enum: ["GET", "HEAD", "DELETE"]
},
...inputSchema ? {
queryParams: {
type: "object",
...typeof inputSchema === "object" ? inputSchema : {}
}
} : {}
},
required: ["type"],
additionalProperties: false
},
...output?.example ? {
output: {
type: "object",
properties: {
type: {
type: "string"
},
example: {
type: "object",
...output.schema && typeof output.schema === "object" ? output.schema : {}
}
},
required: ["type"]
}
} : {}
},
required: ["input"]
}
};
}
function createBodyDiscoveryExtension({
method,
input = {},
inputSchema = { properties: {} },
bodyType,
output
}) {
return {
info: {
input: {
type: "http",
...method ? { method } : {},
bodyType,
body: input
},
...output?.example ? {
output: {
type: "json",
example: output.example
}
} : {}
},
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
input: {
type: "object",
properties: {
type: {
type: "string",
const: "http"
},
method: {
type: "string",
enum: ["POST", "PUT", "PATCH"]
},
bodyType: {
type: "string",
enum: ["json", "form-data", "text"]
},
body: inputSchema
},
required: ["type", "bodyType", "body"],
additionalProperties: false
},
...output?.example ? {
output: {
type: "object",
properties: {
type: {
type: "string"
},
example: {
type: "object",
...output.schema && typeof output.schema === "object" ? output.schema : {}
}
},
required: ["type"]
}
} : {}
},
required: ["input"]
}
};
}
// src/bazaar/mcp/resourceService.ts
function createMcpDiscoveryExtension({
toolName,
description,
transport,
inputSchema,
example,
output
}) {
return {
info: {
input: {
type: "mcp",
toolName,
...description !== void 0 ? { description } : {},
...transport !== void 0 ? { transport } : {},
inputSchema,
...example !== void 0 ? { example } : {}
},
...output?.example ? {
output: {
type: "json",
example: output.example
}
} : {}
},
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
input: {
type: "object",
properties: {
type: {
type: "string",
const: "mcp"
},
toolName: {
type: "string"
},
...description !== void 0 ? {
description: {
type: "string"
}
} : {},
...transport !== void 0 ? {
transport: {
type: "string",
enum: ["streamable-http", "sse"]
}
} : {},
inputSchema: {
type: "object"
},
...example !== void 0 ? {
example: {
type: "object"
}
} : {}
},
required: ["type", "toolName", "inputSchema"],
additionalProperties: false
},
...output?.example ? {
output: {
type: "object",
properties: {
type: {
type: "string"
},
example: {
type: "object",
...output.schema && typeof output.schema === "object" ? output.schema : {}
}
},
required: ["type"]
}
} : {}
},
required: ["input"]
}
};
}
// src/bazaar/resourceService.ts
function declareDiscoveryExtension(config) {
if ("toolName" in config) {
const extension2 = createMcpDiscoveryExtension(config);
return { bazaar: extension2 };
}
const bodyType = config.bodyType;
const isBodyMethod2 = bodyType !== void 0;
const extension = isBodyMethod2 ? createBodyDiscoveryExtension(config) : createQueryDiscoveryExtension(config);
return { bazaar: extension };
}
// src/bazaar/server.ts
function isHTTPRequestContext(ctx) {
return ctx !== null && typeof ctx === "object" && "method" in ctx && "adapter" in ctx;
}
var bazaarResourceServerExtension = {
key: BAZAAR.key,
enrichDeclaration: (declaration, transportContext) => {
if (!isHTTPRequestContext(transportContext)) {
return declaration;
}
const extension = declaration;
if (extension.info?.input?.type === "mcp") {
return declaration;
}
const method = transportContext.method;
const existingInputProps = extension.schema?.properties?.input?.properties || {};
const updatedInputProps = {
...existingInputProps,
method: {
type: "string",
enum: [method]
}
};
return {
...extension,
info: {
...extension.info || {},
input: {
...extension.info?.input || {},
method
}
},
schema: {
...extension.schema || {},
properties: {
...extension.schema?.properties || {},
input: {
...extension.schema?.properties?.input || {},
properties: updatedInputProps,
required: [
...extension.schema?.properties?.input?.required || [],
...!(extension.schema?.properties?.input?.required || []).includes("method") ? ["method"] : []
]
}
}
}
};
}
};
// src/bazaar/facilitator.ts
import Ajv from "ajv/dist/2020.js";
// src/bazaar/v1/facilitator.ts
function hasV1OutputSchema(obj) {
return obj !== null && typeof obj === "object" && "input" in obj && obj.input !== null && typeof obj.input === "object" && "type" in obj.input && obj.input.type === "http" && "method" in obj.input;
}
function isQueryMethod(method) {
const upperMethod = method.toUpperCase();
return upperMethod === "GET" || upperMethod === "HEAD" || upperMethod === "DELETE";
}
function isBodyMethod(method) {
const upperMethod = method.toUpperCase();
return upperMethod === "POST" || upperMethod === "PUT" || upperMethod === "PATCH";
}
function extractQueryParams(v1Input) {
if (v1Input.queryParams && typeof v1Input.queryParams === "object") {
return v1Input.queryParams;
}
if (v1Input.query_params && typeof v1Input.query_params === "object") {
return v1Input.query_params;
}
if (v1Input.query && typeof v1Input.query === "object") {
return v1Input.query;
}
if (v1Input.params && typeof v1Input.params === "object") {
return v1Input.params;
}
return void 0;
}
function extractBodyInfo(v1Input) {
let bodyType = "json";
const bodyTypeField = v1Input.bodyType || v1Input.body_type;
if (bodyTypeField && typeof bodyTypeField === "string") {
const type = bodyTypeField.toLowerCase();
if (type.includes("form") || type.includes("multipart")) {
bodyType = "form-data";
} else if (type.includes("text") || type.includes("plain")) {
bodyType = "text";
} else {
bodyType = "json";
}
}
let body = {};
if (v1Input.bodyFields && typeof v1Input.bodyFields === "object") {
body = v1Input.bodyFields;
} else if (v1Input.body_fields && v1Input.body_fields !== null && typeof v1Input.body_fields === "object") {
body = v1Input.body_fields;
} else if (v1Input.bodyParams && typeof v1Input.bodyParams === "object") {
body = v1Input.bodyParams;
} else if (v1Input.body && typeof v1Input.body === "object") {
body = v1Input.body;
} else if (v1Input.data && typeof v1Input.data === "object") {
body = v1Input.data;
} else if (v1Input.properties && typeof v1Input.properties === "object") {
body = v1Input.properties;
}
return { body, bodyType };
}
function extractDiscoveryInfoV1(paymentRequirements) {
const { outputSchema } = paymentRequirements;
if (!outputSchema || !hasV1OutputSchema(outputSchema)) {
return null;
}
const v1Input = outputSchema.input;
const isDiscoverable = v1Input.discoverable ?? true;
if (!isDiscoverable) {
return null;
}
const method = typeof v1Input.method === "string" ? v1Input.method.toUpperCase() : "";
const headersRaw = v1Input.headerFields || v1Input.header_fields || v1Input.headers;
const headers = headersRaw && typeof headersRaw === "object" ? headersRaw : void 0;
const output = outputSchema.output ? {
type: "json",
example: outputSchema.output
} : void 0;
if (isQueryMethod(method)) {
const queryParams = extractQueryParams(v1Input);
const discoveryInfo = {
input: {
type: "http",
method,
...queryParams ? { queryParams } : {},
...headers ? { headers } : {}
},
...output ? { output } : {}
};
return discoveryInfo;
} else if (isBodyMethod(method)) {
const { body, bodyType } = extractBodyInfo(v1Input);
const queryParams = extractQueryParams(v1Input);
const discoveryInfo = {
input: {
type: "http",
method,
bodyType,
body,
...queryParams ? { queryParams } : {},
...headers ? { headers } : {}
},
...output ? { output } : {}
};
return discoveryInfo;
}
return null;
}
function isDiscoverableV1(paymentRequirements) {
return extractDiscoveryInfoV1(paymentRequirements) !== null;
}
function extractResourceMetadataV1(paymentRequirements) {
return {
url: paymentRequirements.resource,
description: paymentRequirements.description,
mimeType: paymentRequirements.mimeType
};
}
// src/bazaar/facilitator.ts
function validateDiscoveryExtension(extension) {
try {
const ajv = new Ajv({ strict: false, allErrors: true });
const validate = ajv.compile(extension.schema);
const valid = validate(extension.info);
if (valid) {
return { valid: true };
}
const errors = validate.errors?.map((err) => {
const path = err.instancePath || "(root)";
return `${path}: ${err.message}`;
}) || ["Unknown validation error"];
return { valid: false, errors };
} catch (error) {
return {
valid: false,
errors: [
`Schema validation failed: ${error instanceof Error ? error.message : String(error)}`
]
};
}
}
function extractDiscoveryInfo(paymentPayload, paymentRequirements, validate = true) {
let discoveryInfo = null;
let resourceUrl;
if (paymentPayload.x402Version === 2) {
resourceUrl = paymentPayload.resource?.url ?? "";
if (paymentPayload.extensions) {
const bazaarExtension = paymentPayload.extensions[BAZAAR.key];
if (bazaarExtension && typeof bazaarExtension === "object") {
try {
const extension = bazaarExtension;
if (validate) {
const result = validateDiscoveryExtension(extension);
if (!result.valid) {
console.warn(
`V2 discovery extension validation failed: ${result.errors?.join(", ")}`
);
} else {
discoveryInfo = extension.info;
}
} else {
discoveryInfo = extension.info;
}
} catch (error) {
console.warn(`V2 discovery extension extraction failed: ${error}`);
}
}
}
} else if (paymentPayload.x402Version === 1) {
const requirementsV1 = paymentRequirements;
resourceUrl = requirementsV1.resource;
discoveryInfo = extractDiscoveryInfoV1(requirementsV1);
} else {
return null;
}
if (!discoveryInfo) {
return null;
}
const url = new URL(resourceUrl);
const normalizedResourceUrl = `${url.origin}${url.pathname}`;
let description;
let mimeType;
if (paymentPayload.x402Version === 2) {
description = paymentPayload.resource?.description;
mimeType = paymentPayload.resource?.mimeType;
} else if (paymentPayload.x402Version === 1) {
const requirementsV1 = paymentRequirements;
description = requirementsV1.description;
mimeType = requirementsV1.mimeType;
}
const base = {
resourceUrl: normalizedResourceUrl,
description,
mimeType,
x402Version: paymentPayload.x402Version,
discoveryInfo
};
if (discoveryInfo.input.type === "mcp") {
return { ...base, toolName: discoveryInfo.input.toolName };
}
return { ...base, method: discoveryInfo.input.method };
}
function extractDiscoveryInfoFromExtension(extension, validate = true) {
if (validate) {
const result = validateDiscoveryExtension(extension);
if (!result.valid) {
throw new Error(
`Invalid discovery extension: ${result.errors?.join(", ") || "Unknown error"}`
);
}
}
return extension.info;
}
function validateAndExtract(extension) {
const result = validateDiscoveryExtension(extension);
if (result.valid) {
return {
valid: true,
info: extension.info
};
}
return {
valid: false,
errors: result.errors
};
}
// src/bazaar/facilitatorClient.ts
function withBazaar(client) {
const existingExtensions = client.extensions ?? {};
const extended = client;
extended.extensions = {
...existingExtensions,
discovery: {
async listResources(params) {
let headers = {
"Content-Type": "application/json"
};
const authHeaders = await client.createAuthHeaders("discovery");
headers = { ...headers, ...authHeaders.headers };
const queryParams = new URLSearchParams();
if (params?.type !== void 0) {
queryParams.set("type", params.type);
}
if (params?.limit !== void 0) {
queryParams.set("limit", params.limit.toString());
}
if (params?.offset !== void 0) {
queryParams.set("offset", params.offset.toString());
}
const queryString = queryParams.toString();
const endpoint = `${client.url}/discovery/resources${queryString ? `?${queryString}` : ""}`;
const response = await fetch(endpoint, {
method: "GET",
headers
});
if (!response.ok) {
const errorText = await response.text().catch(() => response.statusText);
throw new Error(
`Facilitator listDiscoveryResources failed (${response.status}): ${errorText}`
);
}
return await response.json();
}
}
};
return extended;
}
export {
isQueryExtensionConfig,
isBodyExtensionConfig,
isMcpExtensionConfig,
BAZAAR,
declareDiscoveryExtension,
bazaarResourceServerExtension,
extractDiscoveryInfoV1,
isDiscoverableV1,
extractResourceMetadataV1,
validateDiscoveryExtension,
extractDiscoveryInfo,
extractDiscoveryInfoFromExtension,
validateAndExtract,
withBazaar
};
//# sourceMappingURL=chunk-ANAQVNUK.mjs.map
{"version":3,"sources":["../../src/bazaar/http/types.ts","../../src/bazaar/mcp/types.ts","../../src/bazaar/types.ts","../../src/bazaar/http/resourceService.ts","../../src/bazaar/mcp/resourceService.ts","../../src/bazaar/resourceService.ts","../../src/bazaar/server.ts","../../src/bazaar/facilitator.ts","../../src/bazaar/v1/facilitator.ts","../../src/bazaar/facilitatorClient.ts"],"sourcesContent":["/**\n * HTTP-specific type definitions for the Bazaar Discovery Extension\n */\n\nimport type { BodyMethods, QueryParamMethods } from \"@x402/core/http\";\nimport type { DiscoveryInfo } from \"../types\";\n\n/**\n * Discovery info for query parameter methods (GET, HEAD, DELETE)\n */\nexport interface QueryDiscoveryInfo {\n input: {\n type: \"http\";\n /** Absent at declaration time; set by bazaarResourceServerExtension.enrichDeclaration */\n method?: QueryParamMethods;\n queryParams?: Record<string, unknown>;\n headers?: Record<string, string>;\n };\n output?: {\n type?: string;\n format?: string;\n example?: unknown;\n };\n}\n\n/**\n * Discovery info for body methods (POST, PUT, PATCH)\n */\nexport interface BodyDiscoveryInfo {\n input: {\n type: \"http\";\n /** Absent at declaration time; set by bazaarResourceServerExtension.enrichDeclaration */\n method?: BodyMethods;\n bodyType: \"json\" | \"form-data\" | \"text\";\n body: Record<string, unknown>;\n queryParams?: Record<string, unknown>;\n headers?: Record<string, string>;\n };\n output?: {\n type?: string;\n format?: string;\n example?: unknown;\n };\n}\n\n/**\n * Discovery extension for query parameter methods (GET, HEAD, DELETE)\n */\nexport interface QueryDiscoveryExtension {\n info: QueryDiscoveryInfo;\n\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\";\n type: \"object\";\n properties: {\n input: {\n type: \"object\";\n properties: {\n type: {\n type: \"string\";\n const: \"http\";\n };\n method: {\n type: \"string\";\n enum: QueryParamMethods[];\n };\n queryParams?: {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n };\n headers?: {\n type: \"object\";\n additionalProperties: {\n type: \"string\";\n };\n };\n };\n required: (\"type\" | \"method\")[];\n additionalProperties?: boolean;\n };\n output?: {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: readonly string[];\n additionalProperties?: boolean;\n };\n };\n required: [\"input\"];\n };\n}\n\n/**\n * Discovery extension for body methods (POST, PUT, PATCH)\n */\nexport interface BodyDiscoveryExtension {\n info: BodyDiscoveryInfo;\n\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\";\n type: \"object\";\n properties: {\n input: {\n type: \"object\";\n properties: {\n type: {\n type: \"string\";\n const: \"http\";\n };\n method: {\n type: \"string\";\n enum: BodyMethods[];\n };\n bodyType: {\n type: \"string\";\n enum: [\"json\", \"form-data\", \"text\"];\n };\n body: Record<string, unknown>;\n queryParams?: {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n };\n headers?: {\n type: \"object\";\n additionalProperties: {\n type: \"string\";\n };\n };\n };\n required: (\"type\" | \"method\" | \"bodyType\" | \"body\")[];\n additionalProperties?: boolean;\n };\n output?: {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: readonly string[];\n additionalProperties?: boolean;\n };\n };\n required: [\"input\"];\n };\n}\n\nexport interface DeclareQueryDiscoveryExtensionConfig {\n method?: QueryParamMethods;\n input?: Record<string, unknown>;\n inputSchema?: Record<string, unknown>;\n output?: {\n example?: unknown;\n schema?: Record<string, unknown>;\n };\n}\n\nexport interface DeclareBodyDiscoveryExtensionConfig {\n method?: BodyMethods;\n input?: Record<string, unknown>;\n inputSchema?: Record<string, unknown>;\n bodyType: \"json\" | \"form-data\" | \"text\";\n output?: {\n example?: unknown;\n schema?: Record<string, unknown>;\n };\n}\n\nexport interface DiscoveredHTTPResource {\n resourceUrl: string;\n description?: string;\n mimeType?: string;\n /** Present after server extension enrichment; may be absent for pre-enrichment data */\n method?: string;\n x402Version: number;\n discoveryInfo: DiscoveryInfo;\n}\n\nexport const isQueryExtensionConfig = (\n config: DeclareQueryDiscoveryExtensionConfig | DeclareBodyDiscoveryExtensionConfig,\n): config is DeclareQueryDiscoveryExtensionConfig => {\n return !(\"bodyType\" in config) && !(\"toolName\" in config);\n};\n\nexport const isBodyExtensionConfig = (\n config: DeclareQueryDiscoveryExtensionConfig | DeclareBodyDiscoveryExtensionConfig,\n): config is DeclareBodyDiscoveryExtensionConfig => {\n return \"bodyType\" in config;\n};\n","/**\n * MCP-specific type definitions for the Bazaar Discovery Extension\n */\n\nimport type { DiscoveryInfo } from \"../types\";\n\n/**\n * Discovery info for MCP tools\n */\nexport interface McpDiscoveryInfo {\n input: {\n type: \"mcp\";\n toolName: string;\n description?: string;\n transport?: \"streamable-http\" | \"sse\";\n inputSchema: Record<string, unknown>;\n example?: Record<string, unknown>;\n };\n output?: {\n type?: string;\n format?: string;\n example?: unknown;\n };\n}\n\n/**\n * Discovery extension for MCP tools\n */\nexport interface McpDiscoveryExtension {\n info: McpDiscoveryInfo;\n\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\";\n type: \"object\";\n properties: {\n input: {\n type: \"object\";\n properties: {\n type: {\n type: \"string\";\n const: \"mcp\";\n };\n toolName: {\n type: \"string\";\n };\n description?: {\n type: \"string\";\n };\n transport?: {\n type: \"string\";\n enum: [\"streamable-http\", \"sse\"];\n };\n inputSchema: Record<string, unknown>;\n example?: Record<string, unknown>;\n };\n required: (\"type\" | \"toolName\" | \"inputSchema\")[];\n additionalProperties?: boolean;\n };\n output?: {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: readonly string[];\n additionalProperties?: boolean;\n };\n };\n required: [\"input\"];\n };\n}\n\nexport interface DeclareMcpDiscoveryExtensionConfig {\n toolName: string;\n description?: string;\n transport?: \"streamable-http\" | \"sse\";\n inputSchema: Record<string, unknown>;\n example?: Record<string, unknown>;\n output?: {\n example?: unknown;\n schema?: Record<string, unknown>;\n };\n}\n\nexport interface DiscoveredMCPResource {\n resourceUrl: string;\n description?: string;\n mimeType?: string;\n toolName: string;\n x402Version: number;\n discoveryInfo: DiscoveryInfo;\n}\n\nexport const isMcpExtensionConfig = (\n config: DeclareMcpDiscoveryExtensionConfig | Record<string, unknown>,\n): config is DeclareMcpDiscoveryExtensionConfig => {\n return \"toolName\" in config;\n};\n","/**\n * Shared type definitions for the Bazaar Discovery Extension\n *\n * Protocol-specific types live in their own directories (http/, mcp/).\n * This file defines the shared unions, constants, and utility types,\n * and re-exports all protocol-specific types for backwards compatibility.\n */\n\nimport type { FacilitatorExtension } from \"@x402/core/types\";\n\n// --- Shared union types ---\n\nimport type { QueryDiscoveryInfo, BodyDiscoveryInfo } from \"./http/types\";\nimport type { McpDiscoveryInfo } from \"./mcp/types\";\nimport type { QueryDiscoveryExtension, BodyDiscoveryExtension } from \"./http/types\";\nimport type { McpDiscoveryExtension } from \"./mcp/types\";\nimport type {\n DeclareQueryDiscoveryExtensionConfig,\n DeclareBodyDiscoveryExtensionConfig,\n} from \"./http/types\";\nimport type { DeclareMcpDiscoveryExtensionConfig } from \"./mcp/types\";\n\n// Re-export protocol-specific types\nexport type {\n QueryDiscoveryInfo,\n BodyDiscoveryInfo,\n QueryDiscoveryExtension,\n BodyDiscoveryExtension,\n DeclareQueryDiscoveryExtensionConfig,\n DeclareBodyDiscoveryExtensionConfig,\n DiscoveredHTTPResource,\n} from \"./http/types\";\n\nexport { isQueryExtensionConfig, isBodyExtensionConfig } from \"./http/types\";\n\nexport type {\n McpDiscoveryInfo,\n McpDiscoveryExtension,\n DeclareMcpDiscoveryExtensionConfig,\n DiscoveredMCPResource,\n} from \"./mcp/types\";\n\nexport { isMcpExtensionConfig } from \"./mcp/types\";\n\n// --- Shared constants ---\n\n/**\n * Extension identifier for the Bazaar discovery extension.\n */\nexport const BAZAAR: FacilitatorExtension = { key: \"bazaar\" };\n\n/**\n * Combined discovery info type\n */\nexport type DiscoveryInfo = QueryDiscoveryInfo | BodyDiscoveryInfo | McpDiscoveryInfo;\n\n/**\n * Combined discovery extension type\n */\nexport type DiscoveryExtension =\n | QueryDiscoveryExtension\n | BodyDiscoveryExtension\n | McpDiscoveryExtension;\n\nexport type DeclareDiscoveryExtensionConfig =\n | DeclareQueryDiscoveryExtensionConfig\n | DeclareBodyDiscoveryExtensionConfig\n | DeclareMcpDiscoveryExtensionConfig;\n\n/**\n * Distributive Omit - properly distributes Omit over union types.\n *\n * Standard `Omit<A | B, K>` collapses to common properties only,\n * losing discriminant properties like `bodyType`.\n *\n * This type uses conditional type distribution to preserve the union:\n * `DistributiveOmit<A | B, K>` = `Omit<A, K> | Omit<B, K>`\n */\nexport type DistributiveOmit<T, K extends keyof T> = T extends T ? Omit<T, K> : never;\n\n/**\n * Config type for declareDiscoveryExtension function.\n * Uses DistributiveOmit to preserve bodyType discriminant in the union for HTTP configs.\n * MCP config has no `method` field so it's included directly.\n */\nexport type DeclareDiscoveryExtensionInput =\n | DistributiveOmit<DeclareQueryDiscoveryExtensionConfig, \"method\">\n | DistributiveOmit<DeclareBodyDiscoveryExtensionConfig, \"method\">\n | DeclareMcpDiscoveryExtensionConfig;\n","/**\n * HTTP resource service functions for creating Bazaar discovery extensions\n */\n\nimport type {\n QueryDiscoveryExtension,\n BodyDiscoveryExtension,\n DeclareQueryDiscoveryExtensionConfig,\n DeclareBodyDiscoveryExtensionConfig,\n} from \"./types\";\n\n/**\n * Create a query discovery extension (GET, HEAD, DELETE)\n *\n * @param root0 - Configuration object for query discovery extension\n * @param root0.method - HTTP method (GET, HEAD, DELETE)\n * @param root0.input - Query parameters\n * @param root0.inputSchema - JSON schema for query parameters\n * @param root0.output - Output specification with example\n * @returns QueryDiscoveryExtension with info and schema\n */\nexport function createQueryDiscoveryExtension({\n method,\n input = {},\n inputSchema = { properties: {} },\n output,\n}: DeclareQueryDiscoveryExtensionConfig): QueryDiscoveryExtension {\n return {\n info: {\n input: {\n type: \"http\" as const,\n ...(method ? { method } : {}),\n ...(input ? { queryParams: input } : {}),\n },\n ...(output?.example\n ? {\n output: {\n type: \"json\",\n example: output.example,\n },\n }\n : {}),\n },\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties: {\n input: {\n type: \"object\",\n properties: {\n type: {\n type: \"string\",\n const: \"http\",\n },\n method: {\n type: \"string\",\n enum: [\"GET\", \"HEAD\", \"DELETE\"],\n },\n ...(inputSchema\n ? {\n queryParams: {\n type: \"object\" as const,\n ...(typeof inputSchema === \"object\" ? inputSchema : {}),\n },\n }\n : {}),\n },\n required: [\"type\"] as (\"type\" | \"method\")[],\n additionalProperties: false,\n },\n ...(output?.example\n ? {\n output: {\n type: \"object\" as const,\n properties: {\n type: {\n type: \"string\" as const,\n },\n example: {\n type: \"object\" as const,\n ...(output.schema && typeof output.schema === \"object\" ? output.schema : {}),\n },\n },\n required: [\"type\"] as const,\n },\n }\n : {}),\n },\n required: [\"input\"],\n },\n };\n}\n\n/**\n * Create a body discovery extension (POST, PUT, PATCH)\n *\n * @param root0 - Configuration object for body discovery extension\n * @param root0.method - HTTP method (POST, PUT, PATCH)\n * @param root0.input - Request body specification\n * @param root0.inputSchema - JSON schema for request body\n * @param root0.bodyType - Content type of body (json, form-data, text)\n * @param root0.output - Output specification with example\n * @returns BodyDiscoveryExtension with info and schema\n */\nexport function createBodyDiscoveryExtension({\n method,\n input = {},\n inputSchema = { properties: {} },\n bodyType,\n output,\n}: DeclareBodyDiscoveryExtensionConfig): BodyDiscoveryExtension {\n return {\n info: {\n input: {\n type: \"http\" as const,\n ...(method ? { method } : {}),\n bodyType,\n body: input,\n },\n ...(output?.example\n ? {\n output: {\n type: \"json\",\n example: output.example,\n },\n }\n : {}),\n },\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties: {\n input: {\n type: \"object\",\n properties: {\n type: {\n type: \"string\",\n const: \"http\",\n },\n method: {\n type: \"string\",\n enum: [\"POST\", \"PUT\", \"PATCH\"],\n },\n bodyType: {\n type: \"string\",\n enum: [\"json\", \"form-data\", \"text\"],\n },\n body: inputSchema,\n },\n required: [\"type\", \"bodyType\", \"body\"] as (\"type\" | \"method\" | \"bodyType\" | \"body\")[],\n additionalProperties: false,\n },\n ...(output?.example\n ? {\n output: {\n type: \"object\" as const,\n properties: {\n type: {\n type: \"string\" as const,\n },\n example: {\n type: \"object\" as const,\n ...(output.schema && typeof output.schema === \"object\" ? output.schema : {}),\n },\n },\n required: [\"type\"] as const,\n },\n }\n : {}),\n },\n required: [\"input\"],\n },\n };\n}\n","/**\n * MCP resource service functions for creating Bazaar discovery extensions\n */\n\nimport type { McpDiscoveryExtension, DeclareMcpDiscoveryExtensionConfig } from \"./types\";\n\n/**\n * Create an MCP tool discovery extension\n *\n * @param root0 - Configuration object for MCP discovery extension\n * @param root0.toolName - MCP tool name\n * @param root0.description - Tool description\n * @param root0.inputSchema - JSON Schema for tool arguments\n * @param root0.example - Example tool arguments\n * @param root0.output - Output specification with example\n * @param root0.transport - MCP transport type (streamable-http or sse)\n * @returns McpDiscoveryExtension with info and schema\n */\nexport function createMcpDiscoveryExtension({\n toolName,\n description,\n transport,\n inputSchema,\n example,\n output,\n}: DeclareMcpDiscoveryExtensionConfig): McpDiscoveryExtension {\n return {\n info: {\n input: {\n type: \"mcp\",\n toolName,\n ...(description !== undefined ? { description } : {}),\n ...(transport !== undefined ? { transport } : {}),\n inputSchema,\n ...(example !== undefined ? { example } : {}),\n },\n ...(output?.example\n ? {\n output: {\n type: \"json\",\n example: output.example,\n },\n }\n : {}),\n },\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties: {\n input: {\n type: \"object\",\n properties: {\n type: {\n type: \"string\",\n const: \"mcp\",\n },\n toolName: {\n type: \"string\",\n },\n ...(description !== undefined\n ? {\n description: {\n type: \"string\" as const,\n },\n }\n : {}),\n ...(transport !== undefined\n ? {\n transport: {\n type: \"string\" as const,\n enum: [\"streamable-http\", \"sse\"],\n },\n }\n : {}),\n inputSchema: {\n type: \"object\" as const,\n },\n ...(example !== undefined\n ? {\n example: {\n type: \"object\" as const,\n },\n }\n : {}),\n },\n required: [\"type\", \"toolName\", \"inputSchema\"] as (\"type\" | \"toolName\" | \"inputSchema\")[],\n additionalProperties: false,\n },\n ...(output?.example\n ? {\n output: {\n type: \"object\" as const,\n properties: {\n type: {\n type: \"string\" as const,\n },\n example: {\n type: \"object\" as const,\n ...(output.schema && typeof output.schema === \"object\" ? output.schema : {}),\n },\n },\n required: [\"type\"] as const,\n },\n }\n : {}),\n },\n required: [\"input\"],\n },\n };\n}\n","/**\n * Resource Service entry point for creating Bazaar discovery extensions\n *\n * This module provides the unified `declareDiscoveryExtension` function that\n * routes to protocol-specific builders in http/ and mcp/.\n */\n\nimport type { DiscoveryExtension, DeclareDiscoveryExtensionInput } from \"./types\";\nimport type {\n DeclareQueryDiscoveryExtensionConfig,\n DeclareBodyDiscoveryExtensionConfig,\n} from \"./http/types\";\nimport type { DeclareMcpDiscoveryExtensionConfig } from \"./mcp/types\";\nimport {\n createQueryDiscoveryExtension,\n createBodyDiscoveryExtension,\n} from \"./http/resourceService\";\nimport { createMcpDiscoveryExtension } from \"./mcp/resourceService\";\n\n/**\n * Create a discovery extension for any HTTP method or MCP tool\n *\n * This function helps servers declare how their endpoint should be called,\n * including the expected input parameters/body and output format.\n *\n * @param config - Configuration object for the discovery extension\n * @returns A discovery extension object with both info and schema\n *\n * @example\n * ```typescript\n * // For a GET endpoint with no input\n * const getExtension = declareDiscoveryExtension({\n * method: \"GET\",\n * output: {\n * example: { message: \"Success\", timestamp: \"2024-01-01T00:00:00Z\" }\n * }\n * });\n *\n * // For a GET endpoint with query params\n * const getWithParams = declareDiscoveryExtension({\n * method: \"GET\",\n * input: { query: \"example\" },\n * inputSchema: {\n * properties: {\n * query: { type: \"string\" }\n * },\n * required: [\"query\"]\n * }\n * });\n *\n * // For a POST endpoint with JSON body\n * const postExtension = declareDiscoveryExtension({\n * method: \"POST\",\n * input: { name: \"John\", age: 30 },\n * inputSchema: {\n * properties: {\n * name: { type: \"string\" },\n * age: { type: \"number\" }\n * },\n * required: [\"name\"]\n * },\n * bodyType: \"json\",\n * output: {\n * example: { success: true, id: \"123\" }\n * }\n * });\n *\n * // For an MCP tool\n * const mcpExtension = declareDiscoveryExtension({\n * toolName: \"financial_analysis\",\n * description: \"Analyze financial data for a given ticker\",\n * inputSchema: {\n * type: \"object\",\n * properties: {\n * ticker: { type: \"string\" },\n * },\n * required: [\"ticker\"],\n * },\n * output: {\n * example: { pe_ratio: 28.5, recommendation: \"hold\" }\n * }\n * });\n * ```\n */\nexport function declareDiscoveryExtension(\n config: DeclareDiscoveryExtensionInput,\n): Record<string, DiscoveryExtension> {\n if (\"toolName\" in config) {\n const extension = createMcpDiscoveryExtension(config as DeclareMcpDiscoveryExtensionConfig);\n return { bazaar: extension as DiscoveryExtension };\n }\n\n const bodyType = (config as DeclareBodyDiscoveryExtensionConfig).bodyType;\n const isBodyMethod = bodyType !== undefined;\n\n const extension = isBodyMethod\n ? createBodyDiscoveryExtension(config as DeclareBodyDiscoveryExtensionConfig)\n : createQueryDiscoveryExtension(config as DeclareQueryDiscoveryExtensionConfig);\n\n return { bazaar: extension as DiscoveryExtension };\n}\n","import type { ResourceServerExtension } from \"@x402/core/types\";\nimport type { HTTPRequestContext } from \"@x402/core/http\";\nimport { BAZAAR } from \"./types\";\n\n/**\n * Type guard to check if context is an HTTP request context.\n *\n * @param ctx - The context to check\n * @returns True if context is an HTTPRequestContext\n */\nfunction isHTTPRequestContext(ctx: unknown): ctx is HTTPRequestContext {\n return ctx !== null && typeof ctx === \"object\" && \"method\" in ctx && \"adapter\" in ctx;\n}\n\ninterface ExtensionDeclaration {\n [key: string]: unknown;\n info?: {\n [key: string]: unknown;\n input?: Record<string, unknown>;\n };\n schema?: {\n [key: string]: unknown;\n properties?: {\n [key: string]: unknown;\n input?: {\n [key: string]: unknown;\n properties?: {\n [key: string]: unknown;\n method?: Record<string, unknown>;\n };\n required?: string[];\n };\n };\n };\n}\n\nexport const bazaarResourceServerExtension: ResourceServerExtension = {\n key: BAZAAR.key,\n\n enrichDeclaration: (declaration, transportContext) => {\n if (!isHTTPRequestContext(transportContext)) {\n return declaration;\n }\n\n const extension = declaration as ExtensionDeclaration;\n\n // MCP extensions don't need HTTP method enrichment\n if (extension.info?.input?.type === \"mcp\") {\n return declaration;\n }\n\n const method = transportContext.method;\n\n // At declaration time, the schema uses a broad enum ([\"GET\", \"HEAD\", \"DELETE\"] or [\"POST\", \"PUT\", \"PATCH\"])\n // because the method isn't known until the HTTP context is available.\n // Here we narrow it to the actual method for precise schema validation.\n const existingInputProps = extension.schema?.properties?.input?.properties || {};\n const updatedInputProps = {\n ...existingInputProps,\n method: {\n type: \"string\",\n enum: [method],\n },\n };\n\n return {\n ...extension,\n info: {\n ...(extension.info || {}),\n input: {\n ...(extension.info?.input || {}),\n method,\n },\n },\n schema: {\n ...(extension.schema || {}),\n properties: {\n ...(extension.schema?.properties || {}),\n input: {\n ...(extension.schema?.properties?.input || {}),\n properties: updatedInputProps,\n required: [\n ...(extension.schema?.properties?.input?.required || []),\n ...(!(extension.schema?.properties?.input?.required || []).includes(\"method\")\n ? [\"method\"]\n : []),\n ],\n },\n },\n },\n };\n },\n};\n","/**\n * Facilitator functions for validating and extracting Bazaar discovery extensions\n *\n * These functions help facilitators validate extension data against schemas\n * and extract the discovery information for cataloging in the Bazaar.\n *\n * Supports both v2 (extensions in PaymentRequired) and v1 (outputSchema in PaymentRequirements).\n */\n\nimport Ajv from \"ajv/dist/2020.js\";\nimport type { PaymentPayload, PaymentRequirements, PaymentRequirementsV1 } from \"@x402/core/types\";\nimport type { DiscoveryExtension, DiscoveryInfo } from \"./types\";\nimport type { McpDiscoveryInfo } from \"./mcp/types\";\nimport type { DiscoveredHTTPResource } from \"./http/types\";\nimport type { DiscoveredMCPResource } from \"./mcp/types\";\nimport { BAZAAR } from \"./types\";\nimport { extractDiscoveryInfoV1 } from \"./v1/facilitator\";\n\n/**\n * Validation result for discovery extensions\n */\nexport interface ValidationResult {\n valid: boolean;\n errors?: string[];\n}\n\n/**\n * Validates a discovery extension's info against its schema\n *\n * @param extension - The discovery extension containing info and schema\n * @returns Validation result indicating if the info matches the schema\n *\n * @example\n * ```typescript\n * const extension = declareDiscoveryExtension(...);\n * const result = validateDiscoveryExtension(extension);\n *\n * if (result.valid) {\n * console.log(\"Extension is valid\");\n * } else {\n * console.error(\"Validation errors:\", result.errors);\n * }\n * ```\n */\nexport function validateDiscoveryExtension(extension: DiscoveryExtension): ValidationResult {\n try {\n const ajv = new Ajv({ strict: false, allErrors: true });\n const validate = ajv.compile(extension.schema);\n\n // The schema describes the structure of info directly\n // Schema has properties: { input: {...}, output: {...} }\n // So we validate extension.info which has { input: {...}, output: {...} }\n const valid = validate(extension.info);\n\n if (valid) {\n return { valid: true };\n }\n\n const errors = validate.errors?.map(err => {\n const path = err.instancePath || \"(root)\";\n return `${path}: ${err.message}`;\n }) || [\"Unknown validation error\"];\n\n return { valid: false, errors };\n } catch (error) {\n return {\n valid: false,\n errors: [\n `Schema validation failed: ${error instanceof Error ? error.message : String(error)}`,\n ],\n };\n }\n}\n\n/**\n * Extracts the discovery info from payment payload and requirements\n *\n * This function handles both v2 (extensions) and v1 (outputSchema) formats.\n *\n * For v2: Discovery info is in PaymentPayload.extensions (client copied it from PaymentRequired)\n * For v1: Discovery info is in PaymentRequirements.outputSchema\n *\n * V1 data is automatically transformed to v2 DiscoveryInfo format, making smart\n * assumptions about field names (queryParams/query/params for GET, bodyFields/body/data for POST, etc.)\n *\n * @param paymentPayload - The payment payload containing extensions (v2) and version info\n * @param paymentRequirements - The payment requirements (contains outputSchema for v1)\n * @param validate - Whether to validate v2 extensions before extracting (default: true)\n * @returns The discovery info in v2 format if present, or null if not discoverable\n *\n * @example\n * ```typescript\n * // V2 - extensions are in PaymentPayload\n * const info = extractDiscoveryInfo(paymentPayload, paymentRequirements);\n *\n * // V1 - discovery info is in PaymentRequirements.outputSchema\n * const info = extractDiscoveryInfo(paymentPayloadV1, paymentRequirementsV1);\n *\n * if (info) {\n * // Both v1 and v2 return the same DiscoveryInfo structure\n * console.log(\"Method:\", info.input.method);\n * }\n * ```\n */\nexport type { DiscoveredHTTPResource } from \"./http/types\";\nexport type { DiscoveredMCPResource } from \"./mcp/types\";\n\nexport type DiscoveredResource = DiscoveredHTTPResource | DiscoveredMCPResource;\n\n/**\n * Extracts discovery information from payment payload and requirements.\n * Combines resource URL, HTTP method, version, and discovery info into a single object.\n *\n * @param paymentPayload - The payment payload containing extensions and resource info\n * @param paymentRequirements - The payment requirements to validate against\n * @param validate - Whether to validate the discovery info against the schema (default: true)\n * @returns Discovered resource info with URL, method, version and discovery data, or null if not found\n */\nexport function extractDiscoveryInfo(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements | PaymentRequirementsV1,\n validate: boolean = true,\n): DiscoveredResource | null {\n let discoveryInfo: DiscoveryInfo | null = null;\n let resourceUrl: string;\n\n if (paymentPayload.x402Version === 2) {\n resourceUrl = paymentPayload.resource?.url ?? \"\";\n\n if (paymentPayload.extensions) {\n const bazaarExtension = paymentPayload.extensions[BAZAAR.key];\n\n if (bazaarExtension && typeof bazaarExtension === \"object\") {\n try {\n const extension = bazaarExtension as DiscoveryExtension;\n\n if (validate) {\n const result = validateDiscoveryExtension(extension);\n if (!result.valid) {\n console.warn(\n `V2 discovery extension validation failed: ${result.errors?.join(\", \")}`,\n );\n } else {\n discoveryInfo = extension.info;\n }\n } else {\n discoveryInfo = extension.info;\n }\n } catch (error) {\n console.warn(`V2 discovery extension extraction failed: ${error}`);\n }\n }\n }\n } else if (paymentPayload.x402Version === 1) {\n const requirementsV1 = paymentRequirements as PaymentRequirementsV1;\n resourceUrl = requirementsV1.resource;\n discoveryInfo = extractDiscoveryInfoV1(requirementsV1);\n } else {\n return null;\n }\n\n if (!discoveryInfo) {\n return null;\n }\n\n // Strip query params (?) and hash sections (#) for discovery cataloging\n const url = new URL(resourceUrl);\n const normalizedResourceUrl = `${url.origin}${url.pathname}`;\n\n // Extract description and mimeType from resource info (v2) or requirements (v1)\n let description: string | undefined;\n let mimeType: string | undefined;\n\n if (paymentPayload.x402Version === 2) {\n description = paymentPayload.resource?.description;\n mimeType = paymentPayload.resource?.mimeType;\n } else if (paymentPayload.x402Version === 1) {\n const requirementsV1 = paymentRequirements as PaymentRequirementsV1;\n description = requirementsV1.description;\n mimeType = requirementsV1.mimeType;\n }\n\n const base = {\n resourceUrl: normalizedResourceUrl,\n description,\n mimeType,\n x402Version: paymentPayload.x402Version,\n discoveryInfo,\n };\n\n if (discoveryInfo.input.type === \"mcp\") {\n return { ...base, toolName: (discoveryInfo as McpDiscoveryInfo).input.toolName };\n }\n\n return { ...base, method: discoveryInfo.input.method };\n}\n\n/**\n * Extracts discovery info from a v2 extension directly\n *\n * This is a lower-level function for when you already have the extension object.\n * For general use, prefer the main extractDiscoveryInfo function.\n *\n * @param extension - The discovery extension to extract info from\n * @param validate - Whether to validate before extracting (default: true)\n * @returns The discovery info if valid\n * @throws Error if validation fails and validate is true\n */\nexport function extractDiscoveryInfoFromExtension(\n extension: DiscoveryExtension,\n validate: boolean = true,\n): DiscoveryInfo {\n if (validate) {\n const result = validateDiscoveryExtension(extension);\n if (!result.valid) {\n throw new Error(\n `Invalid discovery extension: ${result.errors?.join(\", \") || \"Unknown error\"}`,\n );\n }\n }\n\n return extension.info;\n}\n\n/**\n * Validates and extracts discovery info in one step\n *\n * This is a convenience function that combines validation and extraction,\n * returning both the validation result and the info if valid.\n *\n * @param extension - The discovery extension to validate and extract\n * @returns Object containing validation result and info (if valid)\n *\n * @example\n * ```typescript\n * const extension = declareDiscoveryExtension(...);\n * const { valid, info, errors } = validateAndExtract(extension);\n *\n * if (valid && info) {\n * // Store info in Bazaar catalog\n * } else {\n * console.error(\"Validation errors:\", errors);\n * }\n * ```\n */\nexport function validateAndExtract(extension: DiscoveryExtension): {\n valid: boolean;\n info?: DiscoveryInfo;\n errors?: string[];\n} {\n const result = validateDiscoveryExtension(extension);\n\n if (result.valid) {\n return {\n valid: true,\n info: extension.info,\n };\n }\n\n return {\n valid: false,\n errors: result.errors,\n };\n}\n","/**\n * V1 Facilitator functions for extracting Bazaar discovery information\n *\n * In v1, discovery information is stored in the `outputSchema` field\n * of PaymentRequirements, which has a different structure than v2.\n *\n * This module transforms v1 data into v2 DiscoveryInfo format.\n */\n\nimport type { PaymentRequirementsV1 } from \"@x402/core/types\";\nimport type { BodyMethods, QueryParamMethods } from \"@x402/core/http\";\nimport type { DiscoveryInfo, QueryDiscoveryInfo, BodyDiscoveryInfo } from \"../types\";\n\n/**\n * Type guard to check if an object has the v1 outputSchema structure\n *\n * @param obj - The object to check\n * @returns True if object has v1 outputSchema structure\n */\nfunction hasV1OutputSchema(\n obj: unknown,\n): obj is { input: Record<string, unknown>; output?: Record<string, unknown> } {\n return (\n obj !== null &&\n typeof obj === \"object\" &&\n \"input\" in obj &&\n obj.input !== null &&\n typeof obj.input === \"object\" &&\n \"type\" in obj.input &&\n obj.input.type === \"http\" &&\n \"method\" in obj.input\n );\n}\n\n/**\n * Checks if a method is a query parameter method\n *\n * @param method - HTTP method string to check\n * @returns True if method is GET, HEAD, or DELETE\n */\nfunction isQueryMethod(method: string): method is QueryParamMethods {\n const upperMethod = method.toUpperCase();\n return upperMethod === \"GET\" || upperMethod === \"HEAD\" || upperMethod === \"DELETE\";\n}\n\n/**\n * Checks if a method is a body method\n *\n * @param method - HTTP method string to check\n * @returns True if method is POST, PUT, or PATCH\n */\nfunction isBodyMethod(method: string): method is BodyMethods {\n const upperMethod = method.toUpperCase();\n return upperMethod === \"POST\" || upperMethod === \"PUT\" || upperMethod === \"PATCH\";\n}\n\n/**\n * Extracts query parameters from v1 input, making smart assumptions\n * about common field names used in v1\n *\n * @param v1Input - V1 input object from payment requirements\n * @returns Extracted query parameters or undefined\n */\nfunction extractQueryParams(v1Input: Record<string, unknown>): Record<string, unknown> | undefined {\n // Check various common field names used in v1 (both camelCase and snake_case)\n if (v1Input.queryParams && typeof v1Input.queryParams === \"object\") {\n return v1Input.queryParams as Record<string, unknown>;\n }\n if (v1Input.query_params && typeof v1Input.query_params === \"object\") {\n return v1Input.query_params as Record<string, unknown>;\n }\n if (v1Input.query && typeof v1Input.query === \"object\") {\n return v1Input.query as Record<string, unknown>;\n }\n if (v1Input.params && typeof v1Input.params === \"object\") {\n return v1Input.params as Record<string, unknown>;\n }\n return undefined;\n}\n\n/**\n * Extracts body information from v1 input, making smart assumptions\n *\n * @param v1Input - V1 input object from payment requirements\n * @returns Object containing body content and bodyType\n */\nfunction extractBodyInfo(v1Input: Record<string, unknown>): {\n body: Record<string, unknown>;\n bodyType: \"json\" | \"form-data\" | \"text\";\n} {\n // Determine body type (check both camelCase and snake_case)\n let bodyType: \"json\" | \"form-data\" | \"text\" = \"json\";\n const bodyTypeField = v1Input.bodyType || v1Input.body_type;\n\n if (bodyTypeField && typeof bodyTypeField === \"string\") {\n const type = bodyTypeField.toLowerCase();\n if (type.includes(\"form\") || type.includes(\"multipart\")) {\n bodyType = \"form-data\";\n } else if (type.includes(\"text\") || type.includes(\"plain\")) {\n bodyType = \"text\";\n } else {\n bodyType = \"json\";\n }\n }\n\n // Extract body content from various possible fields\n // Priority order based on observed patterns in real data\n let body: Record<string, unknown> = {};\n\n if (v1Input.bodyFields && typeof v1Input.bodyFields === \"object\") {\n body = v1Input.bodyFields as Record<string, unknown>;\n } else if (\n v1Input.body_fields &&\n v1Input.body_fields !== null &&\n typeof v1Input.body_fields === \"object\"\n ) {\n body = v1Input.body_fields as Record<string, unknown>;\n } else if (v1Input.bodyParams && typeof v1Input.bodyParams === \"object\") {\n body = v1Input.bodyParams as Record<string, unknown>;\n } else if (v1Input.body && typeof v1Input.body === \"object\") {\n body = v1Input.body as Record<string, unknown>;\n } else if (v1Input.data && typeof v1Input.data === \"object\") {\n body = v1Input.data as Record<string, unknown>;\n } else if (v1Input.properties && typeof v1Input.properties === \"object\") {\n // Some endpoints have properties directly at the input level\n body = v1Input.properties as Record<string, unknown>;\n }\n\n return { body, bodyType };\n}\n\n/**\n * Extracts discovery info from v1 PaymentRequirements and transforms to v2 format\n *\n * In v1, the discovery information is stored in the `outputSchema` field,\n * which contains both input (endpoint shape) and output (response schema) information.\n *\n * This function makes smart assumptions to normalize v1 data into v2 DiscoveryInfo format:\n * - For GET/HEAD/DELETE: Looks for queryParams, query, or params fields\n * - For POST/PUT/PATCH: Looks for bodyFields, body, or data fields and normalizes bodyType\n * - Extracts optional headers if present\n *\n * @param paymentRequirements - V1 payment requirements\n * @returns Discovery info in v2 format if present and valid, or null if not discoverable\n *\n * @example\n * ```typescript\n * const requirements: PaymentRequirementsV1 = {\n * scheme: \"exact\",\n * network: \"eip155:8453\",\n * maxAmountRequired: \"100000\",\n * resource: \"https://api.example.com/data\",\n * description: \"Get data\",\n * mimeType: \"application/json\",\n * outputSchema: {\n * input: {\n * type: \"http\",\n * method: \"GET\",\n * discoverable: true,\n * queryParams: { query: \"string\" }\n * },\n * output: { type: \"object\" }\n * },\n * payTo: \"0x...\",\n * maxTimeoutSeconds: 300,\n * asset: \"0x...\",\n * extra: {}\n * };\n *\n * const info = extractDiscoveryInfoV1(requirements);\n * if (info) {\n * console.log(\"Endpoint method:\", info.input.method);\n * }\n * ```\n */\nexport function extractDiscoveryInfoV1(\n paymentRequirements: PaymentRequirementsV1,\n): DiscoveryInfo | null {\n const { outputSchema } = paymentRequirements;\n\n // Check if outputSchema exists and has the expected structure\n if (!outputSchema || !hasV1OutputSchema(outputSchema)) {\n return null;\n }\n\n const v1Input = outputSchema.input;\n\n // Check if the endpoint is marked as discoverable\n // Default to true if not specified (for backwards compatibility)\n const isDiscoverable = v1Input.discoverable ?? true;\n\n if (!isDiscoverable) {\n return null;\n }\n\n const method = typeof v1Input.method === \"string\" ? v1Input.method.toUpperCase() : \"\";\n\n // Extract headers if present (check both camelCase and snake_case)\n const headersRaw = v1Input.headerFields || v1Input.header_fields || v1Input.headers;\n const headers =\n headersRaw && typeof headersRaw === \"object\"\n ? (headersRaw as Record<string, string>)\n : undefined;\n\n // Extract output example/schema if present\n const output = outputSchema.output\n ? {\n type: \"json\" as const,\n example: outputSchema.output,\n }\n : undefined;\n\n // Transform based on method type\n if (isQueryMethod(method)) {\n // Query parameter method (GET, HEAD, DELETE)\n const queryParams = extractQueryParams(v1Input);\n\n const discoveryInfo: QueryDiscoveryInfo = {\n input: {\n type: \"http\",\n method: method as QueryParamMethods,\n ...(queryParams ? { queryParams } : {}),\n ...(headers ? { headers } : {}),\n },\n ...(output ? { output } : {}),\n };\n\n return discoveryInfo;\n } else if (isBodyMethod(method)) {\n // Body method (POST, PUT, PATCH)\n const { body, bodyType } = extractBodyInfo(v1Input);\n const queryParams = extractQueryParams(v1Input); // Some POST requests also have query params\n\n const discoveryInfo: BodyDiscoveryInfo = {\n input: {\n type: \"http\",\n method: method as BodyMethods,\n bodyType,\n body,\n ...(queryParams ? { queryParams } : {}),\n ...(headers ? { headers } : {}),\n },\n ...(output ? { output } : {}),\n };\n\n return discoveryInfo;\n }\n\n // Unsupported method, return null\n return null;\n}\n\n/**\n * Checks if v1 PaymentRequirements contains discoverable information\n *\n * @param paymentRequirements - V1 payment requirements\n * @returns True if the requirements contain valid discovery info\n *\n * @example\n * ```typescript\n * if (isDiscoverableV1(requirements)) {\n * const info = extractDiscoveryInfoV1(requirements);\n * // Catalog info in Bazaar\n * }\n * ```\n */\nexport function isDiscoverableV1(paymentRequirements: PaymentRequirementsV1): boolean {\n return extractDiscoveryInfoV1(paymentRequirements) !== null;\n}\n\n/**\n * Extracts resource metadata from v1 PaymentRequirements\n *\n * In v1, resource information is embedded directly in the payment requirements\n * rather than in a separate resource object.\n *\n * @param paymentRequirements - V1 payment requirements\n * @returns Resource metadata\n *\n * @example\n * ```typescript\n * const metadata = extractResourceMetadataV1(requirements);\n * console.log(\"Resource URL:\", metadata.url);\n * console.log(\"Description:\", metadata.description);\n * ```\n */\nexport function extractResourceMetadataV1(paymentRequirements: PaymentRequirementsV1): {\n url: string;\n description: string;\n mimeType: string;\n} {\n return {\n url: paymentRequirements.resource,\n description: paymentRequirements.description,\n mimeType: paymentRequirements.mimeType,\n };\n}\n","/**\n * Client extensions for querying Bazaar discovery resources\n */\n\nimport { HTTPFacilitatorClient } from \"@x402/core/http\";\nimport type { PaymentRequirements } from \"@x402/core/types\";\nimport { WithExtensions } from \"../types\";\n\n/**\n * Parameters for listing discovery resources.\n * All parameters are optional and used for filtering/pagination.\n */\nexport interface ListDiscoveryResourcesParams {\n /**\n * Filter by protocol type (e.g., \"http\", \"mcp\").\n */\n type?: string;\n\n /**\n * The number of discovered x402 resources to return per page.\n */\n limit?: number;\n\n /**\n * The offset of the first discovered x402 resource to return.\n */\n offset?: number;\n}\n\n/**\n * A discovered x402 resource from the bazaar.\n */\nexport interface DiscoveryResource {\n /** The URL or identifier of the discovered resource */\n resource: string;\n /** The protocol type of the resource (e.g., \"http\") */\n type: string;\n /** The x402 protocol version supported by this resource */\n x402Version: number;\n /** Array of accepted payment methods for this resource */\n accepts: PaymentRequirements[];\n /** ISO 8601 timestamp of when the resource was last updated */\n lastUpdated: string;\n /** Additional metadata about the resource */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Response from listing discovery resources.\n */\nexport interface DiscoveryResourcesResponse {\n /** The x402 protocol version of this response */\n x402Version: number;\n /** The list of discovered resources */\n items: DiscoveryResource[];\n /** Pagination information for the response */\n pagination: {\n /** Maximum number of results returned */\n limit: number;\n /** Number of results skipped */\n offset: number;\n /** Total count of resources matching the query */\n total: number;\n };\n}\n\n/**\n * Bazaar client extension interface providing discovery query functionality.\n */\nexport interface BazaarClientExtension {\n discovery: {\n /**\n * List x402 discovery resources from the bazaar.\n *\n * @param params - Optional filtering and pagination parameters\n * @returns A promise resolving to the discovery resources response\n */\n listResources(params?: ListDiscoveryResourcesParams): Promise<DiscoveryResourcesResponse>;\n };\n}\n\n/**\n * Extends a facilitator client with Bazaar discovery query functionality.\n * Preserves and merges with any existing extensions from prior chaining.\n *\n * @param client - The facilitator client to extend\n * @returns The client extended with bazaar discovery capabilities\n *\n * @example\n * ```ts\n * // Basic usage\n * const client = withBazaar(new HTTPFacilitatorClient());\n * const resources = await client.extensions.discovery.listResources({ type: \"http\" });\n *\n * // Chaining with other extensions\n * const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient()));\n * await client.extensions.other.someMethod();\n * await client.extensions.discovery.listResources();\n * ```\n */\nexport function withBazaar<T extends HTTPFacilitatorClient>(\n client: T,\n): WithExtensions<T, BazaarClientExtension> {\n // Preserve any existing extensions from prior chaining\n const existingExtensions =\n (client as T & { extensions?: Record<string, unknown> }).extensions ?? {};\n\n const extended = client as WithExtensions<T, BazaarClientExtension>;\n\n extended.extensions = {\n ...existingExtensions,\n discovery: {\n async listResources(\n params?: ListDiscoveryResourcesParams,\n ): Promise<DiscoveryResourcesResponse> {\n let headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n const authHeaders = await client.createAuthHeaders(\"discovery\");\n headers = { ...headers, ...authHeaders.headers };\n\n const queryParams = new URLSearchParams();\n if (params?.type !== undefined) {\n queryParams.set(\"type\", params.type);\n }\n if (params?.limit !== undefined) {\n queryParams.set(\"limit\", params.limit.toString());\n }\n if (params?.offset !== undefined) {\n queryParams.set(\"offset\", params.offset.toString());\n }\n\n const queryString = queryParams.toString();\n const endpoint = `${client.url}/discovery/resources${queryString ? `?${queryString}` : \"\"}`;\n\n const response = await fetch(endpoint, {\n method: \"GET\",\n headers,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n throw new Error(\n `Facilitator listDiscoveryResources failed (${response.status}): ${errorText}`,\n );\n }\n\n return (await response.json()) as DiscoveryResourcesResponse;\n },\n },\n } as WithExtensions<T, BazaarClientExtension>[\"extensions\"];\n\n return extended;\n}\n"],"mappings":"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","names":["extension","isBodyMethod"]}
import { FacilitatorExtension, ResourceServerExtension, PaymentPayload, PaymentRequirements, PaymentRequirementsV1 } from '@x402/core/types';
import { BodyMethods, QueryParamMethods, HTTPFacilitatorClient } from '@x402/core/http';
/**
* Shared type utilities for x402 extensions
*/
/**
* Type utility to merge extensions properly when chaining.
* If T already has extensions, merge them; otherwise add new extensions.
*
* @example
* ```ts
* // Chaining multiple extensions preserves all types:
* const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient()));
* // Type: HTTPFacilitatorClient & { extensions: OtherExtension & BazaarExtension }
* ```
*/
type WithExtensions<T, E> = T extends {
extensions: infer Existing;
} ? Omit<T, "extensions"> & {
extensions: Existing & E;
} : T & {
extensions: E;
};
/**
* HTTP-specific type definitions for the Bazaar Discovery Extension
*/
/**
* Discovery info for query parameter methods (GET, HEAD, DELETE)
*/
interface QueryDiscoveryInfo {
input: {
type: "http";
/** Absent at declaration time; set by bazaarResourceServerExtension.enrichDeclaration */
method?: QueryParamMethods;
queryParams?: Record<string, unknown>;
headers?: Record<string, string>;
};
output?: {
type?: string;
format?: string;
example?: unknown;
};
}
/**
* Discovery info for body methods (POST, PUT, PATCH)
*/
interface BodyDiscoveryInfo {
input: {
type: "http";
/** Absent at declaration time; set by bazaarResourceServerExtension.enrichDeclaration */
method?: BodyMethods;
bodyType: "json" | "form-data" | "text";
body: Record<string, unknown>;
queryParams?: Record<string, unknown>;
headers?: Record<string, string>;
};
output?: {
type?: string;
format?: string;
example?: unknown;
};
}
/**
* Discovery extension for query parameter methods (GET, HEAD, DELETE)
*/
interface QueryDiscoveryExtension {
info: QueryDiscoveryInfo;
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema";
type: "object";
properties: {
input: {
type: "object";
properties: {
type: {
type: "string";
const: "http";
};
method: {
type: "string";
enum: QueryParamMethods[];
};
queryParams?: {
type: "object";
properties?: Record<string, unknown>;
required?: string[];
additionalProperties?: boolean;
};
headers?: {
type: "object";
additionalProperties: {
type: "string";
};
};
};
required: ("type" | "method")[];
additionalProperties?: boolean;
};
output?: {
type: "object";
properties?: Record<string, unknown>;
required?: readonly string[];
additionalProperties?: boolean;
};
};
required: ["input"];
};
}
/**
* Discovery extension for body methods (POST, PUT, PATCH)
*/
interface BodyDiscoveryExtension {
info: BodyDiscoveryInfo;
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema";
type: "object";
properties: {
input: {
type: "object";
properties: {
type: {
type: "string";
const: "http";
};
method: {
type: "string";
enum: BodyMethods[];
};
bodyType: {
type: "string";
enum: ["json", "form-data", "text"];
};
body: Record<string, unknown>;
queryParams?: {
type: "object";
properties?: Record<string, unknown>;
required?: string[];
additionalProperties?: boolean;
};
headers?: {
type: "object";
additionalProperties: {
type: "string";
};
};
};
required: ("type" | "method" | "bodyType" | "body")[];
additionalProperties?: boolean;
};
output?: {
type: "object";
properties?: Record<string, unknown>;
required?: readonly string[];
additionalProperties?: boolean;
};
};
required: ["input"];
};
}
interface DeclareQueryDiscoveryExtensionConfig {
method?: QueryParamMethods;
input?: Record<string, unknown>;
inputSchema?: Record<string, unknown>;
output?: {
example?: unknown;
schema?: Record<string, unknown>;
};
}
interface DeclareBodyDiscoveryExtensionConfig {
method?: BodyMethods;
input?: Record<string, unknown>;
inputSchema?: Record<string, unknown>;
bodyType: "json" | "form-data" | "text";
output?: {
example?: unknown;
schema?: Record<string, unknown>;
};
}
interface DiscoveredHTTPResource {
resourceUrl: string;
description?: string;
mimeType?: string;
/** Present after server extension enrichment; may be absent for pre-enrichment data */
method?: string;
x402Version: number;
discoveryInfo: DiscoveryInfo;
}
declare const isQueryExtensionConfig: (config: DeclareQueryDiscoveryExtensionConfig | DeclareBodyDiscoveryExtensionConfig) => config is DeclareQueryDiscoveryExtensionConfig;
declare const isBodyExtensionConfig: (config: DeclareQueryDiscoveryExtensionConfig | DeclareBodyDiscoveryExtensionConfig) => config is DeclareBodyDiscoveryExtensionConfig;
/**
* MCP-specific type definitions for the Bazaar Discovery Extension
*/
/**
* Discovery info for MCP tools
*/
interface McpDiscoveryInfo {
input: {
type: "mcp";
toolName: string;
description?: string;
transport?: "streamable-http" | "sse";
inputSchema: Record<string, unknown>;
example?: Record<string, unknown>;
};
output?: {
type?: string;
format?: string;
example?: unknown;
};
}
/**
* Discovery extension for MCP tools
*/
interface McpDiscoveryExtension {
info: McpDiscoveryInfo;
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema";
type: "object";
properties: {
input: {
type: "object";
properties: {
type: {
type: "string";
const: "mcp";
};
toolName: {
type: "string";
};
description?: {
type: "string";
};
transport?: {
type: "string";
enum: ["streamable-http", "sse"];
};
inputSchema: Record<string, unknown>;
example?: Record<string, unknown>;
};
required: ("type" | "toolName" | "inputSchema")[];
additionalProperties?: boolean;
};
output?: {
type: "object";
properties?: Record<string, unknown>;
required?: readonly string[];
additionalProperties?: boolean;
};
};
required: ["input"];
};
}
interface DeclareMcpDiscoveryExtensionConfig {
toolName: string;
description?: string;
transport?: "streamable-http" | "sse";
inputSchema: Record<string, unknown>;
example?: Record<string, unknown>;
output?: {
example?: unknown;
schema?: Record<string, unknown>;
};
}
interface DiscoveredMCPResource {
resourceUrl: string;
description?: string;
mimeType?: string;
toolName: string;
x402Version: number;
discoveryInfo: DiscoveryInfo;
}
declare const isMcpExtensionConfig: (config: DeclareMcpDiscoveryExtensionConfig | Record<string, unknown>) => config is DeclareMcpDiscoveryExtensionConfig;
/**
* Shared type definitions for the Bazaar Discovery Extension
*
* Protocol-specific types live in their own directories (http/, mcp/).
* This file defines the shared unions, constants, and utility types,
* and re-exports all protocol-specific types for backwards compatibility.
*/
/**
* Extension identifier for the Bazaar discovery extension.
*/
declare const BAZAAR: FacilitatorExtension;
/**
* Combined discovery info type
*/
type DiscoveryInfo = QueryDiscoveryInfo | BodyDiscoveryInfo | McpDiscoveryInfo;
/**
* Combined discovery extension type
*/
type DiscoveryExtension = QueryDiscoveryExtension | BodyDiscoveryExtension | McpDiscoveryExtension;
type DeclareDiscoveryExtensionConfig = DeclareQueryDiscoveryExtensionConfig | DeclareBodyDiscoveryExtensionConfig | DeclareMcpDiscoveryExtensionConfig;
/**
* Distributive Omit - properly distributes Omit over union types.
*
* Standard `Omit<A | B, K>` collapses to common properties only,
* losing discriminant properties like `bodyType`.
*
* This type uses conditional type distribution to preserve the union:
* `DistributiveOmit<A | B, K>` = `Omit<A, K> | Omit<B, K>`
*/
type DistributiveOmit<T, K extends keyof T> = T extends T ? Omit<T, K> : never;
/**
* Config type for declareDiscoveryExtension function.
* Uses DistributiveOmit to preserve bodyType discriminant in the union for HTTP configs.
* MCP config has no `method` field so it's included directly.
*/
type DeclareDiscoveryExtensionInput = DistributiveOmit<DeclareQueryDiscoveryExtensionConfig, "method"> | DistributiveOmit<DeclareBodyDiscoveryExtensionConfig, "method"> | DeclareMcpDiscoveryExtensionConfig;
/**
* Resource Service entry point for creating Bazaar discovery extensions
*
* This module provides the unified `declareDiscoveryExtension` function that
* routes to protocol-specific builders in http/ and mcp/.
*/
/**
* Create a discovery extension for any HTTP method or MCP tool
*
* This function helps servers declare how their endpoint should be called,
* including the expected input parameters/body and output format.
*
* @param config - Configuration object for the discovery extension
* @returns A discovery extension object with both info and schema
*
* @example
* ```typescript
* // For a GET endpoint with no input
* const getExtension = declareDiscoveryExtension({
* method: "GET",
* output: {
* example: { message: "Success", timestamp: "2024-01-01T00:00:00Z" }
* }
* });
*
* // For a GET endpoint with query params
* const getWithParams = declareDiscoveryExtension({
* method: "GET",
* input: { query: "example" },
* inputSchema: {
* properties: {
* query: { type: "string" }
* },
* required: ["query"]
* }
* });
*
* // For a POST endpoint with JSON body
* const postExtension = declareDiscoveryExtension({
* method: "POST",
* input: { name: "John", age: 30 },
* inputSchema: {
* properties: {
* name: { type: "string" },
* age: { type: "number" }
* },
* required: ["name"]
* },
* bodyType: "json",
* output: {
* example: { success: true, id: "123" }
* }
* });
*
* // For an MCP tool
* const mcpExtension = declareDiscoveryExtension({
* toolName: "financial_analysis",
* description: "Analyze financial data for a given ticker",
* inputSchema: {
* type: "object",
* properties: {
* ticker: { type: "string" },
* },
* required: ["ticker"],
* },
* output: {
* example: { pe_ratio: 28.5, recommendation: "hold" }
* }
* });
* ```
*/
declare function declareDiscoveryExtension(config: DeclareDiscoveryExtensionInput): Record<string, DiscoveryExtension>;
declare const bazaarResourceServerExtension: ResourceServerExtension;
/**
* Facilitator functions for validating and extracting Bazaar discovery extensions
*
* These functions help facilitators validate extension data against schemas
* and extract the discovery information for cataloging in the Bazaar.
*
* Supports both v2 (extensions in PaymentRequired) and v1 (outputSchema in PaymentRequirements).
*/
/**
* Validation result for discovery extensions
*/
interface ValidationResult {
valid: boolean;
errors?: string[];
}
/**
* Validates a discovery extension's info against its schema
*
* @param extension - The discovery extension containing info and schema
* @returns Validation result indicating if the info matches the schema
*
* @example
* ```typescript
* const extension = declareDiscoveryExtension(...);
* const result = validateDiscoveryExtension(extension);
*
* if (result.valid) {
* console.log("Extension is valid");
* } else {
* console.error("Validation errors:", result.errors);
* }
* ```
*/
declare function validateDiscoveryExtension(extension: DiscoveryExtension): ValidationResult;
type DiscoveredResource = DiscoveredHTTPResource | DiscoveredMCPResource;
/**
* Extracts discovery information from payment payload and requirements.
* Combines resource URL, HTTP method, version, and discovery info into a single object.
*
* @param paymentPayload - The payment payload containing extensions and resource info
* @param paymentRequirements - The payment requirements to validate against
* @param validate - Whether to validate the discovery info against the schema (default: true)
* @returns Discovered resource info with URL, method, version and discovery data, or null if not found
*/
declare function extractDiscoveryInfo(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements | PaymentRequirementsV1, validate?: boolean): DiscoveredResource | null;
/**
* Extracts discovery info from a v2 extension directly
*
* This is a lower-level function for when you already have the extension object.
* For general use, prefer the main extractDiscoveryInfo function.
*
* @param extension - The discovery extension to extract info from
* @param validate - Whether to validate before extracting (default: true)
* @returns The discovery info if valid
* @throws Error if validation fails and validate is true
*/
declare function extractDiscoveryInfoFromExtension(extension: DiscoveryExtension, validate?: boolean): DiscoveryInfo;
/**
* Validates and extracts discovery info in one step
*
* This is a convenience function that combines validation and extraction,
* returning both the validation result and the info if valid.
*
* @param extension - The discovery extension to validate and extract
* @returns Object containing validation result and info (if valid)
*
* @example
* ```typescript
* const extension = declareDiscoveryExtension(...);
* const { valid, info, errors } = validateAndExtract(extension);
*
* if (valid && info) {
* // Store info in Bazaar catalog
* } else {
* console.error("Validation errors:", errors);
* }
* ```
*/
declare function validateAndExtract(extension: DiscoveryExtension): {
valid: boolean;
info?: DiscoveryInfo;
errors?: string[];
};
/**
* V1 Facilitator functions for extracting Bazaar discovery information
*
* In v1, discovery information is stored in the `outputSchema` field
* of PaymentRequirements, which has a different structure than v2.
*
* This module transforms v1 data into v2 DiscoveryInfo format.
*/
/**
* Extracts discovery info from v1 PaymentRequirements and transforms to v2 format
*
* In v1, the discovery information is stored in the `outputSchema` field,
* which contains both input (endpoint shape) and output (response schema) information.
*
* This function makes smart assumptions to normalize v1 data into v2 DiscoveryInfo format:
* - For GET/HEAD/DELETE: Looks for queryParams, query, or params fields
* - For POST/PUT/PATCH: Looks for bodyFields, body, or data fields and normalizes bodyType
* - Extracts optional headers if present
*
* @param paymentRequirements - V1 payment requirements
* @returns Discovery info in v2 format if present and valid, or null if not discoverable
*
* @example
* ```typescript
* const requirements: PaymentRequirementsV1 = {
* scheme: "exact",
* network: "eip155:8453",
* maxAmountRequired: "100000",
* resource: "https://api.example.com/data",
* description: "Get data",
* mimeType: "application/json",
* outputSchema: {
* input: {
* type: "http",
* method: "GET",
* discoverable: true,
* queryParams: { query: "string" }
* },
* output: { type: "object" }
* },
* payTo: "0x...",
* maxTimeoutSeconds: 300,
* asset: "0x...",
* extra: {}
* };
*
* const info = extractDiscoveryInfoV1(requirements);
* if (info) {
* console.log("Endpoint method:", info.input.method);
* }
* ```
*/
declare function extractDiscoveryInfoV1(paymentRequirements: PaymentRequirementsV1): DiscoveryInfo | null;
/**
* Checks if v1 PaymentRequirements contains discoverable information
*
* @param paymentRequirements - V1 payment requirements
* @returns True if the requirements contain valid discovery info
*
* @example
* ```typescript
* if (isDiscoverableV1(requirements)) {
* const info = extractDiscoveryInfoV1(requirements);
* // Catalog info in Bazaar
* }
* ```
*/
declare function isDiscoverableV1(paymentRequirements: PaymentRequirementsV1): boolean;
/**
* Extracts resource metadata from v1 PaymentRequirements
*
* In v1, resource information is embedded directly in the payment requirements
* rather than in a separate resource object.
*
* @param paymentRequirements - V1 payment requirements
* @returns Resource metadata
*
* @example
* ```typescript
* const metadata = extractResourceMetadataV1(requirements);
* console.log("Resource URL:", metadata.url);
* console.log("Description:", metadata.description);
* ```
*/
declare function extractResourceMetadataV1(paymentRequirements: PaymentRequirementsV1): {
url: string;
description: string;
mimeType: string;
};
/**
* Client extensions for querying Bazaar discovery resources
*/
/**
* Parameters for listing discovery resources.
* All parameters are optional and used for filtering/pagination.
*/
interface ListDiscoveryResourcesParams {
/**
* Filter by protocol type (e.g., "http", "mcp").
*/
type?: string;
/**
* The number of discovered x402 resources to return per page.
*/
limit?: number;
/**
* The offset of the first discovered x402 resource to return.
*/
offset?: number;
}
/**
* A discovered x402 resource from the bazaar.
*/
interface DiscoveryResource {
/** The URL or identifier of the discovered resource */
resource: string;
/** The protocol type of the resource (e.g., "http") */
type: string;
/** The x402 protocol version supported by this resource */
x402Version: number;
/** Array of accepted payment methods for this resource */
accepts: PaymentRequirements[];
/** ISO 8601 timestamp of when the resource was last updated */
lastUpdated: string;
/** Additional metadata about the resource */
metadata?: Record<string, unknown>;
}
/**
* Response from listing discovery resources.
*/
interface DiscoveryResourcesResponse {
/** The x402 protocol version of this response */
x402Version: number;
/** The list of discovered resources */
items: DiscoveryResource[];
/** Pagination information for the response */
pagination: {
/** Maximum number of results returned */
limit: number;
/** Number of results skipped */
offset: number;
/** Total count of resources matching the query */
total: number;
};
}
/**
* Bazaar client extension interface providing discovery query functionality.
*/
interface BazaarClientExtension {
discovery: {
/**
* List x402 discovery resources from the bazaar.
*
* @param params - Optional filtering and pagination parameters
* @returns A promise resolving to the discovery resources response
*/
listResources(params?: ListDiscoveryResourcesParams): Promise<DiscoveryResourcesResponse>;
};
}
/**
* Extends a facilitator client with Bazaar discovery query functionality.
* Preserves and merges with any existing extensions from prior chaining.
*
* @param client - The facilitator client to extend
* @returns The client extended with bazaar discovery capabilities
*
* @example
* ```ts
* // Basic usage
* const client = withBazaar(new HTTPFacilitatorClient());
* const resources = await client.extensions.discovery.listResources({ type: "http" });
*
* // Chaining with other extensions
* const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient()));
* await client.extensions.other.someMethod();
* await client.extensions.discovery.listResources();
* ```
*/
declare function withBazaar<T extends HTTPFacilitatorClient>(client: T): WithExtensions<T, BazaarClientExtension>;
export { validateAndExtract as A, BAZAAR as B, validateDiscoveryExtension as C, type DeclareBodyDiscoveryExtensionConfig as D, withBazaar as E, type ListDiscoveryResourcesParams as L, type McpDiscoveryExtension as M, type QueryDiscoveryExtension as Q, type ValidationResult as V, type WithExtensions as W, type BazaarClientExtension as a, type BodyDiscoveryExtension as b, type BodyDiscoveryInfo as c, type DeclareDiscoveryExtensionConfig as d, type DeclareDiscoveryExtensionInput as e, type DeclareMcpDiscoveryExtensionConfig as f, type DeclareQueryDiscoveryExtensionConfig as g, type DiscoveredHTTPResource as h, type DiscoveredMCPResource as i, type DiscoveredResource as j, type DiscoveryExtension as k, type DiscoveryInfo as l, type DiscoveryResource as m, type DiscoveryResourcesResponse as n, type McpDiscoveryInfo as o, type QueryDiscoveryInfo as p, bazaarResourceServerExtension as q, declareDiscoveryExtension as r, extractDiscoveryInfo as s, extractDiscoveryInfoFromExtension as t, extractDiscoveryInfoV1 as u, extractResourceMetadataV1 as v, isBodyExtensionConfig as w, isDiscoverableV1 as x, isMcpExtensionConfig as y, isQueryExtensionConfig as z };
+2
-2

@@ -1,3 +0,3 @@

export { B as BAZAAR, a as BazaarClientExtension, b as BodyDiscoveryExtension, c as BodyDiscoveryInfo, D as DiscoveredResource, d as DiscoveryExtension, e as DiscoveryInfo, f as DiscoveryResource, g as DiscoveryResourcesResponse, L as ListDiscoveryResourcesParams, Q as QueryDiscoveryExtension, h as QueryDiscoveryInfo, V as ValidationResult, i as bazaarResourceServerExtension, j as declareDiscoveryExtension, k as extractDiscoveryInfo, l as extractDiscoveryInfoFromExtension, m as extractDiscoveryInfoV1, n as extractResourceMetadataV1, o as isDiscoverableV1, v as validateAndExtract, p as validateDiscoveryExtension, w as withBazaar } from '../index-DvDlinmy.js';
export { B as BAZAAR, a as BazaarClientExtension, b as BodyDiscoveryExtension, c as BodyDiscoveryInfo, D as DeclareBodyDiscoveryExtensionConfig, d as DeclareDiscoveryExtensionConfig, e as DeclareDiscoveryExtensionInput, f as DeclareMcpDiscoveryExtensionConfig, g as DeclareQueryDiscoveryExtensionConfig, h as DiscoveredHTTPResource, i as DiscoveredMCPResource, j as DiscoveredResource, k as DiscoveryExtension, l as DiscoveryInfo, m as DiscoveryResource, n as DiscoveryResourcesResponse, L as ListDiscoveryResourcesParams, M as McpDiscoveryExtension, o as McpDiscoveryInfo, Q as QueryDiscoveryExtension, p as QueryDiscoveryInfo, V as ValidationResult, q as bazaarResourceServerExtension, r as declareDiscoveryExtension, s as extractDiscoveryInfo, t as extractDiscoveryInfoFromExtension, u as extractDiscoveryInfoV1, v as extractResourceMetadataV1, w as isBodyExtensionConfig, x as isDiscoverableV1, y as isMcpExtensionConfig, z as isQueryExtensionConfig, A as validateAndExtract, C as validateDiscoveryExtension, E as withBazaar } from '../index-G8RNfr6X.js';
import '@x402/core/types';
import '@x402/core/http';
import '@x402/core/types';

@@ -40,3 +40,6 @@ "use strict";

extractResourceMetadataV1: () => extractResourceMetadataV1,
isBodyExtensionConfig: () => isBodyExtensionConfig,
isDiscoverableV1: () => isDiscoverableV1,
isMcpExtensionConfig: () => isMcpExtensionConfig,
isQueryExtensionConfig: () => isQueryExtensionConfig,
validateAndExtract: () => validateAndExtract,

@@ -48,6 +51,19 @@ validateDiscoveryExtension: () => validateDiscoveryExtension,

// src/bazaar/http/types.ts
var isQueryExtensionConfig = (config) => {
return !("bodyType" in config) && !("toolName" in config);
};
var isBodyExtensionConfig = (config) => {
return "bodyType" in config;
};
// src/bazaar/mcp/types.ts
var isMcpExtensionConfig = (config) => {
return "toolName" in config;
};
// src/bazaar/types.ts
var BAZAAR = "bazaar";
var BAZAAR = { key: "bazaar" };
// src/bazaar/resourceService.ts
// src/bazaar/http/resourceService.ts
function createQueryDiscoveryExtension({

@@ -184,3 +200,93 @@ method,

}
// src/bazaar/mcp/resourceService.ts
function createMcpDiscoveryExtension({
toolName,
description,
transport,
inputSchema,
example,
output
}) {
return {
info: {
input: {
type: "mcp",
toolName,
...description !== void 0 ? { description } : {},
...transport !== void 0 ? { transport } : {},
inputSchema,
...example !== void 0 ? { example } : {}
},
...output?.example ? {
output: {
type: "json",
example: output.example
}
} : {}
},
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
input: {
type: "object",
properties: {
type: {
type: "string",
const: "mcp"
},
toolName: {
type: "string"
},
...description !== void 0 ? {
description: {
type: "string"
}
} : {},
...transport !== void 0 ? {
transport: {
type: "string",
enum: ["streamable-http", "sse"]
}
} : {},
inputSchema: {
type: "object"
},
...example !== void 0 ? {
example: {
type: "object"
}
} : {}
},
required: ["type", "toolName", "inputSchema"],
additionalProperties: false
},
...output?.example ? {
output: {
type: "object",
properties: {
type: {
type: "string"
},
example: {
type: "object",
...output.schema && typeof output.schema === "object" ? output.schema : {}
}
},
required: ["type"]
}
} : {}
},
required: ["input"]
}
};
}
// src/bazaar/resourceService.ts
function declareDiscoveryExtension(config) {
if ("toolName" in config) {
const extension2 = createMcpDiscoveryExtension(config);
return { bazaar: extension2 };
}
const bodyType = config.bodyType;

@@ -197,3 +303,3 @@ const isBodyMethod2 = bodyType !== void 0;

var bazaarResourceServerExtension = {
key: BAZAAR,
key: BAZAAR.key,
enrichDeclaration: (declaration, transportContext) => {

@@ -204,2 +310,5 @@ if (!isHTTPRequestContext(transportContext)) {

const extension = declaration;
if (extension.info?.input?.type === "mcp") {
return declaration;
}
const method = transportContext.method;

@@ -387,3 +496,3 @@ const existingInputProps = extension.schema?.properties?.input?.properties || {};

if (paymentPayload.extensions) {
const bazaarExtension = paymentPayload.extensions[BAZAAR];
const bazaarExtension = paymentPayload.extensions[BAZAAR.key];
if (bazaarExtension && typeof bazaarExtension === "object") {

@@ -431,10 +540,13 @@ try {

}
return {
const base = {
resourceUrl: normalizedResourceUrl,
description,
mimeType,
method: discoveryInfo.input.method,
x402Version: paymentPayload.x402Version,
discoveryInfo
};
if (discoveryInfo.input.type === "mcp") {
return { ...base, toolName: discoveryInfo.input.toolName };
}
return { ...base, method: discoveryInfo.input.method };
}

@@ -516,3 +628,6 @@ function extractDiscoveryInfoFromExtension(extension, validate = true) {

extractResourceMetadataV1,
isBodyExtensionConfig,
isDiscoverableV1,
isMcpExtensionConfig,
isQueryExtensionConfig,
validateAndExtract,

@@ -519,0 +634,0 @@ validateDiscoveryExtension,

@@ -1,6 +0,134 @@

export { B as BAZAAR, a as BazaarClientExtension, b as BodyDiscoveryExtension, c as BodyDiscoveryInfo, D as DiscoveredResource, d as DiscoveryExtension, e as DiscoveryInfo, f as DiscoveryResource, g as DiscoveryResourcesResponse, L as ListDiscoveryResourcesParams, Q as QueryDiscoveryExtension, h as QueryDiscoveryInfo, V as ValidationResult, W as WithExtensions, i as bazaarResourceServerExtension, j as declareDiscoveryExtension, k as extractDiscoveryInfo, l as extractDiscoveryInfoFromExtension, m as extractDiscoveryInfoV1, n as extractResourceMetadataV1, o as isDiscoverableV1, v as validateAndExtract, p as validateDiscoveryExtension, w as withBazaar } from './index-DvDlinmy.js';
export { B as BAZAAR, a as BazaarClientExtension, b as BodyDiscoveryExtension, c as BodyDiscoveryInfo, D as DeclareBodyDiscoveryExtensionConfig, d as DeclareDiscoveryExtensionConfig, e as DeclareDiscoveryExtensionInput, f as DeclareMcpDiscoveryExtensionConfig, g as DeclareQueryDiscoveryExtensionConfig, h as DiscoveredHTTPResource, i as DiscoveredMCPResource, j as DiscoveredResource, k as DiscoveryExtension, l as DiscoveryInfo, m as DiscoveryResource, n as DiscoveryResourcesResponse, L as ListDiscoveryResourcesParams, M as McpDiscoveryExtension, o as McpDiscoveryInfo, Q as QueryDiscoveryExtension, p as QueryDiscoveryInfo, V as ValidationResult, W as WithExtensions, q as bazaarResourceServerExtension, r as declareDiscoveryExtension, s as extractDiscoveryInfo, t as extractDiscoveryInfoFromExtension, u as extractDiscoveryInfoV1, v as extractResourceMetadataV1, w as isBodyExtensionConfig, x as isDiscoverableV1, y as isMcpExtensionConfig, z as isQueryExtensionConfig, A as validateAndExtract, C as validateDiscoveryExtension, E as withBazaar } from './index-G8RNfr6X.js';
export { CompleteSIWxInfo, CreateSIWxHookOptions, DeclareSIWxOptions, EVMMessageVerifier, EVMSigner, InMemorySIWxStorage, SIGN_IN_WITH_X, SIWxExtension, SIWxExtensionInfo, SIWxExtensionSchema, SIWxHookEvent, SIWxPayload, SIWxPayloadSchema, SIWxSigner, SIWxStorage, SIWxValidationOptions, SIWxValidationResult, SIWxVerifyOptions, SIWxVerifyResult, SOLANA_DEVNET, SOLANA_MAINNET, SOLANA_TESTNET, SignatureScheme, SignatureType, SolanaSigner, SupportedChain, buildSIWxSchema, createSIWxClientHook, createSIWxMessage, createSIWxPayload, createSIWxRequestHook, createSIWxSettleHook, declareSIWxExtension, decodeBase58, encodeBase58, encodeSIWxHeader, extractEVMChainId, extractSolanaChainReference, formatSIWEMessage, formatSIWSMessage, getEVMAddress, getSolanaAddress, isEVMSigner, isSolanaSigner, parseSIWxHeader, signEVMMessage, signSolanaMessage, siwxResourceServerExtension, validateSIWxMessage, verifyEVMSignature, verifySIWxSignature, verifySolanaSignature, wrapFetchWithSIWx } from './sign-in-with-x/index.js';
export { PAYMENT_IDENTIFIER, PAYMENT_ID_MAX_LENGTH, PAYMENT_ID_MIN_LENGTH, PAYMENT_ID_PATTERN, PaymentIdentifierExtension, PaymentIdentifierInfo, PaymentIdentifierSchema, PaymentIdentifierValidationResult, appendPaymentIdentifierToExtensions, declarePaymentIdentifierExtension, extractAndValidatePaymentIdentifier, extractPaymentIdentifier, generatePaymentId, hasPaymentIdentifier, isPaymentIdentifierExtension, isPaymentIdentifierRequired, isValidPaymentId, paymentIdentifierResourceServerExtension, paymentIdentifierSchema, validatePaymentIdentifier, validatePaymentIdentifierRequirement } from './payment-identifier/index.js';
import { FacilitatorExtension, PaymentPayload } from '@x402/core/types';
import '@x402/core/http';
import '@x402/core/types';
import 'zod';
/**
* Type definitions for the EIP-2612 Gas Sponsoring Extension
*
* This extension enables gasless approval of the Permit2 contract for tokens
* that implement EIP-2612. The client signs an off-chain permit, and the
* facilitator submits it on-chain via `x402Permit2Proxy.settleWithPermit`.
*/
/**
* Extension identifier for the EIP-2612 gas sponsoring extension.
*/
declare const EIP2612_GAS_SPONSORING: FacilitatorExtension;
/**
* EIP-2612 gas sponsoring info populated by the client.
*
* Contains the EIP-2612 permit signature and parameters that the facilitator
* needs to call `x402Permit2Proxy.settleWithPermit`.
*/
interface Eip2612GasSponsoringInfo {
/** Index signature for compatibility with Record<string, unknown> */
[key: string]: unknown;
/** The address of the sender (token owner). */
from: string;
/** The address of the ERC-20 token contract. */
asset: string;
/** The address of the spender (Canonical Permit2). */
spender: string;
/** The amount to approve (uint256 as decimal string). Typically MaxUint256. */
amount: string;
/** The current EIP-2612 nonce of the sender (decimal string). */
nonce: string;
/** The timestamp at which the permit signature expires (decimal string). */
deadline: string;
/** The 65-byte concatenated EIP-2612 permit signature (r, s, v) as a hex string. */
signature: string;
/** Schema version identifier. */
version: string;
}
/**
* Server-side EIP-2612 gas sponsoring info included in PaymentRequired.
* Contains a description and version; the client populates the rest.
*/
interface Eip2612GasSponsoringServerInfo {
/** Index signature for compatibility with Record<string, unknown> */
[key: string]: unknown;
/** Human-readable description of the extension. */
description: string;
/** Schema version identifier. */
version: string;
}
/**
* The full extension object as it appears in PaymentRequired.extensions
* and PaymentPayload.extensions.
*/
interface Eip2612GasSponsoringExtension {
/** Extension info - server-provided or client-enriched. */
info: Eip2612GasSponsoringServerInfo | Eip2612GasSponsoringInfo;
/** JSON Schema describing the expected structure of info. */
schema: Record<string, unknown>;
}
/**
* Resource Service functions for declaring the EIP-2612 Gas Sponsoring extension.
*
* These functions help servers declare support for EIP-2612 gasless Permit2 approvals
* in the PaymentRequired response extensions.
*/
/**
* Declares the EIP-2612 gas sponsoring extension for inclusion in
* PaymentRequired.extensions.
*
* The server advertises that it (or its facilitator) supports EIP-2612
* gasless Permit2 approval. The client will populate the info with the
* actual permit signature data.
*
* @returns An object keyed by the extension identifier containing the extension declaration
*
* @example
* ```typescript
* import { declareEip2612GasSponsoringExtension } from '@x402/extensions';
*
* const routes = [
* {
* path: "/api/data",
* price: "$0.01",
* extensions: {
* ...declareEip2612GasSponsoringExtension(),
* },
* },
* ];
* ```
*/
declare function declareEip2612GasSponsoringExtension(): Record<string, Eip2612GasSponsoringExtension>;
/**
* Facilitator functions for extracting and validating EIP-2612 Gas Sponsoring extension data.
*
* These functions help facilitators extract the EIP-2612 permit data from payment
* payloads and validate it before calling settleWithPermit.
*/
/**
* Extracts the EIP-2612 gas sponsoring info from a payment payload's extensions.
*
* Returns the info if the extension is present and contains the required client-populated
* fields (from, asset, spender, amount, nonce, deadline, signature, version).
*
* @param paymentPayload - The payment payload to extract from
* @returns The EIP-2612 gas sponsoring info, or null if not present
*/
declare function extractEip2612GasSponsoringInfo(paymentPayload: PaymentPayload): Eip2612GasSponsoringInfo | null;
/**
* Validates that the EIP-2612 gas sponsoring info has valid format.
*
* Performs basic validation on the info fields:
* - Addresses are valid hex (0x + 40 hex chars)
* - Amount, nonce, deadline are numeric strings
* - Signature is a hex string
* - Version is a numeric version string
*
* @param info - The EIP-2612 gas sponsoring info to validate
* @returns True if the info is valid, false otherwise
*/
declare function validateEip2612GasSponsoringInfo(info: Eip2612GasSponsoringInfo): boolean;
export { EIP2612_GAS_SPONSORING, type Eip2612GasSponsoringExtension, type Eip2612GasSponsoringInfo, type Eip2612GasSponsoringServerInfo, declareEip2612GasSponsoringExtension, extractEip2612GasSponsoringInfo, validateEip2612GasSponsoringInfo };

@@ -34,2 +34,3 @@ "use strict";

BAZAAR: () => BAZAAR,
EIP2612_GAS_SPONSORING: () => EIP2612_GAS_SPONSORING,
InMemorySIWxStorage: () => InMemorySIWxStorage,

@@ -54,2 +55,3 @@ PAYMENT_IDENTIFIER: () => PAYMENT_IDENTIFIER,

declareDiscoveryExtension: () => declareDiscoveryExtension,
declareEip2612GasSponsoringExtension: () => declareEip2612GasSponsoringExtension,
declarePaymentIdentifierExtension: () => declarePaymentIdentifierExtension,

@@ -65,2 +67,3 @@ declareSIWxExtension: () => declareSIWxExtension,

extractEVMChainId: () => extractEVMChainId,
extractEip2612GasSponsoringInfo: () => extractEip2612GasSponsoringInfo,
extractPaymentIdentifier: () => extractPaymentIdentifier,

@@ -75,6 +78,9 @@ extractResourceMetadataV1: () => extractResourceMetadataV1,

hasPaymentIdentifier: () => hasPaymentIdentifier,
isBodyExtensionConfig: () => isBodyExtensionConfig,
isDiscoverableV1: () => isDiscoverableV1,
isEVMSigner: () => isEVMSigner,
isMcpExtensionConfig: () => isMcpExtensionConfig,
isPaymentIdentifierExtension: () => isPaymentIdentifierExtension,
isPaymentIdentifierRequired: () => isPaymentIdentifierRequired,
isQueryExtensionConfig: () => isQueryExtensionConfig,
isSolanaSigner: () => isSolanaSigner,

@@ -90,2 +96,3 @@ isValidPaymentId: () => isValidPaymentId,

validateDiscoveryExtension: () => validateDiscoveryExtension,
validateEip2612GasSponsoringInfo: () => validateEip2612GasSponsoringInfo,
validatePaymentIdentifier: () => validatePaymentIdentifier,

@@ -102,6 +109,19 @@ validatePaymentIdentifierRequirement: () => validatePaymentIdentifierRequirement,

// src/bazaar/http/types.ts
var isQueryExtensionConfig = (config) => {
return !("bodyType" in config) && !("toolName" in config);
};
var isBodyExtensionConfig = (config) => {
return "bodyType" in config;
};
// src/bazaar/mcp/types.ts
var isMcpExtensionConfig = (config) => {
return "toolName" in config;
};
// src/bazaar/types.ts
var BAZAAR = "bazaar";
var BAZAAR = { key: "bazaar" };
// src/bazaar/resourceService.ts
// src/bazaar/http/resourceService.ts
function createQueryDiscoveryExtension({

@@ -238,3 +258,93 @@ method,

}
// src/bazaar/mcp/resourceService.ts
function createMcpDiscoveryExtension({
toolName,
description,
transport,
inputSchema,
example,
output
}) {
return {
info: {
input: {
type: "mcp",
toolName,
...description !== void 0 ? { description } : {},
...transport !== void 0 ? { transport } : {},
inputSchema,
...example !== void 0 ? { example } : {}
},
...output?.example ? {
output: {
type: "json",
example: output.example
}
} : {}
},
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
input: {
type: "object",
properties: {
type: {
type: "string",
const: "mcp"
},
toolName: {
type: "string"
},
...description !== void 0 ? {
description: {
type: "string"
}
} : {},
...transport !== void 0 ? {
transport: {
type: "string",
enum: ["streamable-http", "sse"]
}
} : {},
inputSchema: {
type: "object"
},
...example !== void 0 ? {
example: {
type: "object"
}
} : {}
},
required: ["type", "toolName", "inputSchema"],
additionalProperties: false
},
...output?.example ? {
output: {
type: "object",
properties: {
type: {
type: "string"
},
example: {
type: "object",
...output.schema && typeof output.schema === "object" ? output.schema : {}
}
},
required: ["type"]
}
} : {}
},
required: ["input"]
}
};
}
// src/bazaar/resourceService.ts
function declareDiscoveryExtension(config) {
if ("toolName" in config) {
const extension2 = createMcpDiscoveryExtension(config);
return { bazaar: extension2 };
}
const bodyType = config.bodyType;

@@ -251,3 +361,3 @@ const isBodyMethod2 = bodyType !== void 0;

var bazaarResourceServerExtension = {
key: BAZAAR,
key: BAZAAR.key,
enrichDeclaration: (declaration, transportContext) => {

@@ -258,2 +368,5 @@ if (!isHTTPRequestContext(transportContext)) {

const extension = declaration;
if (extension.info?.input?.type === "mcp") {
return declaration;
}
const method = transportContext.method;

@@ -441,3 +554,3 @@ const existingInputProps = extension.schema?.properties?.input?.properties || {};

if (paymentPayload.extensions) {
const bazaarExtension = paymentPayload.extensions[BAZAAR];
const bazaarExtension = paymentPayload.extensions[BAZAAR.key];
if (bazaarExtension && typeof bazaarExtension === "object") {

@@ -485,10 +598,13 @@ try {

}
return {
const base = {
resourceUrl: normalizedResourceUrl,
description,
mimeType,
method: discoveryInfo.input.method,
x402Version: paymentPayload.x402Version,
discoveryInfo
};
if (discoveryInfo.input.type === "mcp") {
return { ...base, toolName: discoveryInfo.input.toolName };
}
return { ...base, method: discoveryInfo.input.method };
}

@@ -1513,5 +1629,93 @@ function extractDiscoveryInfoFromExtension(extension, validate = true) {

};
// src/eip2612-gas-sponsoring/types.ts
var EIP2612_GAS_SPONSORING = { key: "eip2612GasSponsoring" };
// src/eip2612-gas-sponsoring/resourceService.ts
var eip2612GasSponsoringSchema = {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
from: {
type: "string",
pattern: "^0x[a-fA-F0-9]{40}$",
description: "The address of the sender."
},
asset: {
type: "string",
pattern: "^0x[a-fA-F0-9]{40}$",
description: "The address of the ERC-20 token contract."
},
spender: {
type: "string",
pattern: "^0x[a-fA-F0-9]{40}$",
description: "The address of the spender (Canonical Permit2)."
},
amount: {
type: "string",
pattern: "^[0-9]+$",
description: "The amount to approve (uint256). Typically MaxUint."
},
nonce: {
type: "string",
pattern: "^[0-9]+$",
description: "The current nonce of the sender."
},
deadline: {
type: "string",
pattern: "^[0-9]+$",
description: "The timestamp at which the signature expires."
},
signature: {
type: "string",
pattern: "^0x[a-fA-F0-9]+$",
description: "The 65-byte concatenated signature (r, s, v) as a hex string."
},
version: {
type: "string",
pattern: "^[0-9]+(\\.[0-9]+)*$",
description: "Schema version identifier."
}
},
required: ["from", "asset", "spender", "amount", "nonce", "deadline", "signature", "version"]
};
function declareEip2612GasSponsoringExtension() {
const key = EIP2612_GAS_SPONSORING.key;
return {
[key]: {
info: {
description: "The facilitator accepts EIP-2612 gasless Permit to `Permit2` canonical contract.",
version: "1"
},
schema: eip2612GasSponsoringSchema
}
};
}
// src/eip2612-gas-sponsoring/facilitator.ts
function extractEip2612GasSponsoringInfo(paymentPayload) {
if (!paymentPayload.extensions) {
return null;
}
const extension = paymentPayload.extensions[EIP2612_GAS_SPONSORING.key];
if (!extension?.info) {
return null;
}
const info = extension.info;
if (!info.from || !info.asset || !info.spender || !info.amount || !info.nonce || !info.deadline || !info.signature || !info.version) {
return null;
}
return info;
}
function validateEip2612GasSponsoringInfo(info) {
const addressPattern = /^0x[a-fA-F0-9]{40}$/;
const numericPattern = /^[0-9]+$/;
const hexPattern = /^0x[a-fA-F0-9]+$/;
const versionPattern = /^[0-9]+(\.[0-9]+)*$/;
return addressPattern.test(info.from) && addressPattern.test(info.asset) && addressPattern.test(info.spender) && numericPattern.test(info.amount) && numericPattern.test(info.nonce) && numericPattern.test(info.deadline) && hexPattern.test(info.signature) && versionPattern.test(info.version);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BAZAAR,
EIP2612_GAS_SPONSORING,
InMemorySIWxStorage,

@@ -1536,2 +1740,3 @@ PAYMENT_IDENTIFIER,

declareDiscoveryExtension,
declareEip2612GasSponsoringExtension,
declarePaymentIdentifierExtension,

@@ -1547,2 +1752,3 @@ declareSIWxExtension,

extractEVMChainId,
extractEip2612GasSponsoringInfo,
extractPaymentIdentifier,

@@ -1557,6 +1763,9 @@ extractResourceMetadataV1,

hasPaymentIdentifier,
isBodyExtensionConfig,
isDiscoverableV1,
isEVMSigner,
isMcpExtensionConfig,
isPaymentIdentifierExtension,
isPaymentIdentifierRequired,
isQueryExtensionConfig,
isSolanaSigner,

@@ -1572,2 +1781,3 @@ isValidPaymentId,

validateDiscoveryExtension,
validateEip2612GasSponsoringInfo,
validatePaymentIdentifier,

@@ -1574,0 +1784,0 @@ validatePaymentIdentifierRequirement,

@@ -1,3 +0,3 @@

export { B as BAZAAR, a as BazaarClientExtension, b as BodyDiscoveryExtension, c as BodyDiscoveryInfo, D as DiscoveredResource, d as DiscoveryExtension, e as DiscoveryInfo, f as DiscoveryResource, g as DiscoveryResourcesResponse, L as ListDiscoveryResourcesParams, Q as QueryDiscoveryExtension, h as QueryDiscoveryInfo, V as ValidationResult, i as bazaarResourceServerExtension, j as declareDiscoveryExtension, k as extractDiscoveryInfo, l as extractDiscoveryInfoFromExtension, m as extractDiscoveryInfoV1, n as extractResourceMetadataV1, o as isDiscoverableV1, v as validateAndExtract, p as validateDiscoveryExtension, w as withBazaar } from '../index-DvDlinmy.mjs';
export { B as BAZAAR, a as BazaarClientExtension, b as BodyDiscoveryExtension, c as BodyDiscoveryInfo, D as DeclareBodyDiscoveryExtensionConfig, d as DeclareDiscoveryExtensionConfig, e as DeclareDiscoveryExtensionInput, f as DeclareMcpDiscoveryExtensionConfig, g as DeclareQueryDiscoveryExtensionConfig, h as DiscoveredHTTPResource, i as DiscoveredMCPResource, j as DiscoveredResource, k as DiscoveryExtension, l as DiscoveryInfo, m as DiscoveryResource, n as DiscoveryResourcesResponse, L as ListDiscoveryResourcesParams, M as McpDiscoveryExtension, o as McpDiscoveryInfo, Q as QueryDiscoveryExtension, p as QueryDiscoveryInfo, V as ValidationResult, q as bazaarResourceServerExtension, r as declareDiscoveryExtension, s as extractDiscoveryInfo, t as extractDiscoveryInfoFromExtension, u as extractDiscoveryInfoV1, v as extractResourceMetadataV1, w as isBodyExtensionConfig, x as isDiscoverableV1, y as isMcpExtensionConfig, z as isQueryExtensionConfig, A as validateAndExtract, C as validateDiscoveryExtension, E as withBazaar } from '../index-G8RNfr6X.mjs';
import '@x402/core/types';
import '@x402/core/http';
import '@x402/core/types';

@@ -9,7 +9,10 @@ import {

extractResourceMetadataV1,
isBodyExtensionConfig,
isDiscoverableV1,
isMcpExtensionConfig,
isQueryExtensionConfig,
validateAndExtract,
validateDiscoveryExtension,
withBazaar
} from "../chunk-DFJ4ZQFO.mjs";
} from "../chunk-ANAQVNUK.mjs";
export {

@@ -23,3 +26,6 @@ BAZAAR,

extractResourceMetadataV1,
isBodyExtensionConfig,
isDiscoverableV1,
isMcpExtensionConfig,
isQueryExtensionConfig,
validateAndExtract,

@@ -26,0 +32,0 @@ validateDiscoveryExtension,

@@ -1,6 +0,134 @@

export { B as BAZAAR, a as BazaarClientExtension, b as BodyDiscoveryExtension, c as BodyDiscoveryInfo, D as DiscoveredResource, d as DiscoveryExtension, e as DiscoveryInfo, f as DiscoveryResource, g as DiscoveryResourcesResponse, L as ListDiscoveryResourcesParams, Q as QueryDiscoveryExtension, h as QueryDiscoveryInfo, V as ValidationResult, W as WithExtensions, i as bazaarResourceServerExtension, j as declareDiscoveryExtension, k as extractDiscoveryInfo, l as extractDiscoveryInfoFromExtension, m as extractDiscoveryInfoV1, n as extractResourceMetadataV1, o as isDiscoverableV1, v as validateAndExtract, p as validateDiscoveryExtension, w as withBazaar } from './index-DvDlinmy.mjs';
export { B as BAZAAR, a as BazaarClientExtension, b as BodyDiscoveryExtension, c as BodyDiscoveryInfo, D as DeclareBodyDiscoveryExtensionConfig, d as DeclareDiscoveryExtensionConfig, e as DeclareDiscoveryExtensionInput, f as DeclareMcpDiscoveryExtensionConfig, g as DeclareQueryDiscoveryExtensionConfig, h as DiscoveredHTTPResource, i as DiscoveredMCPResource, j as DiscoveredResource, k as DiscoveryExtension, l as DiscoveryInfo, m as DiscoveryResource, n as DiscoveryResourcesResponse, L as ListDiscoveryResourcesParams, M as McpDiscoveryExtension, o as McpDiscoveryInfo, Q as QueryDiscoveryExtension, p as QueryDiscoveryInfo, V as ValidationResult, W as WithExtensions, q as bazaarResourceServerExtension, r as declareDiscoveryExtension, s as extractDiscoveryInfo, t as extractDiscoveryInfoFromExtension, u as extractDiscoveryInfoV1, v as extractResourceMetadataV1, w as isBodyExtensionConfig, x as isDiscoverableV1, y as isMcpExtensionConfig, z as isQueryExtensionConfig, A as validateAndExtract, C as validateDiscoveryExtension, E as withBazaar } from './index-G8RNfr6X.mjs';
export { CompleteSIWxInfo, CreateSIWxHookOptions, DeclareSIWxOptions, EVMMessageVerifier, EVMSigner, InMemorySIWxStorage, SIGN_IN_WITH_X, SIWxExtension, SIWxExtensionInfo, SIWxExtensionSchema, SIWxHookEvent, SIWxPayload, SIWxPayloadSchema, SIWxSigner, SIWxStorage, SIWxValidationOptions, SIWxValidationResult, SIWxVerifyOptions, SIWxVerifyResult, SOLANA_DEVNET, SOLANA_MAINNET, SOLANA_TESTNET, SignatureScheme, SignatureType, SolanaSigner, SupportedChain, buildSIWxSchema, createSIWxClientHook, createSIWxMessage, createSIWxPayload, createSIWxRequestHook, createSIWxSettleHook, declareSIWxExtension, decodeBase58, encodeBase58, encodeSIWxHeader, extractEVMChainId, extractSolanaChainReference, formatSIWEMessage, formatSIWSMessage, getEVMAddress, getSolanaAddress, isEVMSigner, isSolanaSigner, parseSIWxHeader, signEVMMessage, signSolanaMessage, siwxResourceServerExtension, validateSIWxMessage, verifyEVMSignature, verifySIWxSignature, verifySolanaSignature, wrapFetchWithSIWx } from './sign-in-with-x/index.mjs';
export { PAYMENT_IDENTIFIER, PAYMENT_ID_MAX_LENGTH, PAYMENT_ID_MIN_LENGTH, PAYMENT_ID_PATTERN, PaymentIdentifierExtension, PaymentIdentifierInfo, PaymentIdentifierSchema, PaymentIdentifierValidationResult, appendPaymentIdentifierToExtensions, declarePaymentIdentifierExtension, extractAndValidatePaymentIdentifier, extractPaymentIdentifier, generatePaymentId, hasPaymentIdentifier, isPaymentIdentifierExtension, isPaymentIdentifierRequired, isValidPaymentId, paymentIdentifierResourceServerExtension, paymentIdentifierSchema, validatePaymentIdentifier, validatePaymentIdentifierRequirement } from './payment-identifier/index.mjs';
import { FacilitatorExtension, PaymentPayload } from '@x402/core/types';
import '@x402/core/http';
import '@x402/core/types';
import 'zod';
/**
* Type definitions for the EIP-2612 Gas Sponsoring Extension
*
* This extension enables gasless approval of the Permit2 contract for tokens
* that implement EIP-2612. The client signs an off-chain permit, and the
* facilitator submits it on-chain via `x402Permit2Proxy.settleWithPermit`.
*/
/**
* Extension identifier for the EIP-2612 gas sponsoring extension.
*/
declare const EIP2612_GAS_SPONSORING: FacilitatorExtension;
/**
* EIP-2612 gas sponsoring info populated by the client.
*
* Contains the EIP-2612 permit signature and parameters that the facilitator
* needs to call `x402Permit2Proxy.settleWithPermit`.
*/
interface Eip2612GasSponsoringInfo {
/** Index signature for compatibility with Record<string, unknown> */
[key: string]: unknown;
/** The address of the sender (token owner). */
from: string;
/** The address of the ERC-20 token contract. */
asset: string;
/** The address of the spender (Canonical Permit2). */
spender: string;
/** The amount to approve (uint256 as decimal string). Typically MaxUint256. */
amount: string;
/** The current EIP-2612 nonce of the sender (decimal string). */
nonce: string;
/** The timestamp at which the permit signature expires (decimal string). */
deadline: string;
/** The 65-byte concatenated EIP-2612 permit signature (r, s, v) as a hex string. */
signature: string;
/** Schema version identifier. */
version: string;
}
/**
* Server-side EIP-2612 gas sponsoring info included in PaymentRequired.
* Contains a description and version; the client populates the rest.
*/
interface Eip2612GasSponsoringServerInfo {
/** Index signature for compatibility with Record<string, unknown> */
[key: string]: unknown;
/** Human-readable description of the extension. */
description: string;
/** Schema version identifier. */
version: string;
}
/**
* The full extension object as it appears in PaymentRequired.extensions
* and PaymentPayload.extensions.
*/
interface Eip2612GasSponsoringExtension {
/** Extension info - server-provided or client-enriched. */
info: Eip2612GasSponsoringServerInfo | Eip2612GasSponsoringInfo;
/** JSON Schema describing the expected structure of info. */
schema: Record<string, unknown>;
}
/**
* Resource Service functions for declaring the EIP-2612 Gas Sponsoring extension.
*
* These functions help servers declare support for EIP-2612 gasless Permit2 approvals
* in the PaymentRequired response extensions.
*/
/**
* Declares the EIP-2612 gas sponsoring extension for inclusion in
* PaymentRequired.extensions.
*
* The server advertises that it (or its facilitator) supports EIP-2612
* gasless Permit2 approval. The client will populate the info with the
* actual permit signature data.
*
* @returns An object keyed by the extension identifier containing the extension declaration
*
* @example
* ```typescript
* import { declareEip2612GasSponsoringExtension } from '@x402/extensions';
*
* const routes = [
* {
* path: "/api/data",
* price: "$0.01",
* extensions: {
* ...declareEip2612GasSponsoringExtension(),
* },
* },
* ];
* ```
*/
declare function declareEip2612GasSponsoringExtension(): Record<string, Eip2612GasSponsoringExtension>;
/**
* Facilitator functions for extracting and validating EIP-2612 Gas Sponsoring extension data.
*
* These functions help facilitators extract the EIP-2612 permit data from payment
* payloads and validate it before calling settleWithPermit.
*/
/**
* Extracts the EIP-2612 gas sponsoring info from a payment payload's extensions.
*
* Returns the info if the extension is present and contains the required client-populated
* fields (from, asset, spender, amount, nonce, deadline, signature, version).
*
* @param paymentPayload - The payment payload to extract from
* @returns The EIP-2612 gas sponsoring info, or null if not present
*/
declare function extractEip2612GasSponsoringInfo(paymentPayload: PaymentPayload): Eip2612GasSponsoringInfo | null;
/**
* Validates that the EIP-2612 gas sponsoring info has valid format.
*
* Performs basic validation on the info fields:
* - Addresses are valid hex (0x + 40 hex chars)
* - Amount, nonce, deadline are numeric strings
* - Signature is a hex string
* - Version is a numeric version string
*
* @param info - The EIP-2612 gas sponsoring info to validate
* @returns True if the info is valid, false otherwise
*/
declare function validateEip2612GasSponsoringInfo(info: Eip2612GasSponsoringInfo): boolean;
export { EIP2612_GAS_SPONSORING, type Eip2612GasSponsoringExtension, type Eip2612GasSponsoringInfo, type Eip2612GasSponsoringServerInfo, declareEip2612GasSponsoringExtension, extractEip2612GasSponsoringInfo, validateEip2612GasSponsoringInfo };

@@ -9,7 +9,10 @@ import {

extractResourceMetadataV1,
isBodyExtensionConfig,
isDiscoverableV1,
isMcpExtensionConfig,
isQueryExtensionConfig,
validateAndExtract,
validateDiscoveryExtension,
withBazaar
} from "./chunk-DFJ4ZQFO.mjs";
} from "./chunk-ANAQVNUK.mjs";
import {

@@ -69,4 +72,92 @@ InMemorySIWxStorage,

} from "./chunk-73HCOE6N.mjs";
// src/eip2612-gas-sponsoring/types.ts
var EIP2612_GAS_SPONSORING = { key: "eip2612GasSponsoring" };
// src/eip2612-gas-sponsoring/resourceService.ts
var eip2612GasSponsoringSchema = {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
from: {
type: "string",
pattern: "^0x[a-fA-F0-9]{40}$",
description: "The address of the sender."
},
asset: {
type: "string",
pattern: "^0x[a-fA-F0-9]{40}$",
description: "The address of the ERC-20 token contract."
},
spender: {
type: "string",
pattern: "^0x[a-fA-F0-9]{40}$",
description: "The address of the spender (Canonical Permit2)."
},
amount: {
type: "string",
pattern: "^[0-9]+$",
description: "The amount to approve (uint256). Typically MaxUint."
},
nonce: {
type: "string",
pattern: "^[0-9]+$",
description: "The current nonce of the sender."
},
deadline: {
type: "string",
pattern: "^[0-9]+$",
description: "The timestamp at which the signature expires."
},
signature: {
type: "string",
pattern: "^0x[a-fA-F0-9]+$",
description: "The 65-byte concatenated signature (r, s, v) as a hex string."
},
version: {
type: "string",
pattern: "^[0-9]+(\\.[0-9]+)*$",
description: "Schema version identifier."
}
},
required: ["from", "asset", "spender", "amount", "nonce", "deadline", "signature", "version"]
};
function declareEip2612GasSponsoringExtension() {
const key = EIP2612_GAS_SPONSORING.key;
return {
[key]: {
info: {
description: "The facilitator accepts EIP-2612 gasless Permit to `Permit2` canonical contract.",
version: "1"
},
schema: eip2612GasSponsoringSchema
}
};
}
// src/eip2612-gas-sponsoring/facilitator.ts
function extractEip2612GasSponsoringInfo(paymentPayload) {
if (!paymentPayload.extensions) {
return null;
}
const extension = paymentPayload.extensions[EIP2612_GAS_SPONSORING.key];
if (!extension?.info) {
return null;
}
const info = extension.info;
if (!info.from || !info.asset || !info.spender || !info.amount || !info.nonce || !info.deadline || !info.signature || !info.version) {
return null;
}
return info;
}
function validateEip2612GasSponsoringInfo(info) {
const addressPattern = /^0x[a-fA-F0-9]{40}$/;
const numericPattern = /^[0-9]+$/;
const hexPattern = /^0x[a-fA-F0-9]+$/;
const versionPattern = /^[0-9]+(\.[0-9]+)*$/;
return addressPattern.test(info.from) && addressPattern.test(info.asset) && addressPattern.test(info.spender) && numericPattern.test(info.amount) && numericPattern.test(info.nonce) && numericPattern.test(info.deadline) && hexPattern.test(info.signature) && versionPattern.test(info.version);
}
export {
BAZAAR,
EIP2612_GAS_SPONSORING,
InMemorySIWxStorage,

@@ -91,2 +182,3 @@ PAYMENT_IDENTIFIER,

declareDiscoveryExtension,
declareEip2612GasSponsoringExtension,
declarePaymentIdentifierExtension,

@@ -102,2 +194,3 @@ declareSIWxExtension,

extractEVMChainId,
extractEip2612GasSponsoringInfo,
extractPaymentIdentifier,

@@ -112,6 +205,9 @@ extractResourceMetadataV1,

hasPaymentIdentifier,
isBodyExtensionConfig,
isDiscoverableV1,
isEVMSigner,
isMcpExtensionConfig,
isPaymentIdentifierExtension,
isPaymentIdentifierRequired,
isQueryExtensionConfig,
isSolanaSigner,

@@ -127,2 +223,3 @@ isValidPaymentId,

validateDiscoveryExtension,
validateEip2612GasSponsoringInfo,
validatePaymentIdentifier,

@@ -129,0 +226,0 @@ validatePaymentIdentifierRequirement,

@@ -1,1 +0,1 @@

{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
{"version":3,"sources":["../../src/eip2612-gas-sponsoring/types.ts","../../src/eip2612-gas-sponsoring/resourceService.ts","../../src/eip2612-gas-sponsoring/facilitator.ts"],"sourcesContent":["/**\n * Type definitions for the EIP-2612 Gas Sponsoring Extension\n *\n * This extension enables gasless approval of the Permit2 contract for tokens\n * that implement EIP-2612. The client signs an off-chain permit, and the\n * facilitator submits it on-chain via `x402Permit2Proxy.settleWithPermit`.\n */\n\nimport type { FacilitatorExtension } from \"@x402/core/types\";\n\n/**\n * Extension identifier for the EIP-2612 gas sponsoring extension.\n */\nexport const EIP2612_GAS_SPONSORING: FacilitatorExtension = { key: \"eip2612GasSponsoring\" };\n\n/**\n * EIP-2612 gas sponsoring info populated by the client.\n *\n * Contains the EIP-2612 permit signature and parameters that the facilitator\n * needs to call `x402Permit2Proxy.settleWithPermit`.\n */\nexport interface Eip2612GasSponsoringInfo {\n /** Index signature for compatibility with Record<string, unknown> */\n [key: string]: unknown;\n /** The address of the sender (token owner). */\n from: string;\n /** The address of the ERC-20 token contract. */\n asset: string;\n /** The address of the spender (Canonical Permit2). */\n spender: string;\n /** The amount to approve (uint256 as decimal string). Typically MaxUint256. */\n amount: string;\n /** The current EIP-2612 nonce of the sender (decimal string). */\n nonce: string;\n /** The timestamp at which the permit signature expires (decimal string). */\n deadline: string;\n /** The 65-byte concatenated EIP-2612 permit signature (r, s, v) as a hex string. */\n signature: string;\n /** Schema version identifier. */\n version: string;\n}\n\n/**\n * Server-side EIP-2612 gas sponsoring info included in PaymentRequired.\n * Contains a description and version; the client populates the rest.\n */\nexport interface Eip2612GasSponsoringServerInfo {\n /** Index signature for compatibility with Record<string, unknown> */\n [key: string]: unknown;\n /** Human-readable description of the extension. */\n description: string;\n /** Schema version identifier. */\n version: string;\n}\n\n/**\n * The full extension object as it appears in PaymentRequired.extensions\n * and PaymentPayload.extensions.\n */\nexport interface Eip2612GasSponsoringExtension {\n /** Extension info - server-provided or client-enriched. */\n info: Eip2612GasSponsoringServerInfo | Eip2612GasSponsoringInfo;\n /** JSON Schema describing the expected structure of info. */\n schema: Record<string, unknown>;\n}\n","/**\n * Resource Service functions for declaring the EIP-2612 Gas Sponsoring extension.\n *\n * These functions help servers declare support for EIP-2612 gasless Permit2 approvals\n * in the PaymentRequired response extensions.\n */\n\nimport { EIP2612_GAS_SPONSORING, type Eip2612GasSponsoringExtension } from \"./types\";\n\n/**\n * The JSON Schema for the EIP-2612 gas sponsoring extension info.\n * Matches the schema defined in the spec.\n */\nconst eip2612GasSponsoringSchema: Record<string, unknown> = {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties: {\n from: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the sender.\",\n },\n asset: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the ERC-20 token contract.\",\n },\n spender: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the spender (Canonical Permit2).\",\n },\n amount: {\n type: \"string\",\n pattern: \"^[0-9]+$\",\n description: \"The amount to approve (uint256). Typically MaxUint.\",\n },\n nonce: {\n type: \"string\",\n pattern: \"^[0-9]+$\",\n description: \"The current nonce of the sender.\",\n },\n deadline: {\n type: \"string\",\n pattern: \"^[0-9]+$\",\n description: \"The timestamp at which the signature expires.\",\n },\n signature: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]+$\",\n description: \"The 65-byte concatenated signature (r, s, v) as a hex string.\",\n },\n version: {\n type: \"string\",\n pattern: \"^[0-9]+(\\\\.[0-9]+)*$\",\n description: \"Schema version identifier.\",\n },\n },\n required: [\"from\", \"asset\", \"spender\", \"amount\", \"nonce\", \"deadline\", \"signature\", \"version\"],\n};\n\n/**\n * Declares the EIP-2612 gas sponsoring extension for inclusion in\n * PaymentRequired.extensions.\n *\n * The server advertises that it (or its facilitator) supports EIP-2612\n * gasless Permit2 approval. The client will populate the info with the\n * actual permit signature data.\n *\n * @returns An object keyed by the extension identifier containing the extension declaration\n *\n * @example\n * ```typescript\n * import { declareEip2612GasSponsoringExtension } from '@x402/extensions';\n *\n * const routes = [\n * {\n * path: \"/api/data\",\n * price: \"$0.01\",\n * extensions: {\n * ...declareEip2612GasSponsoringExtension(),\n * },\n * },\n * ];\n * ```\n */\nexport function declareEip2612GasSponsoringExtension(): Record<\n string,\n Eip2612GasSponsoringExtension\n> {\n const key = EIP2612_GAS_SPONSORING.key;\n return {\n [key]: {\n info: {\n description:\n \"The facilitator accepts EIP-2612 gasless Permit to `Permit2` canonical contract.\",\n version: \"1\",\n },\n schema: eip2612GasSponsoringSchema,\n },\n };\n}\n","/**\n * Facilitator functions for extracting and validating EIP-2612 Gas Sponsoring extension data.\n *\n * These functions help facilitators extract the EIP-2612 permit data from payment\n * payloads and validate it before calling settleWithPermit.\n */\n\nimport type { PaymentPayload } from \"@x402/core/types\";\nimport {\n EIP2612_GAS_SPONSORING,\n type Eip2612GasSponsoringInfo,\n type Eip2612GasSponsoringExtension,\n} from \"./types\";\n\n/**\n * Extracts the EIP-2612 gas sponsoring info from a payment payload's extensions.\n *\n * Returns the info if the extension is present and contains the required client-populated\n * fields (from, asset, spender, amount, nonce, deadline, signature, version).\n *\n * @param paymentPayload - The payment payload to extract from\n * @returns The EIP-2612 gas sponsoring info, or null if not present\n */\nexport function extractEip2612GasSponsoringInfo(\n paymentPayload: PaymentPayload,\n): Eip2612GasSponsoringInfo | null {\n if (!paymentPayload.extensions) {\n return null;\n }\n\n const extension = paymentPayload.extensions[EIP2612_GAS_SPONSORING.key] as\n | Eip2612GasSponsoringExtension\n | undefined;\n\n if (!extension?.info) {\n return null;\n }\n\n const info = extension.info as Record<string, unknown>;\n\n // Check that the client has populated the required fields\n if (\n !info.from ||\n !info.asset ||\n !info.spender ||\n !info.amount ||\n !info.nonce ||\n !info.deadline ||\n !info.signature ||\n !info.version\n ) {\n return null;\n }\n\n return info as unknown as Eip2612GasSponsoringInfo;\n}\n\n/**\n * Validates that the EIP-2612 gas sponsoring info has valid format.\n *\n * Performs basic validation on the info fields:\n * - Addresses are valid hex (0x + 40 hex chars)\n * - Amount, nonce, deadline are numeric strings\n * - Signature is a hex string\n * - Version is a numeric version string\n *\n * @param info - The EIP-2612 gas sponsoring info to validate\n * @returns True if the info is valid, false otherwise\n */\nexport function validateEip2612GasSponsoringInfo(info: Eip2612GasSponsoringInfo): boolean {\n const addressPattern = /^0x[a-fA-F0-9]{40}$/;\n const numericPattern = /^[0-9]+$/;\n const hexPattern = /^0x[a-fA-F0-9]+$/;\n const versionPattern = /^[0-9]+(\\.[0-9]+)*$/;\n\n return (\n addressPattern.test(info.from) &&\n addressPattern.test(info.asset) &&\n addressPattern.test(info.spender) &&\n numericPattern.test(info.amount) &&\n numericPattern.test(info.nonce) &&\n numericPattern.test(info.deadline) &&\n hexPattern.test(info.signature) &&\n versionPattern.test(info.version)\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaO,IAAM,yBAA+C,EAAE,KAAK,uBAAuB;;;ACA1F,IAAM,6BAAsD;AAAA,EAC1D,SAAS;AAAA,EACT,MAAM;AAAA,EACN,YAAY;AAAA,IACV,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,WAAW;AAAA,MACT,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,UAAU,CAAC,QAAQ,SAAS,WAAW,UAAU,SAAS,YAAY,aAAa,SAAS;AAC9F;AA2BO,SAAS,uCAGd;AACA,QAAM,MAAM,uBAAuB;AACnC,SAAO;AAAA,IACL,CAAC,GAAG,GAAG;AAAA,MACL,MAAM;AAAA,QACJ,aACE;AAAA,QACF,SAAS;AAAA,MACX;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACF;;;AC9EO,SAAS,gCACd,gBACiC;AACjC,MAAI,CAAC,eAAe,YAAY;AAC9B,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,eAAe,WAAW,uBAAuB,GAAG;AAItE,MAAI,CAAC,WAAW,MAAM;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,UAAU;AAGvB,MACE,CAAC,KAAK,QACN,CAAC,KAAK,SACN,CAAC,KAAK,WACN,CAAC,KAAK,UACN,CAAC,KAAK,SACN,CAAC,KAAK,YACN,CAAC,KAAK,aACN,CAAC,KAAK,SACN;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAcO,SAAS,iCAAiC,MAAyC;AACxF,QAAM,iBAAiB;AACvB,QAAM,iBAAiB;AACvB,QAAM,aAAa;AACnB,QAAM,iBAAiB;AAEvB,SACE,eAAe,KAAK,KAAK,IAAI,KAC7B,eAAe,KAAK,KAAK,KAAK,KAC9B,eAAe,KAAK,KAAK,OAAO,KAChC,eAAe,KAAK,KAAK,MAAM,KAC/B,eAAe,KAAK,KAAK,KAAK,KAC9B,eAAe,KAAK,KAAK,QAAQ,KACjC,WAAW,KAAK,KAAK,SAAS,KAC9B,eAAe,KAAK,KAAK,OAAO;AAEpC;","names":[]}
{
"name": "@x402/extensions",
"version": "2.3.1",
"version": "2.4.0",
"main": "./dist/cjs/index.js",

@@ -41,3 +41,3 @@ "module": "./dist/esm/index.js",

"zod": "^3.24.2",
"@x402/core": "~2.3.1"
"@x402/core": "~2.4.0"
},

@@ -44,0 +44,0 @@ "exports": {

@@ -187,2 +187,48 @@ # @x402/extensions

#### Example: MCP Tool
For MCP (Model Context Protocol) tools, use the `toolName` field instead of `bodyType`/`input`. The HTTP method is not relevant -- MCP tools are invoked by name.
```typescript
import { declareDiscoveryExtension } from "@x402/extensions/bazaar";
const resources = {
"POST /mcp": {
accepts: {
scheme: "exact",
price: "$0.01",
network: "eip155:84532",
payTo: "0xYourAddress"
},
extensions: {
...declareDiscoveryExtension({
toolName: "financial_analysis",
description: "Analyze financial data for a given ticker",
inputSchema: {
type: "object",
properties: {
ticker: { type: "string", description: "Stock ticker symbol" },
analysis_type: {
type: "string",
enum: ["fundamental", "technical", "sentiment"],
},
},
required: ["ticker"],
},
example: { ticker: "AAPL", analysis_type: "fundamental" },
output: {
example: {
pe_ratio: 28.5,
recommendation: "hold",
confidence: 0.85
}
},
}),
},
},
};
```
You can optionally specify `transport` to indicate the MCP transport type (`"streamable-http"` or `"sse"`). When omitted, `streamable-http` is assumed per the MCP spec.
#### Using with Next.js Middleware

@@ -309,5 +355,5 @@

Creates a discovery extension object for resource servers.
Creates a discovery extension object for resource servers. Accepts either an HTTP endpoint config or an MCP tool config.
**Parameters:**
**HTTP Parameters:**
- `config.input` (optional): Example input values (query params for GET/HEAD/DELETE, body for POST/PUT/PATCH)

@@ -322,7 +368,18 @@ - `config.inputSchema` (optional): JSON Schema for input validation

**MCP Parameters:**
- `config.toolName` (required): MCP tool name — the presence of this field identifies the config as MCP
- `config.description` (optional): Human-readable tool description
- `config.inputSchema` (required): JSON Schema for tool arguments
- `config.example` (optional): Example tool arguments
- `config.transport` (optional): MCP transport type (`"streamable-http"` or `"sse"`). Defaults to `streamable-http` per the MCP spec when omitted.
- `config.output` (optional): Output specification
- `output.example`: Example output data
- `output.schema`: JSON Schema for output validation
**Returns:** An object with a `bazaar` key containing the discovery extension.
**Example:**
**Examples:**
```typescript
const extension = declareDiscoveryExtension({
// HTTP endpoint
const httpExtension = declareDiscoveryExtension({
input: { query: "search term" },

@@ -337,3 +394,17 @@ inputSchema: {

});
// Returns: { bazaar: { info: {...}, schema: {...} } }
// MCP tool
const mcpExtension = declareDiscoveryExtension({
toolName: "search",
description: "Search for documents",
inputSchema: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"]
},
output: {
example: { results: [] }
}
});
// Both return: { bazaar: { info: {...}, schema: {...} } }
```

@@ -353,8 +424,17 @@

```typescript
interface DiscoveredResource {
interface DiscoveredHTTPResource {
resourceUrl: string;
method: string;
method: string; // e.g. "GET", "POST"
x402Version: number;
discoveryInfo: DiscoveryInfo;
}
interface DiscoveredMCPResource {
resourceUrl: string;
toolName: string; // MCP tool name
x402Version: number;
discoveryInfo: DiscoveryInfo;
}
type DiscoveredResource = DiscoveredHTTPResource | DiscoveredMCPResource;
```

@@ -376,3 +456,3 @@

A server extension that automatically enriches discovery extensions with HTTP method information from the request context.
A server extension that automatically enriches HTTP discovery extensions with method information from the request context. MCP extensions are passed through unchanged.

@@ -379,0 +459,0 @@ **Usage:**

import { BodyMethods, QueryParamMethods, HTTPFacilitatorClient } from '@x402/core/http';
import { ResourceServerExtension, PaymentPayload, PaymentRequirements, PaymentRequirementsV1 } from '@x402/core/types';
/**
* Shared type utilities for x402 extensions
*/
/**
* Type utility to merge extensions properly when chaining.
* If T already has extensions, merge them; otherwise add new extensions.
*
* @example
* ```ts
* // Chaining multiple extensions preserves all types:
* const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient()));
* // Type: HTTPFacilitatorClient & { extensions: OtherExtension & BazaarExtension }
* ```
*/
type WithExtensions<T, E> = T extends {
extensions: infer Existing;
} ? Omit<T, "extensions"> & {
extensions: Existing & E;
} : T & {
extensions: E;
};
/**
* Type definitions for the Bazaar Discovery Extension
*/
/**
* Extension identifier constant for the Bazaar discovery extension
*/
declare const BAZAAR = "bazaar";
/**
* Discovery info for query parameter methods (GET, HEAD, DELETE)
*/
interface QueryDiscoveryInfo {
input: {
type: "http";
method: QueryParamMethods;
queryParams?: Record<string, unknown>;
headers?: Record<string, string>;
};
output?: {
type?: string;
format?: string;
example?: unknown;
};
}
/**
* Discovery info for body methods (POST, PUT, PATCH)
*/
interface BodyDiscoveryInfo {
input: {
type: "http";
method: BodyMethods;
bodyType: "json" | "form-data" | "text";
body: Record<string, unknown>;
queryParams?: Record<string, unknown>;
headers?: Record<string, string>;
};
output?: {
type?: string;
format?: string;
example?: unknown;
};
}
/**
* Combined discovery info type
*/
type DiscoveryInfo = QueryDiscoveryInfo | BodyDiscoveryInfo;
/**
* Discovery extension for query parameter methods (GET, HEAD, DELETE)
*/
interface QueryDiscoveryExtension {
info: QueryDiscoveryInfo;
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema";
type: "object";
properties: {
input: {
type: "object";
properties: {
type: {
type: "string";
const: "http";
};
method: {
type: "string";
enum: QueryParamMethods[];
};
queryParams?: {
type: "object";
properties?: Record<string, unknown>;
required?: string[];
additionalProperties?: boolean;
};
headers?: {
type: "object";
additionalProperties: {
type: "string";
};
};
};
required: ("type" | "method")[];
additionalProperties?: boolean;
};
output?: {
type: "object";
properties?: Record<string, unknown>;
required?: readonly string[];
additionalProperties?: boolean;
};
};
required: ["input"];
};
}
/**
* Discovery extension for body methods (POST, PUT, PATCH)
*/
interface BodyDiscoveryExtension {
info: BodyDiscoveryInfo;
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema";
type: "object";
properties: {
input: {
type: "object";
properties: {
type: {
type: "string";
const: "http";
};
method: {
type: "string";
enum: BodyMethods[];
};
bodyType: {
type: "string";
enum: ["json", "form-data", "text"];
};
body: Record<string, unknown>;
queryParams?: {
type: "object";
properties?: Record<string, unknown>;
required?: string[];
additionalProperties?: boolean;
};
headers?: {
type: "object";
additionalProperties: {
type: "string";
};
};
};
required: ("type" | "method" | "bodyType" | "body")[];
additionalProperties?: boolean;
};
output?: {
type: "object";
properties?: Record<string, unknown>;
required?: readonly string[];
additionalProperties?: boolean;
};
};
required: ["input"];
};
}
/**
* Combined discovery extension type
*/
type DiscoveryExtension = QueryDiscoveryExtension | BodyDiscoveryExtension;
interface DeclareQueryDiscoveryExtensionConfig {
method?: QueryParamMethods;
input?: Record<string, unknown>;
inputSchema?: Record<string, unknown>;
output?: {
example?: unknown;
schema?: Record<string, unknown>;
};
}
interface DeclareBodyDiscoveryExtensionConfig {
method?: BodyMethods;
input?: Record<string, unknown>;
inputSchema?: Record<string, unknown>;
bodyType: "json" | "form-data" | "text";
output?: {
example?: unknown;
schema?: Record<string, unknown>;
};
}
type DeclareDiscoveryExtensionConfig = DeclareQueryDiscoveryExtensionConfig | DeclareBodyDiscoveryExtensionConfig;
/**
* Distributive Omit - properly distributes Omit over union types.
*
* Standard `Omit<A | B, K>` collapses to common properties only,
* losing discriminant properties like `bodyType`.
*
* This type uses conditional type distribution to preserve the union:
* `DistributiveOmit<A | B, K>` = `Omit<A, K> | Omit<B, K>`
*/
type DistributiveOmit<T, K extends keyof T> = T extends T ? Omit<T, K> : never;
/**
* Config type for declareDiscoveryExtension function.
* Uses DistributiveOmit to preserve bodyType discriminant in the union.
*/
type DeclareDiscoveryExtensionInput = DistributiveOmit<DeclareDiscoveryExtensionConfig, "method">;
/**
* Resource Service functions for creating Bazaar discovery extensions
*
* These functions help servers declare the shape of their endpoints
* for facilitator discovery and cataloging in the Bazaar.
*/
/**
* Create a discovery extension for any HTTP method
*
* This function helps servers declare how their endpoint should be called,
* including the expected input parameters/body and output format.
*
* @param config - Configuration object for the discovery extension
* @returns A discovery extension object with both info and schema
*
* @example
* ```typescript
* // For a GET endpoint with no input
* const getExtension = declareDiscoveryExtension({
* method: "GET",
* output: {
* example: { message: "Success", timestamp: "2024-01-01T00:00:00Z" }
* }
* });
*
* // For a GET endpoint with query params
* const getWithParams = declareDiscoveryExtension({
* method: "GET",
* input: { query: "example" },
* inputSchema: {
* properties: {
* query: { type: "string" }
* },
* required: ["query"]
* }
* });
*
* // For a POST endpoint with JSON body
* const postExtension = declareDiscoveryExtension({
* method: "POST",
* input: { name: "John", age: 30 },
* inputSchema: {
* properties: {
* name: { type: "string" },
* age: { type: "number" }
* },
* required: ["name"]
* },
* bodyType: "json",
* output: {
* example: { success: true, id: "123" }
* }
* });
* ```
*/
declare function declareDiscoveryExtension(config: DeclareDiscoveryExtensionInput): Record<string, DiscoveryExtension>;
declare const bazaarResourceServerExtension: ResourceServerExtension;
/**
* Facilitator functions for validating and extracting Bazaar discovery extensions
*
* These functions help facilitators validate extension data against schemas
* and extract the discovery information for cataloging in the Bazaar.
*
* Supports both v2 (extensions in PaymentRequired) and v1 (outputSchema in PaymentRequirements).
*/
/**
* Validation result for discovery extensions
*/
interface ValidationResult {
valid: boolean;
errors?: string[];
}
/**
* Validates a discovery extension's info against its schema
*
* @param extension - The discovery extension containing info and schema
* @returns Validation result indicating if the info matches the schema
*
* @example
* ```typescript
* const extension = declareDiscoveryExtension(...);
* const result = validateDiscoveryExtension(extension);
*
* if (result.valid) {
* console.log("Extension is valid");
* } else {
* console.error("Validation errors:", result.errors);
* }
* ```
*/
declare function validateDiscoveryExtension(extension: DiscoveryExtension): ValidationResult;
/**
* Extracts the discovery info from payment payload and requirements
*
* This function handles both v2 (extensions) and v1 (outputSchema) formats.
*
* For v2: Discovery info is in PaymentPayload.extensions (client copied it from PaymentRequired)
* For v1: Discovery info is in PaymentRequirements.outputSchema
*
* V1 data is automatically transformed to v2 DiscoveryInfo format, making smart
* assumptions about field names (queryParams/query/params for GET, bodyFields/body/data for POST, etc.)
*
* @param paymentPayload - The payment payload containing extensions (v2) and version info
* @param paymentRequirements - The payment requirements (contains outputSchema for v1)
* @param validate - Whether to validate v2 extensions before extracting (default: true)
* @returns The discovery info in v2 format if present, or null if not discoverable
*
* @example
* ```typescript
* // V2 - extensions are in PaymentPayload
* const info = extractDiscoveryInfo(paymentPayload, paymentRequirements);
*
* // V1 - discovery info is in PaymentRequirements.outputSchema
* const info = extractDiscoveryInfo(paymentPayloadV1, paymentRequirementsV1);
*
* if (info) {
* // Both v1 and v2 return the same DiscoveryInfo structure
* console.log("Method:", info.input.method);
* }
* ```
*/
interface DiscoveredResource {
resourceUrl: string;
description?: string;
mimeType?: string;
method: string;
x402Version: number;
discoveryInfo: DiscoveryInfo;
}
/**
* Extracts discovery information from payment payload and requirements.
* Combines resource URL, HTTP method, version, and discovery info into a single object.
*
* @param paymentPayload - The payment payload containing extensions and resource info
* @param paymentRequirements - The payment requirements to validate against
* @param validate - Whether to validate the discovery info against the schema (default: true)
* @returns Discovered resource info with URL, method, version and discovery data, or null if not found
*/
declare function extractDiscoveryInfo(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements | PaymentRequirementsV1, validate?: boolean): DiscoveredResource | null;
/**
* Extracts discovery info from a v2 extension directly
*
* This is a lower-level function for when you already have the extension object.
* For general use, prefer the main extractDiscoveryInfo function.
*
* @param extension - The discovery extension to extract info from
* @param validate - Whether to validate before extracting (default: true)
* @returns The discovery info if valid
* @throws Error if validation fails and validate is true
*/
declare function extractDiscoveryInfoFromExtension(extension: DiscoveryExtension, validate?: boolean): DiscoveryInfo;
/**
* Validates and extracts discovery info in one step
*
* This is a convenience function that combines validation and extraction,
* returning both the validation result and the info if valid.
*
* @param extension - The discovery extension to validate and extract
* @returns Object containing validation result and info (if valid)
*
* @example
* ```typescript
* const extension = declareDiscoveryExtension(...);
* const { valid, info, errors } = validateAndExtract(extension);
*
* if (valid && info) {
* // Store info in Bazaar catalog
* } else {
* console.error("Validation errors:", errors);
* }
* ```
*/
declare function validateAndExtract(extension: DiscoveryExtension): {
valid: boolean;
info?: DiscoveryInfo;
errors?: string[];
};
/**
* V1 Facilitator functions for extracting Bazaar discovery information
*
* In v1, discovery information is stored in the `outputSchema` field
* of PaymentRequirements, which has a different structure than v2.
*
* This module transforms v1 data into v2 DiscoveryInfo format.
*/
/**
* Extracts discovery info from v1 PaymentRequirements and transforms to v2 format
*
* In v1, the discovery information is stored in the `outputSchema` field,
* which contains both input (endpoint shape) and output (response schema) information.
*
* This function makes smart assumptions to normalize v1 data into v2 DiscoveryInfo format:
* - For GET/HEAD/DELETE: Looks for queryParams, query, or params fields
* - For POST/PUT/PATCH: Looks for bodyFields, body, or data fields and normalizes bodyType
* - Extracts optional headers if present
*
* @param paymentRequirements - V1 payment requirements
* @returns Discovery info in v2 format if present and valid, or null if not discoverable
*
* @example
* ```typescript
* const requirements: PaymentRequirementsV1 = {
* scheme: "exact",
* network: "eip155:8453",
* maxAmountRequired: "100000",
* resource: "https://api.example.com/data",
* description: "Get data",
* mimeType: "application/json",
* outputSchema: {
* input: {
* type: "http",
* method: "GET",
* discoverable: true,
* queryParams: { query: "string" }
* },
* output: { type: "object" }
* },
* payTo: "0x...",
* maxTimeoutSeconds: 300,
* asset: "0x...",
* extra: {}
* };
*
* const info = extractDiscoveryInfoV1(requirements);
* if (info) {
* console.log("Endpoint method:", info.input.method);
* }
* ```
*/
declare function extractDiscoveryInfoV1(paymentRequirements: PaymentRequirementsV1): DiscoveryInfo | null;
/**
* Checks if v1 PaymentRequirements contains discoverable information
*
* @param paymentRequirements - V1 payment requirements
* @returns True if the requirements contain valid discovery info
*
* @example
* ```typescript
* if (isDiscoverableV1(requirements)) {
* const info = extractDiscoveryInfoV1(requirements);
* // Catalog info in Bazaar
* }
* ```
*/
declare function isDiscoverableV1(paymentRequirements: PaymentRequirementsV1): boolean;
/**
* Extracts resource metadata from v1 PaymentRequirements
*
* In v1, resource information is embedded directly in the payment requirements
* rather than in a separate resource object.
*
* @param paymentRequirements - V1 payment requirements
* @returns Resource metadata
*
* @example
* ```typescript
* const metadata = extractResourceMetadataV1(requirements);
* console.log("Resource URL:", metadata.url);
* console.log("Description:", metadata.description);
* ```
*/
declare function extractResourceMetadataV1(paymentRequirements: PaymentRequirementsV1): {
url: string;
description: string;
mimeType: string;
};
/**
* Client extensions for querying Bazaar discovery resources
*/
/**
* Parameters for listing discovery resources.
* All parameters are optional and used for filtering/pagination.
*/
interface ListDiscoveryResourcesParams {
/**
* Filter by protocol type (e.g., "http", "mcp").
* Currently, the only supported protocol type is "http".
*/
type?: string;
/**
* The number of discovered x402 resources to return per page.
*/
limit?: number;
/**
* The offset of the first discovered x402 resource to return.
*/
offset?: number;
}
/**
* A discovered x402 resource from the bazaar.
*/
interface DiscoveryResource {
/** The URL or identifier of the discovered resource */
resource: string;
/** The protocol type of the resource (e.g., "http") */
type: string;
/** The x402 protocol version supported by this resource */
x402Version: number;
/** Array of accepted payment methods for this resource */
accepts: PaymentRequirements[];
/** ISO 8601 timestamp of when the resource was last updated */
lastUpdated: string;
/** Additional metadata about the resource */
metadata?: Record<string, unknown>;
}
/**
* Response from listing discovery resources.
*/
interface DiscoveryResourcesResponse {
/** The x402 protocol version of this response */
x402Version: number;
/** The list of discovered resources */
items: DiscoveryResource[];
/** Pagination information for the response */
pagination: {
/** Maximum number of results returned */
limit: number;
/** Number of results skipped */
offset: number;
/** Total count of resources matching the query */
total: number;
};
}
/**
* Bazaar client extension interface providing discovery query functionality.
*/
interface BazaarClientExtension {
discovery: {
/**
* List x402 discovery resources from the bazaar.
*
* @param params - Optional filtering and pagination parameters
* @returns A promise resolving to the discovery resources response
*/
listResources(params?: ListDiscoveryResourcesParams): Promise<DiscoveryResourcesResponse>;
};
}
/**
* Extends a facilitator client with Bazaar discovery query functionality.
* Preserves and merges with any existing extensions from prior chaining.
*
* @param client - The facilitator client to extend
* @returns The client extended with bazaar discovery capabilities
*
* @example
* ```ts
* // Basic usage
* const client = withBazaar(new HTTPFacilitatorClient());
* const resources = await client.extensions.discovery.listResources({ type: "http" });
*
* // Chaining with other extensions
* const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient()));
* await client.extensions.other.someMethod();
* await client.extensions.discovery.listResources();
* ```
*/
declare function withBazaar<T extends HTTPFacilitatorClient>(client: T): WithExtensions<T, BazaarClientExtension>;
export { BAZAAR as B, type DiscoveredResource as D, type ListDiscoveryResourcesParams as L, type QueryDiscoveryExtension as Q, type ValidationResult as V, type WithExtensions as W, type BazaarClientExtension as a, type BodyDiscoveryExtension as b, type BodyDiscoveryInfo as c, type DiscoveryExtension as d, type DiscoveryInfo as e, type DiscoveryResource as f, type DiscoveryResourcesResponse as g, type QueryDiscoveryInfo as h, bazaarResourceServerExtension as i, declareDiscoveryExtension as j, extractDiscoveryInfo as k, extractDiscoveryInfoFromExtension as l, extractDiscoveryInfoV1 as m, extractResourceMetadataV1 as n, isDiscoverableV1 as o, validateDiscoveryExtension as p, validateAndExtract as v, withBazaar as w };
// src/bazaar/types.ts
var BAZAAR = "bazaar";
// src/bazaar/resourceService.ts
function createQueryDiscoveryExtension({
method,
input = {},
inputSchema = { properties: {} },
output
}) {
return {
info: {
input: {
type: "http",
...method ? { method } : {},
...input ? { queryParams: input } : {}
},
...output?.example ? {
output: {
type: "json",
example: output.example
}
} : {}
},
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
input: {
type: "object",
properties: {
type: {
type: "string",
const: "http"
},
method: {
type: "string",
enum: ["GET", "HEAD", "DELETE"]
},
...inputSchema ? {
queryParams: {
type: "object",
...typeof inputSchema === "object" ? inputSchema : {}
}
} : {}
},
required: ["type"],
additionalProperties: false
},
...output?.example ? {
output: {
type: "object",
properties: {
type: {
type: "string"
},
example: {
type: "object",
...output.schema && typeof output.schema === "object" ? output.schema : {}
}
},
required: ["type"]
}
} : {}
},
required: ["input"]
}
};
}
function createBodyDiscoveryExtension({
method,
input = {},
inputSchema = { properties: {} },
bodyType,
output
}) {
return {
info: {
input: {
type: "http",
...method ? { method } : {},
bodyType,
body: input
},
...output?.example ? {
output: {
type: "json",
example: output.example
}
} : {}
},
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
input: {
type: "object",
properties: {
type: {
type: "string",
const: "http"
},
method: {
type: "string",
enum: ["POST", "PUT", "PATCH"]
},
bodyType: {
type: "string",
enum: ["json", "form-data", "text"]
},
body: inputSchema
},
required: ["type", "bodyType", "body"],
additionalProperties: false
},
...output?.example ? {
output: {
type: "object",
properties: {
type: {
type: "string"
},
example: {
type: "object",
...output.schema && typeof output.schema === "object" ? output.schema : {}
}
},
required: ["type"]
}
} : {}
},
required: ["input"]
}
};
}
function declareDiscoveryExtension(config) {
const bodyType = config.bodyType;
const isBodyMethod2 = bodyType !== void 0;
const extension = isBodyMethod2 ? createBodyDiscoveryExtension(config) : createQueryDiscoveryExtension(config);
return { bazaar: extension };
}
// src/bazaar/server.ts
function isHTTPRequestContext(ctx) {
return ctx !== null && typeof ctx === "object" && "method" in ctx && "adapter" in ctx;
}
var bazaarResourceServerExtension = {
key: BAZAAR,
enrichDeclaration: (declaration, transportContext) => {
if (!isHTTPRequestContext(transportContext)) {
return declaration;
}
const extension = declaration;
const method = transportContext.method;
const existingInputProps = extension.schema?.properties?.input?.properties || {};
const updatedInputProps = {
...existingInputProps,
method: {
type: "string",
enum: [method]
}
};
return {
...extension,
info: {
...extension.info || {},
input: {
...extension.info?.input || {},
method
}
},
schema: {
...extension.schema || {},
properties: {
...extension.schema?.properties || {},
input: {
...extension.schema?.properties?.input || {},
properties: updatedInputProps,
required: [
...extension.schema?.properties?.input?.required || [],
...!(extension.schema?.properties?.input?.required || []).includes("method") ? ["method"] : []
]
}
}
}
};
}
};
// src/bazaar/facilitator.ts
import Ajv from "ajv/dist/2020.js";
// src/bazaar/v1/facilitator.ts
function hasV1OutputSchema(obj) {
return obj !== null && typeof obj === "object" && "input" in obj && obj.input !== null && typeof obj.input === "object" && "type" in obj.input && obj.input.type === "http" && "method" in obj.input;
}
function isQueryMethod(method) {
const upperMethod = method.toUpperCase();
return upperMethod === "GET" || upperMethod === "HEAD" || upperMethod === "DELETE";
}
function isBodyMethod(method) {
const upperMethod = method.toUpperCase();
return upperMethod === "POST" || upperMethod === "PUT" || upperMethod === "PATCH";
}
function extractQueryParams(v1Input) {
if (v1Input.queryParams && typeof v1Input.queryParams === "object") {
return v1Input.queryParams;
}
if (v1Input.query_params && typeof v1Input.query_params === "object") {
return v1Input.query_params;
}
if (v1Input.query && typeof v1Input.query === "object") {
return v1Input.query;
}
if (v1Input.params && typeof v1Input.params === "object") {
return v1Input.params;
}
return void 0;
}
function extractBodyInfo(v1Input) {
let bodyType = "json";
const bodyTypeField = v1Input.bodyType || v1Input.body_type;
if (bodyTypeField && typeof bodyTypeField === "string") {
const type = bodyTypeField.toLowerCase();
if (type.includes("form") || type.includes("multipart")) {
bodyType = "form-data";
} else if (type.includes("text") || type.includes("plain")) {
bodyType = "text";
} else {
bodyType = "json";
}
}
let body = {};
if (v1Input.bodyFields && typeof v1Input.bodyFields === "object") {
body = v1Input.bodyFields;
} else if (v1Input.body_fields && v1Input.body_fields !== null && typeof v1Input.body_fields === "object") {
body = v1Input.body_fields;
} else if (v1Input.bodyParams && typeof v1Input.bodyParams === "object") {
body = v1Input.bodyParams;
} else if (v1Input.body && typeof v1Input.body === "object") {
body = v1Input.body;
} else if (v1Input.data && typeof v1Input.data === "object") {
body = v1Input.data;
} else if (v1Input.properties && typeof v1Input.properties === "object") {
body = v1Input.properties;
}
return { body, bodyType };
}
function extractDiscoveryInfoV1(paymentRequirements) {
const { outputSchema } = paymentRequirements;
if (!outputSchema || !hasV1OutputSchema(outputSchema)) {
return null;
}
const v1Input = outputSchema.input;
const isDiscoverable = v1Input.discoverable ?? true;
if (!isDiscoverable) {
return null;
}
const method = typeof v1Input.method === "string" ? v1Input.method.toUpperCase() : "";
const headersRaw = v1Input.headerFields || v1Input.header_fields || v1Input.headers;
const headers = headersRaw && typeof headersRaw === "object" ? headersRaw : void 0;
const output = outputSchema.output ? {
type: "json",
example: outputSchema.output
} : void 0;
if (isQueryMethod(method)) {
const queryParams = extractQueryParams(v1Input);
const discoveryInfo = {
input: {
type: "http",
method,
...queryParams ? { queryParams } : {},
...headers ? { headers } : {}
},
...output ? { output } : {}
};
return discoveryInfo;
} else if (isBodyMethod(method)) {
const { body, bodyType } = extractBodyInfo(v1Input);
const queryParams = extractQueryParams(v1Input);
const discoveryInfo = {
input: {
type: "http",
method,
bodyType,
body,
...queryParams ? { queryParams } : {},
...headers ? { headers } : {}
},
...output ? { output } : {}
};
return discoveryInfo;
}
return null;
}
function isDiscoverableV1(paymentRequirements) {
return extractDiscoveryInfoV1(paymentRequirements) !== null;
}
function extractResourceMetadataV1(paymentRequirements) {
return {
url: paymentRequirements.resource,
description: paymentRequirements.description,
mimeType: paymentRequirements.mimeType
};
}
// src/bazaar/facilitator.ts
function validateDiscoveryExtension(extension) {
try {
const ajv = new Ajv({ strict: false, allErrors: true });
const validate = ajv.compile(extension.schema);
const valid = validate(extension.info);
if (valid) {
return { valid: true };
}
const errors = validate.errors?.map((err) => {
const path = err.instancePath || "(root)";
return `${path}: ${err.message}`;
}) || ["Unknown validation error"];
return { valid: false, errors };
} catch (error) {
return {
valid: false,
errors: [
`Schema validation failed: ${error instanceof Error ? error.message : String(error)}`
]
};
}
}
function extractDiscoveryInfo(paymentPayload, paymentRequirements, validate = true) {
let discoveryInfo = null;
let resourceUrl;
if (paymentPayload.x402Version === 2) {
resourceUrl = paymentPayload.resource?.url ?? "";
if (paymentPayload.extensions) {
const bazaarExtension = paymentPayload.extensions[BAZAAR];
if (bazaarExtension && typeof bazaarExtension === "object") {
try {
const extension = bazaarExtension;
if (validate) {
const result = validateDiscoveryExtension(extension);
if (!result.valid) {
console.warn(
`V2 discovery extension validation failed: ${result.errors?.join(", ")}`
);
} else {
discoveryInfo = extension.info;
}
} else {
discoveryInfo = extension.info;
}
} catch (error) {
console.warn(`V2 discovery extension extraction failed: ${error}`);
}
}
}
} else if (paymentPayload.x402Version === 1) {
const requirementsV1 = paymentRequirements;
resourceUrl = requirementsV1.resource;
discoveryInfo = extractDiscoveryInfoV1(requirementsV1);
} else {
return null;
}
if (!discoveryInfo) {
return null;
}
const url = new URL(resourceUrl);
const normalizedResourceUrl = `${url.origin}${url.pathname}`;
let description;
let mimeType;
if (paymentPayload.x402Version === 2) {
description = paymentPayload.resource?.description;
mimeType = paymentPayload.resource?.mimeType;
} else if (paymentPayload.x402Version === 1) {
const requirementsV1 = paymentRequirements;
description = requirementsV1.description;
mimeType = requirementsV1.mimeType;
}
return {
resourceUrl: normalizedResourceUrl,
description,
mimeType,
method: discoveryInfo.input.method,
x402Version: paymentPayload.x402Version,
discoveryInfo
};
}
function extractDiscoveryInfoFromExtension(extension, validate = true) {
if (validate) {
const result = validateDiscoveryExtension(extension);
if (!result.valid) {
throw new Error(
`Invalid discovery extension: ${result.errors?.join(", ") || "Unknown error"}`
);
}
}
return extension.info;
}
function validateAndExtract(extension) {
const result = validateDiscoveryExtension(extension);
if (result.valid) {
return {
valid: true,
info: extension.info
};
}
return {
valid: false,
errors: result.errors
};
}
// src/bazaar/facilitatorClient.ts
function withBazaar(client) {
const existingExtensions = client.extensions ?? {};
const extended = client;
extended.extensions = {
...existingExtensions,
discovery: {
async listResources(params) {
let headers = {
"Content-Type": "application/json"
};
const authHeaders = await client.createAuthHeaders("discovery");
headers = { ...headers, ...authHeaders.headers };
const queryParams = new URLSearchParams();
if (params?.type !== void 0) {
queryParams.set("type", params.type);
}
if (params?.limit !== void 0) {
queryParams.set("limit", params.limit.toString());
}
if (params?.offset !== void 0) {
queryParams.set("offset", params.offset.toString());
}
const queryString = queryParams.toString();
const endpoint = `${client.url}/discovery/resources${queryString ? `?${queryString}` : ""}`;
const response = await fetch(endpoint, {
method: "GET",
headers
});
if (!response.ok) {
const errorText = await response.text().catch(() => response.statusText);
throw new Error(
`Facilitator listDiscoveryResources failed (${response.status}): ${errorText}`
);
}
return await response.json();
}
}
};
return extended;
}
export {
BAZAAR,
declareDiscoveryExtension,
bazaarResourceServerExtension,
extractDiscoveryInfoV1,
isDiscoverableV1,
extractResourceMetadataV1,
validateDiscoveryExtension,
extractDiscoveryInfo,
extractDiscoveryInfoFromExtension,
validateAndExtract,
withBazaar
};
//# sourceMappingURL=chunk-DFJ4ZQFO.mjs.map
{"version":3,"sources":["../../src/bazaar/types.ts","../../src/bazaar/resourceService.ts","../../src/bazaar/server.ts","../../src/bazaar/facilitator.ts","../../src/bazaar/v1/facilitator.ts","../../src/bazaar/facilitatorClient.ts"],"sourcesContent":["/**\n * Type definitions for the Bazaar Discovery Extension\n */\n\nimport type { BodyMethods, QueryParamMethods } from \"@x402/core/http\";\n\n/**\n * Extension identifier constant for the Bazaar discovery extension\n */\nexport const BAZAAR = \"bazaar\";\n\n/**\n * Discovery info for query parameter methods (GET, HEAD, DELETE)\n */\nexport interface QueryDiscoveryInfo {\n input: {\n type: \"http\";\n method: QueryParamMethods;\n queryParams?: Record<string, unknown>;\n headers?: Record<string, string>;\n };\n output?: {\n type?: string;\n format?: string;\n example?: unknown;\n };\n}\n\n/**\n * Discovery info for body methods (POST, PUT, PATCH)\n */\nexport interface BodyDiscoveryInfo {\n input: {\n type: \"http\";\n method: BodyMethods;\n bodyType: \"json\" | \"form-data\" | \"text\";\n body: Record<string, unknown>;\n queryParams?: Record<string, unknown>;\n headers?: Record<string, string>;\n };\n output?: {\n type?: string;\n format?: string;\n example?: unknown;\n };\n}\n\n/**\n * Combined discovery info type\n */\nexport type DiscoveryInfo = QueryDiscoveryInfo | BodyDiscoveryInfo;\n\n/**\n * Discovery extension for query parameter methods (GET, HEAD, DELETE)\n */\nexport interface QueryDiscoveryExtension {\n info: QueryDiscoveryInfo;\n\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\";\n type: \"object\";\n properties: {\n input: {\n type: \"object\";\n properties: {\n type: {\n type: \"string\";\n const: \"http\";\n };\n method: {\n type: \"string\";\n enum: QueryParamMethods[];\n };\n queryParams?: {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n };\n headers?: {\n type: \"object\";\n additionalProperties: {\n type: \"string\";\n };\n };\n };\n required: (\"type\" | \"method\")[];\n additionalProperties?: boolean;\n };\n output?: {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: readonly string[];\n additionalProperties?: boolean;\n };\n };\n required: [\"input\"];\n };\n}\n\n/**\n * Discovery extension for body methods (POST, PUT, PATCH)\n */\nexport interface BodyDiscoveryExtension {\n info: BodyDiscoveryInfo;\n\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\";\n type: \"object\";\n properties: {\n input: {\n type: \"object\";\n properties: {\n type: {\n type: \"string\";\n const: \"http\";\n };\n method: {\n type: \"string\";\n enum: BodyMethods[];\n };\n bodyType: {\n type: \"string\";\n enum: [\"json\", \"form-data\", \"text\"];\n };\n body: Record<string, unknown>;\n queryParams?: {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n };\n headers?: {\n type: \"object\";\n additionalProperties: {\n type: \"string\";\n };\n };\n };\n required: (\"type\" | \"method\" | \"bodyType\" | \"body\")[];\n additionalProperties?: boolean;\n };\n output?: {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: readonly string[];\n additionalProperties?: boolean;\n };\n };\n required: [\"input\"];\n };\n}\n\n/**\n * Combined discovery extension type\n */\nexport type DiscoveryExtension = QueryDiscoveryExtension | BodyDiscoveryExtension;\n\nexport interface DeclareQueryDiscoveryExtensionConfig {\n method?: QueryParamMethods;\n input?: Record<string, unknown>;\n inputSchema?: Record<string, unknown>;\n output?: {\n example?: unknown;\n schema?: Record<string, unknown>;\n };\n}\n\nexport interface DeclareBodyDiscoveryExtensionConfig {\n method?: BodyMethods;\n input?: Record<string, unknown>;\n inputSchema?: Record<string, unknown>;\n bodyType: \"json\" | \"form-data\" | \"text\";\n output?: {\n example?: unknown;\n schema?: Record<string, unknown>;\n };\n}\n\nexport type DeclareDiscoveryExtensionConfig =\n | DeclareQueryDiscoveryExtensionConfig\n | DeclareBodyDiscoveryExtensionConfig;\n\n/**\n * Distributive Omit - properly distributes Omit over union types.\n *\n * Standard `Omit<A | B, K>` collapses to common properties only,\n * losing discriminant properties like `bodyType`.\n *\n * This type uses conditional type distribution to preserve the union:\n * `DistributiveOmit<A | B, K>` = `Omit<A, K> | Omit<B, K>`\n */\nexport type DistributiveOmit<T, K extends keyof T> = T extends T ? Omit<T, K> : never;\n\n/**\n * Config type for declareDiscoveryExtension function.\n * Uses DistributiveOmit to preserve bodyType discriminant in the union.\n */\nexport type DeclareDiscoveryExtensionInput = DistributiveOmit<\n DeclareDiscoveryExtensionConfig,\n \"method\"\n>;\n\nexport const isQueryExtensionConfig = (\n config: DeclareDiscoveryExtensionConfig,\n): config is DeclareQueryDiscoveryExtensionConfig => {\n return !(\"bodyType\" in config);\n};\n\nexport const isBodyExtensionConfig = (\n config: DeclareDiscoveryExtensionConfig,\n): config is DeclareBodyDiscoveryExtensionConfig => {\n return \"bodyType\" in config;\n};\n","/**\n * Resource Service functions for creating Bazaar discovery extensions\n *\n * These functions help servers declare the shape of their endpoints\n * for facilitator discovery and cataloging in the Bazaar.\n */\n\nimport {\n type DiscoveryExtension,\n type QueryDiscoveryExtension,\n type BodyDiscoveryExtension,\n type DeclareDiscoveryExtensionInput,\n type DeclareQueryDiscoveryExtensionConfig,\n type DeclareBodyDiscoveryExtensionConfig,\n} from \"./types\";\n\n/**\n * Internal helper to create a query discovery extension\n *\n * @param root0 - Configuration object for query discovery extension\n * @param root0.method - HTTP method (GET, HEAD, DELETE)\n * @param root0.input - Query parameters\n * @param root0.inputSchema - JSON schema for query parameters\n * @param root0.output - Output specification with example\n * @returns QueryDiscoveryExtension with info and schema\n */\nfunction createQueryDiscoveryExtension({\n method,\n input = {},\n inputSchema = { properties: {} },\n output,\n}: DeclareQueryDiscoveryExtensionConfig): QueryDiscoveryExtension {\n return {\n info: {\n input: {\n type: \"http\",\n ...(method ? { method } : {}),\n ...(input ? { queryParams: input } : {}),\n } as QueryDiscoveryExtension[\"info\"][\"input\"],\n ...(output?.example\n ? {\n output: {\n type: \"json\",\n example: output.example,\n },\n }\n : {}),\n },\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties: {\n input: {\n type: \"object\",\n properties: {\n type: {\n type: \"string\",\n const: \"http\",\n },\n method: {\n type: \"string\",\n enum: [\"GET\", \"HEAD\", \"DELETE\"],\n },\n ...(inputSchema\n ? {\n queryParams: {\n type: \"object\" as const,\n ...(typeof inputSchema === \"object\" ? inputSchema : {}),\n },\n }\n : {}),\n },\n required: [\"type\"] as (\"type\" | \"method\")[],\n additionalProperties: false,\n },\n ...(output?.example\n ? {\n output: {\n type: \"object\" as const,\n properties: {\n type: {\n type: \"string\" as const,\n },\n example: {\n type: \"object\" as const,\n ...(output.schema && typeof output.schema === \"object\" ? output.schema : {}),\n },\n },\n required: [\"type\"] as const,\n },\n }\n : {}),\n },\n required: [\"input\"],\n },\n };\n}\n\n/**\n * Internal helper to create a body discovery extension\n *\n * @param root0 - Configuration object for body discovery extension\n * @param root0.method - HTTP method (POST, PUT, PATCH)\n * @param root0.input - Request body specification\n * @param root0.inputSchema - JSON schema for request body\n * @param root0.bodyType - Content type of body (json, form-data, text) - required for body methods\n * @param root0.output - Output specification with example\n * @returns BodyDiscoveryExtension with info and schema\n */\nfunction createBodyDiscoveryExtension({\n method,\n input = {},\n inputSchema = { properties: {} },\n bodyType,\n output,\n}: DeclareBodyDiscoveryExtensionConfig): BodyDiscoveryExtension {\n return {\n info: {\n input: {\n type: \"http\",\n ...(method ? { method } : {}),\n bodyType,\n body: input,\n } as BodyDiscoveryExtension[\"info\"][\"input\"],\n ...(output?.example\n ? {\n output: {\n type: \"json\",\n example: output.example,\n },\n }\n : {}),\n },\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties: {\n input: {\n type: \"object\",\n properties: {\n type: {\n type: \"string\",\n const: \"http\",\n },\n method: {\n type: \"string\",\n enum: [\"POST\", \"PUT\", \"PATCH\"],\n },\n bodyType: {\n type: \"string\",\n enum: [\"json\", \"form-data\", \"text\"],\n },\n body: inputSchema,\n },\n required: [\"type\", \"bodyType\", \"body\"] as (\"type\" | \"method\" | \"bodyType\" | \"body\")[],\n additionalProperties: false,\n },\n ...(output?.example\n ? {\n output: {\n type: \"object\" as const,\n properties: {\n type: {\n type: \"string\" as const,\n },\n example: {\n type: \"object\" as const,\n ...(output.schema && typeof output.schema === \"object\" ? output.schema : {}),\n },\n },\n required: [\"type\"] as const,\n },\n }\n : {}),\n },\n required: [\"input\"],\n },\n };\n}\n\n/**\n * Create a discovery extension for any HTTP method\n *\n * This function helps servers declare how their endpoint should be called,\n * including the expected input parameters/body and output format.\n *\n * @param config - Configuration object for the discovery extension\n * @returns A discovery extension object with both info and schema\n *\n * @example\n * ```typescript\n * // For a GET endpoint with no input\n * const getExtension = declareDiscoveryExtension({\n * method: \"GET\",\n * output: {\n * example: { message: \"Success\", timestamp: \"2024-01-01T00:00:00Z\" }\n * }\n * });\n *\n * // For a GET endpoint with query params\n * const getWithParams = declareDiscoveryExtension({\n * method: \"GET\",\n * input: { query: \"example\" },\n * inputSchema: {\n * properties: {\n * query: { type: \"string\" }\n * },\n * required: [\"query\"]\n * }\n * });\n *\n * // For a POST endpoint with JSON body\n * const postExtension = declareDiscoveryExtension({\n * method: \"POST\",\n * input: { name: \"John\", age: 30 },\n * inputSchema: {\n * properties: {\n * name: { type: \"string\" },\n * age: { type: \"number\" }\n * },\n * required: [\"name\"]\n * },\n * bodyType: \"json\",\n * output: {\n * example: { success: true, id: \"123\" }\n * }\n * });\n * ```\n */\nexport function declareDiscoveryExtension(\n config: DeclareDiscoveryExtensionInput,\n): Record<string, DiscoveryExtension> {\n const bodyType = (config as DeclareBodyDiscoveryExtensionConfig).bodyType;\n const isBodyMethod = bodyType !== undefined;\n\n const extension = isBodyMethod\n ? createBodyDiscoveryExtension(config as DeclareBodyDiscoveryExtensionConfig)\n : createQueryDiscoveryExtension(config as DeclareQueryDiscoveryExtensionConfig);\n\n return { bazaar: extension as DiscoveryExtension };\n}\n","import type { ResourceServerExtension } from \"@x402/core/types\";\nimport type { HTTPRequestContext } from \"@x402/core/http\";\nimport { BAZAAR } from \"./types\";\n\n/**\n * Type guard to check if context is an HTTP request context.\n *\n * @param ctx - The context to check\n * @returns True if context is an HTTPRequestContext\n */\nfunction isHTTPRequestContext(ctx: unknown): ctx is HTTPRequestContext {\n return ctx !== null && typeof ctx === \"object\" && \"method\" in ctx && \"adapter\" in ctx;\n}\n\ninterface ExtensionDeclaration {\n [key: string]: unknown;\n info?: {\n [key: string]: unknown;\n input?: Record<string, unknown>;\n };\n schema?: {\n [key: string]: unknown;\n properties?: {\n [key: string]: unknown;\n input?: {\n [key: string]: unknown;\n properties?: {\n [key: string]: unknown;\n method?: Record<string, unknown>;\n };\n required?: string[];\n };\n };\n };\n}\n\nexport const bazaarResourceServerExtension: ResourceServerExtension = {\n key: BAZAAR,\n\n enrichDeclaration: (declaration, transportContext) => {\n if (!isHTTPRequestContext(transportContext)) {\n return declaration;\n }\n\n const extension = declaration as ExtensionDeclaration;\n const method = transportContext.method;\n\n // At declaration time, the schema uses a broad enum ([\"GET\", \"HEAD\", \"DELETE\"] or [\"POST\", \"PUT\", \"PATCH\"])\n // because the method isn't known until the HTTP context is available.\n // Here we narrow it to the actual method for precise schema validation.\n const existingInputProps = extension.schema?.properties?.input?.properties || {};\n const updatedInputProps = {\n ...existingInputProps,\n method: {\n type: \"string\",\n enum: [method],\n },\n };\n\n return {\n ...extension,\n info: {\n ...(extension.info || {}),\n input: {\n ...(extension.info?.input || {}),\n method,\n },\n },\n schema: {\n ...(extension.schema || {}),\n properties: {\n ...(extension.schema?.properties || {}),\n input: {\n ...(extension.schema?.properties?.input || {}),\n properties: updatedInputProps,\n required: [\n ...(extension.schema?.properties?.input?.required || []),\n ...(!(extension.schema?.properties?.input?.required || []).includes(\"method\")\n ? [\"method\"]\n : []),\n ],\n },\n },\n },\n };\n },\n};\n","/**\n * Facilitator functions for validating and extracting Bazaar discovery extensions\n *\n * These functions help facilitators validate extension data against schemas\n * and extract the discovery information for cataloging in the Bazaar.\n *\n * Supports both v2 (extensions in PaymentRequired) and v1 (outputSchema in PaymentRequirements).\n */\n\nimport Ajv from \"ajv/dist/2020.js\";\nimport type { PaymentPayload, PaymentRequirements, PaymentRequirementsV1 } from \"@x402/core/types\";\nimport type { DiscoveryExtension, DiscoveryInfo } from \"./types\";\nimport { BAZAAR } from \"./types\";\nimport { extractDiscoveryInfoV1 } from \"./v1/facilitator\";\n\n/**\n * Validation result for discovery extensions\n */\nexport interface ValidationResult {\n valid: boolean;\n errors?: string[];\n}\n\n/**\n * Validates a discovery extension's info against its schema\n *\n * @param extension - The discovery extension containing info and schema\n * @returns Validation result indicating if the info matches the schema\n *\n * @example\n * ```typescript\n * const extension = declareDiscoveryExtension(...);\n * const result = validateDiscoveryExtension(extension);\n *\n * if (result.valid) {\n * console.log(\"Extension is valid\");\n * } else {\n * console.error(\"Validation errors:\", result.errors);\n * }\n * ```\n */\nexport function validateDiscoveryExtension(extension: DiscoveryExtension): ValidationResult {\n try {\n const ajv = new Ajv({ strict: false, allErrors: true });\n const validate = ajv.compile(extension.schema);\n\n // The schema describes the structure of info directly\n // Schema has properties: { input: {...}, output: {...} }\n // So we validate extension.info which has { input: {...}, output: {...} }\n const valid = validate(extension.info);\n\n if (valid) {\n return { valid: true };\n }\n\n const errors = validate.errors?.map(err => {\n const path = err.instancePath || \"(root)\";\n return `${path}: ${err.message}`;\n }) || [\"Unknown validation error\"];\n\n return { valid: false, errors };\n } catch (error) {\n return {\n valid: false,\n errors: [\n `Schema validation failed: ${error instanceof Error ? error.message : String(error)}`,\n ],\n };\n }\n}\n\n/**\n * Extracts the discovery info from payment payload and requirements\n *\n * This function handles both v2 (extensions) and v1 (outputSchema) formats.\n *\n * For v2: Discovery info is in PaymentPayload.extensions (client copied it from PaymentRequired)\n * For v1: Discovery info is in PaymentRequirements.outputSchema\n *\n * V1 data is automatically transformed to v2 DiscoveryInfo format, making smart\n * assumptions about field names (queryParams/query/params for GET, bodyFields/body/data for POST, etc.)\n *\n * @param paymentPayload - The payment payload containing extensions (v2) and version info\n * @param paymentRequirements - The payment requirements (contains outputSchema for v1)\n * @param validate - Whether to validate v2 extensions before extracting (default: true)\n * @returns The discovery info in v2 format if present, or null if not discoverable\n *\n * @example\n * ```typescript\n * // V2 - extensions are in PaymentPayload\n * const info = extractDiscoveryInfo(paymentPayload, paymentRequirements);\n *\n * // V1 - discovery info is in PaymentRequirements.outputSchema\n * const info = extractDiscoveryInfo(paymentPayloadV1, paymentRequirementsV1);\n *\n * if (info) {\n * // Both v1 and v2 return the same DiscoveryInfo structure\n * console.log(\"Method:\", info.input.method);\n * }\n * ```\n */\nexport interface DiscoveredResource {\n resourceUrl: string;\n description?: string;\n mimeType?: string;\n method: string;\n x402Version: number;\n discoveryInfo: DiscoveryInfo;\n}\n\n/**\n * Extracts discovery information from payment payload and requirements.\n * Combines resource URL, HTTP method, version, and discovery info into a single object.\n *\n * @param paymentPayload - The payment payload containing extensions and resource info\n * @param paymentRequirements - The payment requirements to validate against\n * @param validate - Whether to validate the discovery info against the schema (default: true)\n * @returns Discovered resource info with URL, method, version and discovery data, or null if not found\n */\nexport function extractDiscoveryInfo(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements | PaymentRequirementsV1,\n validate: boolean = true,\n): DiscoveredResource | null {\n let discoveryInfo: DiscoveryInfo | null = null;\n let resourceUrl: string;\n\n if (paymentPayload.x402Version === 2) {\n resourceUrl = paymentPayload.resource?.url ?? \"\";\n\n if (paymentPayload.extensions) {\n const bazaarExtension = paymentPayload.extensions[BAZAAR];\n\n if (bazaarExtension && typeof bazaarExtension === \"object\") {\n try {\n const extension = bazaarExtension as DiscoveryExtension;\n\n if (validate) {\n const result = validateDiscoveryExtension(extension);\n if (!result.valid) {\n console.warn(\n `V2 discovery extension validation failed: ${result.errors?.join(\", \")}`,\n );\n } else {\n discoveryInfo = extension.info;\n }\n } else {\n discoveryInfo = extension.info;\n }\n } catch (error) {\n console.warn(`V2 discovery extension extraction failed: ${error}`);\n }\n }\n }\n } else if (paymentPayload.x402Version === 1) {\n const requirementsV1 = paymentRequirements as PaymentRequirementsV1;\n resourceUrl = requirementsV1.resource;\n discoveryInfo = extractDiscoveryInfoV1(requirementsV1);\n } else {\n return null;\n }\n\n if (!discoveryInfo) {\n return null;\n }\n\n // Strip query params (?) and hash sections (#) for discovery cataloging\n const url = new URL(resourceUrl);\n const normalizedResourceUrl = `${url.origin}${url.pathname}`;\n\n // Extract description and mimeType from resource info (v2) or requirements (v1)\n let description: string | undefined;\n let mimeType: string | undefined;\n\n if (paymentPayload.x402Version === 2) {\n description = paymentPayload.resource?.description;\n mimeType = paymentPayload.resource?.mimeType;\n } else if (paymentPayload.x402Version === 1) {\n const requirementsV1 = paymentRequirements as PaymentRequirementsV1;\n description = requirementsV1.description;\n mimeType = requirementsV1.mimeType;\n }\n\n return {\n resourceUrl: normalizedResourceUrl,\n description,\n mimeType,\n method: discoveryInfo.input.method,\n x402Version: paymentPayload.x402Version,\n discoveryInfo,\n };\n}\n\n/**\n * Extracts discovery info from a v2 extension directly\n *\n * This is a lower-level function for when you already have the extension object.\n * For general use, prefer the main extractDiscoveryInfo function.\n *\n * @param extension - The discovery extension to extract info from\n * @param validate - Whether to validate before extracting (default: true)\n * @returns The discovery info if valid\n * @throws Error if validation fails and validate is true\n */\nexport function extractDiscoveryInfoFromExtension(\n extension: DiscoveryExtension,\n validate: boolean = true,\n): DiscoveryInfo {\n if (validate) {\n const result = validateDiscoveryExtension(extension);\n if (!result.valid) {\n throw new Error(\n `Invalid discovery extension: ${result.errors?.join(\", \") || \"Unknown error\"}`,\n );\n }\n }\n\n return extension.info;\n}\n\n/**\n * Validates and extracts discovery info in one step\n *\n * This is a convenience function that combines validation and extraction,\n * returning both the validation result and the info if valid.\n *\n * @param extension - The discovery extension to validate and extract\n * @returns Object containing validation result and info (if valid)\n *\n * @example\n * ```typescript\n * const extension = declareDiscoveryExtension(...);\n * const { valid, info, errors } = validateAndExtract(extension);\n *\n * if (valid && info) {\n * // Store info in Bazaar catalog\n * } else {\n * console.error(\"Validation errors:\", errors);\n * }\n * ```\n */\nexport function validateAndExtract(extension: DiscoveryExtension): {\n valid: boolean;\n info?: DiscoveryInfo;\n errors?: string[];\n} {\n const result = validateDiscoveryExtension(extension);\n\n if (result.valid) {\n return {\n valid: true,\n info: extension.info,\n };\n }\n\n return {\n valid: false,\n errors: result.errors,\n };\n}\n","/**\n * V1 Facilitator functions for extracting Bazaar discovery information\n *\n * In v1, discovery information is stored in the `outputSchema` field\n * of PaymentRequirements, which has a different structure than v2.\n *\n * This module transforms v1 data into v2 DiscoveryInfo format.\n */\n\nimport type { PaymentRequirementsV1 } from \"@x402/core/types\";\nimport type { BodyMethods, QueryParamMethods } from \"@x402/core/http\";\nimport type { DiscoveryInfo, QueryDiscoveryInfo, BodyDiscoveryInfo } from \"../types\";\n\n/**\n * Type guard to check if an object has the v1 outputSchema structure\n *\n * @param obj - The object to check\n * @returns True if object has v1 outputSchema structure\n */\nfunction hasV1OutputSchema(\n obj: unknown,\n): obj is { input: Record<string, unknown>; output?: Record<string, unknown> } {\n return (\n obj !== null &&\n typeof obj === \"object\" &&\n \"input\" in obj &&\n obj.input !== null &&\n typeof obj.input === \"object\" &&\n \"type\" in obj.input &&\n obj.input.type === \"http\" &&\n \"method\" in obj.input\n );\n}\n\n/**\n * Checks if a method is a query parameter method\n *\n * @param method - HTTP method string to check\n * @returns True if method is GET, HEAD, or DELETE\n */\nfunction isQueryMethod(method: string): method is QueryParamMethods {\n const upperMethod = method.toUpperCase();\n return upperMethod === \"GET\" || upperMethod === \"HEAD\" || upperMethod === \"DELETE\";\n}\n\n/**\n * Checks if a method is a body method\n *\n * @param method - HTTP method string to check\n * @returns True if method is POST, PUT, or PATCH\n */\nfunction isBodyMethod(method: string): method is BodyMethods {\n const upperMethod = method.toUpperCase();\n return upperMethod === \"POST\" || upperMethod === \"PUT\" || upperMethod === \"PATCH\";\n}\n\n/**\n * Extracts query parameters from v1 input, making smart assumptions\n * about common field names used in v1\n *\n * @param v1Input - V1 input object from payment requirements\n * @returns Extracted query parameters or undefined\n */\nfunction extractQueryParams(v1Input: Record<string, unknown>): Record<string, unknown> | undefined {\n // Check various common field names used in v1 (both camelCase and snake_case)\n if (v1Input.queryParams && typeof v1Input.queryParams === \"object\") {\n return v1Input.queryParams as Record<string, unknown>;\n }\n if (v1Input.query_params && typeof v1Input.query_params === \"object\") {\n return v1Input.query_params as Record<string, unknown>;\n }\n if (v1Input.query && typeof v1Input.query === \"object\") {\n return v1Input.query as Record<string, unknown>;\n }\n if (v1Input.params && typeof v1Input.params === \"object\") {\n return v1Input.params as Record<string, unknown>;\n }\n return undefined;\n}\n\n/**\n * Extracts body information from v1 input, making smart assumptions\n *\n * @param v1Input - V1 input object from payment requirements\n * @returns Object containing body content and bodyType\n */\nfunction extractBodyInfo(v1Input: Record<string, unknown>): {\n body: Record<string, unknown>;\n bodyType: \"json\" | \"form-data\" | \"text\";\n} {\n // Determine body type (check both camelCase and snake_case)\n let bodyType: \"json\" | \"form-data\" | \"text\" = \"json\";\n const bodyTypeField = v1Input.bodyType || v1Input.body_type;\n\n if (bodyTypeField && typeof bodyTypeField === \"string\") {\n const type = bodyTypeField.toLowerCase();\n if (type.includes(\"form\") || type.includes(\"multipart\")) {\n bodyType = \"form-data\";\n } else if (type.includes(\"text\") || type.includes(\"plain\")) {\n bodyType = \"text\";\n } else {\n bodyType = \"json\";\n }\n }\n\n // Extract body content from various possible fields\n // Priority order based on observed patterns in real data\n let body: Record<string, unknown> = {};\n\n if (v1Input.bodyFields && typeof v1Input.bodyFields === \"object\") {\n body = v1Input.bodyFields as Record<string, unknown>;\n } else if (\n v1Input.body_fields &&\n v1Input.body_fields !== null &&\n typeof v1Input.body_fields === \"object\"\n ) {\n body = v1Input.body_fields as Record<string, unknown>;\n } else if (v1Input.bodyParams && typeof v1Input.bodyParams === \"object\") {\n body = v1Input.bodyParams as Record<string, unknown>;\n } else if (v1Input.body && typeof v1Input.body === \"object\") {\n body = v1Input.body as Record<string, unknown>;\n } else if (v1Input.data && typeof v1Input.data === \"object\") {\n body = v1Input.data as Record<string, unknown>;\n } else if (v1Input.properties && typeof v1Input.properties === \"object\") {\n // Some endpoints have properties directly at the input level\n body = v1Input.properties as Record<string, unknown>;\n }\n\n return { body, bodyType };\n}\n\n/**\n * Extracts discovery info from v1 PaymentRequirements and transforms to v2 format\n *\n * In v1, the discovery information is stored in the `outputSchema` field,\n * which contains both input (endpoint shape) and output (response schema) information.\n *\n * This function makes smart assumptions to normalize v1 data into v2 DiscoveryInfo format:\n * - For GET/HEAD/DELETE: Looks for queryParams, query, or params fields\n * - For POST/PUT/PATCH: Looks for bodyFields, body, or data fields and normalizes bodyType\n * - Extracts optional headers if present\n *\n * @param paymentRequirements - V1 payment requirements\n * @returns Discovery info in v2 format if present and valid, or null if not discoverable\n *\n * @example\n * ```typescript\n * const requirements: PaymentRequirementsV1 = {\n * scheme: \"exact\",\n * network: \"eip155:8453\",\n * maxAmountRequired: \"100000\",\n * resource: \"https://api.example.com/data\",\n * description: \"Get data\",\n * mimeType: \"application/json\",\n * outputSchema: {\n * input: {\n * type: \"http\",\n * method: \"GET\",\n * discoverable: true,\n * queryParams: { query: \"string\" }\n * },\n * output: { type: \"object\" }\n * },\n * payTo: \"0x...\",\n * maxTimeoutSeconds: 300,\n * asset: \"0x...\",\n * extra: {}\n * };\n *\n * const info = extractDiscoveryInfoV1(requirements);\n * if (info) {\n * console.log(\"Endpoint method:\", info.input.method);\n * }\n * ```\n */\nexport function extractDiscoveryInfoV1(\n paymentRequirements: PaymentRequirementsV1,\n): DiscoveryInfo | null {\n const { outputSchema } = paymentRequirements;\n\n // Check if outputSchema exists and has the expected structure\n if (!outputSchema || !hasV1OutputSchema(outputSchema)) {\n return null;\n }\n\n const v1Input = outputSchema.input;\n\n // Check if the endpoint is marked as discoverable\n // Default to true if not specified (for backwards compatibility)\n const isDiscoverable = v1Input.discoverable ?? true;\n\n if (!isDiscoverable) {\n return null;\n }\n\n const method = typeof v1Input.method === \"string\" ? v1Input.method.toUpperCase() : \"\";\n\n // Extract headers if present (check both camelCase and snake_case)\n const headersRaw = v1Input.headerFields || v1Input.header_fields || v1Input.headers;\n const headers =\n headersRaw && typeof headersRaw === \"object\"\n ? (headersRaw as Record<string, string>)\n : undefined;\n\n // Extract output example/schema if present\n const output = outputSchema.output\n ? {\n type: \"json\" as const,\n example: outputSchema.output,\n }\n : undefined;\n\n // Transform based on method type\n if (isQueryMethod(method)) {\n // Query parameter method (GET, HEAD, DELETE)\n const queryParams = extractQueryParams(v1Input);\n\n const discoveryInfo: QueryDiscoveryInfo = {\n input: {\n type: \"http\",\n method: method as QueryParamMethods,\n ...(queryParams ? { queryParams } : {}),\n ...(headers ? { headers } : {}),\n },\n ...(output ? { output } : {}),\n };\n\n return discoveryInfo;\n } else if (isBodyMethod(method)) {\n // Body method (POST, PUT, PATCH)\n const { body, bodyType } = extractBodyInfo(v1Input);\n const queryParams = extractQueryParams(v1Input); // Some POST requests also have query params\n\n const discoveryInfo: BodyDiscoveryInfo = {\n input: {\n type: \"http\",\n method: method as BodyMethods,\n bodyType,\n body,\n ...(queryParams ? { queryParams } : {}),\n ...(headers ? { headers } : {}),\n },\n ...(output ? { output } : {}),\n };\n\n return discoveryInfo;\n }\n\n // Unsupported method, return null\n return null;\n}\n\n/**\n * Checks if v1 PaymentRequirements contains discoverable information\n *\n * @param paymentRequirements - V1 payment requirements\n * @returns True if the requirements contain valid discovery info\n *\n * @example\n * ```typescript\n * if (isDiscoverableV1(requirements)) {\n * const info = extractDiscoveryInfoV1(requirements);\n * // Catalog info in Bazaar\n * }\n * ```\n */\nexport function isDiscoverableV1(paymentRequirements: PaymentRequirementsV1): boolean {\n return extractDiscoveryInfoV1(paymentRequirements) !== null;\n}\n\n/**\n * Extracts resource metadata from v1 PaymentRequirements\n *\n * In v1, resource information is embedded directly in the payment requirements\n * rather than in a separate resource object.\n *\n * @param paymentRequirements - V1 payment requirements\n * @returns Resource metadata\n *\n * @example\n * ```typescript\n * const metadata = extractResourceMetadataV1(requirements);\n * console.log(\"Resource URL:\", metadata.url);\n * console.log(\"Description:\", metadata.description);\n * ```\n */\nexport function extractResourceMetadataV1(paymentRequirements: PaymentRequirementsV1): {\n url: string;\n description: string;\n mimeType: string;\n} {\n return {\n url: paymentRequirements.resource,\n description: paymentRequirements.description,\n mimeType: paymentRequirements.mimeType,\n };\n}\n","/**\n * Client extensions for querying Bazaar discovery resources\n */\n\nimport { HTTPFacilitatorClient } from \"@x402/core/http\";\nimport type { PaymentRequirements } from \"@x402/core/types\";\nimport { WithExtensions } from \"../types\";\n\n/**\n * Parameters for listing discovery resources.\n * All parameters are optional and used for filtering/pagination.\n */\nexport interface ListDiscoveryResourcesParams {\n /**\n * Filter by protocol type (e.g., \"http\", \"mcp\").\n * Currently, the only supported protocol type is \"http\".\n */\n type?: string;\n\n /**\n * The number of discovered x402 resources to return per page.\n */\n limit?: number;\n\n /**\n * The offset of the first discovered x402 resource to return.\n */\n offset?: number;\n}\n\n/**\n * A discovered x402 resource from the bazaar.\n */\nexport interface DiscoveryResource {\n /** The URL or identifier of the discovered resource */\n resource: string;\n /** The protocol type of the resource (e.g., \"http\") */\n type: string;\n /** The x402 protocol version supported by this resource */\n x402Version: number;\n /** Array of accepted payment methods for this resource */\n accepts: PaymentRequirements[];\n /** ISO 8601 timestamp of when the resource was last updated */\n lastUpdated: string;\n /** Additional metadata about the resource */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Response from listing discovery resources.\n */\nexport interface DiscoveryResourcesResponse {\n /** The x402 protocol version of this response */\n x402Version: number;\n /** The list of discovered resources */\n items: DiscoveryResource[];\n /** Pagination information for the response */\n pagination: {\n /** Maximum number of results returned */\n limit: number;\n /** Number of results skipped */\n offset: number;\n /** Total count of resources matching the query */\n total: number;\n };\n}\n\n/**\n * Bazaar client extension interface providing discovery query functionality.\n */\nexport interface BazaarClientExtension {\n discovery: {\n /**\n * List x402 discovery resources from the bazaar.\n *\n * @param params - Optional filtering and pagination parameters\n * @returns A promise resolving to the discovery resources response\n */\n listResources(params?: ListDiscoveryResourcesParams): Promise<DiscoveryResourcesResponse>;\n };\n}\n\n/**\n * Extends a facilitator client with Bazaar discovery query functionality.\n * Preserves and merges with any existing extensions from prior chaining.\n *\n * @param client - The facilitator client to extend\n * @returns The client extended with bazaar discovery capabilities\n *\n * @example\n * ```ts\n * // Basic usage\n * const client = withBazaar(new HTTPFacilitatorClient());\n * const resources = await client.extensions.discovery.listResources({ type: \"http\" });\n *\n * // Chaining with other extensions\n * const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient()));\n * await client.extensions.other.someMethod();\n * await client.extensions.discovery.listResources();\n * ```\n */\nexport function withBazaar<T extends HTTPFacilitatorClient>(\n client: T,\n): WithExtensions<T, BazaarClientExtension> {\n // Preserve any existing extensions from prior chaining\n const existingExtensions =\n (client as T & { extensions?: Record<string, unknown> }).extensions ?? {};\n\n const extended = client as WithExtensions<T, BazaarClientExtension>;\n\n extended.extensions = {\n ...existingExtensions,\n discovery: {\n async listResources(\n params?: ListDiscoveryResourcesParams,\n ): Promise<DiscoveryResourcesResponse> {\n let headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n const authHeaders = await client.createAuthHeaders(\"discovery\");\n headers = { ...headers, ...authHeaders.headers };\n\n const queryParams = new URLSearchParams();\n if (params?.type !== undefined) {\n queryParams.set(\"type\", params.type);\n }\n if (params?.limit !== undefined) {\n queryParams.set(\"limit\", params.limit.toString());\n }\n if (params?.offset !== undefined) {\n queryParams.set(\"offset\", params.offset.toString());\n }\n\n const queryString = queryParams.toString();\n const endpoint = `${client.url}/discovery/resources${queryString ? `?${queryString}` : \"\"}`;\n\n const response = await fetch(endpoint, {\n method: \"GET\",\n headers,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n throw new Error(\n `Facilitator listDiscoveryResources failed (${response.status}): ${errorText}`,\n );\n }\n\n return (await response.json()) as DiscoveryResourcesResponse;\n },\n },\n } as WithExtensions<T, BazaarClientExtension>[\"extensions\"];\n\n return extended;\n}\n"],"mappings":"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","names":["isBodyMethod"]}
import { BodyMethods, QueryParamMethods, HTTPFacilitatorClient } from '@x402/core/http';
import { ResourceServerExtension, PaymentPayload, PaymentRequirements, PaymentRequirementsV1 } from '@x402/core/types';
/**
* Shared type utilities for x402 extensions
*/
/**
* Type utility to merge extensions properly when chaining.
* If T already has extensions, merge them; otherwise add new extensions.
*
* @example
* ```ts
* // Chaining multiple extensions preserves all types:
* const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient()));
* // Type: HTTPFacilitatorClient & { extensions: OtherExtension & BazaarExtension }
* ```
*/
type WithExtensions<T, E> = T extends {
extensions: infer Existing;
} ? Omit<T, "extensions"> & {
extensions: Existing & E;
} : T & {
extensions: E;
};
/**
* Type definitions for the Bazaar Discovery Extension
*/
/**
* Extension identifier constant for the Bazaar discovery extension
*/
declare const BAZAAR = "bazaar";
/**
* Discovery info for query parameter methods (GET, HEAD, DELETE)
*/
interface QueryDiscoveryInfo {
input: {
type: "http";
method: QueryParamMethods;
queryParams?: Record<string, unknown>;
headers?: Record<string, string>;
};
output?: {
type?: string;
format?: string;
example?: unknown;
};
}
/**
* Discovery info for body methods (POST, PUT, PATCH)
*/
interface BodyDiscoveryInfo {
input: {
type: "http";
method: BodyMethods;
bodyType: "json" | "form-data" | "text";
body: Record<string, unknown>;
queryParams?: Record<string, unknown>;
headers?: Record<string, string>;
};
output?: {
type?: string;
format?: string;
example?: unknown;
};
}
/**
* Combined discovery info type
*/
type DiscoveryInfo = QueryDiscoveryInfo | BodyDiscoveryInfo;
/**
* Discovery extension for query parameter methods (GET, HEAD, DELETE)
*/
interface QueryDiscoveryExtension {
info: QueryDiscoveryInfo;
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema";
type: "object";
properties: {
input: {
type: "object";
properties: {
type: {
type: "string";
const: "http";
};
method: {
type: "string";
enum: QueryParamMethods[];
};
queryParams?: {
type: "object";
properties?: Record<string, unknown>;
required?: string[];
additionalProperties?: boolean;
};
headers?: {
type: "object";
additionalProperties: {
type: "string";
};
};
};
required: ("type" | "method")[];
additionalProperties?: boolean;
};
output?: {
type: "object";
properties?: Record<string, unknown>;
required?: readonly string[];
additionalProperties?: boolean;
};
};
required: ["input"];
};
}
/**
* Discovery extension for body methods (POST, PUT, PATCH)
*/
interface BodyDiscoveryExtension {
info: BodyDiscoveryInfo;
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema";
type: "object";
properties: {
input: {
type: "object";
properties: {
type: {
type: "string";
const: "http";
};
method: {
type: "string";
enum: BodyMethods[];
};
bodyType: {
type: "string";
enum: ["json", "form-data", "text"];
};
body: Record<string, unknown>;
queryParams?: {
type: "object";
properties?: Record<string, unknown>;
required?: string[];
additionalProperties?: boolean;
};
headers?: {
type: "object";
additionalProperties: {
type: "string";
};
};
};
required: ("type" | "method" | "bodyType" | "body")[];
additionalProperties?: boolean;
};
output?: {
type: "object";
properties?: Record<string, unknown>;
required?: readonly string[];
additionalProperties?: boolean;
};
};
required: ["input"];
};
}
/**
* Combined discovery extension type
*/
type DiscoveryExtension = QueryDiscoveryExtension | BodyDiscoveryExtension;
interface DeclareQueryDiscoveryExtensionConfig {
method?: QueryParamMethods;
input?: Record<string, unknown>;
inputSchema?: Record<string, unknown>;
output?: {
example?: unknown;
schema?: Record<string, unknown>;
};
}
interface DeclareBodyDiscoveryExtensionConfig {
method?: BodyMethods;
input?: Record<string, unknown>;
inputSchema?: Record<string, unknown>;
bodyType: "json" | "form-data" | "text";
output?: {
example?: unknown;
schema?: Record<string, unknown>;
};
}
type DeclareDiscoveryExtensionConfig = DeclareQueryDiscoveryExtensionConfig | DeclareBodyDiscoveryExtensionConfig;
/**
* Distributive Omit - properly distributes Omit over union types.
*
* Standard `Omit<A | B, K>` collapses to common properties only,
* losing discriminant properties like `bodyType`.
*
* This type uses conditional type distribution to preserve the union:
* `DistributiveOmit<A | B, K>` = `Omit<A, K> | Omit<B, K>`
*/
type DistributiveOmit<T, K extends keyof T> = T extends T ? Omit<T, K> : never;
/**
* Config type for declareDiscoveryExtension function.
* Uses DistributiveOmit to preserve bodyType discriminant in the union.
*/
type DeclareDiscoveryExtensionInput = DistributiveOmit<DeclareDiscoveryExtensionConfig, "method">;
/**
* Resource Service functions for creating Bazaar discovery extensions
*
* These functions help servers declare the shape of their endpoints
* for facilitator discovery and cataloging in the Bazaar.
*/
/**
* Create a discovery extension for any HTTP method
*
* This function helps servers declare how their endpoint should be called,
* including the expected input parameters/body and output format.
*
* @param config - Configuration object for the discovery extension
* @returns A discovery extension object with both info and schema
*
* @example
* ```typescript
* // For a GET endpoint with no input
* const getExtension = declareDiscoveryExtension({
* method: "GET",
* output: {
* example: { message: "Success", timestamp: "2024-01-01T00:00:00Z" }
* }
* });
*
* // For a GET endpoint with query params
* const getWithParams = declareDiscoveryExtension({
* method: "GET",
* input: { query: "example" },
* inputSchema: {
* properties: {
* query: { type: "string" }
* },
* required: ["query"]
* }
* });
*
* // For a POST endpoint with JSON body
* const postExtension = declareDiscoveryExtension({
* method: "POST",
* input: { name: "John", age: 30 },
* inputSchema: {
* properties: {
* name: { type: "string" },
* age: { type: "number" }
* },
* required: ["name"]
* },
* bodyType: "json",
* output: {
* example: { success: true, id: "123" }
* }
* });
* ```
*/
declare function declareDiscoveryExtension(config: DeclareDiscoveryExtensionInput): Record<string, DiscoveryExtension>;
declare const bazaarResourceServerExtension: ResourceServerExtension;
/**
* Facilitator functions for validating and extracting Bazaar discovery extensions
*
* These functions help facilitators validate extension data against schemas
* and extract the discovery information for cataloging in the Bazaar.
*
* Supports both v2 (extensions in PaymentRequired) and v1 (outputSchema in PaymentRequirements).
*/
/**
* Validation result for discovery extensions
*/
interface ValidationResult {
valid: boolean;
errors?: string[];
}
/**
* Validates a discovery extension's info against its schema
*
* @param extension - The discovery extension containing info and schema
* @returns Validation result indicating if the info matches the schema
*
* @example
* ```typescript
* const extension = declareDiscoveryExtension(...);
* const result = validateDiscoveryExtension(extension);
*
* if (result.valid) {
* console.log("Extension is valid");
* } else {
* console.error("Validation errors:", result.errors);
* }
* ```
*/
declare function validateDiscoveryExtension(extension: DiscoveryExtension): ValidationResult;
/**
* Extracts the discovery info from payment payload and requirements
*
* This function handles both v2 (extensions) and v1 (outputSchema) formats.
*
* For v2: Discovery info is in PaymentPayload.extensions (client copied it from PaymentRequired)
* For v1: Discovery info is in PaymentRequirements.outputSchema
*
* V1 data is automatically transformed to v2 DiscoveryInfo format, making smart
* assumptions about field names (queryParams/query/params for GET, bodyFields/body/data for POST, etc.)
*
* @param paymentPayload - The payment payload containing extensions (v2) and version info
* @param paymentRequirements - The payment requirements (contains outputSchema for v1)
* @param validate - Whether to validate v2 extensions before extracting (default: true)
* @returns The discovery info in v2 format if present, or null if not discoverable
*
* @example
* ```typescript
* // V2 - extensions are in PaymentPayload
* const info = extractDiscoveryInfo(paymentPayload, paymentRequirements);
*
* // V1 - discovery info is in PaymentRequirements.outputSchema
* const info = extractDiscoveryInfo(paymentPayloadV1, paymentRequirementsV1);
*
* if (info) {
* // Both v1 and v2 return the same DiscoveryInfo structure
* console.log("Method:", info.input.method);
* }
* ```
*/
interface DiscoveredResource {
resourceUrl: string;
description?: string;
mimeType?: string;
method: string;
x402Version: number;
discoveryInfo: DiscoveryInfo;
}
/**
* Extracts discovery information from payment payload and requirements.
* Combines resource URL, HTTP method, version, and discovery info into a single object.
*
* @param paymentPayload - The payment payload containing extensions and resource info
* @param paymentRequirements - The payment requirements to validate against
* @param validate - Whether to validate the discovery info against the schema (default: true)
* @returns Discovered resource info with URL, method, version and discovery data, or null if not found
*/
declare function extractDiscoveryInfo(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements | PaymentRequirementsV1, validate?: boolean): DiscoveredResource | null;
/**
* Extracts discovery info from a v2 extension directly
*
* This is a lower-level function for when you already have the extension object.
* For general use, prefer the main extractDiscoveryInfo function.
*
* @param extension - The discovery extension to extract info from
* @param validate - Whether to validate before extracting (default: true)
* @returns The discovery info if valid
* @throws Error if validation fails and validate is true
*/
declare function extractDiscoveryInfoFromExtension(extension: DiscoveryExtension, validate?: boolean): DiscoveryInfo;
/**
* Validates and extracts discovery info in one step
*
* This is a convenience function that combines validation and extraction,
* returning both the validation result and the info if valid.
*
* @param extension - The discovery extension to validate and extract
* @returns Object containing validation result and info (if valid)
*
* @example
* ```typescript
* const extension = declareDiscoveryExtension(...);
* const { valid, info, errors } = validateAndExtract(extension);
*
* if (valid && info) {
* // Store info in Bazaar catalog
* } else {
* console.error("Validation errors:", errors);
* }
* ```
*/
declare function validateAndExtract(extension: DiscoveryExtension): {
valid: boolean;
info?: DiscoveryInfo;
errors?: string[];
};
/**
* V1 Facilitator functions for extracting Bazaar discovery information
*
* In v1, discovery information is stored in the `outputSchema` field
* of PaymentRequirements, which has a different structure than v2.
*
* This module transforms v1 data into v2 DiscoveryInfo format.
*/
/**
* Extracts discovery info from v1 PaymentRequirements and transforms to v2 format
*
* In v1, the discovery information is stored in the `outputSchema` field,
* which contains both input (endpoint shape) and output (response schema) information.
*
* This function makes smart assumptions to normalize v1 data into v2 DiscoveryInfo format:
* - For GET/HEAD/DELETE: Looks for queryParams, query, or params fields
* - For POST/PUT/PATCH: Looks for bodyFields, body, or data fields and normalizes bodyType
* - Extracts optional headers if present
*
* @param paymentRequirements - V1 payment requirements
* @returns Discovery info in v2 format if present and valid, or null if not discoverable
*
* @example
* ```typescript
* const requirements: PaymentRequirementsV1 = {
* scheme: "exact",
* network: "eip155:8453",
* maxAmountRequired: "100000",
* resource: "https://api.example.com/data",
* description: "Get data",
* mimeType: "application/json",
* outputSchema: {
* input: {
* type: "http",
* method: "GET",
* discoverable: true,
* queryParams: { query: "string" }
* },
* output: { type: "object" }
* },
* payTo: "0x...",
* maxTimeoutSeconds: 300,
* asset: "0x...",
* extra: {}
* };
*
* const info = extractDiscoveryInfoV1(requirements);
* if (info) {
* console.log("Endpoint method:", info.input.method);
* }
* ```
*/
declare function extractDiscoveryInfoV1(paymentRequirements: PaymentRequirementsV1): DiscoveryInfo | null;
/**
* Checks if v1 PaymentRequirements contains discoverable information
*
* @param paymentRequirements - V1 payment requirements
* @returns True if the requirements contain valid discovery info
*
* @example
* ```typescript
* if (isDiscoverableV1(requirements)) {
* const info = extractDiscoveryInfoV1(requirements);
* // Catalog info in Bazaar
* }
* ```
*/
declare function isDiscoverableV1(paymentRequirements: PaymentRequirementsV1): boolean;
/**
* Extracts resource metadata from v1 PaymentRequirements
*
* In v1, resource information is embedded directly in the payment requirements
* rather than in a separate resource object.
*
* @param paymentRequirements - V1 payment requirements
* @returns Resource metadata
*
* @example
* ```typescript
* const metadata = extractResourceMetadataV1(requirements);
* console.log("Resource URL:", metadata.url);
* console.log("Description:", metadata.description);
* ```
*/
declare function extractResourceMetadataV1(paymentRequirements: PaymentRequirementsV1): {
url: string;
description: string;
mimeType: string;
};
/**
* Client extensions for querying Bazaar discovery resources
*/
/**
* Parameters for listing discovery resources.
* All parameters are optional and used for filtering/pagination.
*/
interface ListDiscoveryResourcesParams {
/**
* Filter by protocol type (e.g., "http", "mcp").
* Currently, the only supported protocol type is "http".
*/
type?: string;
/**
* The number of discovered x402 resources to return per page.
*/
limit?: number;
/**
* The offset of the first discovered x402 resource to return.
*/
offset?: number;
}
/**
* A discovered x402 resource from the bazaar.
*/
interface DiscoveryResource {
/** The URL or identifier of the discovered resource */
resource: string;
/** The protocol type of the resource (e.g., "http") */
type: string;
/** The x402 protocol version supported by this resource */
x402Version: number;
/** Array of accepted payment methods for this resource */
accepts: PaymentRequirements[];
/** ISO 8601 timestamp of when the resource was last updated */
lastUpdated: string;
/** Additional metadata about the resource */
metadata?: Record<string, unknown>;
}
/**
* Response from listing discovery resources.
*/
interface DiscoveryResourcesResponse {
/** The x402 protocol version of this response */
x402Version: number;
/** The list of discovered resources */
items: DiscoveryResource[];
/** Pagination information for the response */
pagination: {
/** Maximum number of results returned */
limit: number;
/** Number of results skipped */
offset: number;
/** Total count of resources matching the query */
total: number;
};
}
/**
* Bazaar client extension interface providing discovery query functionality.
*/
interface BazaarClientExtension {
discovery: {
/**
* List x402 discovery resources from the bazaar.
*
* @param params - Optional filtering and pagination parameters
* @returns A promise resolving to the discovery resources response
*/
listResources(params?: ListDiscoveryResourcesParams): Promise<DiscoveryResourcesResponse>;
};
}
/**
* Extends a facilitator client with Bazaar discovery query functionality.
* Preserves and merges with any existing extensions from prior chaining.
*
* @param client - The facilitator client to extend
* @returns The client extended with bazaar discovery capabilities
*
* @example
* ```ts
* // Basic usage
* const client = withBazaar(new HTTPFacilitatorClient());
* const resources = await client.extensions.discovery.listResources({ type: "http" });
*
* // Chaining with other extensions
* const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient()));
* await client.extensions.other.someMethod();
* await client.extensions.discovery.listResources();
* ```
*/
declare function withBazaar<T extends HTTPFacilitatorClient>(client: T): WithExtensions<T, BazaarClientExtension>;
export { BAZAAR as B, type DiscoveredResource as D, type ListDiscoveryResourcesParams as L, type QueryDiscoveryExtension as Q, type ValidationResult as V, type WithExtensions as W, type BazaarClientExtension as a, type BodyDiscoveryExtension as b, type BodyDiscoveryInfo as c, type DiscoveryExtension as d, type DiscoveryInfo as e, type DiscoveryResource as f, type DiscoveryResourcesResponse as g, type QueryDiscoveryInfo as h, bazaarResourceServerExtension as i, declareDiscoveryExtension as j, extractDiscoveryInfo as k, extractDiscoveryInfoFromExtension as l, extractDiscoveryInfoV1 as m, extractResourceMetadataV1 as n, isDiscoverableV1 as o, validateDiscoveryExtension as p, validateAndExtract as v, withBazaar as w };

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display