@piprail/sdk 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/README.md +64 -24
- package/dist/index.cjs +204 -79
- package/dist/index.d.cts +122 -5
- package/dist/index.d.ts +122 -5
- package/dist/index.js +185 -60
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -4365,6 +4365,55 @@ declare function register402Index(input: RegisterInput): Promise<RegisterOutcome
|
|
|
4365
4365
|
declare function registerX402Scan(input: {
|
|
4366
4366
|
url: string;
|
|
4367
4367
|
}, signer: DiscoverySigner): Promise<RegisterOutcome>;
|
|
4368
|
+
/** What {@link claim402IndexDomain} returns — the proof to SERVE so 402 Index will
|
|
4369
|
+
* approve your domain (and flip your `pending-review` listings to searchable). */
|
|
4370
|
+
interface DomainClaim {
|
|
4371
|
+
ok: boolean;
|
|
4372
|
+
domain: string;
|
|
4373
|
+
/** The exact text to serve as the ENTIRE body of `verificationUrl` — this is what
|
|
4374
|
+
* 402 Index fetches and checks (the SHA-256 of the token). Always populated on
|
|
4375
|
+
* success: read from the response, or computed as `sha256(verificationToken)` if
|
|
4376
|
+
* the API returns only the token. Serve THIS. */
|
|
4377
|
+
verificationHash?: string;
|
|
4378
|
+
/** The raw 64-hex token 402 Index issued (the preimage of `verificationHash`). */
|
|
4379
|
+
verificationToken?: string;
|
|
4380
|
+
/** Where to serve `verificationHash` — your `https://<domain>/.well-known/402index-verify.txt`. */
|
|
4381
|
+
verificationUrl?: string;
|
|
4382
|
+
/** 402 Index's own human instructions. */
|
|
4383
|
+
instructions?: string;
|
|
4384
|
+
httpStatus?: number;
|
|
4385
|
+
/** Failure reason when `ok:false`. */
|
|
4386
|
+
detail?: string;
|
|
4387
|
+
}
|
|
4388
|
+
/** What {@link verify402IndexDomain} returns once the proof is in place. */
|
|
4389
|
+
interface DomainVerification {
|
|
4390
|
+
ok: boolean;
|
|
4391
|
+
domain: string;
|
|
4392
|
+
/** 402 Index's status string, e.g. `'verified'`. */
|
|
4393
|
+
status?: string;
|
|
4394
|
+
/** How many of your pending listings were approved by the verification. */
|
|
4395
|
+
servicesCount?: number;
|
|
4396
|
+
httpStatus?: number;
|
|
4397
|
+
detail?: string;
|
|
4398
|
+
}
|
|
4399
|
+
/**
|
|
4400
|
+
* Step 1 of 402 Index domain verification: claim the host of `domainOrUrl`. 402 Index
|
|
4401
|
+
* lists a self-registered resource as PENDING REVIEW; verifying the domain approves it
|
|
4402
|
+
* (and every other pending listing on that domain) so it becomes searchable. Returns the
|
|
4403
|
+
* `verificationHash` to serve as the entire body of `verificationUrl`
|
|
4404
|
+
* (`https://<domain>/.well-known/402index-verify.txt`). Then call {@link verify402IndexDomain}.
|
|
4405
|
+
* No funds move. Never throws.
|
|
4406
|
+
*/
|
|
4407
|
+
declare function claim402IndexDomain(domainOrUrl: string, opts?: {
|
|
4408
|
+
contactEmail?: string;
|
|
4409
|
+
}): Promise<DomainClaim>;
|
|
4410
|
+
/**
|
|
4411
|
+
* Step 2 of 402 Index domain verification: after {@link claim402IndexDomain} and serving
|
|
4412
|
+
* the `verificationHash` at `verificationUrl`, tell 402 Index to re-fetch + approve. On
|
|
4413
|
+
* success, the domain's pending listings become searchable (`status:'verified'`,
|
|
4414
|
+
* `servicesCount` approved). No funds move. Never throws.
|
|
4415
|
+
*/
|
|
4416
|
+
declare function verify402IndexDomain(domainOrUrl: string): Promise<DomainVerification>;
|
|
4368
4417
|
|
|
4369
4418
|
interface PaymentPolicy {
|
|
4370
4419
|
/** Per-payment ceiling, human-readable (e.g. '0.10'). Compared using the
|
|
@@ -4849,6 +4898,30 @@ declare class PipRailClient {
|
|
|
4849
4898
|
* on them before calling.
|
|
4850
4899
|
*/
|
|
4851
4900
|
register(url: string, opts?: RegisterOptions): Promise<RegisterOutcome[]>;
|
|
4901
|
+
/**
|
|
4902
|
+
* **402 Index domain verification, step 1 of 2.** A self-registered 402 Index
|
|
4903
|
+
* listing is `pending-review` (see {@link register}); verifying your domain flips
|
|
4904
|
+
* it — and every other pending listing on that domain — to APPROVED/searchable.
|
|
4905
|
+
* Pass the resource URL or a bare domain; returns the `verificationHash` to serve
|
|
4906
|
+
* as the entire body of `verificationUrl` (your `/.well-known/402index-verify.txt`).
|
|
4907
|
+
* Then serve it and call {@link verifyDomain}. Moves no funds; never throws.
|
|
4908
|
+
*
|
|
4909
|
+
* ```ts
|
|
4910
|
+
* const claim = await client.claimDomain('https://api.example.com/report')
|
|
4911
|
+
* // serve claim.verificationHash at claim.verificationUrl, then:
|
|
4912
|
+
* const res = await client.verifyDomain('api.example.com') // → { ok:true, status:'verified' }
|
|
4913
|
+
* ```
|
|
4914
|
+
*/
|
|
4915
|
+
claimDomain(urlOrDomain: string, opts?: {
|
|
4916
|
+
contactEmail?: string;
|
|
4917
|
+
}): Promise<DomainClaim>;
|
|
4918
|
+
/**
|
|
4919
|
+
* **402 Index domain verification, step 2 of 2.** After {@link claimDomain} and
|
|
4920
|
+
* serving the hash at your `/.well-known/402index-verify.txt`, this tells 402 Index
|
|
4921
|
+
* to re-fetch + approve. On success the domain's pending listings become searchable
|
|
4922
|
+
* (`{ ok:true, status:'verified', servicesCount }`). Moves no funds; never throws.
|
|
4923
|
+
*/
|
|
4924
|
+
verifyDomain(urlOrDomain: string): Promise<DomainVerification>;
|
|
4852
4925
|
/**
|
|
4853
4926
|
* The discovery signer for the bound wallet (its address + a message signer),
|
|
4854
4927
|
* or `null` if the chain family doesn't support it (EVM does today). For
|
|
@@ -5061,10 +5134,6 @@ interface OpenApiOperation {
|
|
|
5061
5134
|
'x-payment-info': {
|
|
5062
5135
|
x402Version: 2;
|
|
5063
5136
|
accepts: PaymentRail[];
|
|
5064
|
-
/** Bazaar-style input schema marker so a strict index doesn't "skip" the op. */
|
|
5065
|
-
bazaar: {
|
|
5066
|
-
discoverable: true;
|
|
5067
|
-
};
|
|
5068
5137
|
};
|
|
5069
5138
|
}
|
|
5070
5139
|
/** x402scan's legacy origin file (`/.well-known/x402`). */
|
|
@@ -5073,6 +5142,46 @@ interface WellKnownX402 {
|
|
|
5073
5142
|
resources: string[];
|
|
5074
5143
|
ownershipProofs?: string[];
|
|
5075
5144
|
}
|
|
5145
|
+
/**
|
|
5146
|
+
* Describes a resource's INPUT for discovery. The open indexes that REQUIRE an
|
|
5147
|
+
* input schema (x402scan rejects a listing without one) read this from a
|
|
5148
|
+
* `extensions.bazaar` block. Pass it to a gate's `discovery` option (emits the
|
|
5149
|
+
* block in the 402 challenge) or build it directly with {@link buildBazaarExtension}.
|
|
5150
|
+
*/
|
|
5151
|
+
interface DiscoveryDescriptor {
|
|
5152
|
+
/** HTTP method the resource answers. Default `'GET'`. */
|
|
5153
|
+
method?: string;
|
|
5154
|
+
/** Query params the resource reads, as a JSON-Schema `properties` object
|
|
5155
|
+
* (name → schema). Default `{}` — a no-input GET. */
|
|
5156
|
+
queryParams?: Record<string, unknown>;
|
|
5157
|
+
/** Optional output hint (shape/example) for a richer listing. */
|
|
5158
|
+
output?: {
|
|
5159
|
+
type?: string;
|
|
5160
|
+
example?: unknown;
|
|
5161
|
+
};
|
|
5162
|
+
}
|
|
5163
|
+
/** The `extensions.bazaar` discovery block (the x402 "bazaar" convention the open
|
|
5164
|
+
* indexes parse: `info.input` describes the request, `schema` is its JSON Schema). */
|
|
5165
|
+
interface BazaarExtension {
|
|
5166
|
+
info: {
|
|
5167
|
+
input: {
|
|
5168
|
+
type: 'http';
|
|
5169
|
+
method: string;
|
|
5170
|
+
queryParams: Record<string, unknown>;
|
|
5171
|
+
};
|
|
5172
|
+
output?: {
|
|
5173
|
+
type?: string;
|
|
5174
|
+
example?: unknown;
|
|
5175
|
+
};
|
|
5176
|
+
};
|
|
5177
|
+
schema: Record<string, unknown>;
|
|
5178
|
+
}
|
|
5179
|
+
/**
|
|
5180
|
+
* Build the `extensions.bazaar` block that satisfies x402scan's mandatory input-schema
|
|
5181
|
+
* check, from a {@link DiscoveryDescriptor}. Pure. Defaults to a no-input GET — the
|
|
5182
|
+
* minimal shape a live x402scan listing accepts.
|
|
5183
|
+
*/
|
|
5184
|
+
declare function buildBazaarExtension(descriptor?: DiscoveryDescriptor): BazaarExtension;
|
|
5076
5185
|
/** The `_x402` DNS TXT pointer record (experimental draft). */
|
|
5077
5186
|
interface X402DnsRecord {
|
|
5078
5187
|
name: string;
|
|
@@ -5224,6 +5333,14 @@ interface RequirePaymentOptions {
|
|
|
5224
5333
|
* Omit to keep the gate exactly as today (`onchain-proof` only).
|
|
5225
5334
|
*/
|
|
5226
5335
|
exact?: ExactRailOption;
|
|
5336
|
+
/**
|
|
5337
|
+
* Make this gate's 402 self-describing for the open indexes — **x402scan REQUIRES
|
|
5338
|
+
* an input schema or it won't list the resource.** Set `true` for a no-input GET,
|
|
5339
|
+
* or pass a {@link DiscoveryDescriptor} to describe the request. Emits an
|
|
5340
|
+
* `extensions.bazaar` block in the 402 challenge. Opt-in; omitting it leaves the
|
|
5341
|
+
* challenge byte-identical to before.
|
|
5342
|
+
*/
|
|
5343
|
+
discovery?: boolean | DiscoveryDescriptor;
|
|
5227
5344
|
}
|
|
5228
5345
|
type VerifyPaymentResult = {
|
|
5229
5346
|
kind: 'paid';
|
|
@@ -5830,4 +5947,4 @@ declare function readExactDomain(publicClient: PublicClient, asset: string): Pro
|
|
|
5830
5947
|
version: string;
|
|
5831
5948
|
} | null>;
|
|
5832
5949
|
|
|
5833
|
-
export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoverySigner, type DiscoverySource, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, buildChallengeHeader, buildExactAuthorization, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody };
|
|
5950
|
+
export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BazaarExtension, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoveryDescriptor, type DiscoverySigner, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, buildBazaarExtension, buildChallengeHeader, buildExactAuthorization, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
|
package/dist/index.js
CHANGED
|
@@ -1344,6 +1344,8 @@ function decorateOutcome(o) {
|
|
|
1344
1344
|
var BAZAAR_URL = "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources";
|
|
1345
1345
|
var INDEX402_SEARCH = "https://402index.io/api/v1/services";
|
|
1346
1346
|
var INDEX402_REGISTER = "https://402index.io/api/v1/register";
|
|
1347
|
+
var INDEX402_CLAIM = "https://402index.io/api/v1/claim";
|
|
1348
|
+
var INDEX402_VERIFY = "https://402index.io/api/v1/claim/verify";
|
|
1347
1349
|
var X402SCAN_REGISTER = "https://www.x402scan.com/api/x402/registry/register";
|
|
1348
1350
|
var USER_AGENT = "@piprail/sdk (+https://piprail.com)";
|
|
1349
1351
|
function clientHeaders(extra = {}) {
|
|
@@ -1579,12 +1581,72 @@ async function registerX402Scan(input, signer) {
|
|
|
1579
1581
|
return { source: "x402scan", ok: false, detail: errMsg(err) };
|
|
1580
1582
|
}
|
|
1581
1583
|
}
|
|
1584
|
+
async function claim402IndexDomain(domainOrUrl, opts = {}) {
|
|
1585
|
+
const domain = hostOf(domainOrUrl);
|
|
1586
|
+
try {
|
|
1587
|
+
const res = await fetch(INDEX402_CLAIM, {
|
|
1588
|
+
method: "POST",
|
|
1589
|
+
headers: clientHeaders({ "content-type": "application/json", accept: "application/json" }),
|
|
1590
|
+
body: JSON.stringify({ domain, ...opts.contactEmail ? { contact_email: opts.contactEmail } : {} })
|
|
1591
|
+
});
|
|
1592
|
+
const body = await res.json().catch(() => ({}));
|
|
1593
|
+
if (!res.ok) {
|
|
1594
|
+
return { ok: false, domain, httpStatus: res.status, detail: pickString(body, "error", "detail", "message") ?? `402 Index claim returned HTTP ${res.status}.` };
|
|
1595
|
+
}
|
|
1596
|
+
const verificationToken = pickString(body, "verification_token");
|
|
1597
|
+
const verificationHash = pickString(body, "verification_hash") ?? (verificationToken ? await sha256Hex(verificationToken) : void 0);
|
|
1598
|
+
return {
|
|
1599
|
+
ok: true,
|
|
1600
|
+
domain,
|
|
1601
|
+
httpStatus: res.status,
|
|
1602
|
+
...optionalString("verificationHash", verificationHash),
|
|
1603
|
+
...optionalString("verificationToken", verificationToken),
|
|
1604
|
+
...optionalString("verificationUrl", pickString(body, "verification_url")),
|
|
1605
|
+
...optionalString("instructions", pickString(body, "instructions"))
|
|
1606
|
+
};
|
|
1607
|
+
} catch (err) {
|
|
1608
|
+
return { ok: false, domain, detail: errMsg(err) };
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
async function sha256Hex(input) {
|
|
1612
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(input));
|
|
1613
|
+
return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1614
|
+
}
|
|
1615
|
+
async function verify402IndexDomain(domainOrUrl) {
|
|
1616
|
+
const domain = hostOf(domainOrUrl);
|
|
1617
|
+
try {
|
|
1618
|
+
const res = await fetch(INDEX402_VERIFY, {
|
|
1619
|
+
method: "POST",
|
|
1620
|
+
headers: clientHeaders({ "content-type": "application/json", accept: "application/json" }),
|
|
1621
|
+
body: JSON.stringify({ domain })
|
|
1622
|
+
});
|
|
1623
|
+
const body = await res.json().catch(() => ({}));
|
|
1624
|
+
if (!res.ok) {
|
|
1625
|
+
return { ok: false, domain, httpStatus: res.status, detail: pickString(body, "error", "detail", "message") ?? `402 Index verify returned HTTP ${res.status}.` };
|
|
1626
|
+
}
|
|
1627
|
+
return {
|
|
1628
|
+
ok: true,
|
|
1629
|
+
domain,
|
|
1630
|
+
httpStatus: res.status,
|
|
1631
|
+
...optionalString("status", pickString(body, "status")),
|
|
1632
|
+
...typeof body.services_count === "number" ? { servicesCount: body.services_count } : {}
|
|
1633
|
+
};
|
|
1634
|
+
} catch (err) {
|
|
1635
|
+
return { ok: false, domain, detail: errMsg(err) };
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1582
1638
|
async function readSiwxInfo(res) {
|
|
1583
1639
|
try {
|
|
1584
1640
|
const body = await res.json();
|
|
1585
1641
|
const ext = body.extensions;
|
|
1586
1642
|
const siwx = ext?.["sign-in-with-x"];
|
|
1587
1643
|
const info = siwx?.info ?? siwx;
|
|
1644
|
+
if (info && info.chainId == null && Array.isArray(siwx?.supportedChains)) {
|
|
1645
|
+
const evm = siwx.supportedChains.find(
|
|
1646
|
+
(c) => typeof c?.chainId === "string" && c.chainId.startsWith("eip155:")
|
|
1647
|
+
);
|
|
1648
|
+
if (evm && typeof evm.chainId === "string") info.chainId = evm.chainId;
|
|
1649
|
+
}
|
|
1588
1650
|
if (info && typeof info.domain === "string" && info.domain.length > 0 && typeof info.nonce === "string" && info.nonce.length > 0 && typeof info.uri === "string" && info.uri.length > 0) {
|
|
1589
1651
|
return info;
|
|
1590
1652
|
}
|
|
@@ -1668,7 +1730,8 @@ function firstArray(o, ...keys) {
|
|
|
1668
1730
|
}
|
|
1669
1731
|
function hostOf(url) {
|
|
1670
1732
|
try {
|
|
1671
|
-
|
|
1733
|
+
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(url) ? url : `https://${url}`;
|
|
1734
|
+
return new URL(withScheme).hostname || url;
|
|
1672
1735
|
} catch {
|
|
1673
1736
|
return url;
|
|
1674
1737
|
}
|
|
@@ -1677,8 +1740,13 @@ function errMsg(err) {
|
|
|
1677
1740
|
return err instanceof Error ? err.message : String(err);
|
|
1678
1741
|
}
|
|
1679
1742
|
function encodeBase642(str) {
|
|
1680
|
-
if (typeof btoa === "function") return btoa(str);
|
|
1681
1743
|
if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
|
|
1744
|
+
if (typeof btoa === "function" && typeof TextEncoder !== "undefined") {
|
|
1745
|
+
const bytes = new TextEncoder().encode(str);
|
|
1746
|
+
let binary = "";
|
|
1747
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
1748
|
+
return btoa(binary);
|
|
1749
|
+
}
|
|
1682
1750
|
throw new Error("No base64 encoder available in this runtime.");
|
|
1683
1751
|
}
|
|
1684
1752
|
|
|
@@ -2052,6 +2120,32 @@ var PipRailClient = class {
|
|
|
2052
2120
|
}
|
|
2053
2121
|
return outcomes.map(decorateOutcome);
|
|
2054
2122
|
}
|
|
2123
|
+
/**
|
|
2124
|
+
* **402 Index domain verification, step 1 of 2.** A self-registered 402 Index
|
|
2125
|
+
* listing is `pending-review` (see {@link register}); verifying your domain flips
|
|
2126
|
+
* it — and every other pending listing on that domain — to APPROVED/searchable.
|
|
2127
|
+
* Pass the resource URL or a bare domain; returns the `verificationHash` to serve
|
|
2128
|
+
* as the entire body of `verificationUrl` (your `/.well-known/402index-verify.txt`).
|
|
2129
|
+
* Then serve it and call {@link verifyDomain}. Moves no funds; never throws.
|
|
2130
|
+
*
|
|
2131
|
+
* ```ts
|
|
2132
|
+
* const claim = await client.claimDomain('https://api.example.com/report')
|
|
2133
|
+
* // serve claim.verificationHash at claim.verificationUrl, then:
|
|
2134
|
+
* const res = await client.verifyDomain('api.example.com') // → { ok:true, status:'verified' }
|
|
2135
|
+
* ```
|
|
2136
|
+
*/
|
|
2137
|
+
async claimDomain(urlOrDomain, opts = {}) {
|
|
2138
|
+
return claim402IndexDomain(urlOrDomain, opts);
|
|
2139
|
+
}
|
|
2140
|
+
/**
|
|
2141
|
+
* **402 Index domain verification, step 2 of 2.** After {@link claimDomain} and
|
|
2142
|
+
* serving the hash at your `/.well-known/402index-verify.txt`, this tells 402 Index
|
|
2143
|
+
* to re-fetch + approve. On success the domain's pending listings become searchable
|
|
2144
|
+
* (`{ ok:true, status:'verified', servicesCount }`). Moves no funds; never throws.
|
|
2145
|
+
*/
|
|
2146
|
+
async verifyDomain(urlOrDomain) {
|
|
2147
|
+
return verify402IndexDomain(urlOrDomain);
|
|
2148
|
+
}
|
|
2055
2149
|
/**
|
|
2056
2150
|
* The discovery signer for the bound wallet (its address + a message signer),
|
|
2057
2151
|
* or `null` if the chain family doesn't support it (EVM does today). For
|
|
@@ -2698,7 +2792,7 @@ function paymentTools(client) {
|
|
|
2698
2792
|
},
|
|
2699
2793
|
{
|
|
2700
2794
|
name: "piprail_register",
|
|
2701
|
-
description: "List an x402 payment-gated resource YOU run on the open indexes so other agents can discover it. Default target is 402 Index \u2014 no auth, no signature, no payment; a self-registered listing is pending review (verify your domain on 402index.io for instant approval). Returns one outcome per index ({ source, ok, detail, visibility, note }); a step the chain can't satisfy comes back ok:false with the reason. Moves no funds; nothing is PipRail-hosted.",
|
|
2795
|
+
description: "List an x402 payment-gated resource YOU run on the open indexes so other agents can discover it. Default target is 402 Index \u2014 no auth, no signature, no payment; a self-registered listing is pending review (verify your domain on 402index.io for instant approval). Returns one outcome per index ({ source, ok, detail, visibility, note }); a step the chain can't satisfy comes back ok:false with the reason. Moves no funds; nothing is PipRail-hosted. NOTE: index/agent payers are overwhelmingly standard `exact` clients \u2014 a default onchain-proof-only gate gets listed but they cannot pay it, so add an `exact` rail (and set the gate's `discovery` option, required for x402scan) to be usefully discoverable AND payable.",
|
|
2702
2796
|
annotations: {
|
|
2703
2797
|
title: "Register an x402 endpoint",
|
|
2704
2798
|
readOnlyHint: false,
|
|
@@ -2732,6 +2826,87 @@ function paymentTools(client) {
|
|
|
2732
2826
|
];
|
|
2733
2827
|
}
|
|
2734
2828
|
|
|
2829
|
+
// src/discovery.ts
|
|
2830
|
+
var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
|
|
2831
|
+
function buildBazaarExtension(descriptor = {}) {
|
|
2832
|
+
const method = (descriptor.method ?? "GET").toUpperCase();
|
|
2833
|
+
const queryParams = descriptor.queryParams ?? {};
|
|
2834
|
+
return {
|
|
2835
|
+
info: {
|
|
2836
|
+
input: { type: "http", method, queryParams },
|
|
2837
|
+
output: descriptor.output ?? { type: "json" }
|
|
2838
|
+
},
|
|
2839
|
+
schema: {
|
|
2840
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
2841
|
+
type: "object",
|
|
2842
|
+
properties: {
|
|
2843
|
+
input: {
|
|
2844
|
+
type: "object",
|
|
2845
|
+
properties: {
|
|
2846
|
+
type: { type: "string", const: "http" },
|
|
2847
|
+
method: { type: "string", enum: ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"] },
|
|
2848
|
+
queryParams: { type: "object", properties: queryParams, additionalProperties: false }
|
|
2849
|
+
},
|
|
2850
|
+
required: ["type", "method"],
|
|
2851
|
+
additionalProperties: false
|
|
2852
|
+
}
|
|
2853
|
+
},
|
|
2854
|
+
required: ["input"]
|
|
2855
|
+
}
|
|
2856
|
+
};
|
|
2857
|
+
}
|
|
2858
|
+
function pathOf(url) {
|
|
2859
|
+
try {
|
|
2860
|
+
return new URL(url).pathname || "/";
|
|
2861
|
+
} catch {
|
|
2862
|
+
return url.startsWith("/") ? url : `/${url}`;
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
function buildOpenApi(input) {
|
|
2866
|
+
const paths = {};
|
|
2867
|
+
for (const r of input.resources) {
|
|
2868
|
+
const path = pathOf(r.url);
|
|
2869
|
+
const method = (r.method ?? "GET").toLowerCase();
|
|
2870
|
+
const op = {
|
|
2871
|
+
...r.description ? { summary: r.description } : {},
|
|
2872
|
+
responses: {
|
|
2873
|
+
"200": { description: "Paid \u2014 the resource." },
|
|
2874
|
+
"402": { description: "Payment required (x402)." }
|
|
2875
|
+
},
|
|
2876
|
+
"x-payment-info": {
|
|
2877
|
+
x402Version: 2,
|
|
2878
|
+
accepts: r.accepts
|
|
2879
|
+
}
|
|
2880
|
+
};
|
|
2881
|
+
paths[path] = { ...paths[path] ?? {}, [method]: op };
|
|
2882
|
+
}
|
|
2883
|
+
return {
|
|
2884
|
+
openapi: "3.1.0",
|
|
2885
|
+
info: { title: input.title ?? "PipRail x402 resources", version: input.version ?? "1.0.0" },
|
|
2886
|
+
servers: [{ url: input.origin }],
|
|
2887
|
+
paths,
|
|
2888
|
+
// "Built with @piprail/sdk" — default on (opt out with attribution:false). At the
|
|
2889
|
+
// document ROOT so `info` stays exactly { title, version }.
|
|
2890
|
+
...input.attribution === false ? {} : { "x-generator": GENERATOR },
|
|
2891
|
+
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { "x-agentcash-provenance": { ownershipProofs: input.ownershipProofs } } : {}
|
|
2892
|
+
};
|
|
2893
|
+
}
|
|
2894
|
+
function buildWellKnownX402(input) {
|
|
2895
|
+
return {
|
|
2896
|
+
version: 1,
|
|
2897
|
+
resources: input.resources.map((r) => r.url),
|
|
2898
|
+
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
|
|
2899
|
+
};
|
|
2900
|
+
}
|
|
2901
|
+
function buildX402DnsTxt(input) {
|
|
2902
|
+
const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
|
|
2903
|
+
return {
|
|
2904
|
+
name: `_x402.${input.host}`,
|
|
2905
|
+
type: "TXT",
|
|
2906
|
+
value: `v=x4021;${descriptor}url=${input.discoveryUrl}`
|
|
2907
|
+
};
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2735
2910
|
// src/facilitator.ts
|
|
2736
2911
|
function safeStringify(value) {
|
|
2737
2912
|
return JSON.stringify(value, (_k, v) => typeof v === "bigint" ? v.toString() : v);
|
|
@@ -2980,6 +3155,8 @@ function createPaymentGate(options) {
|
|
|
2980
3155
|
async function makeChallenge(resourceUrl, opts) {
|
|
2981
3156
|
const specs = await ready();
|
|
2982
3157
|
const nonce = genNonce();
|
|
3158
|
+
const bazaar = options.discovery ? { bazaar: buildBazaarExtension(options.discovery === true ? {} : options.discovery) } : void 0;
|
|
3159
|
+
const extensions = { ...bazaar, ...opts?.extensions };
|
|
2983
3160
|
const challenge2 = {
|
|
2984
3161
|
x402Version: 2,
|
|
2985
3162
|
resource: {
|
|
@@ -2988,7 +3165,7 @@ function createPaymentGate(options) {
|
|
|
2988
3165
|
},
|
|
2989
3166
|
accepts: buildAccepts(specs, nonce),
|
|
2990
3167
|
...opts?.error ? { error: opts.error } : {},
|
|
2991
|
-
...
|
|
3168
|
+
...Object.keys(extensions).length > 0 ? { extensions } : {}
|
|
2992
3169
|
};
|
|
2993
3170
|
return { challenge: challenge2, requiredHeader: buildChallengeHeader(challenge2) };
|
|
2994
3171
|
}
|
|
@@ -3174,61 +3351,6 @@ function normaliseHeader(value) {
|
|
|
3174
3351
|
if (Array.isArray(value)) return value[0];
|
|
3175
3352
|
return value;
|
|
3176
3353
|
}
|
|
3177
|
-
|
|
3178
|
-
// src/discovery.ts
|
|
3179
|
-
var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
|
|
3180
|
-
function pathOf(url) {
|
|
3181
|
-
try {
|
|
3182
|
-
return new URL(url).pathname || "/";
|
|
3183
|
-
} catch {
|
|
3184
|
-
return url.startsWith("/") ? url : `/${url}`;
|
|
3185
|
-
}
|
|
3186
|
-
}
|
|
3187
|
-
function buildOpenApi(input) {
|
|
3188
|
-
const paths = {};
|
|
3189
|
-
for (const r of input.resources) {
|
|
3190
|
-
const path = pathOf(r.url);
|
|
3191
|
-
const method = (r.method ?? "GET").toLowerCase();
|
|
3192
|
-
const op = {
|
|
3193
|
-
...r.description ? { summary: r.description } : {},
|
|
3194
|
-
responses: {
|
|
3195
|
-
"200": { description: "Paid \u2014 the resource." },
|
|
3196
|
-
"402": { description: "Payment required (x402)." }
|
|
3197
|
-
},
|
|
3198
|
-
"x-payment-info": {
|
|
3199
|
-
x402Version: 2,
|
|
3200
|
-
accepts: r.accepts,
|
|
3201
|
-
bazaar: { discoverable: true }
|
|
3202
|
-
}
|
|
3203
|
-
};
|
|
3204
|
-
paths[path] = { ...paths[path] ?? {}, [method]: op };
|
|
3205
|
-
}
|
|
3206
|
-
return {
|
|
3207
|
-
openapi: "3.1.0",
|
|
3208
|
-
info: { title: input.title ?? "PipRail x402 resources", version: input.version ?? "1.0.0" },
|
|
3209
|
-
servers: [{ url: input.origin }],
|
|
3210
|
-
paths,
|
|
3211
|
-
// "Built with @piprail/sdk" — default on (opt out with attribution:false). At the
|
|
3212
|
-
// document ROOT so `info` stays exactly { title, version }.
|
|
3213
|
-
...input.attribution === false ? {} : { "x-generator": GENERATOR },
|
|
3214
|
-
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { "x-agentcash-provenance": { ownershipProofs: input.ownershipProofs } } : {}
|
|
3215
|
-
};
|
|
3216
|
-
}
|
|
3217
|
-
function buildWellKnownX402(input) {
|
|
3218
|
-
return {
|
|
3219
|
-
version: 1,
|
|
3220
|
-
resources: input.resources.map((r) => r.url),
|
|
3221
|
-
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
|
|
3222
|
-
};
|
|
3223
|
-
}
|
|
3224
|
-
function buildX402DnsTxt(input) {
|
|
3225
|
-
const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
|
|
3226
|
-
return {
|
|
3227
|
-
name: `_x402.${input.host}`,
|
|
3228
|
-
type: "TXT",
|
|
3229
|
-
value: `v=x4021;${descriptor}url=${input.discoveryUrl}`
|
|
3230
|
-
};
|
|
3231
|
-
}
|
|
3232
3354
|
export {
|
|
3233
3355
|
CHAINS,
|
|
3234
3356
|
ConfirmationTimeoutError,
|
|
@@ -3257,6 +3379,7 @@ export {
|
|
|
3257
3379
|
UnsupportedNetworkError,
|
|
3258
3380
|
WrongChainError,
|
|
3259
3381
|
WrongFamilyError,
|
|
3382
|
+
buildBazaarExtension,
|
|
3260
3383
|
buildChallengeHeader,
|
|
3261
3384
|
buildExactAuthorization,
|
|
3262
3385
|
buildOpenApi,
|
|
@@ -3265,6 +3388,7 @@ export {
|
|
|
3265
3388
|
buildWellKnownX402,
|
|
3266
3389
|
buildX402DnsTxt,
|
|
3267
3390
|
chainIdForExactNetwork,
|
|
3391
|
+
claim402IndexDomain,
|
|
3268
3392
|
createPaymentGate,
|
|
3269
3393
|
decorateOutcome,
|
|
3270
3394
|
eip3009Abi,
|
|
@@ -3289,5 +3413,6 @@ export {
|
|
|
3289
3413
|
searchOpenIndexes,
|
|
3290
3414
|
settleViaFacilitator,
|
|
3291
3415
|
toInsufficientFundsError,
|
|
3292
|
-
toInvalidBody
|
|
3416
|
+
toInvalidBody,
|
|
3417
|
+
verify402IndexDomain
|
|
3293
3418
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piprail/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Accept x402 crypto payments across 29 chains — every major EVM chain plus Solana, TON, Tron, NEAR, Sui, Aptos, Algorand, Stellar & XRPL — in a couple of lines. No backend, no database, no fee; payments settle straight to your wallet.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|