@profullstack/x402-gateway 0.10.1 → 0.10.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/README.md CHANGED
@@ -18,7 +18,7 @@ npm install @profullstack/x402-gateway
18
18
  | --- | --- |
19
19
  | A person, Googlebot, Bingbot, Applebot, OAI-SearchBot, Claude-SearchBot, PerplexityBot… | the site, untouched |
20
20
  | GPTBot, ClaudeBot, CCBot, meta-externalagent, Bytespider, Applebot-Extended… | `402` with an x402 offer, or the HTML sales page if it asked for HTML |
21
- | Anyone at `/crawl` | the sales page (HTML) or the offer (JSON), and the place to pay |
21
+ | Anyone at `/crawl` | the sales page (HTML, or always with `?format=html`) or the offer (JSON), and the place to pay. The 402 prose points at `/crawl?format=html`, so a client that sent no Accept header still reaches the explanation |
22
22
  | A request with a valid pass | the site |
23
23
 
24
24
  The sales page explains the price, how to pay with an x402 client, and how to pay with the CoinPay CLI:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profullstack/x402-gateway",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "type": "module",
5
5
  "description": "Sell crawl access to AI training crawlers by the day over x402, settled by CoinPay. One middleware: 402 with an offer, a sales page with CLI instructions, signed passes, Profullstack Power Keys honoured as a pass, and a robots.txt that keeps search crawlers welcome.",
6
6
  "keywords": [
package/src/index.js CHANGED
@@ -106,6 +106,13 @@ export function createGateway(options = {}) {
106
106
  const money = (cents) => `${(cents / 100).toFixed(2)} ${o.currency}`;
107
107
  const price = money(o.priceCents);
108
108
  const buyUrl = `${o.siteUrl}${o.path}`;
109
+ /*
110
+ * Where the prose points. A bare GET of the sales page answers JSON, because
111
+ * the body is the only place an x402 client reads the offer from, so a
112
+ * pointer to it would loop for the reader who needs the explanation most.
113
+ * `?format=html` is the explainer whatever the Accept header says.
114
+ */
115
+ const howUrl = `${buyUrl}?format=html`;
109
116
 
110
117
  /**
111
118
  * How many terms a request is asking to buy: `?days=N`, clamped to
@@ -374,7 +381,7 @@ export function createGateway(options = {}) {
374
381
  );
375
382
  }
376
383
 
377
- if (wantsHtml(request.headers.get('accept'))) {
384
+ if (wantsHtml(request.headers.get('accept')) || new URL(request.url).searchParams.get('format') === 'html') {
378
385
  return html(o.page(pageCtx(asked, usage, quota)), 402, rateHeaders);
379
386
  }
380
387
 
@@ -401,7 +408,7 @@ export function createGateway(options = {}) {
401
408
  );
402
409
  }
403
410
 
404
- return json(receipt(asked, { error: `Payment required for training crawlers. Read ${buyUrl} for how.` }), 402);
411
+ return json(receipt(asked, { error: `Payment required for training crawlers. Read ${howUrl} for how.` }), 402);
405
412
  }
406
413
 
407
414
  /**
@@ -472,7 +479,7 @@ export function createGateway(options = {}) {
472
479
  if (!wantsHtml(request.headers.get('accept'))) {
473
480
  return json(
474
481
  receipt(1, {
475
- error: `${path} is read in a browser (it sets a cookie with one line of script) or with a pass. Read ${buyUrl} for how.`,
482
+ error: `${path} is read in a browser (it sets a cookie with one line of script) or with a pass. Read ${howUrl} for how.`,
476
483
  }),
477
484
  402,
478
485
  );