@t2000/serve 10.1.0 → 10.1.2
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/dist/index.cjs +12 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -73,7 +73,7 @@ function buildLlmsTxt(serve, origin) {
|
|
|
73
73
|
"HTTP 402 with an `accepts[]` envelope; sign it and retry with the `X-PAYMENT` header.",
|
|
74
74
|
"Invalid input returns 422 before any payment is taken. A failed call is never charged.",
|
|
75
75
|
"",
|
|
76
|
-
"Easiest client: `npm i -g @t2000/cli` then `t2 pay <url> --
|
|
76
|
+
"Easiest client: `npm i -g @t2000/cli` then `t2 pay <url> --data '{...}'`,",
|
|
77
77
|
"or the t2000 MCP server (`t2000_pay`), or `@t2000/sdk` `pay()`.",
|
|
78
78
|
""
|
|
79
79
|
);
|
|
@@ -164,7 +164,11 @@ async function validateBody(schema, value) {
|
|
|
164
164
|
if (isStandardSchema(schema)) {
|
|
165
165
|
const result2 = await schema["~standard"].validate(value);
|
|
166
166
|
if (result2.issues) {
|
|
167
|
-
|
|
167
|
+
const message = result2.issues.map((i) => {
|
|
168
|
+
const path = (i.path ?? []).map((seg) => typeof seg === "object" ? String(seg.key) : String(seg)).join(".");
|
|
169
|
+
return path ? `${path}: ${i.message}` : i.message;
|
|
170
|
+
}).join("; ");
|
|
171
|
+
return { ok: false, message };
|
|
168
172
|
}
|
|
169
173
|
return { ok: true, data: result2.value };
|
|
170
174
|
}
|
|
@@ -253,9 +257,13 @@ var RouteBuilder = class {
|
|
|
253
257
|
const runHandler = async (payer) => {
|
|
254
258
|
let validated = parsedBody;
|
|
255
259
|
if (bodySchema) {
|
|
256
|
-
if (bodyParseError)
|
|
260
|
+
if (bodyParseError) {
|
|
261
|
+
return json(422, { error: bodyParseError, paid: false });
|
|
262
|
+
}
|
|
257
263
|
const result = await validateBody(bodySchema, parsedBody ?? {});
|
|
258
|
-
if (!result.ok)
|
|
264
|
+
if (!result.ok) {
|
|
265
|
+
return json(422, { error: result.message, paid: false });
|
|
266
|
+
}
|
|
259
267
|
validated = result.data;
|
|
260
268
|
}
|
|
261
269
|
const out = await fn({ body: validated, req, payer });
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/discovery.ts","../src/chain.ts","../src/route.ts","../src/store.ts","../src/serve.ts"],"names":["USDC_TESTNET","USDC","SuiGrpcClient","X402_PAYMENT_HEADER","X402_PAYMENT_RESPONSE_HEADER","result","isX402EscrowHeader","parseX402Header","verifyX402Payment","settleX402Payment","encodeX402Response","createX402Requirements","X402_VERSION","isValidSuiAddress","normalizeSuiAddress","InMemoryDigestStore"],"mappings":"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","file":"index.cjs","sourcesContent":["import { USDC, USDC_TESTNET } from '@suimpp/mpp/server';\nimport type { Serve } from './serve.js';\n\n// ---------------------------------------------------------------------------\n// Discovery docs — /openapi.json + /llms.txt.\n//\n// The shapes here are graded by the catalog's ingest (apps/gateway/lib/\n// catalog-ingest.ts `gradeListing`): a warning-free listing needs info.title,\n// a one-paragraph info.description, a flat string `x-payment-info.price` per\n// paid operation, and an application/json requestBody schema with typed\n// properties. Everything serve can derive is emitted automatically; the JSON\n// request schema comes from the route's `inputSchema` (zod v4 users:\n// `z.toJSONSchema(schema)`).\n// ---------------------------------------------------------------------------\n\nexport function buildOpenApiDocument(serve: Serve, origin?: string): Record<string, unknown> {\n const base = serve.baseUrl ?? origin;\n const paths: Record<string, unknown> = {};\n\n for (const route of serve.routes.values()) {\n const { path, priceUsdc, description, inputSchema } = route.meta;\n const operation: Record<string, unknown> = {\n operationId: path.replace(/[^a-zA-Z0-9]+/g, '_'),\n summary: description ?? path,\n responses: {\n '200': { description: 'Success' },\n ...(priceUsdc\n ? {\n '402': {\n description:\n 'Payment required — the body carries an x402 accepts[] envelope (scheme \"exact\", network sui). Sign it and retry with the X-PAYMENT header.',\n },\n }\n : {}),\n '422': { description: 'Invalid request body — never charged' },\n },\n };\n if (priceUsdc) {\n // Same shape the gateway's own /openapi.json emits: 'mpp' is the\n // protocol family, 'x402' the dialect; the x402 block mirrors the\n // static half of the live accepts[] entry (dynamic fields ride the 402).\n operation['x-payment-info'] = {\n pricingMode: 'fixed',\n price: priceUsdc,\n currency: 'USDC',\n protocols: ['mpp', 'x402'],\n x402: {\n scheme: 'exact',\n network: `sui:${serve.network}`,\n asset: (serve.network === 'testnet' ? USDC_TESTNET : USDC).type,\n payTo: serve.payTo,\n },\n };\n }\n if (inputSchema) {\n operation.requestBody = {\n required: true,\n content: { 'application/json': { schema: inputSchema } },\n };\n }\n paths[`/${path}`] = { post: operation };\n }\n\n return {\n openapi: '3.1.0',\n info: {\n title: serve.name ?? 'Paid API',\n version: '1.0.0',\n description:\n serve.description ??\n 'Agent-payable API. Every paid endpoint answers 402 with an x402 accepts[] envelope; payment settles in USDC on Sui.',\n },\n ...(base ? { servers: [{ url: base }] } : {}),\n paths,\n };\n}\n\nexport function buildLlmsTxt(serve: Serve, origin?: string): string {\n const base = serve.baseUrl ?? origin ?? '';\n const lines: string[] = [];\n lines.push(`# ${serve.name ?? 'Paid API'}`);\n lines.push('');\n if (serve.description) {\n lines.push(serve.description);\n lines.push('');\n }\n lines.push('## How to pay');\n lines.push('');\n lines.push(\n 'Endpoints below are paid per call in USDC on Sui (x402). An unpaid request returns',\n 'HTTP 402 with an `accepts[]` envelope; sign it and retry with the `X-PAYMENT` header.',\n 'Invalid input returns 422 before any payment is taken. A failed call is never charged.',\n '',\n 'Easiest client: `npm i -g @t2000/cli` then `t2 pay <url> --method POST --body \\'{...}\\'`,',\n 'or the t2000 MCP server (`t2000_pay`), or `@t2000/sdk` `pay()`.',\n '',\n );\n lines.push('## Endpoints');\n lines.push('');\n for (const route of serve.routes.values()) {\n const { path, priceUsdc, description, inputSchema } = route.meta;\n const price = priceUsdc ? `${priceUsdc} USDC per call` : 'free';\n lines.push(`### POST ${base}/${path} — ${price}`);\n if (description) lines.push(description);\n if (inputSchema) {\n lines.push('Request body (JSON Schema):');\n lines.push('```json');\n lines.push(JSON.stringify(inputSchema, null, 2));\n lines.push('```');\n }\n lines.push('');\n }\n lines.push(`Discovery: ${base}/openapi.json`);\n return lines.join('\\n');\n}\n","import { SuiGrpcClient } from '@mysten/sui/grpc';\nimport type { ServeNetwork } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Chain plumbing — same shape as the gateway's x402-dialect.ts (the reference\n// composition). All reads are gRPC; this package never touches JSON-RPC.\n//\n// Cache policy: the chain identifier (genesis digest) is immutable per\n// network — cached forever. The epoch advances ~daily and x402 requirements\n// are valid for [epoch, epoch+1], so a 10-minute TTL is conservatively fresh.\n// ---------------------------------------------------------------------------\n\nconst FULLNODE_URLS: Record<ServeNetwork, string> = {\n mainnet: 'https://fullnode.mainnet.sui.io:443',\n testnet: 'https://fullnode.testnet.sui.io:443',\n};\n\nconst EPOCH_TTL_MS = 10 * 60 * 1000;\n\nexport interface ChainInfo {\n chain: string;\n epoch: string;\n}\n\ninterface ChainState {\n client?: SuiGrpcClient;\n chainId?: string;\n epoch?: { value: string; fetchedAt: number };\n}\n\nconst state: Partial<Record<ServeNetwork, ChainState>> = {};\n\nexport function getGrpcClient(network: ServeNetwork, rpcUrl?: string): SuiGrpcClient {\n const s = (state[network] ??= {});\n if (!s.client) {\n s.client = new SuiGrpcClient({\n baseUrl: rpcUrl ?? FULLNODE_URLS[network],\n network,\n });\n }\n return s.client;\n}\n\nexport async function getChainInfo(network: ServeNetwork, rpcUrl?: string): Promise<ChainInfo> {\n const client = getGrpcClient(network, rpcUrl);\n const s = (state[network] ??= {});\n if (!s.chainId) {\n const res = await client.core.getChainIdentifier();\n s.chainId = res.chainIdentifier;\n }\n if (!s.epoch || Date.now() - s.epoch.fetchedAt > EPOCH_TTL_MS) {\n const res = await client.core.getCurrentSystemState();\n s.epoch = { value: String(res.systemState.epoch), fetchedAt: Date.now() };\n }\n return { chain: s.chainId, epoch: s.epoch.value };\n}\n\n/** Test seam — reset module caches between cases. */\nexport function __resetChainCaches(): void {\n delete state.mainnet;\n delete state.testnet;\n}\n\n/** Test seam — pre-seed chain info so tests never hit the network. */\nexport function __seedChainInfo(network: ServeNetwork, chain: string, epoch: string): void {\n const s = (state[network] ??= {});\n s.chainId = chain;\n s.epoch = { value: epoch, fetchedAt: Date.now() };\n}\n","import type { DigestStore } from '@suimpp/mpp/server';\nimport type { Currency } from '@suimpp/mpp/server';\nimport {\n createX402Requirements,\n encodeX402Response,\n isX402EscrowHeader,\n parseX402Header,\n settleX402Payment,\n verifyX402Payment,\n X402_PAYMENT_HEADER,\n X402_PAYMENT_RESPONSE_HEADER,\n X402_VERSION,\n type X402SettleResponse,\n} from '@suimpp/mpp/x402';\nimport { getChainInfo, getGrpcClient } from './chain.js';\nimport type {\n BuiltRoute,\n HandlerContext,\n HandlerResult,\n ServeNetwork,\n ServeSchema,\n StandardSchemaLike,\n} from './types.js';\n\n// ---------------------------------------------------------------------------\n// The paid-request lifecycle (SPEC_T2000_SERVE §3 — sign-then-settle,\n// handler-then-settle):\n//\n// no X-PAYMENT → 402 with the accepts[] envelope (never a charge;\n// the catalog probe and every discovery tool read\n// this, so it fires BEFORE body validation)\n// X-PAYMENT present:\n// 1. parse + STRUCTURAL verify (right amount/recipient/nonce — no RPC)\n// 2. challenge-once check (a signed payload is single-use)\n// 3. validate the body — invalid → 422, payment NEVER submitted\n// (the JMPR paid-422 class is impossible: the buyer keeps their money)\n// 4. run the handler — throws → 500, payment NEVER submitted\n// 5. settle (submit the buyer-signed gasless bytes; digest-once inside)\n// 6. consume the challenge, attach the X-PAYMENT-RESPONSE receipt\n//\n// Money only moves at step 5, after the seller has already produced the\n// result. A forged payload can waste seller compute (signature authority is\n// the chain at settle time), never buyer money.\n// ---------------------------------------------------------------------------\n\nexport interface RouteRuntime {\n payTo: string;\n network: ServeNetwork;\n currency: Currency;\n store: DigestStore;\n baseUrl?: string;\n rpcUrl?: string;\n report: boolean;\n}\n\nexport interface RouteOptions {\n path: string;\n description?: string;\n}\n\nconst MPP_REPORT_URL = 'https://mpp.t2000.ai/api/mpp/report';\nconst REPORT_TIMEOUT_MS = 2_000;\n\n/** Listing cap on mpp.t2000.ai (catalog-ingest price-cap gate). */\nconst CATALOG_PRICE_CAP_USDC = 5;\n\nconst CORS_HEADERS: Record<string, string> = {\n 'access-control-allow-origin': '*',\n 'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'access-control-allow-headers': `content-type, ${X402_PAYMENT_HEADER}`,\n 'access-control-expose-headers': `${X402_PAYMENT_RESPONSE_HEADER}, WWW-Authenticate`,\n};\n\nfunction withCors(response: Response): Response {\n const headers = new Headers(response.headers);\n for (const [k, v] of Object.entries(CORS_HEADERS)) headers.set(k, v);\n return new Response(response.body, { status: response.status, headers });\n}\n\nfunction json(status: number, body: unknown, headers?: Record<string, string>): Response {\n return withCors(\n new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json', ...headers },\n }),\n );\n}\n\nfunction isStandardSchema(schema: ServeSchema): schema is StandardSchemaLike {\n return typeof schema === 'object' && schema !== null && '~standard' in schema;\n}\n\nasync function validateBody(\n schema: ServeSchema,\n value: unknown,\n): Promise<{ ok: true; data: unknown } | { ok: false; message: string }> {\n if (isStandardSchema(schema)) {\n const result = await schema['~standard'].validate(value);\n if (result.issues) {\n return { ok: false, message: result.issues.map((i) => i.message).join('; ') };\n }\n return { ok: true, data: result.value };\n }\n const result = schema.safeParse(value);\n if (!result.success) {\n return { ok: false, message: result.error.message ?? 'invalid body' };\n }\n return { ok: true, data: result.data };\n}\n\n/** Positive decimal USDC string, max 6dp (atomic precision). */\nfunction assertValidPrice(price: string, path: string): void {\n if (!/^\\d+(\\.\\d{1,6})?$/.test(price) || Number(price) <= 0) {\n throw new Error(\n `[serve] Route \"${path}\": price must be a positive decimal USDC string with up to 6 decimals, got \"${price}\"`,\n );\n }\n if (Number(price) > CATALOG_PRICE_CAP_USDC) {\n console.warn(\n `[serve] Route \"${path}\": price ${price} USDC is above the ${CATALOG_PRICE_CAP_USDC} USDC listing cap — ` +\n 'the route works, but it will not list on mpp.t2000.ai. Job-class work belongs in `t2 service create` (escrow).',\n );\n }\n}\n\nexport class RouteBuilder<TBody = undefined> {\n private priceUsdc?: string;\n private bodySchema?: ServeSchema;\n private inputSchema?: Record<string, unknown>;\n private isFree = false;\n\n constructor(\n private readonly runtime: RouteRuntime,\n private readonly options: RouteOptions,\n private readonly register: (route: BuiltRoute) => void,\n ) {}\n\n /** Charge this many USDC per call (human units, e.g. \"0.01\"). */\n paid(priceUsdc: string): this {\n assertValidPrice(priceUsdc, this.options.path);\n this.priceUsdc = priceUsdc;\n this.isFree = false;\n return this;\n }\n\n /** Serve without payment (health checks, previews, docs). */\n unprotected(): this {\n this.isFree = true;\n this.priceUsdc = undefined;\n return this;\n }\n\n /**\n * Validate the JSON request body. zod v4 / valibot / arktype / anything\n * Standard-Schema, or anything with a zod-style safeParse.\n *\n * Pass the JSON Schema as the second argument to publish it in\n * /openapi.json + /llms.txt (zod v4: `z.toJSONSchema(schema)`) — buyers'\n * agents build request bodies from it, and the catalog grades listings\n * without one.\n */\n body<T>(schema: ServeSchema<T>, jsonSchema?: Record<string, unknown>): RouteBuilder<T> {\n this.bodySchema = schema;\n this.inputSchema = jsonSchema;\n return this as unknown as RouteBuilder<T>;\n }\n\n handler(fn: (ctx: HandlerContext<TBody>) => HandlerResult | Promise<HandlerResult>): BuiltRoute {\n if (!this.isFree && !this.priceUsdc) {\n throw new Error(\n `[serve] Route \"${this.options.path}\": call .paid('<usdc>') or .unprotected() before .handler()`,\n );\n }\n const runtime = this.runtime;\n const { path, description } = this.options;\n const priceUsdc = this.priceUsdc;\n const bodySchema = this.bodySchema;\n\n const route = (async (req: Request): Promise<Response> => {\n if (req.method === 'OPTIONS') {\n return withCors(new Response(null, { status: 204 }));\n }\n\n // Read + parse the body once, up front. A missing/empty body on a\n // schema-less route is fine; JSON parse failures only matter when a\n // paid request must be validated (the unpaid 402 fires regardless).\n let parsedBody: unknown;\n let bodyParseError: string | undefined;\n if (req.method !== 'GET' && req.method !== 'HEAD') {\n const text = await req.text();\n if (text.trim().length > 0) {\n try {\n parsedBody = JSON.parse(text);\n } catch {\n bodyParseError = 'request body is not valid JSON';\n }\n }\n }\n\n const resource = (runtime.baseUrl ?? new URL(req.url).origin).replace(/\\/$/, '') + `/${path}`;\n\n const runHandler = async (payer?: string): Promise<Response> => {\n let validated: unknown = parsedBody;\n if (bodySchema) {\n if (bodyParseError) return json(422, { error: bodyParseError });\n const result = await validateBody(bodySchema, parsedBody ?? {});\n if (!result.ok) return json(422, { error: result.message });\n validated = result.data;\n }\n const out = await fn({ body: validated as TBody, req, payer });\n if (out instanceof Response) return withCors(out);\n return json(200, out);\n };\n\n // Free route — no payment machinery at all.\n if (!priceUsdc) {\n try {\n return await runHandler();\n } catch (err) {\n console.error(`[serve] Route \"${path}\" handler failed:`, err);\n return json(500, { error: 'internal error' });\n }\n }\n\n const paymentHeader = req.headers.get(X402_PAYMENT_HEADER);\n\n // Unpaid → 402 with the accepts[] envelope. This fires before body\n // validation on purpose: the catalog probe (and every discovery tool)\n // POSTs `{}` and must see the challenge, and an unpaid request can\n // never be charged, so there is nothing to protect yet.\n if (!paymentHeader) {\n return await respond402(runtime, { resource, priceUsdc });\n }\n\n if (isX402EscrowHeader(paymentHeader)) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error:\n 'this endpoint sells instant per-call work (settle-then-serve), not escrow jobs — retry with a signed x402 payment',\n });\n }\n\n // 1. Parse + structural verify — right terms, right recipient, right\n // nonce. No RPC, no state. Wrong-terms payloads never reach the\n // handler.\n let payment: ReturnType<typeof parseX402Header>;\n try {\n payment = parseX402Header(paymentHeader);\n verifyX402Payment({\n payment,\n expected: {\n challengeId: payment.payload.challengeId,\n amount: priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n network: runtime.network,\n },\n });\n } catch (err) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: `invalid payment: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // 2. Challenge-once — a signed payload is single-use even before it\n // settles (the settled digest is separately consumed inside\n // settleX402Payment, digest-once).\n const challengeKey = `challenge:${payment.payload.challengeId}`;\n if (await runtime.store.has(challengeKey)) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: 'payment challenge already used — sign a fresh payment',\n });\n }\n\n // 3 + 4. Validate, then compute the result. Any failure here returns\n // WITHOUT settling — the buyer-signed bytes are never submitted.\n let served: Response;\n try {\n served = await runHandler(payment.payload.senderAddress);\n } catch (err) {\n console.error(`[serve] Route \"${path}\" handler failed (payment NOT settled):`, err);\n return json(500, { error: 'internal error — you were not charged' });\n }\n if (served.status >= 400) return served; // 422 etc. — not charged\n\n // 5. Settle — submit the buyer-signed gasless bytes, confirm the\n // on-chain balance change, record the digest (digest-once).\n let settle: X402SettleResponse;\n try {\n settle = await settleX402Payment({\n payment,\n client: getGrpcClient(runtime.network, runtime.rpcUrl),\n store: runtime.store,\n expected: {\n challengeId: payment.payload.challengeId,\n amount: priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n network: runtime.network,\n },\n });\n } catch (err) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: `settlement failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // 6. Consume the challenge + attach the receipt.\n try {\n await runtime.store.set(challengeKey);\n } catch {\n // Digest-once already holds; challenge-once is defense in depth.\n }\n\n if (runtime.report) {\n reportPayment(settle.transaction, resource);\n }\n\n const headers = new Headers(served.headers);\n headers.set(X402_PAYMENT_RESPONSE_HEADER, encodeX402Response(settle));\n return new Response(served.body, { status: served.status, headers });\n }) as BuiltRoute;\n\n route.meta = { path, priceUsdc, description, bodySchema, inputSchema: this.inputSchema };\n this.register(route);\n return route;\n }\n}\n\nasync function respond402(\n runtime: RouteRuntime,\n args: { resource: string; priceUsdc: string; error?: string },\n): Promise<Response> {\n try {\n const { chain, epoch } = await getChainInfo(runtime.network, runtime.rpcUrl);\n const requirements = createX402Requirements({\n challengeId: crypto.randomUUID(),\n amount: args.priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n resource: args.resource,\n network: runtime.network,\n chain,\n currentEpoch: epoch,\n });\n return json(402, {\n x402Version: X402_VERSION,\n error: args.error ?? 'Payment required',\n accepts: [requirements],\n });\n } catch (err) {\n // Chain info unreachable — a 402 without the envelope is unpayable, so\n // be honest about the outage instead of serving a dead challenge.\n console.error('[serve] failed to build 402 challenge:', err);\n return json(503, { error: 'payment challenge temporarily unavailable' });\n }\n}\n\n/**\n * Best-effort activity-feed report (mpp.t2000.ai). The gateway verifies the\n * digest on-chain before recording anything, so this carries no trusted\n * data — a lost or duplicate report is harmless.\n */\nfunction reportPayment(digest: string, url: string): void {\n void fetch(MPP_REPORT_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ digest, url }),\n signal: AbortSignal.timeout(REPORT_TIMEOUT_MS),\n }).catch(() => {});\n}\n","import type { DigestStore } from '@suimpp/mpp/server';\n\nexport { InMemoryDigestStore } from '@suimpp/mpp/server';\nexport type { DigestStore } from '@suimpp/mpp/server';\n\n// ---------------------------------------------------------------------------\n// Upstash-REST digest store — the production replay store for serverless\n// hosts. Mirrors the gateway's upstash-digest-store.ts but speaks the\n// Upstash REST API over plain fetch (no @upstash/redis dependency).\n//\n// TTL: 72h. x402 payments are chain-valid for the whole ValidDuring window\n// ([minEpoch, minEpoch+1] ≈ up to ~48h on mainnet). Sui resubmission of an\n// executed tx is idempotent, so if the digest/challenge keys expired BEFORE\n// the window closed, a replayed X-PAYMENT would re-settle \"successfully\"\n// and serve again on a single payment. 72h > max window + drift.\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_TTL_SECONDS = 72 * 60 * 60;\nconst PREFIX = 'serve:digest:';\n\nexport interface UpstashDigestStoreOptions {\n url: string;\n token: string;\n /** Key TTL in seconds. Default 72h — do not lower below ~50h (see above). */\n ttlSeconds?: number;\n}\n\nexport class UpstashDigestStore implements DigestStore {\n private readonly url: string;\n private readonly token: string;\n private readonly ttlSeconds: number;\n\n constructor(options: UpstashDigestStoreOptions) {\n this.url = options.url.replace(/\\/$/, '');\n this.token = options.token;\n this.ttlSeconds = options.ttlSeconds ?? DEFAULT_TTL_SECONDS;\n }\n\n private async command(segments: string[]): Promise<unknown> {\n const res = await fetch(`${this.url}/${segments.map(encodeURIComponent).join('/')}`, {\n headers: { authorization: `Bearer ${this.token}` },\n });\n if (!res.ok) {\n throw new Error(`Upstash command failed: ${res.status} ${await res.text()}`);\n }\n const body = (await res.json()) as { result?: unknown; error?: string };\n if (body.error) throw new Error(`Upstash error: ${body.error}`);\n return body.result;\n }\n\n async has(digest: string): Promise<boolean> {\n const result = await this.command(['GET', PREFIX + digest]);\n return result !== null && result !== undefined;\n }\n\n async set(digest: string): Promise<void> {\n // SET key 1 EX <ttl> NX — atomic set-if-absent. A null result means the\n // key already existed: the digest (or challenge) was already consumed.\n const result = await this.command([\n 'SET',\n PREFIX + digest,\n '1',\n 'EX',\n String(this.ttlSeconds),\n 'NX',\n ]);\n if (result === null || result === undefined) {\n throw new Error(`Digest already used: ${digest}`);\n }\n }\n}\n","import { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';\nimport { InMemoryDigestStore, USDC, USDC_TESTNET, type Currency } from '@suimpp/mpp/server';\nimport { buildLlmsTxt, buildOpenApiDocument } from './discovery.js';\nimport { RouteBuilder, type RouteOptions, type RouteRuntime } from './route.js';\nimport { UpstashDigestStore } from './store.js';\nimport type { BuiltRoute, ServeConfig, ServeNetwork } from './types.js';\n\nexport class Serve {\n private readonly runtime: RouteRuntime;\n /** Every route built through this instance, keyed by path (discovery). */\n readonly routes = new Map<string, BuiltRoute>();\n\n readonly payTo: string;\n readonly network: ServeNetwork;\n readonly name?: string;\n readonly description?: string;\n readonly baseUrl?: string;\n\n constructor(config: ServeConfig) {\n if (!config.payTo || !isValidSuiAddress(config.payTo)) {\n throw new Error(\n `[serve] payTo must be a valid Sui address (the wallet your payments settle to), got \"${config.payTo}\"`,\n );\n }\n this.payTo = normalizeSuiAddress(config.payTo);\n this.network = config.network ?? 'mainnet';\n this.name = config.name;\n this.description = config.description;\n this.baseUrl = config.baseUrl?.replace(/\\/$/, '');\n\n const currency: Currency = this.network === 'testnet' ? USDC_TESTNET : USDC;\n this.runtime = {\n payTo: this.payTo,\n network: this.network,\n currency,\n store: config.store ?? new InMemoryDigestStore(),\n baseUrl: this.baseUrl,\n rpcUrl: config.rpcUrl,\n report: config.report ?? true,\n };\n }\n\n /** Start building a route. Chain `.paid()` / `.body()` / `.handler()`. */\n route(options: RouteOptions): RouteBuilder {\n const path = options.path.replace(/^\\/+/, '').replace(/\\/+$/, '');\n if (!path) throw new Error('[serve] route path must be non-empty');\n return new RouteBuilder({ ...this.runtime }, { ...options, path }, (route) => {\n this.routes.set(path, route);\n });\n }\n\n /**\n * Discovery: GET handler for /openapi.json. OpenAPI 3.1 with the\n * `x-payment-info` pricing extension on every paid operation — the shape\n * the mpp.t2000.ai catalog (and x402 tooling generally) indexes.\n *\n * export const GET = serve.openapi(); // app/openapi.json/route.ts\n */\n openapi(): (req: Request) => Response {\n return (req: Request) =>\n new Response(JSON.stringify(buildOpenApiDocument(this, new URL(req.url).origin), null, 2), {\n headers: { 'content-type': 'application/json', 'access-control-allow-origin': '*' },\n });\n }\n\n /**\n * Discovery: GET handler for /llms.txt — plain-text guidance agents read\n * to understand what the API sells, what it costs, and how to pay.\n *\n * export const GET = serve.llms(); // app/llms.txt/route.ts\n */\n llms(): (req: Request) => Response {\n return (req: Request) =>\n new Response(buildLlmsTxt(this, new URL(req.url).origin), {\n headers: { 'content-type': 'text/plain; charset=utf-8', 'access-control-allow-origin': '*' },\n });\n }\n\n /**\n * One fetch handler for the whole app — routes + discovery docs. For\n * fetch-native runtimes (Bun.serve, Deno.serve, Hono, Cloudflare Workers):\n *\n * Bun.serve({ fetch: serve.fetch });\n * app.all('*', (c) => serve.fetch(c.req.raw)); // Hono\n *\n * Next.js apps can skip this and export route handlers directly.\n */\n readonly fetch = async (req: Request): Promise<Response> => {\n const pathname = new URL(req.url).pathname.replace(/^\\/+/, '').replace(/\\/+$/, '');\n if (pathname === 'openapi.json') return this.openapi()(req);\n if (pathname === 'llms.txt') return this.llms()(req);\n const route = this.routes.get(pathname);\n if (route) return route(req);\n return new Response(\n JSON.stringify({ error: 'not found', discovery: ['/openapi.json', '/llms.txt'] }),\n { status: 404, headers: { 'content-type': 'application/json' } },\n );\n };\n\n /**\n * The curl that lists this API on mpp.t2000.ai / agents.t2000.ai once it\n * is deployed. Listing is a separate, explicit step — the catalog gates\n * (url · probe · dialect · price-cap), not this package, decide outcomes.\n * Dry-run first with /api/catalog/preview.\n */\n catalogSubmitCommand(deployedUrl?: string): string {\n const base = (deployedUrl ?? this.baseUrl ?? 'https://<your-deployed-app>').replace(/\\/$/, '');\n const paidPaths = [...this.routes.values()].filter((r) => r.meta.priceUsdc);\n const example = paidPaths[0]?.meta.path ?? '<route>';\n return [\n '# Dry-run (shows gate results, changes nothing):',\n `curl -X POST https://mpp.t2000.ai/api/catalog/preview -H 'content-type: application/json' -d '{\"url\":\"${base}/${example}\"}'`,\n '# List for real:',\n `curl -X POST https://mpp.t2000.ai/api/catalog/submit -H 'content-type: application/json' -d '{\"url\":\"${base}/${example}\"}'`,\n ].join('\\n');\n }\n}\n\nexport function createServe(config: ServeConfig): Serve {\n return new Serve(config);\n}\n\n/**\n * Build a Serve from environment variables — the template-app path where\n * config lives in the host's env UI, not code.\n *\n * T2000_PAY_TO required — the seller's Sui address\n * T2000_NETWORK optional — 'mainnet' (default) | 'testnet'\n * T2000_BASE_URL optional — public URL of the deployed app\n * T2000_NAME optional — service name for discovery docs\n * T2000_DESCRIPTION optional — one-liner for discovery docs\n * KV_REST_API_URL / KV_REST_API_TOKEN\n * optional — enables the durable Upstash replay store\n * (REQUIRED in serverless production; without it replay\n * state is per-instance memory)\n *\n * Empty strings are treated as unset (the Vercel empty-env bug class).\n */\nexport function createServeFromEnv(env: Record<string, string | undefined> = process.env): Serve {\n const read = (key: string): string | undefined => {\n const v = env[key]?.trim();\n return v && v.length > 0 ? v : undefined;\n };\n\n const payTo = read('T2000_PAY_TO');\n if (!payTo) {\n throw new Error(\n '[serve] T2000_PAY_TO is not set (or is empty). Set it to the Sui address your payments should settle to — `t2 address` prints yours.',\n );\n }\n\n const network = read('T2000_NETWORK');\n if (network && network !== 'mainnet' && network !== 'testnet') {\n throw new Error(`[serve] T2000_NETWORK must be 'mainnet' or 'testnet', got \"${network}\"`);\n }\n\n const kvUrl = read('KV_REST_API_URL');\n const kvToken = read('KV_REST_API_TOKEN');\n const store =\n kvUrl && kvToken ? new UpstashDigestStore({ url: kvUrl, token: kvToken }) : undefined;\n\n if (!store) {\n console.warn(\n '[serve] No KV_REST_API_URL/KV_REST_API_TOKEN — using the in-memory replay store. ' +\n 'Fine for a single long-lived process; on serverless hosts set both so replay protection is durable.',\n );\n }\n\n return new Serve({\n payTo,\n network: (network as ServeNetwork | undefined) ?? 'mainnet',\n baseUrl: read('T2000_BASE_URL'),\n name: read('T2000_NAME'),\n description: read('T2000_DESCRIPTION'),\n store,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/discovery.ts","../src/chain.ts","../src/route.ts","../src/store.ts","../src/serve.ts"],"names":["USDC_TESTNET","USDC","SuiGrpcClient","X402_PAYMENT_HEADER","X402_PAYMENT_RESPONSE_HEADER","result","isX402EscrowHeader","parseX402Header","verifyX402Payment","settleX402Payment","encodeX402Response","createX402Requirements","X402_VERSION","isValidSuiAddress","normalizeSuiAddress","InMemoryDigestStore"],"mappings":"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","file":"index.cjs","sourcesContent":["import { USDC, USDC_TESTNET } from '@suimpp/mpp/server';\nimport type { Serve } from './serve.js';\n\n// ---------------------------------------------------------------------------\n// Discovery docs — /openapi.json + /llms.txt.\n//\n// The shapes here are graded by the catalog's ingest (apps/gateway/lib/\n// catalog-ingest.ts `gradeListing`): a warning-free listing needs info.title,\n// a one-paragraph info.description, a flat string `x-payment-info.price` per\n// paid operation, and an application/json requestBody schema with typed\n// properties. Everything serve can derive is emitted automatically; the JSON\n// request schema comes from the route's `inputSchema` (zod v4 users:\n// `z.toJSONSchema(schema)`).\n// ---------------------------------------------------------------------------\n\nexport function buildOpenApiDocument(serve: Serve, origin?: string): Record<string, unknown> {\n const base = serve.baseUrl ?? origin;\n const paths: Record<string, unknown> = {};\n\n for (const route of serve.routes.values()) {\n const { path, priceUsdc, description, inputSchema } = route.meta;\n const operation: Record<string, unknown> = {\n operationId: path.replace(/[^a-zA-Z0-9]+/g, '_'),\n summary: description ?? path,\n responses: {\n '200': { description: 'Success' },\n ...(priceUsdc\n ? {\n '402': {\n description:\n 'Payment required — the body carries an x402 accepts[] envelope (scheme \"exact\", network sui). Sign it and retry with the X-PAYMENT header.',\n },\n }\n : {}),\n '422': { description: 'Invalid request body — never charged' },\n },\n };\n if (priceUsdc) {\n // Same shape the gateway's own /openapi.json emits: 'mpp' is the\n // protocol family, 'x402' the dialect; the x402 block mirrors the\n // static half of the live accepts[] entry (dynamic fields ride the 402).\n operation['x-payment-info'] = {\n pricingMode: 'fixed',\n price: priceUsdc,\n currency: 'USDC',\n protocols: ['mpp', 'x402'],\n x402: {\n scheme: 'exact',\n network: `sui:${serve.network}`,\n asset: (serve.network === 'testnet' ? USDC_TESTNET : USDC).type,\n payTo: serve.payTo,\n },\n };\n }\n if (inputSchema) {\n operation.requestBody = {\n required: true,\n content: { 'application/json': { schema: inputSchema } },\n };\n }\n paths[`/${path}`] = { post: operation };\n }\n\n return {\n openapi: '3.1.0',\n info: {\n title: serve.name ?? 'Paid API',\n version: '1.0.0',\n description:\n serve.description ??\n 'Agent-payable API. Every paid endpoint answers 402 with an x402 accepts[] envelope; payment settles in USDC on Sui.',\n },\n ...(base ? { servers: [{ url: base }] } : {}),\n paths,\n };\n}\n\nexport function buildLlmsTxt(serve: Serve, origin?: string): string {\n const base = serve.baseUrl ?? origin ?? '';\n const lines: string[] = [];\n lines.push(`# ${serve.name ?? 'Paid API'}`);\n lines.push('');\n if (serve.description) {\n lines.push(serve.description);\n lines.push('');\n }\n lines.push('## How to pay');\n lines.push('');\n lines.push(\n 'Endpoints below are paid per call in USDC on Sui (x402). An unpaid request returns',\n 'HTTP 402 with an `accepts[]` envelope; sign it and retry with the `X-PAYMENT` header.',\n 'Invalid input returns 422 before any payment is taken. A failed call is never charged.',\n '',\n 'Easiest client: `npm i -g @t2000/cli` then `t2 pay <url> --data \\'{...}\\'`,',\n 'or the t2000 MCP server (`t2000_pay`), or `@t2000/sdk` `pay()`.',\n '',\n );\n lines.push('## Endpoints');\n lines.push('');\n for (const route of serve.routes.values()) {\n const { path, priceUsdc, description, inputSchema } = route.meta;\n const price = priceUsdc ? `${priceUsdc} USDC per call` : 'free';\n lines.push(`### POST ${base}/${path} — ${price}`);\n if (description) lines.push(description);\n if (inputSchema) {\n lines.push('Request body (JSON Schema):');\n lines.push('```json');\n lines.push(JSON.stringify(inputSchema, null, 2));\n lines.push('```');\n }\n lines.push('');\n }\n lines.push(`Discovery: ${base}/openapi.json`);\n return lines.join('\\n');\n}\n","import { SuiGrpcClient } from '@mysten/sui/grpc';\nimport type { ServeNetwork } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Chain plumbing — same shape as the gateway's x402-dialect.ts (the reference\n// composition). All reads are gRPC; this package never touches JSON-RPC.\n//\n// Cache policy: the chain identifier (genesis digest) is immutable per\n// network — cached forever. The epoch advances ~daily and x402 requirements\n// are valid for [epoch, epoch+1], so a 10-minute TTL is conservatively fresh.\n// ---------------------------------------------------------------------------\n\nconst FULLNODE_URLS: Record<ServeNetwork, string> = {\n mainnet: 'https://fullnode.mainnet.sui.io:443',\n testnet: 'https://fullnode.testnet.sui.io:443',\n};\n\nconst EPOCH_TTL_MS = 10 * 60 * 1000;\n\nexport interface ChainInfo {\n chain: string;\n epoch: string;\n}\n\ninterface ChainState {\n client?: SuiGrpcClient;\n chainId?: string;\n epoch?: { value: string; fetchedAt: number };\n}\n\nconst state: Partial<Record<ServeNetwork, ChainState>> = {};\n\nexport function getGrpcClient(network: ServeNetwork, rpcUrl?: string): SuiGrpcClient {\n const s = (state[network] ??= {});\n if (!s.client) {\n s.client = new SuiGrpcClient({\n baseUrl: rpcUrl ?? FULLNODE_URLS[network],\n network,\n });\n }\n return s.client;\n}\n\nexport async function getChainInfo(network: ServeNetwork, rpcUrl?: string): Promise<ChainInfo> {\n const client = getGrpcClient(network, rpcUrl);\n const s = (state[network] ??= {});\n if (!s.chainId) {\n const res = await client.core.getChainIdentifier();\n s.chainId = res.chainIdentifier;\n }\n if (!s.epoch || Date.now() - s.epoch.fetchedAt > EPOCH_TTL_MS) {\n const res = await client.core.getCurrentSystemState();\n s.epoch = { value: String(res.systemState.epoch), fetchedAt: Date.now() };\n }\n return { chain: s.chainId, epoch: s.epoch.value };\n}\n\n/** Test seam — reset module caches between cases. */\nexport function __resetChainCaches(): void {\n delete state.mainnet;\n delete state.testnet;\n}\n\n/** Test seam — pre-seed chain info so tests never hit the network. */\nexport function __seedChainInfo(network: ServeNetwork, chain: string, epoch: string): void {\n const s = (state[network] ??= {});\n s.chainId = chain;\n s.epoch = { value: epoch, fetchedAt: Date.now() };\n}\n","import type { DigestStore } from '@suimpp/mpp/server';\nimport type { Currency } from '@suimpp/mpp/server';\nimport {\n createX402Requirements,\n encodeX402Response,\n isX402EscrowHeader,\n parseX402Header,\n settleX402Payment,\n verifyX402Payment,\n X402_PAYMENT_HEADER,\n X402_PAYMENT_RESPONSE_HEADER,\n X402_VERSION,\n type X402SettleResponse,\n} from '@suimpp/mpp/x402';\nimport { getChainInfo, getGrpcClient } from './chain.js';\nimport type {\n BuiltRoute,\n HandlerContext,\n HandlerResult,\n ServeNetwork,\n ServeSchema,\n StandardSchemaLike,\n} from './types.js';\n\n// ---------------------------------------------------------------------------\n// The paid-request lifecycle (SPEC_T2000_SERVE §3 — sign-then-settle,\n// handler-then-settle):\n//\n// no X-PAYMENT → 402 with the accepts[] envelope (never a charge;\n// the catalog probe and every discovery tool read\n// this, so it fires BEFORE body validation)\n// X-PAYMENT present:\n// 1. parse + STRUCTURAL verify (right amount/recipient/nonce — no RPC)\n// 2. challenge-once check (a signed payload is single-use)\n// 3. validate the body — invalid → 422, payment NEVER submitted\n// (the JMPR paid-422 class is impossible: the buyer keeps their money)\n// 4. run the handler — throws → 500, payment NEVER submitted\n// 5. settle (submit the buyer-signed gasless bytes; digest-once inside)\n// 6. consume the challenge, attach the X-PAYMENT-RESPONSE receipt\n//\n// Money only moves at step 5, after the seller has already produced the\n// result. A forged payload can waste seller compute (signature authority is\n// the chain at settle time), never buyer money.\n// ---------------------------------------------------------------------------\n\nexport interface RouteRuntime {\n payTo: string;\n network: ServeNetwork;\n currency: Currency;\n store: DigestStore;\n baseUrl?: string;\n rpcUrl?: string;\n report: boolean;\n}\n\nexport interface RouteOptions {\n path: string;\n description?: string;\n}\n\nconst MPP_REPORT_URL = 'https://mpp.t2000.ai/api/mpp/report';\nconst REPORT_TIMEOUT_MS = 2_000;\n\n/** Listing cap on mpp.t2000.ai (catalog-ingest price-cap gate). */\nconst CATALOG_PRICE_CAP_USDC = 5;\n\nconst CORS_HEADERS: Record<string, string> = {\n 'access-control-allow-origin': '*',\n 'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'access-control-allow-headers': `content-type, ${X402_PAYMENT_HEADER}`,\n 'access-control-expose-headers': `${X402_PAYMENT_RESPONSE_HEADER}, WWW-Authenticate`,\n};\n\nfunction withCors(response: Response): Response {\n const headers = new Headers(response.headers);\n for (const [k, v] of Object.entries(CORS_HEADERS)) headers.set(k, v);\n return new Response(response.body, { status: response.status, headers });\n}\n\nfunction json(status: number, body: unknown, headers?: Record<string, string>): Response {\n return withCors(\n new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json', ...headers },\n }),\n );\n}\n\nfunction isStandardSchema(schema: ServeSchema): schema is StandardSchemaLike {\n return typeof schema === 'object' && schema !== null && '~standard' in schema;\n}\n\nasync function validateBody(\n schema: ServeSchema,\n value: unknown,\n): Promise<{ ok: true; data: unknown } | { ok: false; message: string }> {\n if (isStandardSchema(schema)) {\n const result = await schema['~standard'].validate(value);\n if (result.issues) {\n // Name the failing field — bare \"Invalid input\" ×N gives a paying\n // buyer's agent nothing to self-correct with.\n const message = result.issues\n .map((i) => {\n const path = (i.path ?? [])\n .map((seg) => (typeof seg === 'object' ? String(seg.key) : String(seg)))\n .join('.');\n return path ? `${path}: ${i.message}` : i.message;\n })\n .join('; ');\n return { ok: false, message };\n }\n return { ok: true, data: result.value };\n }\n const result = schema.safeParse(value);\n if (!result.success) {\n return { ok: false, message: result.error.message ?? 'invalid body' };\n }\n return { ok: true, data: result.data };\n}\n\n/** Positive decimal USDC string, max 6dp (atomic precision). */\nfunction assertValidPrice(price: string, path: string): void {\n if (!/^\\d+(\\.\\d{1,6})?$/.test(price) || Number(price) <= 0) {\n throw new Error(\n `[serve] Route \"${path}\": price must be a positive decimal USDC string with up to 6 decimals, got \"${price}\"`,\n );\n }\n if (Number(price) > CATALOG_PRICE_CAP_USDC) {\n console.warn(\n `[serve] Route \"${path}\": price ${price} USDC is above the ${CATALOG_PRICE_CAP_USDC} USDC listing cap — ` +\n 'the route works, but it will not list on mpp.t2000.ai. Job-class work belongs in `t2 service create` (escrow).',\n );\n }\n}\n\nexport class RouteBuilder<TBody = undefined> {\n private priceUsdc?: string;\n private bodySchema?: ServeSchema;\n private inputSchema?: Record<string, unknown>;\n private isFree = false;\n\n constructor(\n private readonly runtime: RouteRuntime,\n private readonly options: RouteOptions,\n private readonly register: (route: BuiltRoute) => void,\n ) {}\n\n /** Charge this many USDC per call (human units, e.g. \"0.01\"). */\n paid(priceUsdc: string): this {\n assertValidPrice(priceUsdc, this.options.path);\n this.priceUsdc = priceUsdc;\n this.isFree = false;\n return this;\n }\n\n /** Serve without payment (health checks, previews, docs). */\n unprotected(): this {\n this.isFree = true;\n this.priceUsdc = undefined;\n return this;\n }\n\n /**\n * Validate the JSON request body. zod v4 / valibot / arktype / anything\n * Standard-Schema, or anything with a zod-style safeParse.\n *\n * Pass the JSON Schema as the second argument to publish it in\n * /openapi.json + /llms.txt (zod v4: `z.toJSONSchema(schema)`) — buyers'\n * agents build request bodies from it, and the catalog grades listings\n * without one.\n */\n body<T>(schema: ServeSchema<T>, jsonSchema?: Record<string, unknown>): RouteBuilder<T> {\n this.bodySchema = schema;\n this.inputSchema = jsonSchema;\n return this as unknown as RouteBuilder<T>;\n }\n\n handler(fn: (ctx: HandlerContext<TBody>) => HandlerResult | Promise<HandlerResult>): BuiltRoute {\n if (!this.isFree && !this.priceUsdc) {\n throw new Error(\n `[serve] Route \"${this.options.path}\": call .paid('<usdc>') or .unprotected() before .handler()`,\n );\n }\n const runtime = this.runtime;\n const { path, description } = this.options;\n const priceUsdc = this.priceUsdc;\n const bodySchema = this.bodySchema;\n\n const route = (async (req: Request): Promise<Response> => {\n if (req.method === 'OPTIONS') {\n return withCors(new Response(null, { status: 204 }));\n }\n\n // Read + parse the body once, up front. A missing/empty body on a\n // schema-less route is fine; JSON parse failures only matter when a\n // paid request must be validated (the unpaid 402 fires regardless).\n let parsedBody: unknown;\n let bodyParseError: string | undefined;\n if (req.method !== 'GET' && req.method !== 'HEAD') {\n const text = await req.text();\n if (text.trim().length > 0) {\n try {\n parsedBody = JSON.parse(text);\n } catch {\n bodyParseError = 'request body is not valid JSON';\n }\n }\n }\n\n const resource = (runtime.baseUrl ?? new URL(req.url).origin).replace(/\\/$/, '') + `/${path}`;\n\n const runHandler = async (payer?: string): Promise<Response> => {\n let validated: unknown = parsedBody;\n if (bodySchema) {\n // `paid: false` is machine-readable charge honesty — a 422 fires\n // BEFORE settlement, so the buyer always keeps their money.\n if (bodyParseError) {\n return json(422, { error: bodyParseError, paid: false });\n }\n const result = await validateBody(bodySchema, parsedBody ?? {});\n if (!result.ok) {\n return json(422, { error: result.message, paid: false });\n }\n validated = result.data;\n }\n const out = await fn({ body: validated as TBody, req, payer });\n if (out instanceof Response) return withCors(out);\n return json(200, out);\n };\n\n // Free route — no payment machinery at all.\n if (!priceUsdc) {\n try {\n return await runHandler();\n } catch (err) {\n console.error(`[serve] Route \"${path}\" handler failed:`, err);\n return json(500, { error: 'internal error' });\n }\n }\n\n const paymentHeader = req.headers.get(X402_PAYMENT_HEADER);\n\n // Unpaid → 402 with the accepts[] envelope. This fires before body\n // validation on purpose: the catalog probe (and every discovery tool)\n // POSTs `{}` and must see the challenge, and an unpaid request can\n // never be charged, so there is nothing to protect yet.\n if (!paymentHeader) {\n return await respond402(runtime, { resource, priceUsdc });\n }\n\n if (isX402EscrowHeader(paymentHeader)) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error:\n 'this endpoint sells instant per-call work (settle-then-serve), not escrow jobs — retry with a signed x402 payment',\n });\n }\n\n // 1. Parse + structural verify — right terms, right recipient, right\n // nonce. No RPC, no state. Wrong-terms payloads never reach the\n // handler.\n let payment: ReturnType<typeof parseX402Header>;\n try {\n payment = parseX402Header(paymentHeader);\n verifyX402Payment({\n payment,\n expected: {\n challengeId: payment.payload.challengeId,\n amount: priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n network: runtime.network,\n },\n });\n } catch (err) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: `invalid payment: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // 2. Challenge-once — a signed payload is single-use even before it\n // settles (the settled digest is separately consumed inside\n // settleX402Payment, digest-once).\n const challengeKey = `challenge:${payment.payload.challengeId}`;\n if (await runtime.store.has(challengeKey)) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: 'payment challenge already used — sign a fresh payment',\n });\n }\n\n // 3 + 4. Validate, then compute the result. Any failure here returns\n // WITHOUT settling — the buyer-signed bytes are never submitted.\n let served: Response;\n try {\n served = await runHandler(payment.payload.senderAddress);\n } catch (err) {\n console.error(`[serve] Route \"${path}\" handler failed (payment NOT settled):`, err);\n return json(500, { error: 'internal error — you were not charged' });\n }\n if (served.status >= 400) return served; // 422 etc. — not charged\n\n // 5. Settle — submit the buyer-signed gasless bytes, confirm the\n // on-chain balance change, record the digest (digest-once).\n let settle: X402SettleResponse;\n try {\n settle = await settleX402Payment({\n payment,\n client: getGrpcClient(runtime.network, runtime.rpcUrl),\n store: runtime.store,\n expected: {\n challengeId: payment.payload.challengeId,\n amount: priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n network: runtime.network,\n },\n });\n } catch (err) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: `settlement failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // 6. Consume the challenge + attach the receipt.\n try {\n await runtime.store.set(challengeKey);\n } catch {\n // Digest-once already holds; challenge-once is defense in depth.\n }\n\n if (runtime.report) {\n reportPayment(settle.transaction, resource);\n }\n\n const headers = new Headers(served.headers);\n headers.set(X402_PAYMENT_RESPONSE_HEADER, encodeX402Response(settle));\n return new Response(served.body, { status: served.status, headers });\n }) as BuiltRoute;\n\n route.meta = { path, priceUsdc, description, bodySchema, inputSchema: this.inputSchema };\n this.register(route);\n return route;\n }\n}\n\nasync function respond402(\n runtime: RouteRuntime,\n args: { resource: string; priceUsdc: string; error?: string },\n): Promise<Response> {\n try {\n const { chain, epoch } = await getChainInfo(runtime.network, runtime.rpcUrl);\n const requirements = createX402Requirements({\n challengeId: crypto.randomUUID(),\n amount: args.priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n resource: args.resource,\n network: runtime.network,\n chain,\n currentEpoch: epoch,\n });\n return json(402, {\n x402Version: X402_VERSION,\n error: args.error ?? 'Payment required',\n accepts: [requirements],\n });\n } catch (err) {\n // Chain info unreachable — a 402 without the envelope is unpayable, so\n // be honest about the outage instead of serving a dead challenge.\n console.error('[serve] failed to build 402 challenge:', err);\n return json(503, { error: 'payment challenge temporarily unavailable' });\n }\n}\n\n/**\n * Best-effort activity-feed report (mpp.t2000.ai). The gateway verifies the\n * digest on-chain before recording anything, so this carries no trusted\n * data — a lost or duplicate report is harmless.\n */\nfunction reportPayment(digest: string, url: string): void {\n void fetch(MPP_REPORT_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ digest, url }),\n signal: AbortSignal.timeout(REPORT_TIMEOUT_MS),\n }).catch(() => {});\n}\n","import type { DigestStore } from '@suimpp/mpp/server';\n\nexport { InMemoryDigestStore } from '@suimpp/mpp/server';\nexport type { DigestStore } from '@suimpp/mpp/server';\n\n// ---------------------------------------------------------------------------\n// Upstash-REST digest store — the production replay store for serverless\n// hosts. Mirrors the gateway's upstash-digest-store.ts but speaks the\n// Upstash REST API over plain fetch (no @upstash/redis dependency).\n//\n// TTL: 72h. x402 payments are chain-valid for the whole ValidDuring window\n// ([minEpoch, minEpoch+1] ≈ up to ~48h on mainnet). Sui resubmission of an\n// executed tx is idempotent, so if the digest/challenge keys expired BEFORE\n// the window closed, a replayed X-PAYMENT would re-settle \"successfully\"\n// and serve again on a single payment. 72h > max window + drift.\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_TTL_SECONDS = 72 * 60 * 60;\nconst PREFIX = 'serve:digest:';\n\nexport interface UpstashDigestStoreOptions {\n url: string;\n token: string;\n /** Key TTL in seconds. Default 72h — do not lower below ~50h (see above). */\n ttlSeconds?: number;\n}\n\nexport class UpstashDigestStore implements DigestStore {\n private readonly url: string;\n private readonly token: string;\n private readonly ttlSeconds: number;\n\n constructor(options: UpstashDigestStoreOptions) {\n this.url = options.url.replace(/\\/$/, '');\n this.token = options.token;\n this.ttlSeconds = options.ttlSeconds ?? DEFAULT_TTL_SECONDS;\n }\n\n private async command(segments: string[]): Promise<unknown> {\n const res = await fetch(`${this.url}/${segments.map(encodeURIComponent).join('/')}`, {\n headers: { authorization: `Bearer ${this.token}` },\n });\n if (!res.ok) {\n throw new Error(`Upstash command failed: ${res.status} ${await res.text()}`);\n }\n const body = (await res.json()) as { result?: unknown; error?: string };\n if (body.error) throw new Error(`Upstash error: ${body.error}`);\n return body.result;\n }\n\n async has(digest: string): Promise<boolean> {\n const result = await this.command(['GET', PREFIX + digest]);\n return result !== null && result !== undefined;\n }\n\n async set(digest: string): Promise<void> {\n // SET key 1 EX <ttl> NX — atomic set-if-absent. A null result means the\n // key already existed: the digest (or challenge) was already consumed.\n const result = await this.command([\n 'SET',\n PREFIX + digest,\n '1',\n 'EX',\n String(this.ttlSeconds),\n 'NX',\n ]);\n if (result === null || result === undefined) {\n throw new Error(`Digest already used: ${digest}`);\n }\n }\n}\n","import { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';\nimport { InMemoryDigestStore, USDC, USDC_TESTNET, type Currency } from '@suimpp/mpp/server';\nimport { buildLlmsTxt, buildOpenApiDocument } from './discovery.js';\nimport { RouteBuilder, type RouteOptions, type RouteRuntime } from './route.js';\nimport { UpstashDigestStore } from './store.js';\nimport type { BuiltRoute, ServeConfig, ServeNetwork } from './types.js';\n\nexport class Serve {\n private readonly runtime: RouteRuntime;\n /** Every route built through this instance, keyed by path (discovery). */\n readonly routes = new Map<string, BuiltRoute>();\n\n readonly payTo: string;\n readonly network: ServeNetwork;\n readonly name?: string;\n readonly description?: string;\n readonly baseUrl?: string;\n\n constructor(config: ServeConfig) {\n if (!config.payTo || !isValidSuiAddress(config.payTo)) {\n throw new Error(\n `[serve] payTo must be a valid Sui address (the wallet your payments settle to), got \"${config.payTo}\"`,\n );\n }\n this.payTo = normalizeSuiAddress(config.payTo);\n this.network = config.network ?? 'mainnet';\n this.name = config.name;\n this.description = config.description;\n this.baseUrl = config.baseUrl?.replace(/\\/$/, '');\n\n const currency: Currency = this.network === 'testnet' ? USDC_TESTNET : USDC;\n this.runtime = {\n payTo: this.payTo,\n network: this.network,\n currency,\n store: config.store ?? new InMemoryDigestStore(),\n baseUrl: this.baseUrl,\n rpcUrl: config.rpcUrl,\n report: config.report ?? true,\n };\n }\n\n /** Start building a route. Chain `.paid()` / `.body()` / `.handler()`. */\n route(options: RouteOptions): RouteBuilder {\n const path = options.path.replace(/^\\/+/, '').replace(/\\/+$/, '');\n if (!path) throw new Error('[serve] route path must be non-empty');\n return new RouteBuilder({ ...this.runtime }, { ...options, path }, (route) => {\n this.routes.set(path, route);\n });\n }\n\n /**\n * Discovery: GET handler for /openapi.json. OpenAPI 3.1 with the\n * `x-payment-info` pricing extension on every paid operation — the shape\n * the mpp.t2000.ai catalog (and x402 tooling generally) indexes.\n *\n * export const GET = serve.openapi(); // app/openapi.json/route.ts\n */\n openapi(): (req: Request) => Response {\n return (req: Request) =>\n new Response(JSON.stringify(buildOpenApiDocument(this, new URL(req.url).origin), null, 2), {\n headers: { 'content-type': 'application/json', 'access-control-allow-origin': '*' },\n });\n }\n\n /**\n * Discovery: GET handler for /llms.txt — plain-text guidance agents read\n * to understand what the API sells, what it costs, and how to pay.\n *\n * export const GET = serve.llms(); // app/llms.txt/route.ts\n */\n llms(): (req: Request) => Response {\n return (req: Request) =>\n new Response(buildLlmsTxt(this, new URL(req.url).origin), {\n headers: { 'content-type': 'text/plain; charset=utf-8', 'access-control-allow-origin': '*' },\n });\n }\n\n /**\n * One fetch handler for the whole app — routes + discovery docs. For\n * fetch-native runtimes (Bun.serve, Deno.serve, Hono, Cloudflare Workers):\n *\n * Bun.serve({ fetch: serve.fetch });\n * app.all('*', (c) => serve.fetch(c.req.raw)); // Hono\n *\n * Next.js apps can skip this and export route handlers directly.\n */\n readonly fetch = async (req: Request): Promise<Response> => {\n const pathname = new URL(req.url).pathname.replace(/^\\/+/, '').replace(/\\/+$/, '');\n if (pathname === 'openapi.json') return this.openapi()(req);\n if (pathname === 'llms.txt') return this.llms()(req);\n const route = this.routes.get(pathname);\n if (route) return route(req);\n return new Response(\n JSON.stringify({ error: 'not found', discovery: ['/openapi.json', '/llms.txt'] }),\n { status: 404, headers: { 'content-type': 'application/json' } },\n );\n };\n\n /**\n * The curl that lists this API on mpp.t2000.ai / agents.t2000.ai once it\n * is deployed. Listing is a separate, explicit step — the catalog gates\n * (url · probe · dialect · price-cap), not this package, decide outcomes.\n * Dry-run first with /api/catalog/preview.\n */\n catalogSubmitCommand(deployedUrl?: string): string {\n const base = (deployedUrl ?? this.baseUrl ?? 'https://<your-deployed-app>').replace(/\\/$/, '');\n const paidPaths = [...this.routes.values()].filter((r) => r.meta.priceUsdc);\n const example = paidPaths[0]?.meta.path ?? '<route>';\n return [\n '# Dry-run (shows gate results, changes nothing):',\n `curl -X POST https://mpp.t2000.ai/api/catalog/preview -H 'content-type: application/json' -d '{\"url\":\"${base}/${example}\"}'`,\n '# List for real:',\n `curl -X POST https://mpp.t2000.ai/api/catalog/submit -H 'content-type: application/json' -d '{\"url\":\"${base}/${example}\"}'`,\n ].join('\\n');\n }\n}\n\nexport function createServe(config: ServeConfig): Serve {\n return new Serve(config);\n}\n\n/**\n * Build a Serve from environment variables — the template-app path where\n * config lives in the host's env UI, not code.\n *\n * T2000_PAY_TO required — the seller's Sui address\n * T2000_NETWORK optional — 'mainnet' (default) | 'testnet'\n * T2000_BASE_URL optional — public URL of the deployed app\n * T2000_NAME optional — service name for discovery docs\n * T2000_DESCRIPTION optional — one-liner for discovery docs\n * KV_REST_API_URL / KV_REST_API_TOKEN\n * optional — enables the durable Upstash replay store\n * (REQUIRED in serverless production; without it replay\n * state is per-instance memory)\n *\n * Empty strings are treated as unset (the Vercel empty-env bug class).\n */\nexport function createServeFromEnv(env: Record<string, string | undefined> = process.env): Serve {\n const read = (key: string): string | undefined => {\n const v = env[key]?.trim();\n return v && v.length > 0 ? v : undefined;\n };\n\n const payTo = read('T2000_PAY_TO');\n if (!payTo) {\n throw new Error(\n '[serve] T2000_PAY_TO is not set (or is empty). Set it to the Sui address your payments should settle to — `t2 address` prints yours.',\n );\n }\n\n const network = read('T2000_NETWORK');\n if (network && network !== 'mainnet' && network !== 'testnet') {\n throw new Error(`[serve] T2000_NETWORK must be 'mainnet' or 'testnet', got \"${network}\"`);\n }\n\n const kvUrl = read('KV_REST_API_URL');\n const kvToken = read('KV_REST_API_TOKEN');\n const store =\n kvUrl && kvToken ? new UpstashDigestStore({ url: kvUrl, token: kvToken }) : undefined;\n\n if (!store) {\n console.warn(\n '[serve] No KV_REST_API_URL/KV_REST_API_TOKEN — using the in-memory replay store. ' +\n 'Fine for a single long-lived process; on serverless hosts set both so replay protection is durable.',\n );\n }\n\n return new Serve({\n payTo,\n network: (network as ServeNetwork | undefined) ?? 'mainnet',\n baseUrl: read('T2000_BASE_URL'),\n name: read('T2000_NAME'),\n description: read('T2000_DESCRIPTION'),\n store,\n });\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -51,6 +51,10 @@ type StandardSchemaResult<T> = {
|
|
|
51
51
|
} | {
|
|
52
52
|
issues: ReadonlyArray<{
|
|
53
53
|
message: string;
|
|
54
|
+
/** Standard Schema path segments (plain keys or `{ key }` objects). */
|
|
55
|
+
path?: ReadonlyArray<PropertyKey | {
|
|
56
|
+
key: PropertyKey;
|
|
57
|
+
}>;
|
|
54
58
|
}>;
|
|
55
59
|
};
|
|
56
60
|
interface SafeParseSchemaLike<T = unknown> {
|
package/dist/index.d.ts
CHANGED
|
@@ -51,6 +51,10 @@ type StandardSchemaResult<T> = {
|
|
|
51
51
|
} | {
|
|
52
52
|
issues: ReadonlyArray<{
|
|
53
53
|
message: string;
|
|
54
|
+
/** Standard Schema path segments (plain keys or `{ key }` objects). */
|
|
55
|
+
path?: ReadonlyArray<PropertyKey | {
|
|
56
|
+
key: PropertyKey;
|
|
57
|
+
}>;
|
|
54
58
|
}>;
|
|
55
59
|
};
|
|
56
60
|
interface SafeParseSchemaLike<T = unknown> {
|
package/dist/index.js
CHANGED
|
@@ -72,7 +72,7 @@ function buildLlmsTxt(serve, origin) {
|
|
|
72
72
|
"HTTP 402 with an `accepts[]` envelope; sign it and retry with the `X-PAYMENT` header.",
|
|
73
73
|
"Invalid input returns 422 before any payment is taken. A failed call is never charged.",
|
|
74
74
|
"",
|
|
75
|
-
"Easiest client: `npm i -g @t2000/cli` then `t2 pay <url> --
|
|
75
|
+
"Easiest client: `npm i -g @t2000/cli` then `t2 pay <url> --data '{...}'`,",
|
|
76
76
|
"or the t2000 MCP server (`t2000_pay`), or `@t2000/sdk` `pay()`.",
|
|
77
77
|
""
|
|
78
78
|
);
|
|
@@ -163,7 +163,11 @@ async function validateBody(schema, value) {
|
|
|
163
163
|
if (isStandardSchema(schema)) {
|
|
164
164
|
const result2 = await schema["~standard"].validate(value);
|
|
165
165
|
if (result2.issues) {
|
|
166
|
-
|
|
166
|
+
const message = result2.issues.map((i) => {
|
|
167
|
+
const path = (i.path ?? []).map((seg) => typeof seg === "object" ? String(seg.key) : String(seg)).join(".");
|
|
168
|
+
return path ? `${path}: ${i.message}` : i.message;
|
|
169
|
+
}).join("; ");
|
|
170
|
+
return { ok: false, message };
|
|
167
171
|
}
|
|
168
172
|
return { ok: true, data: result2.value };
|
|
169
173
|
}
|
|
@@ -252,9 +256,13 @@ var RouteBuilder = class {
|
|
|
252
256
|
const runHandler = async (payer) => {
|
|
253
257
|
let validated = parsedBody;
|
|
254
258
|
if (bodySchema) {
|
|
255
|
-
if (bodyParseError)
|
|
259
|
+
if (bodyParseError) {
|
|
260
|
+
return json(422, { error: bodyParseError, paid: false });
|
|
261
|
+
}
|
|
256
262
|
const result = await validateBody(bodySchema, parsedBody ?? {});
|
|
257
|
-
if (!result.ok)
|
|
263
|
+
if (!result.ok) {
|
|
264
|
+
return json(422, { error: result.message, paid: false });
|
|
265
|
+
}
|
|
258
266
|
validated = result.data;
|
|
259
267
|
}
|
|
260
268
|
const out = await fn({ body: validated, req, payer });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/discovery.ts","../src/chain.ts","../src/route.ts","../src/store.ts","../src/serve.ts"],"names":["result","USDC_TESTNET","USDC","InMemoryDigestStore"],"mappings":"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","file":"index.js","sourcesContent":["import { USDC, USDC_TESTNET } from '@suimpp/mpp/server';\nimport type { Serve } from './serve.js';\n\n// ---------------------------------------------------------------------------\n// Discovery docs — /openapi.json + /llms.txt.\n//\n// The shapes here are graded by the catalog's ingest (apps/gateway/lib/\n// catalog-ingest.ts `gradeListing`): a warning-free listing needs info.title,\n// a one-paragraph info.description, a flat string `x-payment-info.price` per\n// paid operation, and an application/json requestBody schema with typed\n// properties. Everything serve can derive is emitted automatically; the JSON\n// request schema comes from the route's `inputSchema` (zod v4 users:\n// `z.toJSONSchema(schema)`).\n// ---------------------------------------------------------------------------\n\nexport function buildOpenApiDocument(serve: Serve, origin?: string): Record<string, unknown> {\n const base = serve.baseUrl ?? origin;\n const paths: Record<string, unknown> = {};\n\n for (const route of serve.routes.values()) {\n const { path, priceUsdc, description, inputSchema } = route.meta;\n const operation: Record<string, unknown> = {\n operationId: path.replace(/[^a-zA-Z0-9]+/g, '_'),\n summary: description ?? path,\n responses: {\n '200': { description: 'Success' },\n ...(priceUsdc\n ? {\n '402': {\n description:\n 'Payment required — the body carries an x402 accepts[] envelope (scheme \"exact\", network sui). Sign it and retry with the X-PAYMENT header.',\n },\n }\n : {}),\n '422': { description: 'Invalid request body — never charged' },\n },\n };\n if (priceUsdc) {\n // Same shape the gateway's own /openapi.json emits: 'mpp' is the\n // protocol family, 'x402' the dialect; the x402 block mirrors the\n // static half of the live accepts[] entry (dynamic fields ride the 402).\n operation['x-payment-info'] = {\n pricingMode: 'fixed',\n price: priceUsdc,\n currency: 'USDC',\n protocols: ['mpp', 'x402'],\n x402: {\n scheme: 'exact',\n network: `sui:${serve.network}`,\n asset: (serve.network === 'testnet' ? USDC_TESTNET : USDC).type,\n payTo: serve.payTo,\n },\n };\n }\n if (inputSchema) {\n operation.requestBody = {\n required: true,\n content: { 'application/json': { schema: inputSchema } },\n };\n }\n paths[`/${path}`] = { post: operation };\n }\n\n return {\n openapi: '3.1.0',\n info: {\n title: serve.name ?? 'Paid API',\n version: '1.0.0',\n description:\n serve.description ??\n 'Agent-payable API. Every paid endpoint answers 402 with an x402 accepts[] envelope; payment settles in USDC on Sui.',\n },\n ...(base ? { servers: [{ url: base }] } : {}),\n paths,\n };\n}\n\nexport function buildLlmsTxt(serve: Serve, origin?: string): string {\n const base = serve.baseUrl ?? origin ?? '';\n const lines: string[] = [];\n lines.push(`# ${serve.name ?? 'Paid API'}`);\n lines.push('');\n if (serve.description) {\n lines.push(serve.description);\n lines.push('');\n }\n lines.push('## How to pay');\n lines.push('');\n lines.push(\n 'Endpoints below are paid per call in USDC on Sui (x402). An unpaid request returns',\n 'HTTP 402 with an `accepts[]` envelope; sign it and retry with the `X-PAYMENT` header.',\n 'Invalid input returns 422 before any payment is taken. A failed call is never charged.',\n '',\n 'Easiest client: `npm i -g @t2000/cli` then `t2 pay <url> --method POST --body \\'{...}\\'`,',\n 'or the t2000 MCP server (`t2000_pay`), or `@t2000/sdk` `pay()`.',\n '',\n );\n lines.push('## Endpoints');\n lines.push('');\n for (const route of serve.routes.values()) {\n const { path, priceUsdc, description, inputSchema } = route.meta;\n const price = priceUsdc ? `${priceUsdc} USDC per call` : 'free';\n lines.push(`### POST ${base}/${path} — ${price}`);\n if (description) lines.push(description);\n if (inputSchema) {\n lines.push('Request body (JSON Schema):');\n lines.push('```json');\n lines.push(JSON.stringify(inputSchema, null, 2));\n lines.push('```');\n }\n lines.push('');\n }\n lines.push(`Discovery: ${base}/openapi.json`);\n return lines.join('\\n');\n}\n","import { SuiGrpcClient } from '@mysten/sui/grpc';\nimport type { ServeNetwork } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Chain plumbing — same shape as the gateway's x402-dialect.ts (the reference\n// composition). All reads are gRPC; this package never touches JSON-RPC.\n//\n// Cache policy: the chain identifier (genesis digest) is immutable per\n// network — cached forever. The epoch advances ~daily and x402 requirements\n// are valid for [epoch, epoch+1], so a 10-minute TTL is conservatively fresh.\n// ---------------------------------------------------------------------------\n\nconst FULLNODE_URLS: Record<ServeNetwork, string> = {\n mainnet: 'https://fullnode.mainnet.sui.io:443',\n testnet: 'https://fullnode.testnet.sui.io:443',\n};\n\nconst EPOCH_TTL_MS = 10 * 60 * 1000;\n\nexport interface ChainInfo {\n chain: string;\n epoch: string;\n}\n\ninterface ChainState {\n client?: SuiGrpcClient;\n chainId?: string;\n epoch?: { value: string; fetchedAt: number };\n}\n\nconst state: Partial<Record<ServeNetwork, ChainState>> = {};\n\nexport function getGrpcClient(network: ServeNetwork, rpcUrl?: string): SuiGrpcClient {\n const s = (state[network] ??= {});\n if (!s.client) {\n s.client = new SuiGrpcClient({\n baseUrl: rpcUrl ?? FULLNODE_URLS[network],\n network,\n });\n }\n return s.client;\n}\n\nexport async function getChainInfo(network: ServeNetwork, rpcUrl?: string): Promise<ChainInfo> {\n const client = getGrpcClient(network, rpcUrl);\n const s = (state[network] ??= {});\n if (!s.chainId) {\n const res = await client.core.getChainIdentifier();\n s.chainId = res.chainIdentifier;\n }\n if (!s.epoch || Date.now() - s.epoch.fetchedAt > EPOCH_TTL_MS) {\n const res = await client.core.getCurrentSystemState();\n s.epoch = { value: String(res.systemState.epoch), fetchedAt: Date.now() };\n }\n return { chain: s.chainId, epoch: s.epoch.value };\n}\n\n/** Test seam — reset module caches between cases. */\nexport function __resetChainCaches(): void {\n delete state.mainnet;\n delete state.testnet;\n}\n\n/** Test seam — pre-seed chain info so tests never hit the network. */\nexport function __seedChainInfo(network: ServeNetwork, chain: string, epoch: string): void {\n const s = (state[network] ??= {});\n s.chainId = chain;\n s.epoch = { value: epoch, fetchedAt: Date.now() };\n}\n","import type { DigestStore } from '@suimpp/mpp/server';\nimport type { Currency } from '@suimpp/mpp/server';\nimport {\n createX402Requirements,\n encodeX402Response,\n isX402EscrowHeader,\n parseX402Header,\n settleX402Payment,\n verifyX402Payment,\n X402_PAYMENT_HEADER,\n X402_PAYMENT_RESPONSE_HEADER,\n X402_VERSION,\n type X402SettleResponse,\n} from '@suimpp/mpp/x402';\nimport { getChainInfo, getGrpcClient } from './chain.js';\nimport type {\n BuiltRoute,\n HandlerContext,\n HandlerResult,\n ServeNetwork,\n ServeSchema,\n StandardSchemaLike,\n} from './types.js';\n\n// ---------------------------------------------------------------------------\n// The paid-request lifecycle (SPEC_T2000_SERVE §3 — sign-then-settle,\n// handler-then-settle):\n//\n// no X-PAYMENT → 402 with the accepts[] envelope (never a charge;\n// the catalog probe and every discovery tool read\n// this, so it fires BEFORE body validation)\n// X-PAYMENT present:\n// 1. parse + STRUCTURAL verify (right amount/recipient/nonce — no RPC)\n// 2. challenge-once check (a signed payload is single-use)\n// 3. validate the body — invalid → 422, payment NEVER submitted\n// (the JMPR paid-422 class is impossible: the buyer keeps their money)\n// 4. run the handler — throws → 500, payment NEVER submitted\n// 5. settle (submit the buyer-signed gasless bytes; digest-once inside)\n// 6. consume the challenge, attach the X-PAYMENT-RESPONSE receipt\n//\n// Money only moves at step 5, after the seller has already produced the\n// result. A forged payload can waste seller compute (signature authority is\n// the chain at settle time), never buyer money.\n// ---------------------------------------------------------------------------\n\nexport interface RouteRuntime {\n payTo: string;\n network: ServeNetwork;\n currency: Currency;\n store: DigestStore;\n baseUrl?: string;\n rpcUrl?: string;\n report: boolean;\n}\n\nexport interface RouteOptions {\n path: string;\n description?: string;\n}\n\nconst MPP_REPORT_URL = 'https://mpp.t2000.ai/api/mpp/report';\nconst REPORT_TIMEOUT_MS = 2_000;\n\n/** Listing cap on mpp.t2000.ai (catalog-ingest price-cap gate). */\nconst CATALOG_PRICE_CAP_USDC = 5;\n\nconst CORS_HEADERS: Record<string, string> = {\n 'access-control-allow-origin': '*',\n 'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'access-control-allow-headers': `content-type, ${X402_PAYMENT_HEADER}`,\n 'access-control-expose-headers': `${X402_PAYMENT_RESPONSE_HEADER}, WWW-Authenticate`,\n};\n\nfunction withCors(response: Response): Response {\n const headers = new Headers(response.headers);\n for (const [k, v] of Object.entries(CORS_HEADERS)) headers.set(k, v);\n return new Response(response.body, { status: response.status, headers });\n}\n\nfunction json(status: number, body: unknown, headers?: Record<string, string>): Response {\n return withCors(\n new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json', ...headers },\n }),\n );\n}\n\nfunction isStandardSchema(schema: ServeSchema): schema is StandardSchemaLike {\n return typeof schema === 'object' && schema !== null && '~standard' in schema;\n}\n\nasync function validateBody(\n schema: ServeSchema,\n value: unknown,\n): Promise<{ ok: true; data: unknown } | { ok: false; message: string }> {\n if (isStandardSchema(schema)) {\n const result = await schema['~standard'].validate(value);\n if (result.issues) {\n return { ok: false, message: result.issues.map((i) => i.message).join('; ') };\n }\n return { ok: true, data: result.value };\n }\n const result = schema.safeParse(value);\n if (!result.success) {\n return { ok: false, message: result.error.message ?? 'invalid body' };\n }\n return { ok: true, data: result.data };\n}\n\n/** Positive decimal USDC string, max 6dp (atomic precision). */\nfunction assertValidPrice(price: string, path: string): void {\n if (!/^\\d+(\\.\\d{1,6})?$/.test(price) || Number(price) <= 0) {\n throw new Error(\n `[serve] Route \"${path}\": price must be a positive decimal USDC string with up to 6 decimals, got \"${price}\"`,\n );\n }\n if (Number(price) > CATALOG_PRICE_CAP_USDC) {\n console.warn(\n `[serve] Route \"${path}\": price ${price} USDC is above the ${CATALOG_PRICE_CAP_USDC} USDC listing cap — ` +\n 'the route works, but it will not list on mpp.t2000.ai. Job-class work belongs in `t2 service create` (escrow).',\n );\n }\n}\n\nexport class RouteBuilder<TBody = undefined> {\n private priceUsdc?: string;\n private bodySchema?: ServeSchema;\n private inputSchema?: Record<string, unknown>;\n private isFree = false;\n\n constructor(\n private readonly runtime: RouteRuntime,\n private readonly options: RouteOptions,\n private readonly register: (route: BuiltRoute) => void,\n ) {}\n\n /** Charge this many USDC per call (human units, e.g. \"0.01\"). */\n paid(priceUsdc: string): this {\n assertValidPrice(priceUsdc, this.options.path);\n this.priceUsdc = priceUsdc;\n this.isFree = false;\n return this;\n }\n\n /** Serve without payment (health checks, previews, docs). */\n unprotected(): this {\n this.isFree = true;\n this.priceUsdc = undefined;\n return this;\n }\n\n /**\n * Validate the JSON request body. zod v4 / valibot / arktype / anything\n * Standard-Schema, or anything with a zod-style safeParse.\n *\n * Pass the JSON Schema as the second argument to publish it in\n * /openapi.json + /llms.txt (zod v4: `z.toJSONSchema(schema)`) — buyers'\n * agents build request bodies from it, and the catalog grades listings\n * without one.\n */\n body<T>(schema: ServeSchema<T>, jsonSchema?: Record<string, unknown>): RouteBuilder<T> {\n this.bodySchema = schema;\n this.inputSchema = jsonSchema;\n return this as unknown as RouteBuilder<T>;\n }\n\n handler(fn: (ctx: HandlerContext<TBody>) => HandlerResult | Promise<HandlerResult>): BuiltRoute {\n if (!this.isFree && !this.priceUsdc) {\n throw new Error(\n `[serve] Route \"${this.options.path}\": call .paid('<usdc>') or .unprotected() before .handler()`,\n );\n }\n const runtime = this.runtime;\n const { path, description } = this.options;\n const priceUsdc = this.priceUsdc;\n const bodySchema = this.bodySchema;\n\n const route = (async (req: Request): Promise<Response> => {\n if (req.method === 'OPTIONS') {\n return withCors(new Response(null, { status: 204 }));\n }\n\n // Read + parse the body once, up front. A missing/empty body on a\n // schema-less route is fine; JSON parse failures only matter when a\n // paid request must be validated (the unpaid 402 fires regardless).\n let parsedBody: unknown;\n let bodyParseError: string | undefined;\n if (req.method !== 'GET' && req.method !== 'HEAD') {\n const text = await req.text();\n if (text.trim().length > 0) {\n try {\n parsedBody = JSON.parse(text);\n } catch {\n bodyParseError = 'request body is not valid JSON';\n }\n }\n }\n\n const resource = (runtime.baseUrl ?? new URL(req.url).origin).replace(/\\/$/, '') + `/${path}`;\n\n const runHandler = async (payer?: string): Promise<Response> => {\n let validated: unknown = parsedBody;\n if (bodySchema) {\n if (bodyParseError) return json(422, { error: bodyParseError });\n const result = await validateBody(bodySchema, parsedBody ?? {});\n if (!result.ok) return json(422, { error: result.message });\n validated = result.data;\n }\n const out = await fn({ body: validated as TBody, req, payer });\n if (out instanceof Response) return withCors(out);\n return json(200, out);\n };\n\n // Free route — no payment machinery at all.\n if (!priceUsdc) {\n try {\n return await runHandler();\n } catch (err) {\n console.error(`[serve] Route \"${path}\" handler failed:`, err);\n return json(500, { error: 'internal error' });\n }\n }\n\n const paymentHeader = req.headers.get(X402_PAYMENT_HEADER);\n\n // Unpaid → 402 with the accepts[] envelope. This fires before body\n // validation on purpose: the catalog probe (and every discovery tool)\n // POSTs `{}` and must see the challenge, and an unpaid request can\n // never be charged, so there is nothing to protect yet.\n if (!paymentHeader) {\n return await respond402(runtime, { resource, priceUsdc });\n }\n\n if (isX402EscrowHeader(paymentHeader)) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error:\n 'this endpoint sells instant per-call work (settle-then-serve), not escrow jobs — retry with a signed x402 payment',\n });\n }\n\n // 1. Parse + structural verify — right terms, right recipient, right\n // nonce. No RPC, no state. Wrong-terms payloads never reach the\n // handler.\n let payment: ReturnType<typeof parseX402Header>;\n try {\n payment = parseX402Header(paymentHeader);\n verifyX402Payment({\n payment,\n expected: {\n challengeId: payment.payload.challengeId,\n amount: priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n network: runtime.network,\n },\n });\n } catch (err) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: `invalid payment: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // 2. Challenge-once — a signed payload is single-use even before it\n // settles (the settled digest is separately consumed inside\n // settleX402Payment, digest-once).\n const challengeKey = `challenge:${payment.payload.challengeId}`;\n if (await runtime.store.has(challengeKey)) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: 'payment challenge already used — sign a fresh payment',\n });\n }\n\n // 3 + 4. Validate, then compute the result. Any failure here returns\n // WITHOUT settling — the buyer-signed bytes are never submitted.\n let served: Response;\n try {\n served = await runHandler(payment.payload.senderAddress);\n } catch (err) {\n console.error(`[serve] Route \"${path}\" handler failed (payment NOT settled):`, err);\n return json(500, { error: 'internal error — you were not charged' });\n }\n if (served.status >= 400) return served; // 422 etc. — not charged\n\n // 5. Settle — submit the buyer-signed gasless bytes, confirm the\n // on-chain balance change, record the digest (digest-once).\n let settle: X402SettleResponse;\n try {\n settle = await settleX402Payment({\n payment,\n client: getGrpcClient(runtime.network, runtime.rpcUrl),\n store: runtime.store,\n expected: {\n challengeId: payment.payload.challengeId,\n amount: priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n network: runtime.network,\n },\n });\n } catch (err) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: `settlement failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // 6. Consume the challenge + attach the receipt.\n try {\n await runtime.store.set(challengeKey);\n } catch {\n // Digest-once already holds; challenge-once is defense in depth.\n }\n\n if (runtime.report) {\n reportPayment(settle.transaction, resource);\n }\n\n const headers = new Headers(served.headers);\n headers.set(X402_PAYMENT_RESPONSE_HEADER, encodeX402Response(settle));\n return new Response(served.body, { status: served.status, headers });\n }) as BuiltRoute;\n\n route.meta = { path, priceUsdc, description, bodySchema, inputSchema: this.inputSchema };\n this.register(route);\n return route;\n }\n}\n\nasync function respond402(\n runtime: RouteRuntime,\n args: { resource: string; priceUsdc: string; error?: string },\n): Promise<Response> {\n try {\n const { chain, epoch } = await getChainInfo(runtime.network, runtime.rpcUrl);\n const requirements = createX402Requirements({\n challengeId: crypto.randomUUID(),\n amount: args.priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n resource: args.resource,\n network: runtime.network,\n chain,\n currentEpoch: epoch,\n });\n return json(402, {\n x402Version: X402_VERSION,\n error: args.error ?? 'Payment required',\n accepts: [requirements],\n });\n } catch (err) {\n // Chain info unreachable — a 402 without the envelope is unpayable, so\n // be honest about the outage instead of serving a dead challenge.\n console.error('[serve] failed to build 402 challenge:', err);\n return json(503, { error: 'payment challenge temporarily unavailable' });\n }\n}\n\n/**\n * Best-effort activity-feed report (mpp.t2000.ai). The gateway verifies the\n * digest on-chain before recording anything, so this carries no trusted\n * data — a lost or duplicate report is harmless.\n */\nfunction reportPayment(digest: string, url: string): void {\n void fetch(MPP_REPORT_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ digest, url }),\n signal: AbortSignal.timeout(REPORT_TIMEOUT_MS),\n }).catch(() => {});\n}\n","import type { DigestStore } from '@suimpp/mpp/server';\n\nexport { InMemoryDigestStore } from '@suimpp/mpp/server';\nexport type { DigestStore } from '@suimpp/mpp/server';\n\n// ---------------------------------------------------------------------------\n// Upstash-REST digest store — the production replay store for serverless\n// hosts. Mirrors the gateway's upstash-digest-store.ts but speaks the\n// Upstash REST API over plain fetch (no @upstash/redis dependency).\n//\n// TTL: 72h. x402 payments are chain-valid for the whole ValidDuring window\n// ([minEpoch, minEpoch+1] ≈ up to ~48h on mainnet). Sui resubmission of an\n// executed tx is idempotent, so if the digest/challenge keys expired BEFORE\n// the window closed, a replayed X-PAYMENT would re-settle \"successfully\"\n// and serve again on a single payment. 72h > max window + drift.\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_TTL_SECONDS = 72 * 60 * 60;\nconst PREFIX = 'serve:digest:';\n\nexport interface UpstashDigestStoreOptions {\n url: string;\n token: string;\n /** Key TTL in seconds. Default 72h — do not lower below ~50h (see above). */\n ttlSeconds?: number;\n}\n\nexport class UpstashDigestStore implements DigestStore {\n private readonly url: string;\n private readonly token: string;\n private readonly ttlSeconds: number;\n\n constructor(options: UpstashDigestStoreOptions) {\n this.url = options.url.replace(/\\/$/, '');\n this.token = options.token;\n this.ttlSeconds = options.ttlSeconds ?? DEFAULT_TTL_SECONDS;\n }\n\n private async command(segments: string[]): Promise<unknown> {\n const res = await fetch(`${this.url}/${segments.map(encodeURIComponent).join('/')}`, {\n headers: { authorization: `Bearer ${this.token}` },\n });\n if (!res.ok) {\n throw new Error(`Upstash command failed: ${res.status} ${await res.text()}`);\n }\n const body = (await res.json()) as { result?: unknown; error?: string };\n if (body.error) throw new Error(`Upstash error: ${body.error}`);\n return body.result;\n }\n\n async has(digest: string): Promise<boolean> {\n const result = await this.command(['GET', PREFIX + digest]);\n return result !== null && result !== undefined;\n }\n\n async set(digest: string): Promise<void> {\n // SET key 1 EX <ttl> NX — atomic set-if-absent. A null result means the\n // key already existed: the digest (or challenge) was already consumed.\n const result = await this.command([\n 'SET',\n PREFIX + digest,\n '1',\n 'EX',\n String(this.ttlSeconds),\n 'NX',\n ]);\n if (result === null || result === undefined) {\n throw new Error(`Digest already used: ${digest}`);\n }\n }\n}\n","import { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';\nimport { InMemoryDigestStore, USDC, USDC_TESTNET, type Currency } from '@suimpp/mpp/server';\nimport { buildLlmsTxt, buildOpenApiDocument } from './discovery.js';\nimport { RouteBuilder, type RouteOptions, type RouteRuntime } from './route.js';\nimport { UpstashDigestStore } from './store.js';\nimport type { BuiltRoute, ServeConfig, ServeNetwork } from './types.js';\n\nexport class Serve {\n private readonly runtime: RouteRuntime;\n /** Every route built through this instance, keyed by path (discovery). */\n readonly routes = new Map<string, BuiltRoute>();\n\n readonly payTo: string;\n readonly network: ServeNetwork;\n readonly name?: string;\n readonly description?: string;\n readonly baseUrl?: string;\n\n constructor(config: ServeConfig) {\n if (!config.payTo || !isValidSuiAddress(config.payTo)) {\n throw new Error(\n `[serve] payTo must be a valid Sui address (the wallet your payments settle to), got \"${config.payTo}\"`,\n );\n }\n this.payTo = normalizeSuiAddress(config.payTo);\n this.network = config.network ?? 'mainnet';\n this.name = config.name;\n this.description = config.description;\n this.baseUrl = config.baseUrl?.replace(/\\/$/, '');\n\n const currency: Currency = this.network === 'testnet' ? USDC_TESTNET : USDC;\n this.runtime = {\n payTo: this.payTo,\n network: this.network,\n currency,\n store: config.store ?? new InMemoryDigestStore(),\n baseUrl: this.baseUrl,\n rpcUrl: config.rpcUrl,\n report: config.report ?? true,\n };\n }\n\n /** Start building a route. Chain `.paid()` / `.body()` / `.handler()`. */\n route(options: RouteOptions): RouteBuilder {\n const path = options.path.replace(/^\\/+/, '').replace(/\\/+$/, '');\n if (!path) throw new Error('[serve] route path must be non-empty');\n return new RouteBuilder({ ...this.runtime }, { ...options, path }, (route) => {\n this.routes.set(path, route);\n });\n }\n\n /**\n * Discovery: GET handler for /openapi.json. OpenAPI 3.1 with the\n * `x-payment-info` pricing extension on every paid operation — the shape\n * the mpp.t2000.ai catalog (and x402 tooling generally) indexes.\n *\n * export const GET = serve.openapi(); // app/openapi.json/route.ts\n */\n openapi(): (req: Request) => Response {\n return (req: Request) =>\n new Response(JSON.stringify(buildOpenApiDocument(this, new URL(req.url).origin), null, 2), {\n headers: { 'content-type': 'application/json', 'access-control-allow-origin': '*' },\n });\n }\n\n /**\n * Discovery: GET handler for /llms.txt — plain-text guidance agents read\n * to understand what the API sells, what it costs, and how to pay.\n *\n * export const GET = serve.llms(); // app/llms.txt/route.ts\n */\n llms(): (req: Request) => Response {\n return (req: Request) =>\n new Response(buildLlmsTxt(this, new URL(req.url).origin), {\n headers: { 'content-type': 'text/plain; charset=utf-8', 'access-control-allow-origin': '*' },\n });\n }\n\n /**\n * One fetch handler for the whole app — routes + discovery docs. For\n * fetch-native runtimes (Bun.serve, Deno.serve, Hono, Cloudflare Workers):\n *\n * Bun.serve({ fetch: serve.fetch });\n * app.all('*', (c) => serve.fetch(c.req.raw)); // Hono\n *\n * Next.js apps can skip this and export route handlers directly.\n */\n readonly fetch = async (req: Request): Promise<Response> => {\n const pathname = new URL(req.url).pathname.replace(/^\\/+/, '').replace(/\\/+$/, '');\n if (pathname === 'openapi.json') return this.openapi()(req);\n if (pathname === 'llms.txt') return this.llms()(req);\n const route = this.routes.get(pathname);\n if (route) return route(req);\n return new Response(\n JSON.stringify({ error: 'not found', discovery: ['/openapi.json', '/llms.txt'] }),\n { status: 404, headers: { 'content-type': 'application/json' } },\n );\n };\n\n /**\n * The curl that lists this API on mpp.t2000.ai / agents.t2000.ai once it\n * is deployed. Listing is a separate, explicit step — the catalog gates\n * (url · probe · dialect · price-cap), not this package, decide outcomes.\n * Dry-run first with /api/catalog/preview.\n */\n catalogSubmitCommand(deployedUrl?: string): string {\n const base = (deployedUrl ?? this.baseUrl ?? 'https://<your-deployed-app>').replace(/\\/$/, '');\n const paidPaths = [...this.routes.values()].filter((r) => r.meta.priceUsdc);\n const example = paidPaths[0]?.meta.path ?? '<route>';\n return [\n '# Dry-run (shows gate results, changes nothing):',\n `curl -X POST https://mpp.t2000.ai/api/catalog/preview -H 'content-type: application/json' -d '{\"url\":\"${base}/${example}\"}'`,\n '# List for real:',\n `curl -X POST https://mpp.t2000.ai/api/catalog/submit -H 'content-type: application/json' -d '{\"url\":\"${base}/${example}\"}'`,\n ].join('\\n');\n }\n}\n\nexport function createServe(config: ServeConfig): Serve {\n return new Serve(config);\n}\n\n/**\n * Build a Serve from environment variables — the template-app path where\n * config lives in the host's env UI, not code.\n *\n * T2000_PAY_TO required — the seller's Sui address\n * T2000_NETWORK optional — 'mainnet' (default) | 'testnet'\n * T2000_BASE_URL optional — public URL of the deployed app\n * T2000_NAME optional — service name for discovery docs\n * T2000_DESCRIPTION optional — one-liner for discovery docs\n * KV_REST_API_URL / KV_REST_API_TOKEN\n * optional — enables the durable Upstash replay store\n * (REQUIRED in serverless production; without it replay\n * state is per-instance memory)\n *\n * Empty strings are treated as unset (the Vercel empty-env bug class).\n */\nexport function createServeFromEnv(env: Record<string, string | undefined> = process.env): Serve {\n const read = (key: string): string | undefined => {\n const v = env[key]?.trim();\n return v && v.length > 0 ? v : undefined;\n };\n\n const payTo = read('T2000_PAY_TO');\n if (!payTo) {\n throw new Error(\n '[serve] T2000_PAY_TO is not set (or is empty). Set it to the Sui address your payments should settle to — `t2 address` prints yours.',\n );\n }\n\n const network = read('T2000_NETWORK');\n if (network && network !== 'mainnet' && network !== 'testnet') {\n throw new Error(`[serve] T2000_NETWORK must be 'mainnet' or 'testnet', got \"${network}\"`);\n }\n\n const kvUrl = read('KV_REST_API_URL');\n const kvToken = read('KV_REST_API_TOKEN');\n const store =\n kvUrl && kvToken ? new UpstashDigestStore({ url: kvUrl, token: kvToken }) : undefined;\n\n if (!store) {\n console.warn(\n '[serve] No KV_REST_API_URL/KV_REST_API_TOKEN — using the in-memory replay store. ' +\n 'Fine for a single long-lived process; on serverless hosts set both so replay protection is durable.',\n );\n }\n\n return new Serve({\n payTo,\n network: (network as ServeNetwork | undefined) ?? 'mainnet',\n baseUrl: read('T2000_BASE_URL'),\n name: read('T2000_NAME'),\n description: read('T2000_DESCRIPTION'),\n store,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/discovery.ts","../src/chain.ts","../src/route.ts","../src/store.ts","../src/serve.ts"],"names":["result","USDC_TESTNET","USDC","InMemoryDigestStore"],"mappings":";;;;;;;AAeO,SAAS,oBAAA,CAAqB,OAAc,MAAA,EAA0C;AAC3F,EAAA,MAAM,IAAA,GAAO,MAAM,OAAA,IAAW,MAAA;AAC9B,EAAA,MAAM,QAAiC,EAAC;AAExC,EAAA,KAAA,MAAW,KAAA,IAAS,KAAA,CAAM,MAAA,CAAO,MAAA,EAAO,EAAG;AACzC,IAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,WAAA,EAAa,WAAA,KAAgB,KAAA,CAAM,IAAA;AAC5D,IAAA,MAAM,SAAA,GAAqC;AAAA,MACzC,WAAA,EAAa,IAAA,CAAK,OAAA,CAAQ,gBAAA,EAAkB,GAAG,CAAA;AAAA,MAC/C,SAAS,WAAA,IAAe,IAAA;AAAA,MACxB,SAAA,EAAW;AAAA,QACT,KAAA,EAAO,EAAE,WAAA,EAAa,SAAA,EAAU;AAAA,QAChC,GAAI,SAAA,GACA;AAAA,UACE,KAAA,EAAO;AAAA,YACL,WAAA,EACE;AAAA;AACJ,YAEF,EAAC;AAAA,QACL,KAAA,EAAO,EAAE,WAAA,EAAa,2CAAA;AAAuC;AAC/D,KACF;AACA,IAAA,IAAI,SAAA,EAAW;AAIb,MAAA,SAAA,CAAU,gBAAgB,CAAA,GAAI;AAAA,QAC5B,WAAA,EAAa,OAAA;AAAA,QACb,KAAA,EAAO,SAAA;AAAA,QACP,QAAA,EAAU,MAAA;AAAA,QACV,SAAA,EAAW,CAAC,KAAA,EAAO,MAAM,CAAA;AAAA,QACzB,IAAA,EAAM;AAAA,UACJ,MAAA,EAAQ,OAAA;AAAA,UACR,OAAA,EAAS,CAAA,IAAA,EAAO,KAAA,CAAM,OAAO,CAAA,CAAA;AAAA,UAC7B,KAAA,EAAA,CAAQ,KAAA,CAAM,OAAA,KAAY,SAAA,GAAY,eAAe,IAAA,EAAM,IAAA;AAAA,UAC3D,OAAO,KAAA,CAAM;AAAA;AACf,OACF;AAAA,IACF;AACA,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,SAAA,CAAU,WAAA,GAAc;AAAA,QACtB,QAAA,EAAU,IAAA;AAAA,QACV,SAAS,EAAE,kBAAA,EAAoB,EAAE,MAAA,EAAQ,aAAY;AAAE,OACzD;AAAA,IACF;AACA,IAAA,KAAA,CAAM,IAAI,IAAI,CAAA,CAAE,CAAA,GAAI,EAAE,MAAM,SAAA,EAAU;AAAA,EACxC;AAEA,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,OAAA;AAAA,IACT,IAAA,EAAM;AAAA,MACJ,KAAA,EAAO,MAAM,IAAA,IAAQ,UAAA;AAAA,MACrB,OAAA,EAAS,OAAA;AAAA,MACT,WAAA,EACE,MAAM,WAAA,IACN;AAAA,KACJ;AAAA,IACA,GAAI,IAAA,GAAO,EAAE,OAAA,EAAS,CAAC,EAAE,GAAA,EAAK,IAAA,EAAM,CAAA,EAAE,GAAI,EAAC;AAAA,IAC3C;AAAA,GACF;AACF;AAEO,SAAS,YAAA,CAAa,OAAc,MAAA,EAAyB;AAClE,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,OAAA,IAAW,MAAA,IAAU,EAAA;AACxC,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,CAAM,IAAA,CAAK,CAAA,EAAA,EAAK,KAAA,CAAM,IAAA,IAAQ,UAAU,CAAA,CAAE,CAAA;AAC1C,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,IAAI,MAAM,WAAA,EAAa;AACrB,IAAA,KAAA,CAAM,IAAA,CAAK,MAAM,WAAW,CAAA;AAC5B,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AACA,EAAA,KAAA,CAAM,KAAK,eAAe,CAAA;AAC1B,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,KAAA,CAAM,IAAA;AAAA,IACJ,oFAAA;AAAA,IACA,uFAAA;AAAA,IACA,wFAAA;AAAA,IACA,EAAA;AAAA,IACA,2EAAA;AAAA,IACA,iEAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,KAAA,CAAM,KAAK,cAAc,CAAA;AACzB,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,KAAA,MAAW,KAAA,IAAS,KAAA,CAAM,MAAA,CAAO,MAAA,EAAO,EAAG;AACzC,IAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,WAAA,EAAa,WAAA,KAAgB,KAAA,CAAM,IAAA;AAC5D,IAAA,MAAM,KAAA,GAAQ,SAAA,GAAY,CAAA,EAAG,SAAS,CAAA,cAAA,CAAA,GAAmB,MAAA;AACzD,IAAA,KAAA,CAAM,KAAK,CAAA,SAAA,EAAY,IAAI,IAAI,IAAI,CAAA,QAAA,EAAM,KAAK,CAAA,CAAE,CAAA;AAChD,IAAA,IAAI,WAAA,EAAa,KAAA,CAAM,IAAA,CAAK,WAAW,CAAA;AACvC,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,KAAA,CAAM,KAAK,6BAA6B,CAAA;AACxC,MAAA,KAAA,CAAM,KAAK,SAAS,CAAA;AACpB,MAAA,KAAA,CAAM,KAAK,IAAA,CAAK,SAAA,CAAU,WAAA,EAAa,IAAA,EAAM,CAAC,CAAC,CAAA;AAC/C,MAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAAA,IAClB;AACA,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AACA,EAAA,KAAA,CAAM,IAAA,CAAK,CAAA,WAAA,EAAc,IAAI,CAAA,aAAA,CAAe,CAAA;AAC5C,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;ACtGA,IAAM,aAAA,GAA8C;AAAA,EAClD,OAAA,EAAS,qCAAA;AAAA,EACT,OAAA,EAAS;AACX,CAAA;AAEA,IAAM,YAAA,GAAe,KAAK,EAAA,GAAK,GAAA;AAa/B,IAAM,QAAmD,EAAC;AAEnD,SAAS,aAAA,CAAc,SAAuB,MAAA,EAAgC;AACnF,EAAA,MAAM,CAAA,GAAK,KAAA,CAAM,OAAO,CAAA,KAAM,EAAC;AAC/B,EAAA,IAAI,CAAC,EAAE,MAAA,EAAQ;AACb,IAAA,CAAA,CAAE,MAAA,GAAS,IAAI,aAAA,CAAc;AAAA,MAC3B,OAAA,EAAS,MAAA,IAAU,aAAA,CAAc,OAAO,CAAA;AAAA,MACxC;AAAA,KACD,CAAA;AAAA,EACH;AACA,EAAA,OAAO,CAAA,CAAE,MAAA;AACX;AAEA,eAAsB,YAAA,CAAa,SAAuB,MAAA,EAAqC;AAC7F,EAAA,MAAM,MAAA,GAAS,aAAA,CAAc,OAAA,EAAS,MAAM,CAAA;AAC5C,EAAA,MAAM,CAAA,GAAK,KAAA,CAAM,OAAO,CAAA,KAAM,EAAC;AAC/B,EAAA,IAAI,CAAC,EAAE,OAAA,EAAS;AACd,IAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,IAAA,CAAK,kBAAA,EAAmB;AACjD,IAAA,CAAA,CAAE,UAAU,GAAA,CAAI,eAAA;AAAA,EAClB;AACA,EAAA,IAAI,CAAC,EAAE,KAAA,IAAS,IAAA,CAAK,KAAI,GAAI,CAAA,CAAE,KAAA,CAAM,SAAA,GAAY,YAAA,EAAc;AAC7D,IAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,IAAA,CAAK,qBAAA,EAAsB;AACpD,IAAA,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAA,EAAO,MAAA,CAAO,GAAA,CAAI,WAAA,CAAY,KAAK,CAAA,EAAG,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,EAAE;AAAA,EAC1E;AACA,EAAA,OAAO,EAAE,KAAA,EAAO,CAAA,CAAE,SAAS,KAAA,EAAO,CAAA,CAAE,MAAM,KAAA,EAAM;AAClD;AAGO,SAAS,kBAAA,GAA2B;AACzC,EAAA,OAAO,KAAA,CAAM,OAAA;AACb,EAAA,OAAO,KAAA,CAAM,OAAA;AACf;AAGO,SAAS,eAAA,CAAgB,OAAA,EAAuB,KAAA,EAAe,KAAA,EAAqB;AACzF,EAAA,MAAM,CAAA,GAAK,KAAA,CAAM,OAAO,CAAA,KAAM,EAAC;AAC/B,EAAA,CAAA,CAAE,OAAA,GAAU,KAAA;AACZ,EAAA,CAAA,CAAE,QAAQ,EAAE,KAAA,EAAO,OAAO,SAAA,EAAW,IAAA,CAAK,KAAI,EAAE;AAClD;;;ACRA,IAAM,cAAA,GAAiB,qCAAA;AACvB,IAAM,iBAAA,GAAoB,GAAA;AAG1B,IAAM,sBAAA,GAAyB,CAAA;AAE/B,IAAM,YAAA,GAAuC;AAAA,EAC3C,6BAAA,EAA+B,GAAA;AAAA,EAC/B,8BAAA,EAAgC,iCAAA;AAAA,EAChC,8BAAA,EAAgC,iBAAiB,mBAAmB,CAAA,CAAA;AAAA,EACpE,+BAAA,EAAiC,GAAG,4BAA4B,CAAA,kBAAA;AAClE,CAAA;AAEA,SAAS,SAAS,QAAA,EAA8B;AAC9C,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,QAAA,CAAS,OAAO,CAAA;AAC5C,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,CAAA,IAAK,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAA,EAAG,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAG,CAAC,CAAA;AACnE,EAAA,OAAO,IAAI,SAAS,QAAA,CAAS,IAAA,EAAM,EAAE,MAAA,EAAQ,QAAA,CAAS,MAAA,EAAQ,OAAA,EAAS,CAAA;AACzE;AAEA,SAAS,IAAA,CAAK,MAAA,EAAgB,IAAA,EAAe,OAAA,EAA4C;AACvF,EAAA,OAAO,QAAA;AAAA,IACL,IAAI,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAG;AAAA,MACjC,MAAA;AAAA,MACA,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,GAAG,OAAA;AAAQ,KAC3D;AAAA,GACH;AACF;AAEA,SAAS,iBAAiB,MAAA,EAAmD;AAC3E,EAAA,OAAO,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,KAAW,QAAQ,WAAA,IAAe,MAAA;AACzE;AAEA,eAAe,YAAA,CACb,QACA,KAAA,EACuE;AACvE,EAAA,IAAI,gBAAA,CAAiB,MAAM,CAAA,EAAG;AAC5B,IAAA,MAAMA,UAAS,MAAM,MAAA,CAAO,WAAW,CAAA,CAAE,SAAS,KAAK,CAAA;AACvD,IAAA,IAAIA,QAAO,MAAA,EAAQ;AAGjB,MAAA,MAAM,OAAA,GAAUA,OAAAA,CAAO,MAAA,CACpB,GAAA,CAAI,CAAC,CAAA,KAAM;AACV,QAAA,MAAM,IAAA,GAAA,CAAQ,EAAE,IAAA,IAAQ,IACrB,GAAA,CAAI,CAAC,QAAS,OAAO,GAAA,KAAQ,WAAW,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,GAAI,MAAA,CAAO,GAAG,CAAE,CAAA,CACtE,KAAK,GAAG,CAAA;AACX,QAAA,OAAO,OAAO,CAAA,EAAG,IAAI,KAAK,CAAA,CAAE,OAAO,KAAK,CAAA,CAAE,OAAA;AAAA,MAC5C,CAAC,CAAA,CACA,IAAA,CAAK,IAAI,CAAA;AACZ,MAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,OAAA,EAAQ;AAAA,IAC9B;AACA,IAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,IAAA,EAAMA,QAAO,KAAA,EAAM;AAAA,EACxC;AACA,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA;AACrC,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,SAAS,MAAA,CAAO,KAAA,CAAM,WAAW,cAAA,EAAe;AAAA,EACtE;AACA,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,IAAA,EAAM,OAAO,IAAA,EAAK;AACvC;AAGA,SAAS,gBAAA,CAAiB,OAAe,IAAA,EAAoB;AAC3D,EAAA,IAAI,CAAC,oBAAoB,IAAA,CAAK,KAAK,KAAK,MAAA,CAAO,KAAK,KAAK,CAAA,EAAG;AAC1D,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,eAAA,EAAkB,IAAI,CAAA,4EAAA,EAA+E,KAAK,CAAA,CAAA;AAAA,KAC5G;AAAA,EACF;AACA,EAAA,IAAI,MAAA,CAAO,KAAK,CAAA,GAAI,sBAAA,EAAwB;AAC1C,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,CAAA,eAAA,EAAkB,IAAI,CAAA,SAAA,EAAY,KAAK,sBAAsB,sBAAsB,CAAA,yIAAA;AAAA,KAErF;AAAA,EACF;AACF;AAEO,IAAM,eAAN,MAAsC;AAAA,EAM3C,WAAA,CACmB,OAAA,EACA,OAAA,EACA,QAAA,EACjB;AAHiB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA,EAChB;AAAA,EATK,SAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA;AAAA,EACA,MAAA,GAAS,KAAA;AAAA;AAAA,EASjB,KAAK,SAAA,EAAyB;AAC5B,IAAA,gBAAA,CAAiB,SAAA,EAAW,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA;AAC7C,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AACjB,IAAA,IAAA,CAAK,MAAA,GAAS,KAAA;AACd,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA,EAGA,WAAA,GAAoB;AAClB,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,IAAA,IAAA,CAAK,SAAA,GAAY,MAAA;AACjB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IAAA,CAAQ,QAAwB,UAAA,EAAuD;AACrF,IAAA,IAAA,CAAK,UAAA,GAAa,MAAA;AAClB,IAAA,IAAA,CAAK,WAAA,GAAc,UAAA;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,QAAQ,EAAA,EAAwF;AAC9F,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,IAAU,CAAC,KAAK,SAAA,EAAW;AACnC,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,eAAA,EAAkB,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA,2DAAA;AAAA,OACrC;AAAA,IACF;AACA,IAAA,MAAM,UAAU,IAAA,CAAK,OAAA;AACrB,IAAA,MAAM,EAAE,IAAA,EAAM,WAAA,EAAY,GAAI,IAAA,CAAK,OAAA;AACnC,IAAA,MAAM,YAAY,IAAA,CAAK,SAAA;AACvB,IAAA,MAAM,aAAa,IAAA,CAAK,UAAA;AAExB,IAAA,MAAM,KAAA,IAAS,OAAO,GAAA,KAAoC;AACxD,MAAA,IAAI,GAAA,CAAI,WAAW,SAAA,EAAW;AAC5B,QAAA,OAAO,QAAA,CAAS,IAAI,QAAA,CAAS,IAAA,EAAM,EAAE,MAAA,EAAQ,GAAA,EAAK,CAAC,CAAA;AAAA,MACrD;AAKA,MAAA,IAAI,UAAA;AACJ,MAAA,IAAI,cAAA;AACJ,MAAA,IAAI,GAAA,CAAI,MAAA,KAAW,KAAA,IAAS,GAAA,CAAI,WAAW,MAAA,EAAQ;AACjD,QAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,QAAA,IAAI,IAAA,CAAK,IAAA,EAAK,CAAE,MAAA,GAAS,CAAA,EAAG;AAC1B,UAAA,IAAI;AACF,YAAA,UAAA,GAAa,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,UAC9B,CAAA,CAAA,MAAQ;AACN,YAAA,cAAA,GAAiB,gCAAA;AAAA,UACnB;AAAA,QACF;AAAA,MACF;AAEA,MAAA,MAAM,QAAA,GAAA,CAAY,OAAA,CAAQ,OAAA,IAAW,IAAI,IAAI,GAAA,CAAI,GAAG,CAAA,CAAE,MAAA,EAAQ,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,GAAI,IAAI,IAAI,CAAA,CAAA;AAE3F,MAAA,MAAM,UAAA,GAAa,OAAO,KAAA,KAAsC;AAC9D,QAAA,IAAI,SAAA,GAAqB,UAAA;AACzB,QAAA,IAAI,UAAA,EAAY;AAGd,UAAA,IAAI,cAAA,EAAgB;AAClB,YAAA,OAAO,KAAK,GAAA,EAAK,EAAE,OAAO,cAAA,EAAgB,IAAA,EAAM,OAAO,CAAA;AAAA,UACzD;AACA,UAAA,MAAM,SAAS,MAAM,YAAA,CAAa,UAAA,EAAY,UAAA,IAAc,EAAE,CAAA;AAC9D,UAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACd,YAAA,OAAO,IAAA,CAAK,KAAK,EAAE,KAAA,EAAO,OAAO,OAAA,EAAS,IAAA,EAAM,OAAO,CAAA;AAAA,UACzD;AACA,UAAA,SAAA,GAAY,MAAA,CAAO,IAAA;AAAA,QACrB;AACA,QAAA,MAAM,GAAA,GAAM,MAAM,EAAA,CAAG,EAAE,MAAM,SAAA,EAAoB,GAAA,EAAK,OAAO,CAAA;AAC7D,QAAA,IAAI,GAAA,YAAe,QAAA,EAAU,OAAO,QAAA,CAAS,GAAG,CAAA;AAChD,QAAA,OAAO,IAAA,CAAK,KAAK,GAAG,CAAA;AAAA,MACtB,CAAA;AAGA,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,IAAI;AACF,UAAA,OAAO,MAAM,UAAA,EAAW;AAAA,QAC1B,SAAS,GAAA,EAAK;AACZ,UAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,eAAA,EAAkB,IAAI,CAAA,iBAAA,CAAA,EAAqB,GAAG,CAAA;AAC5D,UAAA,OAAO,IAAA,CAAK,GAAA,EAAK,EAAE,KAAA,EAAO,kBAAkB,CAAA;AAAA,QAC9C;AAAA,MACF;AAEA,MAAA,MAAM,aAAA,GAAgB,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,mBAAmB,CAAA;AAMzD,MAAA,IAAI,CAAC,aAAA,EAAe;AAClB,QAAA,OAAO,MAAM,UAAA,CAAW,OAAA,EAAS,EAAE,QAAA,EAAU,WAAW,CAAA;AAAA,MAC1D;AAEA,MAAA,IAAI,kBAAA,CAAmB,aAAa,CAAA,EAAG;AACrC,QAAA,OAAO,MAAM,WAAW,OAAA,EAAS;AAAA,UAC/B,QAAA;AAAA,UACA,SAAA;AAAA,UACA,KAAA,EACE;AAAA,SACH,CAAA;AAAA,MACH;AAKA,MAAA,IAAI,OAAA;AACJ,MAAA,IAAI;AACF,QAAA,OAAA,GAAU,gBAAgB,aAAa,CAAA;AACvC,QAAA,iBAAA,CAAkB;AAAA,UAChB,OAAA;AAAA,UACA,QAAA,EAAU;AAAA,YACR,WAAA,EAAa,QAAQ,OAAA,CAAQ,WAAA;AAAA,YAC7B,MAAA,EAAQ,SAAA;AAAA,YACR,UAAU,OAAA,CAAQ,QAAA;AAAA,YAClB,WAAW,OAAA,CAAQ,KAAA;AAAA,YACnB,SAAS,OAAA,CAAQ;AAAA;AACnB,SACD,CAAA;AAAA,MACH,SAAS,GAAA,EAAK;AACZ,QAAA,OAAO,MAAM,WAAW,OAAA,EAAS;AAAA,UAC/B,QAAA;AAAA,UACA,SAAA;AAAA,UACA,KAAA,EAAO,oBAAoB,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,SAC5E,CAAA;AAAA,MACH;AAKA,MAAA,MAAM,YAAA,GAAe,CAAA,UAAA,EAAa,OAAA,CAAQ,OAAA,CAAQ,WAAW,CAAA,CAAA;AAC7D,MAAA,IAAI,MAAM,OAAA,CAAQ,KAAA,CAAM,GAAA,CAAI,YAAY,CAAA,EAAG;AACzC,QAAA,OAAO,MAAM,WAAW,OAAA,EAAS;AAAA,UAC/B,QAAA;AAAA,UACA,SAAA;AAAA,UACA,KAAA,EAAO;AAAA,SACR,CAAA;AAAA,MACH;AAIA,MAAA,IAAI,MAAA;AACJ,MAAA,IAAI;AACF,QAAA,MAAA,GAAS,MAAM,UAAA,CAAW,OAAA,CAAQ,OAAA,CAAQ,aAAa,CAAA;AAAA,MACzD,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,eAAA,EAAkB,IAAI,CAAA,uCAAA,CAAA,EAA2C,GAAG,CAAA;AAClF,QAAA,OAAO,IAAA,CAAK,GAAA,EAAK,EAAE,KAAA,EAAO,8CAAyC,CAAA;AAAA,MACrE;AACA,MAAA,IAAI,MAAA,CAAO,MAAA,IAAU,GAAA,EAAK,OAAO,MAAA;AAIjC,MAAA,IAAI,MAAA;AACJ,MAAA,IAAI;AACF,QAAA,MAAA,GAAS,MAAM,iBAAA,CAAkB;AAAA,UAC/B,OAAA;AAAA,UACA,MAAA,EAAQ,aAAA,CAAc,OAAA,CAAQ,OAAA,EAAS,QAAQ,MAAM,CAAA;AAAA,UACrD,OAAO,OAAA,CAAQ,KAAA;AAAA,UACf,QAAA,EAAU;AAAA,YACR,WAAA,EAAa,QAAQ,OAAA,CAAQ,WAAA;AAAA,YAC7B,MAAA,EAAQ,SAAA;AAAA,YACR,UAAU,OAAA,CAAQ,QAAA;AAAA,YAClB,WAAW,OAAA,CAAQ,KAAA;AAAA,YACnB,SAAS,OAAA,CAAQ;AAAA;AACnB,SACD,CAAA;AAAA,MACH,SAAS,GAAA,EAAK;AACZ,QAAA,OAAO,MAAM,WAAW,OAAA,EAAS;AAAA,UAC/B,QAAA;AAAA,UACA,SAAA;AAAA,UACA,KAAA,EAAO,sBAAsB,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,SAC9E,CAAA;AAAA,MACH;AAGA,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,CAAQ,KAAA,CAAM,GAAA,CAAI,YAAY,CAAA;AAAA,MACtC,CAAA,CAAA,MAAQ;AAAA,MAER;AAEA,MAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,QAAA,aAAA,CAAc,MAAA,CAAO,aAAa,QAAQ,CAAA;AAAA,MAC5C;AAEA,MAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,MAAA,CAAO,OAAO,CAAA;AAC1C,MAAA,OAAA,CAAQ,GAAA,CAAI,4BAAA,EAA8B,kBAAA,CAAmB,MAAM,CAAC,CAAA;AACpE,MAAA,OAAO,IAAI,SAAS,MAAA,CAAO,IAAA,EAAM,EAAE,MAAA,EAAQ,MAAA,CAAO,MAAA,EAAQ,OAAA,EAAS,CAAA;AAAA,IACrE,CAAA,CAAA;AAEA,IAAA,KAAA,CAAM,IAAA,GAAO,EAAE,IAAA,EAAM,SAAA,EAAW,aAAa,UAAA,EAAY,WAAA,EAAa,KAAK,WAAA,EAAY;AACvF,IAAA,IAAA,CAAK,SAAS,KAAK,CAAA;AACnB,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,eAAe,UAAA,CACb,SACA,IAAA,EACmB;AACnB,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,OAAO,KAAA,EAAM,GAAI,MAAM,YAAA,CAAa,OAAA,CAAQ,OAAA,EAAS,OAAA,CAAQ,MAAM,CAAA;AAC3E,IAAA,MAAM,eAAe,sBAAA,CAAuB;AAAA,MAC1C,WAAA,EAAa,OAAO,UAAA,EAAW;AAAA,MAC/B,QAAQ,IAAA,CAAK,SAAA;AAAA,MACb,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,WAAW,OAAA,CAAQ,KAAA;AAAA,MACnB,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,SAAS,OAAA,CAAQ,OAAA;AAAA,MACjB,KAAA;AAAA,MACA,YAAA,EAAc;AAAA,KACf,CAAA;AACD,IAAA,OAAO,KAAK,GAAA,EAAK;AAAA,MACf,WAAA,EAAa,YAAA;AAAA,MACb,KAAA,EAAO,KAAK,KAAA,IAAS,kBAAA;AAAA,MACrB,OAAA,EAAS,CAAC,YAAY;AAAA,KACvB,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AAGZ,IAAA,OAAA,CAAQ,KAAA,CAAM,0CAA0C,GAAG,CAAA;AAC3D,IAAA,OAAO,IAAA,CAAK,GAAA,EAAK,EAAE,KAAA,EAAO,6CAA6C,CAAA;AAAA,EACzE;AACF;AAOA,SAAS,aAAA,CAAc,QAAgB,GAAA,EAAmB;AACxD,EAAA,KAAK,MAAM,cAAA,EAAgB;AAAA,IACzB,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,MAAA,EAAQ,KAAK,CAAA;AAAA,IACpC,MAAA,EAAQ,WAAA,CAAY,OAAA,CAAQ,iBAAiB;AAAA,GAC9C,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,EAAC,CAAC,CAAA;AACnB;ACxXA,IAAM,mBAAA,GAAsB,KAAK,EAAA,GAAK,EAAA;AACtC,IAAM,MAAA,GAAS,eAAA;AASR,IAAM,qBAAN,MAAgD;AAAA,EACpC,GAAA;AAAA,EACA,KAAA;AAAA,EACA,UAAA;AAAA,EAEjB,YAAY,OAAA,EAAoC;AAC9C,IAAA,IAAA,CAAK,GAAA,GAAM,OAAA,CAAQ,GAAA,CAAI,OAAA,CAAQ,OAAO,EAAE,CAAA;AACxC,IAAA,IAAA,CAAK,QAAQ,OAAA,CAAQ,KAAA;AACrB,IAAA,IAAA,CAAK,UAAA,GAAa,QAAQ,UAAA,IAAc,mBAAA;AAAA,EAC1C;AAAA,EAEA,MAAc,QAAQ,QAAA,EAAsC;AAC1D,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,EAAG,KAAK,GAAG,CAAA,CAAA,EAAI,QAAA,CAAS,GAAA,CAAI,kBAAkB,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,EAAI;AAAA,MACnF,SAAS,EAAE,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,CAAA;AAAG,KAClD,CAAA;AACD,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,GAAA,CAAI,MAAM,IAAI,MAAM,GAAA,CAAI,IAAA,EAAM,CAAA,CAAE,CAAA;AAAA,IAC7E;AACA,IAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAC7B,IAAA,IAAI,IAAA,CAAK,OAAO,MAAM,IAAI,MAAM,CAAA,eAAA,EAAkB,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AAC9D,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA,EAEA,MAAM,IAAI,MAAA,EAAkC;AAC1C,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,CAAC,KAAA,EAAO,MAAA,GAAS,MAAM,CAAC,CAAA;AAC1D,IAAA,OAAO,MAAA,KAAW,QAAQ,MAAA,KAAW,MAAA;AAAA,EACvC;AAAA,EAEA,MAAM,IAAI,MAAA,EAA+B;AAGvC,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAAQ;AAAA,MAChC,KAAA;AAAA,MACA,MAAA,GAAS,MAAA;AAAA,MACT,GAAA;AAAA,MACA,IAAA;AAAA,MACA,MAAA,CAAO,KAAK,UAAU,CAAA;AAAA,MACtB;AAAA,KACD,CAAA;AACD,IAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,MAAA,KAAW,MAAA,EAAW;AAC3C,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,MAAM,CAAA,CAAE,CAAA;AAAA,IAClD;AAAA,EACF;AACF;;;AC/DO,IAAM,QAAN,MAAY;AAAA,EACA,OAAA;AAAA;AAAA,EAER,MAAA,uBAAa,GAAA,EAAwB;AAAA,EAErC,KAAA;AAAA,EACA,OAAA;AAAA,EACA,IAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EAET,YAAY,MAAA,EAAqB;AAC/B,IAAA,IAAI,CAAC,MAAA,CAAO,KAAA,IAAS,CAAC,iBAAA,CAAkB,MAAA,CAAO,KAAK,CAAA,EAAG;AACrD,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,qFAAA,EAAwF,OAAO,KAAK,CAAA,CAAA;AAAA,OACtG;AAAA,IACF;AACA,IAAA,IAAA,CAAK,KAAA,GAAQ,mBAAA,CAAoB,MAAA,CAAO,KAAK,CAAA;AAC7C,IAAA,IAAA,CAAK,OAAA,GAAU,OAAO,OAAA,IAAW,SAAA;AACjC,IAAA,IAAA,CAAK,OAAO,MAAA,CAAO,IAAA;AACnB,IAAA,IAAA,CAAK,cAAc,MAAA,CAAO,WAAA;AAC1B,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA,CAAO,OAAA,EAAS,OAAA,CAAQ,OAAO,EAAE,CAAA;AAEhD,IAAA,MAAM,QAAA,GAAqB,IAAA,CAAK,OAAA,KAAY,SAAA,GAAYC,YAAAA,GAAeC,IAAAA;AACvE,IAAA,IAAA,CAAK,OAAA,GAAU;AAAA,MACb,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,QAAA;AAAA,MACA,KAAA,EAAO,MAAA,CAAO,KAAA,IAAS,IAAIC,mBAAAA,EAAoB;AAAA,MAC/C,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,MAAA,EAAQ,OAAO,MAAA,IAAU;AAAA,KAC3B;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,OAAA,EAAqC;AACzC,IAAA,MAAM,IAAA,GAAO,QAAQ,IAAA,CAAK,OAAA,CAAQ,QAAQ,EAAE,CAAA,CAAE,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAChE,IAAA,IAAI,CAAC,IAAA,EAAM,MAAM,IAAI,MAAM,sCAAsC,CAAA;AACjE,IAAA,OAAO,IAAI,YAAA,CAAa,EAAE,GAAG,IAAA,CAAK,OAAA,EAAQ,EAAG,EAAE,GAAG,OAAA,EAAS,IAAA,EAAK,EAAG,CAAC,KAAA,KAAU;AAC5E,MAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,IAAA,EAAM,KAAK,CAAA;AAAA,IAC7B,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAA,GAAsC;AACpC,IAAA,OAAO,CAAC,GAAA,KACN,IAAI,QAAA,CAAS,IAAA,CAAK,UAAU,oBAAA,CAAqB,IAAA,EAAM,IAAI,GAAA,CAAI,IAAI,GAAG,CAAA,CAAE,MAAM,CAAA,EAAG,IAAA,EAAM,CAAC,CAAA,EAAG;AAAA,MACzF,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,+BAA+B,GAAA;AAAI,KACnF,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAA,GAAmC;AACjC,IAAA,OAAO,CAAC,GAAA,KACN,IAAI,QAAA,CAAS,YAAA,CAAa,IAAA,EAAM,IAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,CAAE,MAAM,CAAA,EAAG;AAAA,MACxD,OAAA,EAAS,EAAE,cAAA,EAAgB,2BAAA,EAA6B,+BAA+B,GAAA;AAAI,KAC5F,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWS,KAAA,GAAQ,OAAO,GAAA,KAAoC;AAC1D,IAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,CAAE,QAAA,CAAS,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA,CAAE,OAAA,CAAQ,QAAQ,EAAE,CAAA;AACjF,IAAA,IAAI,aAAa,cAAA,EAAgB,OAAO,IAAA,CAAK,OAAA,GAAU,GAAG,CAAA;AAC1D,IAAA,IAAI,aAAa,UAAA,EAAY,OAAO,IAAA,CAAK,IAAA,GAAO,GAAG,CAAA;AACnD,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,QAAQ,CAAA;AACtC,IAAA,IAAI,KAAA,EAAO,OAAO,KAAA,CAAM,GAAG,CAAA;AAC3B,IAAA,OAAO,IAAI,QAAA;AAAA,MACT,IAAA,CAAK,SAAA,CAAU,EAAE,KAAA,EAAO,WAAA,EAAa,WAAW,CAAC,eAAA,EAAiB,WAAW,CAAA,EAAG,CAAA;AAAA,MAChF,EAAE,MAAA,EAAQ,GAAA,EAAK,SAAS,EAAE,cAAA,EAAgB,oBAAmB;AAAE,KACjE;AAAA,EACF,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,qBAAqB,WAAA,EAA8B;AACjD,IAAA,MAAM,QAAQ,WAAA,IAAe,IAAA,CAAK,WAAW,6BAAA,EAA+B,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC7F,IAAA,MAAM,SAAA,GAAY,CAAC,GAAG,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,SAAS,CAAA;AAC1E,IAAA,MAAM,OAAA,GAAU,SAAA,CAAU,CAAC,CAAA,EAAG,KAAK,IAAA,IAAQ,SAAA;AAC3C,IAAA,OAAO;AAAA,MACL,kDAAA;AAAA,MACA,CAAA,sGAAA,EAAyG,IAAI,CAAA,CAAA,EAAI,OAAO,CAAA,GAAA,CAAA;AAAA,MACxH,kBAAA;AAAA,MACA,CAAA,qGAAA,EAAwG,IAAI,CAAA,CAAA,EAAI,OAAO,CAAA,GAAA;AAAA,KACzH,CAAE,KAAK,IAAI,CAAA;AAAA,EACb;AACF;AAEO,SAAS,YAAY,MAAA,EAA4B;AACtD,EAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AACzB;AAkBO,SAAS,kBAAA,CAAmB,GAAA,GAA0C,OAAA,CAAQ,GAAA,EAAY;AAC/F,EAAA,MAAM,IAAA,GAAO,CAAC,GAAA,KAAoC;AAChD,IAAA,MAAM,CAAA,GAAI,GAAA,CAAI,GAAG,CAAA,EAAG,IAAA,EAAK;AACzB,IAAA,OAAO,CAAA,IAAK,CAAA,CAAE,MAAA,GAAS,CAAA,GAAI,CAAA,GAAI,MAAA;AAAA,EACjC,CAAA;AAEA,EAAA,MAAM,KAAA,GAAQ,KAAK,cAAc,CAAA;AACjC,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,KAAK,eAAe,CAAA;AACpC,EAAA,IAAI,OAAA,IAAW,OAAA,KAAY,SAAA,IAAa,OAAA,KAAY,SAAA,EAAW;AAC7D,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2DAAA,EAA8D,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,EAC1F;AAEA,EAAA,MAAM,KAAA,GAAQ,KAAK,iBAAiB,CAAA;AACpC,EAAA,MAAM,OAAA,GAAU,KAAK,mBAAmB,CAAA;AACxC,EAAA,MAAM,KAAA,GACJ,KAAA,IAAS,OAAA,GAAU,IAAI,kBAAA,CAAmB,EAAE,GAAA,EAAK,KAAA,EAAO,KAAA,EAAO,OAAA,EAAS,CAAA,GAAI,MAAA;AAE9E,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN;AAAA,KAEF;AAAA,EACF;AAEA,EAAA,OAAO,IAAI,KAAA,CAAM;AAAA,IACf,KAAA;AAAA,IACA,SAAU,OAAA,IAAwC,SAAA;AAAA,IAClD,OAAA,EAAS,KAAK,gBAAgB,CAAA;AAAA,IAC9B,IAAA,EAAM,KAAK,YAAY,CAAA;AAAA,IACvB,WAAA,EAAa,KAAK,mBAAmB,CAAA;AAAA,IACrC;AAAA,GACD,CAAA;AACH","file":"index.js","sourcesContent":["import { USDC, USDC_TESTNET } from '@suimpp/mpp/server';\nimport type { Serve } from './serve.js';\n\n// ---------------------------------------------------------------------------\n// Discovery docs — /openapi.json + /llms.txt.\n//\n// The shapes here are graded by the catalog's ingest (apps/gateway/lib/\n// catalog-ingest.ts `gradeListing`): a warning-free listing needs info.title,\n// a one-paragraph info.description, a flat string `x-payment-info.price` per\n// paid operation, and an application/json requestBody schema with typed\n// properties. Everything serve can derive is emitted automatically; the JSON\n// request schema comes from the route's `inputSchema` (zod v4 users:\n// `z.toJSONSchema(schema)`).\n// ---------------------------------------------------------------------------\n\nexport function buildOpenApiDocument(serve: Serve, origin?: string): Record<string, unknown> {\n const base = serve.baseUrl ?? origin;\n const paths: Record<string, unknown> = {};\n\n for (const route of serve.routes.values()) {\n const { path, priceUsdc, description, inputSchema } = route.meta;\n const operation: Record<string, unknown> = {\n operationId: path.replace(/[^a-zA-Z0-9]+/g, '_'),\n summary: description ?? path,\n responses: {\n '200': { description: 'Success' },\n ...(priceUsdc\n ? {\n '402': {\n description:\n 'Payment required — the body carries an x402 accepts[] envelope (scheme \"exact\", network sui). Sign it and retry with the X-PAYMENT header.',\n },\n }\n : {}),\n '422': { description: 'Invalid request body — never charged' },\n },\n };\n if (priceUsdc) {\n // Same shape the gateway's own /openapi.json emits: 'mpp' is the\n // protocol family, 'x402' the dialect; the x402 block mirrors the\n // static half of the live accepts[] entry (dynamic fields ride the 402).\n operation['x-payment-info'] = {\n pricingMode: 'fixed',\n price: priceUsdc,\n currency: 'USDC',\n protocols: ['mpp', 'x402'],\n x402: {\n scheme: 'exact',\n network: `sui:${serve.network}`,\n asset: (serve.network === 'testnet' ? USDC_TESTNET : USDC).type,\n payTo: serve.payTo,\n },\n };\n }\n if (inputSchema) {\n operation.requestBody = {\n required: true,\n content: { 'application/json': { schema: inputSchema } },\n };\n }\n paths[`/${path}`] = { post: operation };\n }\n\n return {\n openapi: '3.1.0',\n info: {\n title: serve.name ?? 'Paid API',\n version: '1.0.0',\n description:\n serve.description ??\n 'Agent-payable API. Every paid endpoint answers 402 with an x402 accepts[] envelope; payment settles in USDC on Sui.',\n },\n ...(base ? { servers: [{ url: base }] } : {}),\n paths,\n };\n}\n\nexport function buildLlmsTxt(serve: Serve, origin?: string): string {\n const base = serve.baseUrl ?? origin ?? '';\n const lines: string[] = [];\n lines.push(`# ${serve.name ?? 'Paid API'}`);\n lines.push('');\n if (serve.description) {\n lines.push(serve.description);\n lines.push('');\n }\n lines.push('## How to pay');\n lines.push('');\n lines.push(\n 'Endpoints below are paid per call in USDC on Sui (x402). An unpaid request returns',\n 'HTTP 402 with an `accepts[]` envelope; sign it and retry with the `X-PAYMENT` header.',\n 'Invalid input returns 422 before any payment is taken. A failed call is never charged.',\n '',\n 'Easiest client: `npm i -g @t2000/cli` then `t2 pay <url> --data \\'{...}\\'`,',\n 'or the t2000 MCP server (`t2000_pay`), or `@t2000/sdk` `pay()`.',\n '',\n );\n lines.push('## Endpoints');\n lines.push('');\n for (const route of serve.routes.values()) {\n const { path, priceUsdc, description, inputSchema } = route.meta;\n const price = priceUsdc ? `${priceUsdc} USDC per call` : 'free';\n lines.push(`### POST ${base}/${path} — ${price}`);\n if (description) lines.push(description);\n if (inputSchema) {\n lines.push('Request body (JSON Schema):');\n lines.push('```json');\n lines.push(JSON.stringify(inputSchema, null, 2));\n lines.push('```');\n }\n lines.push('');\n }\n lines.push(`Discovery: ${base}/openapi.json`);\n return lines.join('\\n');\n}\n","import { SuiGrpcClient } from '@mysten/sui/grpc';\nimport type { ServeNetwork } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Chain plumbing — same shape as the gateway's x402-dialect.ts (the reference\n// composition). All reads are gRPC; this package never touches JSON-RPC.\n//\n// Cache policy: the chain identifier (genesis digest) is immutable per\n// network — cached forever. The epoch advances ~daily and x402 requirements\n// are valid for [epoch, epoch+1], so a 10-minute TTL is conservatively fresh.\n// ---------------------------------------------------------------------------\n\nconst FULLNODE_URLS: Record<ServeNetwork, string> = {\n mainnet: 'https://fullnode.mainnet.sui.io:443',\n testnet: 'https://fullnode.testnet.sui.io:443',\n};\n\nconst EPOCH_TTL_MS = 10 * 60 * 1000;\n\nexport interface ChainInfo {\n chain: string;\n epoch: string;\n}\n\ninterface ChainState {\n client?: SuiGrpcClient;\n chainId?: string;\n epoch?: { value: string; fetchedAt: number };\n}\n\nconst state: Partial<Record<ServeNetwork, ChainState>> = {};\n\nexport function getGrpcClient(network: ServeNetwork, rpcUrl?: string): SuiGrpcClient {\n const s = (state[network] ??= {});\n if (!s.client) {\n s.client = new SuiGrpcClient({\n baseUrl: rpcUrl ?? FULLNODE_URLS[network],\n network,\n });\n }\n return s.client;\n}\n\nexport async function getChainInfo(network: ServeNetwork, rpcUrl?: string): Promise<ChainInfo> {\n const client = getGrpcClient(network, rpcUrl);\n const s = (state[network] ??= {});\n if (!s.chainId) {\n const res = await client.core.getChainIdentifier();\n s.chainId = res.chainIdentifier;\n }\n if (!s.epoch || Date.now() - s.epoch.fetchedAt > EPOCH_TTL_MS) {\n const res = await client.core.getCurrentSystemState();\n s.epoch = { value: String(res.systemState.epoch), fetchedAt: Date.now() };\n }\n return { chain: s.chainId, epoch: s.epoch.value };\n}\n\n/** Test seam — reset module caches between cases. */\nexport function __resetChainCaches(): void {\n delete state.mainnet;\n delete state.testnet;\n}\n\n/** Test seam — pre-seed chain info so tests never hit the network. */\nexport function __seedChainInfo(network: ServeNetwork, chain: string, epoch: string): void {\n const s = (state[network] ??= {});\n s.chainId = chain;\n s.epoch = { value: epoch, fetchedAt: Date.now() };\n}\n","import type { DigestStore } from '@suimpp/mpp/server';\nimport type { Currency } from '@suimpp/mpp/server';\nimport {\n createX402Requirements,\n encodeX402Response,\n isX402EscrowHeader,\n parseX402Header,\n settleX402Payment,\n verifyX402Payment,\n X402_PAYMENT_HEADER,\n X402_PAYMENT_RESPONSE_HEADER,\n X402_VERSION,\n type X402SettleResponse,\n} from '@suimpp/mpp/x402';\nimport { getChainInfo, getGrpcClient } from './chain.js';\nimport type {\n BuiltRoute,\n HandlerContext,\n HandlerResult,\n ServeNetwork,\n ServeSchema,\n StandardSchemaLike,\n} from './types.js';\n\n// ---------------------------------------------------------------------------\n// The paid-request lifecycle (SPEC_T2000_SERVE §3 — sign-then-settle,\n// handler-then-settle):\n//\n// no X-PAYMENT → 402 with the accepts[] envelope (never a charge;\n// the catalog probe and every discovery tool read\n// this, so it fires BEFORE body validation)\n// X-PAYMENT present:\n// 1. parse + STRUCTURAL verify (right amount/recipient/nonce — no RPC)\n// 2. challenge-once check (a signed payload is single-use)\n// 3. validate the body — invalid → 422, payment NEVER submitted\n// (the JMPR paid-422 class is impossible: the buyer keeps their money)\n// 4. run the handler — throws → 500, payment NEVER submitted\n// 5. settle (submit the buyer-signed gasless bytes; digest-once inside)\n// 6. consume the challenge, attach the X-PAYMENT-RESPONSE receipt\n//\n// Money only moves at step 5, after the seller has already produced the\n// result. A forged payload can waste seller compute (signature authority is\n// the chain at settle time), never buyer money.\n// ---------------------------------------------------------------------------\n\nexport interface RouteRuntime {\n payTo: string;\n network: ServeNetwork;\n currency: Currency;\n store: DigestStore;\n baseUrl?: string;\n rpcUrl?: string;\n report: boolean;\n}\n\nexport interface RouteOptions {\n path: string;\n description?: string;\n}\n\nconst MPP_REPORT_URL = 'https://mpp.t2000.ai/api/mpp/report';\nconst REPORT_TIMEOUT_MS = 2_000;\n\n/** Listing cap on mpp.t2000.ai (catalog-ingest price-cap gate). */\nconst CATALOG_PRICE_CAP_USDC = 5;\n\nconst CORS_HEADERS: Record<string, string> = {\n 'access-control-allow-origin': '*',\n 'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'access-control-allow-headers': `content-type, ${X402_PAYMENT_HEADER}`,\n 'access-control-expose-headers': `${X402_PAYMENT_RESPONSE_HEADER}, WWW-Authenticate`,\n};\n\nfunction withCors(response: Response): Response {\n const headers = new Headers(response.headers);\n for (const [k, v] of Object.entries(CORS_HEADERS)) headers.set(k, v);\n return new Response(response.body, { status: response.status, headers });\n}\n\nfunction json(status: number, body: unknown, headers?: Record<string, string>): Response {\n return withCors(\n new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json', ...headers },\n }),\n );\n}\n\nfunction isStandardSchema(schema: ServeSchema): schema is StandardSchemaLike {\n return typeof schema === 'object' && schema !== null && '~standard' in schema;\n}\n\nasync function validateBody(\n schema: ServeSchema,\n value: unknown,\n): Promise<{ ok: true; data: unknown } | { ok: false; message: string }> {\n if (isStandardSchema(schema)) {\n const result = await schema['~standard'].validate(value);\n if (result.issues) {\n // Name the failing field — bare \"Invalid input\" ×N gives a paying\n // buyer's agent nothing to self-correct with.\n const message = result.issues\n .map((i) => {\n const path = (i.path ?? [])\n .map((seg) => (typeof seg === 'object' ? String(seg.key) : String(seg)))\n .join('.');\n return path ? `${path}: ${i.message}` : i.message;\n })\n .join('; ');\n return { ok: false, message };\n }\n return { ok: true, data: result.value };\n }\n const result = schema.safeParse(value);\n if (!result.success) {\n return { ok: false, message: result.error.message ?? 'invalid body' };\n }\n return { ok: true, data: result.data };\n}\n\n/** Positive decimal USDC string, max 6dp (atomic precision). */\nfunction assertValidPrice(price: string, path: string): void {\n if (!/^\\d+(\\.\\d{1,6})?$/.test(price) || Number(price) <= 0) {\n throw new Error(\n `[serve] Route \"${path}\": price must be a positive decimal USDC string with up to 6 decimals, got \"${price}\"`,\n );\n }\n if (Number(price) > CATALOG_PRICE_CAP_USDC) {\n console.warn(\n `[serve] Route \"${path}\": price ${price} USDC is above the ${CATALOG_PRICE_CAP_USDC} USDC listing cap — ` +\n 'the route works, but it will not list on mpp.t2000.ai. Job-class work belongs in `t2 service create` (escrow).',\n );\n }\n}\n\nexport class RouteBuilder<TBody = undefined> {\n private priceUsdc?: string;\n private bodySchema?: ServeSchema;\n private inputSchema?: Record<string, unknown>;\n private isFree = false;\n\n constructor(\n private readonly runtime: RouteRuntime,\n private readonly options: RouteOptions,\n private readonly register: (route: BuiltRoute) => void,\n ) {}\n\n /** Charge this many USDC per call (human units, e.g. \"0.01\"). */\n paid(priceUsdc: string): this {\n assertValidPrice(priceUsdc, this.options.path);\n this.priceUsdc = priceUsdc;\n this.isFree = false;\n return this;\n }\n\n /** Serve without payment (health checks, previews, docs). */\n unprotected(): this {\n this.isFree = true;\n this.priceUsdc = undefined;\n return this;\n }\n\n /**\n * Validate the JSON request body. zod v4 / valibot / arktype / anything\n * Standard-Schema, or anything with a zod-style safeParse.\n *\n * Pass the JSON Schema as the second argument to publish it in\n * /openapi.json + /llms.txt (zod v4: `z.toJSONSchema(schema)`) — buyers'\n * agents build request bodies from it, and the catalog grades listings\n * without one.\n */\n body<T>(schema: ServeSchema<T>, jsonSchema?: Record<string, unknown>): RouteBuilder<T> {\n this.bodySchema = schema;\n this.inputSchema = jsonSchema;\n return this as unknown as RouteBuilder<T>;\n }\n\n handler(fn: (ctx: HandlerContext<TBody>) => HandlerResult | Promise<HandlerResult>): BuiltRoute {\n if (!this.isFree && !this.priceUsdc) {\n throw new Error(\n `[serve] Route \"${this.options.path}\": call .paid('<usdc>') or .unprotected() before .handler()`,\n );\n }\n const runtime = this.runtime;\n const { path, description } = this.options;\n const priceUsdc = this.priceUsdc;\n const bodySchema = this.bodySchema;\n\n const route = (async (req: Request): Promise<Response> => {\n if (req.method === 'OPTIONS') {\n return withCors(new Response(null, { status: 204 }));\n }\n\n // Read + parse the body once, up front. A missing/empty body on a\n // schema-less route is fine; JSON parse failures only matter when a\n // paid request must be validated (the unpaid 402 fires regardless).\n let parsedBody: unknown;\n let bodyParseError: string | undefined;\n if (req.method !== 'GET' && req.method !== 'HEAD') {\n const text = await req.text();\n if (text.trim().length > 0) {\n try {\n parsedBody = JSON.parse(text);\n } catch {\n bodyParseError = 'request body is not valid JSON';\n }\n }\n }\n\n const resource = (runtime.baseUrl ?? new URL(req.url).origin).replace(/\\/$/, '') + `/${path}`;\n\n const runHandler = async (payer?: string): Promise<Response> => {\n let validated: unknown = parsedBody;\n if (bodySchema) {\n // `paid: false` is machine-readable charge honesty — a 422 fires\n // BEFORE settlement, so the buyer always keeps their money.\n if (bodyParseError) {\n return json(422, { error: bodyParseError, paid: false });\n }\n const result = await validateBody(bodySchema, parsedBody ?? {});\n if (!result.ok) {\n return json(422, { error: result.message, paid: false });\n }\n validated = result.data;\n }\n const out = await fn({ body: validated as TBody, req, payer });\n if (out instanceof Response) return withCors(out);\n return json(200, out);\n };\n\n // Free route — no payment machinery at all.\n if (!priceUsdc) {\n try {\n return await runHandler();\n } catch (err) {\n console.error(`[serve] Route \"${path}\" handler failed:`, err);\n return json(500, { error: 'internal error' });\n }\n }\n\n const paymentHeader = req.headers.get(X402_PAYMENT_HEADER);\n\n // Unpaid → 402 with the accepts[] envelope. This fires before body\n // validation on purpose: the catalog probe (and every discovery tool)\n // POSTs `{}` and must see the challenge, and an unpaid request can\n // never be charged, so there is nothing to protect yet.\n if (!paymentHeader) {\n return await respond402(runtime, { resource, priceUsdc });\n }\n\n if (isX402EscrowHeader(paymentHeader)) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error:\n 'this endpoint sells instant per-call work (settle-then-serve), not escrow jobs — retry with a signed x402 payment',\n });\n }\n\n // 1. Parse + structural verify — right terms, right recipient, right\n // nonce. No RPC, no state. Wrong-terms payloads never reach the\n // handler.\n let payment: ReturnType<typeof parseX402Header>;\n try {\n payment = parseX402Header(paymentHeader);\n verifyX402Payment({\n payment,\n expected: {\n challengeId: payment.payload.challengeId,\n amount: priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n network: runtime.network,\n },\n });\n } catch (err) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: `invalid payment: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // 2. Challenge-once — a signed payload is single-use even before it\n // settles (the settled digest is separately consumed inside\n // settleX402Payment, digest-once).\n const challengeKey = `challenge:${payment.payload.challengeId}`;\n if (await runtime.store.has(challengeKey)) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: 'payment challenge already used — sign a fresh payment',\n });\n }\n\n // 3 + 4. Validate, then compute the result. Any failure here returns\n // WITHOUT settling — the buyer-signed bytes are never submitted.\n let served: Response;\n try {\n served = await runHandler(payment.payload.senderAddress);\n } catch (err) {\n console.error(`[serve] Route \"${path}\" handler failed (payment NOT settled):`, err);\n return json(500, { error: 'internal error — you were not charged' });\n }\n if (served.status >= 400) return served; // 422 etc. — not charged\n\n // 5. Settle — submit the buyer-signed gasless bytes, confirm the\n // on-chain balance change, record the digest (digest-once).\n let settle: X402SettleResponse;\n try {\n settle = await settleX402Payment({\n payment,\n client: getGrpcClient(runtime.network, runtime.rpcUrl),\n store: runtime.store,\n expected: {\n challengeId: payment.payload.challengeId,\n amount: priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n network: runtime.network,\n },\n });\n } catch (err) {\n return await respond402(runtime, {\n resource,\n priceUsdc,\n error: `settlement failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // 6. Consume the challenge + attach the receipt.\n try {\n await runtime.store.set(challengeKey);\n } catch {\n // Digest-once already holds; challenge-once is defense in depth.\n }\n\n if (runtime.report) {\n reportPayment(settle.transaction, resource);\n }\n\n const headers = new Headers(served.headers);\n headers.set(X402_PAYMENT_RESPONSE_HEADER, encodeX402Response(settle));\n return new Response(served.body, { status: served.status, headers });\n }) as BuiltRoute;\n\n route.meta = { path, priceUsdc, description, bodySchema, inputSchema: this.inputSchema };\n this.register(route);\n return route;\n }\n}\n\nasync function respond402(\n runtime: RouteRuntime,\n args: { resource: string; priceUsdc: string; error?: string },\n): Promise<Response> {\n try {\n const { chain, epoch } = await getChainInfo(runtime.network, runtime.rpcUrl);\n const requirements = createX402Requirements({\n challengeId: crypto.randomUUID(),\n amount: args.priceUsdc,\n currency: runtime.currency,\n recipient: runtime.payTo,\n resource: args.resource,\n network: runtime.network,\n chain,\n currentEpoch: epoch,\n });\n return json(402, {\n x402Version: X402_VERSION,\n error: args.error ?? 'Payment required',\n accepts: [requirements],\n });\n } catch (err) {\n // Chain info unreachable — a 402 without the envelope is unpayable, so\n // be honest about the outage instead of serving a dead challenge.\n console.error('[serve] failed to build 402 challenge:', err);\n return json(503, { error: 'payment challenge temporarily unavailable' });\n }\n}\n\n/**\n * Best-effort activity-feed report (mpp.t2000.ai). The gateway verifies the\n * digest on-chain before recording anything, so this carries no trusted\n * data — a lost or duplicate report is harmless.\n */\nfunction reportPayment(digest: string, url: string): void {\n void fetch(MPP_REPORT_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ digest, url }),\n signal: AbortSignal.timeout(REPORT_TIMEOUT_MS),\n }).catch(() => {});\n}\n","import type { DigestStore } from '@suimpp/mpp/server';\n\nexport { InMemoryDigestStore } from '@suimpp/mpp/server';\nexport type { DigestStore } from '@suimpp/mpp/server';\n\n// ---------------------------------------------------------------------------\n// Upstash-REST digest store — the production replay store for serverless\n// hosts. Mirrors the gateway's upstash-digest-store.ts but speaks the\n// Upstash REST API over plain fetch (no @upstash/redis dependency).\n//\n// TTL: 72h. x402 payments are chain-valid for the whole ValidDuring window\n// ([minEpoch, minEpoch+1] ≈ up to ~48h on mainnet). Sui resubmission of an\n// executed tx is idempotent, so if the digest/challenge keys expired BEFORE\n// the window closed, a replayed X-PAYMENT would re-settle \"successfully\"\n// and serve again on a single payment. 72h > max window + drift.\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_TTL_SECONDS = 72 * 60 * 60;\nconst PREFIX = 'serve:digest:';\n\nexport interface UpstashDigestStoreOptions {\n url: string;\n token: string;\n /** Key TTL in seconds. Default 72h — do not lower below ~50h (see above). */\n ttlSeconds?: number;\n}\n\nexport class UpstashDigestStore implements DigestStore {\n private readonly url: string;\n private readonly token: string;\n private readonly ttlSeconds: number;\n\n constructor(options: UpstashDigestStoreOptions) {\n this.url = options.url.replace(/\\/$/, '');\n this.token = options.token;\n this.ttlSeconds = options.ttlSeconds ?? DEFAULT_TTL_SECONDS;\n }\n\n private async command(segments: string[]): Promise<unknown> {\n const res = await fetch(`${this.url}/${segments.map(encodeURIComponent).join('/')}`, {\n headers: { authorization: `Bearer ${this.token}` },\n });\n if (!res.ok) {\n throw new Error(`Upstash command failed: ${res.status} ${await res.text()}`);\n }\n const body = (await res.json()) as { result?: unknown; error?: string };\n if (body.error) throw new Error(`Upstash error: ${body.error}`);\n return body.result;\n }\n\n async has(digest: string): Promise<boolean> {\n const result = await this.command(['GET', PREFIX + digest]);\n return result !== null && result !== undefined;\n }\n\n async set(digest: string): Promise<void> {\n // SET key 1 EX <ttl> NX — atomic set-if-absent. A null result means the\n // key already existed: the digest (or challenge) was already consumed.\n const result = await this.command([\n 'SET',\n PREFIX + digest,\n '1',\n 'EX',\n String(this.ttlSeconds),\n 'NX',\n ]);\n if (result === null || result === undefined) {\n throw new Error(`Digest already used: ${digest}`);\n }\n }\n}\n","import { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';\nimport { InMemoryDigestStore, USDC, USDC_TESTNET, type Currency } from '@suimpp/mpp/server';\nimport { buildLlmsTxt, buildOpenApiDocument } from './discovery.js';\nimport { RouteBuilder, type RouteOptions, type RouteRuntime } from './route.js';\nimport { UpstashDigestStore } from './store.js';\nimport type { BuiltRoute, ServeConfig, ServeNetwork } from './types.js';\n\nexport class Serve {\n private readonly runtime: RouteRuntime;\n /** Every route built through this instance, keyed by path (discovery). */\n readonly routes = new Map<string, BuiltRoute>();\n\n readonly payTo: string;\n readonly network: ServeNetwork;\n readonly name?: string;\n readonly description?: string;\n readonly baseUrl?: string;\n\n constructor(config: ServeConfig) {\n if (!config.payTo || !isValidSuiAddress(config.payTo)) {\n throw new Error(\n `[serve] payTo must be a valid Sui address (the wallet your payments settle to), got \"${config.payTo}\"`,\n );\n }\n this.payTo = normalizeSuiAddress(config.payTo);\n this.network = config.network ?? 'mainnet';\n this.name = config.name;\n this.description = config.description;\n this.baseUrl = config.baseUrl?.replace(/\\/$/, '');\n\n const currency: Currency = this.network === 'testnet' ? USDC_TESTNET : USDC;\n this.runtime = {\n payTo: this.payTo,\n network: this.network,\n currency,\n store: config.store ?? new InMemoryDigestStore(),\n baseUrl: this.baseUrl,\n rpcUrl: config.rpcUrl,\n report: config.report ?? true,\n };\n }\n\n /** Start building a route. Chain `.paid()` / `.body()` / `.handler()`. */\n route(options: RouteOptions): RouteBuilder {\n const path = options.path.replace(/^\\/+/, '').replace(/\\/+$/, '');\n if (!path) throw new Error('[serve] route path must be non-empty');\n return new RouteBuilder({ ...this.runtime }, { ...options, path }, (route) => {\n this.routes.set(path, route);\n });\n }\n\n /**\n * Discovery: GET handler for /openapi.json. OpenAPI 3.1 with the\n * `x-payment-info` pricing extension on every paid operation — the shape\n * the mpp.t2000.ai catalog (and x402 tooling generally) indexes.\n *\n * export const GET = serve.openapi(); // app/openapi.json/route.ts\n */\n openapi(): (req: Request) => Response {\n return (req: Request) =>\n new Response(JSON.stringify(buildOpenApiDocument(this, new URL(req.url).origin), null, 2), {\n headers: { 'content-type': 'application/json', 'access-control-allow-origin': '*' },\n });\n }\n\n /**\n * Discovery: GET handler for /llms.txt — plain-text guidance agents read\n * to understand what the API sells, what it costs, and how to pay.\n *\n * export const GET = serve.llms(); // app/llms.txt/route.ts\n */\n llms(): (req: Request) => Response {\n return (req: Request) =>\n new Response(buildLlmsTxt(this, new URL(req.url).origin), {\n headers: { 'content-type': 'text/plain; charset=utf-8', 'access-control-allow-origin': '*' },\n });\n }\n\n /**\n * One fetch handler for the whole app — routes + discovery docs. For\n * fetch-native runtimes (Bun.serve, Deno.serve, Hono, Cloudflare Workers):\n *\n * Bun.serve({ fetch: serve.fetch });\n * app.all('*', (c) => serve.fetch(c.req.raw)); // Hono\n *\n * Next.js apps can skip this and export route handlers directly.\n */\n readonly fetch = async (req: Request): Promise<Response> => {\n const pathname = new URL(req.url).pathname.replace(/^\\/+/, '').replace(/\\/+$/, '');\n if (pathname === 'openapi.json') return this.openapi()(req);\n if (pathname === 'llms.txt') return this.llms()(req);\n const route = this.routes.get(pathname);\n if (route) return route(req);\n return new Response(\n JSON.stringify({ error: 'not found', discovery: ['/openapi.json', '/llms.txt'] }),\n { status: 404, headers: { 'content-type': 'application/json' } },\n );\n };\n\n /**\n * The curl that lists this API on mpp.t2000.ai / agents.t2000.ai once it\n * is deployed. Listing is a separate, explicit step — the catalog gates\n * (url · probe · dialect · price-cap), not this package, decide outcomes.\n * Dry-run first with /api/catalog/preview.\n */\n catalogSubmitCommand(deployedUrl?: string): string {\n const base = (deployedUrl ?? this.baseUrl ?? 'https://<your-deployed-app>').replace(/\\/$/, '');\n const paidPaths = [...this.routes.values()].filter((r) => r.meta.priceUsdc);\n const example = paidPaths[0]?.meta.path ?? '<route>';\n return [\n '# Dry-run (shows gate results, changes nothing):',\n `curl -X POST https://mpp.t2000.ai/api/catalog/preview -H 'content-type: application/json' -d '{\"url\":\"${base}/${example}\"}'`,\n '# List for real:',\n `curl -X POST https://mpp.t2000.ai/api/catalog/submit -H 'content-type: application/json' -d '{\"url\":\"${base}/${example}\"}'`,\n ].join('\\n');\n }\n}\n\nexport function createServe(config: ServeConfig): Serve {\n return new Serve(config);\n}\n\n/**\n * Build a Serve from environment variables — the template-app path where\n * config lives in the host's env UI, not code.\n *\n * T2000_PAY_TO required — the seller's Sui address\n * T2000_NETWORK optional — 'mainnet' (default) | 'testnet'\n * T2000_BASE_URL optional — public URL of the deployed app\n * T2000_NAME optional — service name for discovery docs\n * T2000_DESCRIPTION optional — one-liner for discovery docs\n * KV_REST_API_URL / KV_REST_API_TOKEN\n * optional — enables the durable Upstash replay store\n * (REQUIRED in serverless production; without it replay\n * state is per-instance memory)\n *\n * Empty strings are treated as unset (the Vercel empty-env bug class).\n */\nexport function createServeFromEnv(env: Record<string, string | undefined> = process.env): Serve {\n const read = (key: string): string | undefined => {\n const v = env[key]?.trim();\n return v && v.length > 0 ? v : undefined;\n };\n\n const payTo = read('T2000_PAY_TO');\n if (!payTo) {\n throw new Error(\n '[serve] T2000_PAY_TO is not set (or is empty). Set it to the Sui address your payments should settle to — `t2 address` prints yours.',\n );\n }\n\n const network = read('T2000_NETWORK');\n if (network && network !== 'mainnet' && network !== 'testnet') {\n throw new Error(`[serve] T2000_NETWORK must be 'mainnet' or 'testnet', got \"${network}\"`);\n }\n\n const kvUrl = read('KV_REST_API_URL');\n const kvToken = read('KV_REST_API_TOKEN');\n const store =\n kvUrl && kvToken ? new UpstashDigestStore({ url: kvUrl, token: kvToken }) : undefined;\n\n if (!store) {\n console.warn(\n '[serve] No KV_REST_API_URL/KV_REST_API_TOKEN — using the in-memory replay store. ' +\n 'Fine for a single long-lived process; on serverless hosts set both so replay protection is durable.',\n );\n }\n\n return new Serve({\n payTo,\n network: (network as ServeNetwork | undefined) ?? 'mainnet',\n baseUrl: read('T2000_BASE_URL'),\n name: read('T2000_NAME'),\n description: read('T2000_DESCRIPTION'),\n store,\n });\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@t2000/serve",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.2",
|
|
4
4
|
"description": "Merchant-side x402 router for Sui — wrap any API so agents can discover it and pay per call in USDC. One builder: .paid().body().handler(). Sign-then-settle, no seller key, no seller gas.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|