@peaje/next 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -0
- package/dist/chunk-7KJLR3FN.js +233 -0
- package/dist/head.cjs +266 -0
- package/dist/head.d.cts +24 -0
- package/dist/head.d.ts +24 -0
- package/dist/head.js +77 -0
- package/dist/index.cjs +205 -0
- package/dist/index.d.cts +48 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +14 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @peaje/next
|
|
2
|
+
|
|
3
|
+
Peaje for Next.js. Two pieces:
|
|
4
|
+
|
|
5
|
+
- `withPeaje(nextConfig, { slug })` adds the proxy rewrites that make your domain serve the Peaje catalog, the MCP server, the OpenAPI spec and the priced links (HTTP 402) that your gateway already publishes.
|
|
6
|
+
- `<PeajeHead slug="..." />` renders the JSON-LD `WebAPI` block and the discovery `<link>` tags in your `<head>`.
|
|
7
|
+
|
|
8
|
+
Both are additive: your existing rewrites, config and head stay as they are.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npm install @peaje/next
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Requires Next.js 14 or newer. `PeajeHead` needs the app router (it is an async server component).
|
|
17
|
+
|
|
18
|
+
## 1. Rewrites
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// next.config.ts
|
|
22
|
+
import { withPeaje } from '@peaje/next'
|
|
23
|
+
|
|
24
|
+
const nextConfig = {
|
|
25
|
+
// your config, including any existing rewrites()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default withPeaje(nextConfig, { slug: 'cafe-andino' })
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`withPeaje` prepends the Peaje rules to `rewrites().beforeFiles` and keeps what you had: an array becomes `afterFiles`, an object keeps its `beforeFiles`, `afterFiles` and `fallback`. It accepts sync or async `rewrites()` and a config written as a function `(phase, { defaultConfig }) => config`. Wrapping twice does not duplicate rules.
|
|
32
|
+
|
|
33
|
+
Options: `slug` (required, the one from your Peaje dashboard) and `gateway` (defaults to `https://peaje-gateway.up.railway.app`, overridable with the `PEAJE_GATEWAY_URL` environment variable).
|
|
34
|
+
|
|
35
|
+
If you have a `middleware.ts` or `proxy.ts` with a `matcher`, exclude `mcp`, `r/`, `discovery/`, `checkout_sessions`, `agentic_commerce/` and `docs` from it: middleware runs before rewrites.
|
|
36
|
+
|
|
37
|
+
## 2. Head
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// app/layout.tsx
|
|
41
|
+
import { PeajeHead } from '@peaje/next/head'
|
|
42
|
+
|
|
43
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
44
|
+
return (
|
|
45
|
+
<html lang="en">
|
|
46
|
+
<head>
|
|
47
|
+
<PeajeHead slug="cafe-andino" />
|
|
48
|
+
</head>
|
|
49
|
+
<body>{children}</body>
|
|
50
|
+
</html>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The offers in the JSON-LD come from your gateway (`/discovery/resources`) and are revalidated hourly. If the gateway is unreachable, the component renders the block without offers and never throws: a Peaje outage cannot break your build or your pages.
|
|
56
|
+
|
|
57
|
+
Props: `slug` (required), `gateway`, `originHost` and `name`. Without `originHost` the component reads the request host through `next/headers`, which makes the layout dynamic; pass `originHost="cafeandino.com"` to keep static rendering.
|
|
58
|
+
|
|
59
|
+
## 3. Footer
|
|
60
|
+
|
|
61
|
+
Auditors look for documentation linked from the homepage, visibly. Add this to your footer or nav:
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<a href="/developers">API for agents</a>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Verify
|
|
68
|
+
|
|
69
|
+
After the deploy is live:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
npx @peaje/cli@1 verify cafe-andino --wait 600
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
MIT
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// ../shared/src/kit/rutas.ts
|
|
2
|
+
var RUTAS_PROXY = [
|
|
3
|
+
{ path: "/llms.txt", nota: "gu\xEDa para agentes (fusionada con la tuya)" },
|
|
4
|
+
{ path: "/pricing.md", nota: "precios por endpoint" },
|
|
5
|
+
{ path: "/auth.md", nota: 'c\xF3mo pagar (el "auth" ac\xE1 es el pago)' },
|
|
6
|
+
{ path: "/agents.md", nota: "qu\xE9 es y cu\xE1ndo usarte" },
|
|
7
|
+
{ path: "/openapi.json", nota: "discovery con precios" },
|
|
8
|
+
{ path: "/mcp", nota: "MCP server con tools pagas, en TU dominio" },
|
|
9
|
+
{ path: "/.well-known/mcp", nota: "el MCP tambi\xE9n ac\xE1: es donde lo buscan los auditores" },
|
|
10
|
+
{ path: "/.well-known/ard.json", nota: "cat\xE1logo ARD (path can\xF3nico)" },
|
|
11
|
+
{ path: "/.well-known/ai-catalog.json", nota: "cat\xE1logo ARD (alias legacy)" },
|
|
12
|
+
{ path: "/.well-known/api-catalog", nota: "linkset RFC 9727" },
|
|
13
|
+
{ path: "/.well-known/agent-card.json", nota: "agent card A2A" },
|
|
14
|
+
{ path: "/.well-known/mcp/server-card.json", nota: "server card MCP" },
|
|
15
|
+
{ path: "/discovery/resources", nota: "lista x402 Bazaar: lo que cobra 402 de verdad" },
|
|
16
|
+
{ path: "/.well-known/ucp", nota: "perfil UCP: qu\xE9 sabe hacer tu negocio" },
|
|
17
|
+
{ path: "/checkout_sessions", nota: "checkout ACP (el de OpenAI)" },
|
|
18
|
+
{ path: "/agentic_commerce/delegate_payment", nota: "delegate payment ACP" },
|
|
19
|
+
{ path: "/developers", nota: "portal de desarrolladores, renderizado con tus precios" },
|
|
20
|
+
{ path: "/.well-known/peaje-indexnow.txt", nota: "clave IndexNow: avisa a Bing y Copilot cuando cambian precios" },
|
|
21
|
+
// Los auditores prueban /docs y /developers; el gateway redirige uno al otro.
|
|
22
|
+
{ path: "/docs", nota: "alias del portal: los auditores prueban ambos" }
|
|
23
|
+
];
|
|
24
|
+
var RUTAS_DINAMICAS = [
|
|
25
|
+
{ path: "/r/:slug", prefijo: "/r/", nota: "links con precio: el 402 en tu dominio" },
|
|
26
|
+
{ path: "/checkout_sessions/:id", prefijo: "/checkout_sessions/", nota: "leer una sesi\xF3n de checkout ACP" }
|
|
27
|
+
];
|
|
28
|
+
var PEAJE_FETCH_HEADER = "x-peaje-fetch";
|
|
29
|
+
function reglasNext(base) {
|
|
30
|
+
return [
|
|
31
|
+
...RUTAS_PROXY.map((r) => ({
|
|
32
|
+
source: r.path,
|
|
33
|
+
destination: `${base}${r.path}`,
|
|
34
|
+
...r.path === "/llms.txt" ? { missing: [{ type: "header", key: PEAJE_FETCH_HEADER }] } : {}
|
|
35
|
+
})),
|
|
36
|
+
...RUTAS_DINAMICAS.map((r) => ({ source: r.path, destination: `${base}${r.path}` }))
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ../shared/src/kit/bloques.ts
|
|
41
|
+
function rutaDe(url, slug) {
|
|
42
|
+
try {
|
|
43
|
+
const path = new URL(url).pathname;
|
|
44
|
+
const prefijo = `/${slug}`;
|
|
45
|
+
return path.startsWith(`${prefijo}/`) ? path.slice(prefijo.length) : path;
|
|
46
|
+
} catch {
|
|
47
|
+
return url;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function jsonParaScript(valor) {
|
|
51
|
+
return JSON.stringify(valor, null, 2).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
52
|
+
}
|
|
53
|
+
function jsonLdWebApi({
|
|
54
|
+
nombre,
|
|
55
|
+
slug,
|
|
56
|
+
originHost,
|
|
57
|
+
ofertas
|
|
58
|
+
}) {
|
|
59
|
+
return {
|
|
60
|
+
"@context": "https://schema.org",
|
|
61
|
+
"@type": "WebAPI",
|
|
62
|
+
"@id": `https://${originHost}/#api`,
|
|
63
|
+
name: nombre,
|
|
64
|
+
// URLs del dominio del negocio, no del gateway: después del proxy
|
|
65
|
+
// responden acá, y es acá donde el auditor las va a buscar.
|
|
66
|
+
documentation: `https://${originHost}/openapi.json`,
|
|
67
|
+
termsOfService: `https://${originHost}/auth.md`,
|
|
68
|
+
provider: { "@id": `https://${originHost}/#organization` },
|
|
69
|
+
potentialAction: {
|
|
70
|
+
"@type": "ConsumeAction",
|
|
71
|
+
target: {
|
|
72
|
+
"@type": "EntryPoint",
|
|
73
|
+
urlTemplate: `https://${originHost}/mcp`,
|
|
74
|
+
actionPlatform: "MCP"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
offers: ofertas.map((o) => ({
|
|
78
|
+
"@type": "Offer",
|
|
79
|
+
name: o.titulo,
|
|
80
|
+
price: o.priceUsd,
|
|
81
|
+
priceCurrency: "USD",
|
|
82
|
+
url: `https://${originHost}${rutaDe(o.url, slug)}`,
|
|
83
|
+
availability: "https://schema.org/InStock"
|
|
84
|
+
}))
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
var LINKS_HEAD = [
|
|
88
|
+
{ rel: "service-desc", type: "application/openapi+json", href: "/openapi.json" },
|
|
89
|
+
{ rel: "service-doc", type: "text/plain", href: "/llms.txt" },
|
|
90
|
+
{ rel: "service-meta", type: "text/markdown", href: "/pricing.md" },
|
|
91
|
+
{ rel: "ard", type: "application/ai-catalog+json", href: "/.well-known/ard.json" }
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
// ../shared/src/index.ts
|
|
95
|
+
var TEMPO = {
|
|
96
|
+
mainnet: {
|
|
97
|
+
chainId: 4217,
|
|
98
|
+
rpcUrl: "https://rpc.tempo.xyz",
|
|
99
|
+
explorerUrl: "https://explore.tempo.xyz"
|
|
100
|
+
},
|
|
101
|
+
testnet: {
|
|
102
|
+
chainId: 42431,
|
|
103
|
+
rpcUrl: "https://rpc.moderato.tempo.xyz",
|
|
104
|
+
explorerUrl: "https://explore.testnet.tempo.xyz"
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var TOKENS = {
|
|
108
|
+
pathUsd: "0x20c0000000000000000000000000000000000000",
|
|
109
|
+
usdc: "0x20C000000000000000000000b9537d11c60E8b50"
|
|
110
|
+
};
|
|
111
|
+
var DEFAULT_CURRENCY = TOKENS.pathUsd;
|
|
112
|
+
var NETWORKS = {
|
|
113
|
+
tempo: {
|
|
114
|
+
id: "tempo",
|
|
115
|
+
label: "Tempo",
|
|
116
|
+
token: TOKENS.pathUsd,
|
|
117
|
+
tokenSymbol: "pathUSD",
|
|
118
|
+
decimals: 6,
|
|
119
|
+
mainnet: TEMPO.mainnet,
|
|
120
|
+
testnet: TEMPO.testnet
|
|
121
|
+
},
|
|
122
|
+
arc: {
|
|
123
|
+
id: "arc",
|
|
124
|
+
label: "Arc",
|
|
125
|
+
// Interfaz ERC-20 del USDC nativo de Arc; el gas de la red se paga en ese mismo USDC.
|
|
126
|
+
token: "0x3600000000000000000000000000000000000000",
|
|
127
|
+
tokenSymbol: "USDC",
|
|
128
|
+
decimals: 6,
|
|
129
|
+
// Leído on-chain del contrato: name() = "USDC", version() = "2".
|
|
130
|
+
eip3009: { name: "USDC", version: "2" },
|
|
131
|
+
// Arc no publica direcciones de mainnet todavía (sept 2026).
|
|
132
|
+
mainnet: null,
|
|
133
|
+
testnet: {
|
|
134
|
+
chainId: 5042002,
|
|
135
|
+
rpcUrl: "https://rpc.testnet.arc.io",
|
|
136
|
+
explorerUrl: "https://testnet.arcscan.app"
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
arbitrum: {
|
|
140
|
+
id: "arbitrum",
|
|
141
|
+
label: "Arbitrum",
|
|
142
|
+
// USDC de Circle en Arbitrum Sepolia. En Arbitrum One vive en otra dirección,
|
|
143
|
+
// por eso mainnet queda en null hasta que el gateway opere allá.
|
|
144
|
+
token: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d",
|
|
145
|
+
tokenSymbol: "USDC",
|
|
146
|
+
decimals: 6,
|
|
147
|
+
// Leído on-chain: name() = "USD Coin", version() = "2" (distinto al USDC de Arc).
|
|
148
|
+
eip3009: { name: "USD Coin", version: "2" },
|
|
149
|
+
mainnet: null,
|
|
150
|
+
testnet: {
|
|
151
|
+
chainId: 421614,
|
|
152
|
+
rpcUrl: "https://sepolia-rollup.arbitrum.io/rpc",
|
|
153
|
+
explorerUrl: "https://sepolia.arbiscan.io"
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"arbitrum-usdg": {
|
|
157
|
+
id: "arbitrum-usdg",
|
|
158
|
+
label: "Arbitrum \xB7 USDG",
|
|
159
|
+
// Mismo contrato y misma cadena que el riel USDC: cambia el stablecoin.
|
|
160
|
+
// Un riel es (cadena, token), y el saldo del negocio se lleva por token.
|
|
161
|
+
token: "0xFFC95faa3d63Cde504a05B567C600B78C0b41892",
|
|
162
|
+
tokenSymbol: "USDG",
|
|
163
|
+
decimals: 6,
|
|
164
|
+
eip3009: { name: "Global Dollar", version: "1" },
|
|
165
|
+
mainnet: null,
|
|
166
|
+
testnet: {
|
|
167
|
+
chainId: 421614,
|
|
168
|
+
rpcUrl: "https://sepolia-rollup.arbitrum.io/rpc",
|
|
169
|
+
explorerUrl: "https://sepolia.arbiscan.io"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
robinhood: {
|
|
173
|
+
id: "robinhood",
|
|
174
|
+
label: "Robinhood",
|
|
175
|
+
// USDG de Paxos en Robinhood Chain Testnet (el "USDC" de esa testnet es un
|
|
176
|
+
// mock sin EIP-3009). Leído on-chain: dominio "Global Dollar", versión "1".
|
|
177
|
+
token: "0x7E955252E15c84f5768B83c41a71F9eba181802F",
|
|
178
|
+
tokenSymbol: "USDG",
|
|
179
|
+
decimals: 6,
|
|
180
|
+
eip3009: { name: "Global Dollar", version: "1" },
|
|
181
|
+
mainnet: null,
|
|
182
|
+
testnet: {
|
|
183
|
+
chainId: 46630,
|
|
184
|
+
rpcUrl: "https://rpc.testnet.chain.robinhood.com",
|
|
185
|
+
explorerUrl: "https://explorer.testnet.chain.robinhood.com"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
var NETWORK_IDS = Object.keys(NETWORKS);
|
|
190
|
+
|
|
191
|
+
// src/index.ts
|
|
192
|
+
var GATEWAY_POR_DEFECTO = "https://peaje-gateway.up.railway.app";
|
|
193
|
+
function baseDe({ slug, gateway }) {
|
|
194
|
+
const raiz = (gateway ?? process.env.PEAJE_GATEWAY_URL ?? GATEWAY_POR_DEFECTO).replace(/\/+$/, "");
|
|
195
|
+
return `${raiz}/${slug}`;
|
|
196
|
+
}
|
|
197
|
+
function fusionarRewrites(previo, reglas) {
|
|
198
|
+
const objeto = Array.isArray(previo) ? { afterFiles: previo } : { ...previo ?? {} };
|
|
199
|
+
const antes = objeto.beforeFiles ?? [];
|
|
200
|
+
const destinos = new Set(antes.map((r) => r.destination));
|
|
201
|
+
const nuevas = reglas.filter((r) => !destinos.has(r.destination));
|
|
202
|
+
return { ...objeto, beforeFiles: [...nuevas, ...antes] };
|
|
203
|
+
}
|
|
204
|
+
function envolverConfig(config, reglas) {
|
|
205
|
+
const original = config.rewrites;
|
|
206
|
+
return {
|
|
207
|
+
...config,
|
|
208
|
+
async rewrites() {
|
|
209
|
+
const previo = original ? await original.call(config) : void 0;
|
|
210
|
+
return fusionarRewrites(previo, reglas);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function withPeaje(nextConfig, opciones) {
|
|
215
|
+
if (!opciones?.slug) throw new Error("withPeaje: `slug` is required (the business slug from your Peaje dashboard).");
|
|
216
|
+
const reglas = reglasNext(baseDe(opciones));
|
|
217
|
+
if (typeof nextConfig === "function") {
|
|
218
|
+
return async (phase, contexto) => envolverConfig(await nextConfig(phase, contexto), reglas);
|
|
219
|
+
}
|
|
220
|
+
return envolverConfig(nextConfig ?? {}, reglas);
|
|
221
|
+
}
|
|
222
|
+
var src_default = withPeaje;
|
|
223
|
+
|
|
224
|
+
export {
|
|
225
|
+
jsonParaScript,
|
|
226
|
+
jsonLdWebApi,
|
|
227
|
+
LINKS_HEAD,
|
|
228
|
+
GATEWAY_POR_DEFECTO,
|
|
229
|
+
baseDe,
|
|
230
|
+
fusionarRewrites,
|
|
231
|
+
withPeaje,
|
|
232
|
+
src_default
|
|
233
|
+
};
|
package/dist/head.cjs
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/head.tsx
|
|
31
|
+
var head_exports = {};
|
|
32
|
+
__export(head_exports, {
|
|
33
|
+
PeajeHead: () => PeajeHead,
|
|
34
|
+
default: () => head_default,
|
|
35
|
+
ofertasDesdeGateway: () => ofertasDesdeGateway
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(head_exports);
|
|
38
|
+
|
|
39
|
+
// ../shared/src/kit/bloques.ts
|
|
40
|
+
function rutaDe(url, slug) {
|
|
41
|
+
try {
|
|
42
|
+
const path = new URL(url).pathname;
|
|
43
|
+
const prefijo = `/${slug}`;
|
|
44
|
+
return path.startsWith(`${prefijo}/`) ? path.slice(prefijo.length) : path;
|
|
45
|
+
} catch {
|
|
46
|
+
return url;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function jsonParaScript(valor) {
|
|
50
|
+
return JSON.stringify(valor, null, 2).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
51
|
+
}
|
|
52
|
+
function jsonLdWebApi({
|
|
53
|
+
nombre,
|
|
54
|
+
slug,
|
|
55
|
+
originHost,
|
|
56
|
+
ofertas
|
|
57
|
+
}) {
|
|
58
|
+
return {
|
|
59
|
+
"@context": "https://schema.org",
|
|
60
|
+
"@type": "WebAPI",
|
|
61
|
+
"@id": `https://${originHost}/#api`,
|
|
62
|
+
name: nombre,
|
|
63
|
+
// URLs del dominio del negocio, no del gateway: después del proxy
|
|
64
|
+
// responden acá, y es acá donde el auditor las va a buscar.
|
|
65
|
+
documentation: `https://${originHost}/openapi.json`,
|
|
66
|
+
termsOfService: `https://${originHost}/auth.md`,
|
|
67
|
+
provider: { "@id": `https://${originHost}/#organization` },
|
|
68
|
+
potentialAction: {
|
|
69
|
+
"@type": "ConsumeAction",
|
|
70
|
+
target: {
|
|
71
|
+
"@type": "EntryPoint",
|
|
72
|
+
urlTemplate: `https://${originHost}/mcp`,
|
|
73
|
+
actionPlatform: "MCP"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
offers: ofertas.map((o) => ({
|
|
77
|
+
"@type": "Offer",
|
|
78
|
+
name: o.titulo,
|
|
79
|
+
price: o.priceUsd,
|
|
80
|
+
priceCurrency: "USD",
|
|
81
|
+
url: `https://${originHost}${rutaDe(o.url, slug)}`,
|
|
82
|
+
availability: "https://schema.org/InStock"
|
|
83
|
+
}))
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
var LINKS_HEAD = [
|
|
87
|
+
{ rel: "service-desc", type: "application/openapi+json", href: "/openapi.json" },
|
|
88
|
+
{ rel: "service-doc", type: "text/plain", href: "/llms.txt" },
|
|
89
|
+
{ rel: "service-meta", type: "text/markdown", href: "/pricing.md" },
|
|
90
|
+
{ rel: "ard", type: "application/ai-catalog+json", href: "/.well-known/ard.json" }
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
// ../shared/src/index.ts
|
|
94
|
+
var TEMPO = {
|
|
95
|
+
mainnet: {
|
|
96
|
+
chainId: 4217,
|
|
97
|
+
rpcUrl: "https://rpc.tempo.xyz",
|
|
98
|
+
explorerUrl: "https://explore.tempo.xyz"
|
|
99
|
+
},
|
|
100
|
+
testnet: {
|
|
101
|
+
chainId: 42431,
|
|
102
|
+
rpcUrl: "https://rpc.moderato.tempo.xyz",
|
|
103
|
+
explorerUrl: "https://explore.testnet.tempo.xyz"
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var TOKENS = {
|
|
107
|
+
pathUsd: "0x20c0000000000000000000000000000000000000",
|
|
108
|
+
usdc: "0x20C000000000000000000000b9537d11c60E8b50"
|
|
109
|
+
};
|
|
110
|
+
var DEFAULT_CURRENCY = TOKENS.pathUsd;
|
|
111
|
+
var NETWORKS = {
|
|
112
|
+
tempo: {
|
|
113
|
+
id: "tempo",
|
|
114
|
+
label: "Tempo",
|
|
115
|
+
token: TOKENS.pathUsd,
|
|
116
|
+
tokenSymbol: "pathUSD",
|
|
117
|
+
decimals: 6,
|
|
118
|
+
mainnet: TEMPO.mainnet,
|
|
119
|
+
testnet: TEMPO.testnet
|
|
120
|
+
},
|
|
121
|
+
arc: {
|
|
122
|
+
id: "arc",
|
|
123
|
+
label: "Arc",
|
|
124
|
+
// Interfaz ERC-20 del USDC nativo de Arc; el gas de la red se paga en ese mismo USDC.
|
|
125
|
+
token: "0x3600000000000000000000000000000000000000",
|
|
126
|
+
tokenSymbol: "USDC",
|
|
127
|
+
decimals: 6,
|
|
128
|
+
// Leído on-chain del contrato: name() = "USDC", version() = "2".
|
|
129
|
+
eip3009: { name: "USDC", version: "2" },
|
|
130
|
+
// Arc no publica direcciones de mainnet todavía (sept 2026).
|
|
131
|
+
mainnet: null,
|
|
132
|
+
testnet: {
|
|
133
|
+
chainId: 5042002,
|
|
134
|
+
rpcUrl: "https://rpc.testnet.arc.io",
|
|
135
|
+
explorerUrl: "https://testnet.arcscan.app"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
arbitrum: {
|
|
139
|
+
id: "arbitrum",
|
|
140
|
+
label: "Arbitrum",
|
|
141
|
+
// USDC de Circle en Arbitrum Sepolia. En Arbitrum One vive en otra dirección,
|
|
142
|
+
// por eso mainnet queda en null hasta que el gateway opere allá.
|
|
143
|
+
token: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d",
|
|
144
|
+
tokenSymbol: "USDC",
|
|
145
|
+
decimals: 6,
|
|
146
|
+
// Leído on-chain: name() = "USD Coin", version() = "2" (distinto al USDC de Arc).
|
|
147
|
+
eip3009: { name: "USD Coin", version: "2" },
|
|
148
|
+
mainnet: null,
|
|
149
|
+
testnet: {
|
|
150
|
+
chainId: 421614,
|
|
151
|
+
rpcUrl: "https://sepolia-rollup.arbitrum.io/rpc",
|
|
152
|
+
explorerUrl: "https://sepolia.arbiscan.io"
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"arbitrum-usdg": {
|
|
156
|
+
id: "arbitrum-usdg",
|
|
157
|
+
label: "Arbitrum \xB7 USDG",
|
|
158
|
+
// Mismo contrato y misma cadena que el riel USDC: cambia el stablecoin.
|
|
159
|
+
// Un riel es (cadena, token), y el saldo del negocio se lleva por token.
|
|
160
|
+
token: "0xFFC95faa3d63Cde504a05B567C600B78C0b41892",
|
|
161
|
+
tokenSymbol: "USDG",
|
|
162
|
+
decimals: 6,
|
|
163
|
+
eip3009: { name: "Global Dollar", version: "1" },
|
|
164
|
+
mainnet: null,
|
|
165
|
+
testnet: {
|
|
166
|
+
chainId: 421614,
|
|
167
|
+
rpcUrl: "https://sepolia-rollup.arbitrum.io/rpc",
|
|
168
|
+
explorerUrl: "https://sepolia.arbiscan.io"
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
robinhood: {
|
|
172
|
+
id: "robinhood",
|
|
173
|
+
label: "Robinhood",
|
|
174
|
+
// USDG de Paxos en Robinhood Chain Testnet (el "USDC" de esa testnet es un
|
|
175
|
+
// mock sin EIP-3009). Leído on-chain: dominio "Global Dollar", versión "1".
|
|
176
|
+
token: "0x7E955252E15c84f5768B83c41a71F9eba181802F",
|
|
177
|
+
tokenSymbol: "USDG",
|
|
178
|
+
decimals: 6,
|
|
179
|
+
eip3009: { name: "Global Dollar", version: "1" },
|
|
180
|
+
mainnet: null,
|
|
181
|
+
testnet: {
|
|
182
|
+
chainId: 46630,
|
|
183
|
+
rpcUrl: "https://rpc.testnet.chain.robinhood.com",
|
|
184
|
+
explorerUrl: "https://explorer.testnet.chain.robinhood.com"
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
var NETWORK_IDS = Object.keys(NETWORKS);
|
|
189
|
+
|
|
190
|
+
// src/index.ts
|
|
191
|
+
var GATEWAY_POR_DEFECTO = "https://peaje-gateway.up.railway.app";
|
|
192
|
+
function baseDe({ slug, gateway }) {
|
|
193
|
+
const raiz = (gateway ?? process.env.PEAJE_GATEWAY_URL ?? GATEWAY_POR_DEFECTO).replace(/\/+$/, "");
|
|
194
|
+
return `${raiz}/${slug}`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// src/head.tsx
|
|
198
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
199
|
+
var TIMEOUT_MS = 2e3;
|
|
200
|
+
async function leerJson(url) {
|
|
201
|
+
try {
|
|
202
|
+
const res = await fetch(url, {
|
|
203
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
204
|
+
// `next` es la extensión de Next.js al RequestInit; fuera de Next se ignora.
|
|
205
|
+
...{ next: { revalidate: 3600 } }
|
|
206
|
+
});
|
|
207
|
+
if (!res.ok) return null;
|
|
208
|
+
return await res.json();
|
|
209
|
+
} catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function ofertasDesdeGateway(base) {
|
|
214
|
+
const cuerpo = await leerJson(`${base}/discovery/resources`);
|
|
215
|
+
return (cuerpo?.items ?? []).filter((i) => typeof i.resource === "string" && esUrlConcreta(i.resource)).map((i) => ({
|
|
216
|
+
titulo: i.extensions?.bazaar?.info?.title ?? i.resource,
|
|
217
|
+
priceUsd: Number(i.extensions?.bazaar?.info?.priceUsd ?? 0),
|
|
218
|
+
url: i.resource
|
|
219
|
+
}));
|
|
220
|
+
}
|
|
221
|
+
function esUrlConcreta(url) {
|
|
222
|
+
try {
|
|
223
|
+
return !/[*:]/.test(new URL(url).pathname);
|
|
224
|
+
} catch {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async function nombreDesdeGateway(base) {
|
|
229
|
+
const card = await leerJson(`${base}/.well-known/agent-card.json`);
|
|
230
|
+
return card?.name ?? null;
|
|
231
|
+
}
|
|
232
|
+
async function hostDeLaRequest() {
|
|
233
|
+
try {
|
|
234
|
+
const mod = await import("next/headers");
|
|
235
|
+
const h = await mod.headers();
|
|
236
|
+
const host = h.get("x-forwarded-host") ?? h.get("host");
|
|
237
|
+
return host ? host.split(",")[0].trim() : null;
|
|
238
|
+
} catch {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
async function PeajeHead(props) {
|
|
243
|
+
const base = baseDe(props);
|
|
244
|
+
const [ofertas, nombreRemoto, hostRequest] = await Promise.all([
|
|
245
|
+
ofertasDesdeGateway(base),
|
|
246
|
+
props.name ? Promise.resolve(null) : nombreDesdeGateway(base),
|
|
247
|
+
props.originHost ? Promise.resolve(null) : hostDeLaRequest()
|
|
248
|
+
]);
|
|
249
|
+
const originHost = props.originHost ?? hostRequest ?? "localhost";
|
|
250
|
+
const datos = jsonLdWebApi({
|
|
251
|
+
nombre: props.name ?? nombreRemoto ?? props.slug,
|
|
252
|
+
slug: props.slug,
|
|
253
|
+
originHost,
|
|
254
|
+
ofertas
|
|
255
|
+
});
|
|
256
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
257
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: jsonParaScript(datos) } }),
|
|
258
|
+
LINKS_HEAD.map((l) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("link", { rel: l.rel, type: l.type, href: l.href }, l.rel))
|
|
259
|
+
] });
|
|
260
|
+
}
|
|
261
|
+
var head_default = PeajeHead;
|
|
262
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
263
|
+
0 && (module.exports = {
|
|
264
|
+
PeajeHead,
|
|
265
|
+
ofertasDesdeGateway
|
|
266
|
+
});
|
package/dist/head.d.cts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { OpcionesPeaje } from './index.cjs';
|
|
3
|
+
|
|
4
|
+
/** Igual al `Oferta` de shared, redeclarado para que el .d.ts publicado no apunte a un paquete privado. */
|
|
5
|
+
type Oferta = {
|
|
6
|
+
titulo: string;
|
|
7
|
+
priceUsd: number;
|
|
8
|
+
url: string;
|
|
9
|
+
};
|
|
10
|
+
type PropsPeajeHead = OpcionesPeaje & {
|
|
11
|
+
/** Host del negocio para las URLs del JSON-LD. Por defecto, el de la request. */
|
|
12
|
+
originHost?: string;
|
|
13
|
+
/** Nombre del negocio. Por defecto se lee del gateway, o se usa el slug. */
|
|
14
|
+
name?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Ofertas desde `/discovery/resources`, el catálogo canónico: así el JSON-LD
|
|
18
|
+
* dice lo mismo que el 402 cobra. Los patrones (`/*`, `/:id`) no son una URL
|
|
19
|
+
* que un comprador pueda abrir, así que quedan fuera.
|
|
20
|
+
*/
|
|
21
|
+
declare function ofertasDesdeGateway(base: string): Promise<Oferta[]>;
|
|
22
|
+
declare function PeajeHead(props: PropsPeajeHead): Promise<react.JSX.Element>;
|
|
23
|
+
|
|
24
|
+
export { type Oferta, PeajeHead, type PropsPeajeHead, PeajeHead as default, ofertasDesdeGateway };
|
package/dist/head.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { OpcionesPeaje } from './index.js';
|
|
3
|
+
|
|
4
|
+
/** Igual al `Oferta` de shared, redeclarado para que el .d.ts publicado no apunte a un paquete privado. */
|
|
5
|
+
type Oferta = {
|
|
6
|
+
titulo: string;
|
|
7
|
+
priceUsd: number;
|
|
8
|
+
url: string;
|
|
9
|
+
};
|
|
10
|
+
type PropsPeajeHead = OpcionesPeaje & {
|
|
11
|
+
/** Host del negocio para las URLs del JSON-LD. Por defecto, el de la request. */
|
|
12
|
+
originHost?: string;
|
|
13
|
+
/** Nombre del negocio. Por defecto se lee del gateway, o se usa el slug. */
|
|
14
|
+
name?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Ofertas desde `/discovery/resources`, el catálogo canónico: así el JSON-LD
|
|
18
|
+
* dice lo mismo que el 402 cobra. Los patrones (`/*`, `/:id`) no son una URL
|
|
19
|
+
* que un comprador pueda abrir, así que quedan fuera.
|
|
20
|
+
*/
|
|
21
|
+
declare function ofertasDesdeGateway(base: string): Promise<Oferta[]>;
|
|
22
|
+
declare function PeajeHead(props: PropsPeajeHead): Promise<react.JSX.Element>;
|
|
23
|
+
|
|
24
|
+
export { type Oferta, PeajeHead, type PropsPeajeHead, PeajeHead as default, ofertasDesdeGateway };
|
package/dist/head.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LINKS_HEAD,
|
|
3
|
+
baseDe,
|
|
4
|
+
jsonLdWebApi,
|
|
5
|
+
jsonParaScript
|
|
6
|
+
} from "./chunk-7KJLR3FN.js";
|
|
7
|
+
|
|
8
|
+
// src/head.tsx
|
|
9
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
var TIMEOUT_MS = 2e3;
|
|
11
|
+
async function leerJson(url) {
|
|
12
|
+
try {
|
|
13
|
+
const res = await fetch(url, {
|
|
14
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
15
|
+
// `next` es la extensión de Next.js al RequestInit; fuera de Next se ignora.
|
|
16
|
+
...{ next: { revalidate: 3600 } }
|
|
17
|
+
});
|
|
18
|
+
if (!res.ok) return null;
|
|
19
|
+
return await res.json();
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function ofertasDesdeGateway(base) {
|
|
25
|
+
const cuerpo = await leerJson(`${base}/discovery/resources`);
|
|
26
|
+
return (cuerpo?.items ?? []).filter((i) => typeof i.resource === "string" && esUrlConcreta(i.resource)).map((i) => ({
|
|
27
|
+
titulo: i.extensions?.bazaar?.info?.title ?? i.resource,
|
|
28
|
+
priceUsd: Number(i.extensions?.bazaar?.info?.priceUsd ?? 0),
|
|
29
|
+
url: i.resource
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
function esUrlConcreta(url) {
|
|
33
|
+
try {
|
|
34
|
+
return !/[*:]/.test(new URL(url).pathname);
|
|
35
|
+
} catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function nombreDesdeGateway(base) {
|
|
40
|
+
const card = await leerJson(`${base}/.well-known/agent-card.json`);
|
|
41
|
+
return card?.name ?? null;
|
|
42
|
+
}
|
|
43
|
+
async function hostDeLaRequest() {
|
|
44
|
+
try {
|
|
45
|
+
const mod = await import("next/headers");
|
|
46
|
+
const h = await mod.headers();
|
|
47
|
+
const host = h.get("x-forwarded-host") ?? h.get("host");
|
|
48
|
+
return host ? host.split(",")[0].trim() : null;
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function PeajeHead(props) {
|
|
54
|
+
const base = baseDe(props);
|
|
55
|
+
const [ofertas, nombreRemoto, hostRequest] = await Promise.all([
|
|
56
|
+
ofertasDesdeGateway(base),
|
|
57
|
+
props.name ? Promise.resolve(null) : nombreDesdeGateway(base),
|
|
58
|
+
props.originHost ? Promise.resolve(null) : hostDeLaRequest()
|
|
59
|
+
]);
|
|
60
|
+
const originHost = props.originHost ?? hostRequest ?? "localhost";
|
|
61
|
+
const datos = jsonLdWebApi({
|
|
62
|
+
nombre: props.name ?? nombreRemoto ?? props.slug,
|
|
63
|
+
slug: props.slug,
|
|
64
|
+
originHost,
|
|
65
|
+
ofertas
|
|
66
|
+
});
|
|
67
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
68
|
+
/* @__PURE__ */ jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: jsonParaScript(datos) } }),
|
|
69
|
+
LINKS_HEAD.map((l) => /* @__PURE__ */ jsx("link", { rel: l.rel, type: l.type, href: l.href }, l.rel))
|
|
70
|
+
] });
|
|
71
|
+
}
|
|
72
|
+
var head_default = PeajeHead;
|
|
73
|
+
export {
|
|
74
|
+
PeajeHead,
|
|
75
|
+
head_default as default,
|
|
76
|
+
ofertasDesdeGateway
|
|
77
|
+
};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
GATEWAY_POR_DEFECTO: () => GATEWAY_POR_DEFECTO,
|
|
24
|
+
baseDe: () => baseDe,
|
|
25
|
+
default: () => src_default,
|
|
26
|
+
fusionarRewrites: () => fusionarRewrites,
|
|
27
|
+
withPeaje: () => withPeaje
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(src_exports);
|
|
30
|
+
|
|
31
|
+
// ../shared/src/kit/rutas.ts
|
|
32
|
+
var RUTAS_PROXY = [
|
|
33
|
+
{ path: "/llms.txt", nota: "gu\xEDa para agentes (fusionada con la tuya)" },
|
|
34
|
+
{ path: "/pricing.md", nota: "precios por endpoint" },
|
|
35
|
+
{ path: "/auth.md", nota: 'c\xF3mo pagar (el "auth" ac\xE1 es el pago)' },
|
|
36
|
+
{ path: "/agents.md", nota: "qu\xE9 es y cu\xE1ndo usarte" },
|
|
37
|
+
{ path: "/openapi.json", nota: "discovery con precios" },
|
|
38
|
+
{ path: "/mcp", nota: "MCP server con tools pagas, en TU dominio" },
|
|
39
|
+
{ path: "/.well-known/mcp", nota: "el MCP tambi\xE9n ac\xE1: es donde lo buscan los auditores" },
|
|
40
|
+
{ path: "/.well-known/ard.json", nota: "cat\xE1logo ARD (path can\xF3nico)" },
|
|
41
|
+
{ path: "/.well-known/ai-catalog.json", nota: "cat\xE1logo ARD (alias legacy)" },
|
|
42
|
+
{ path: "/.well-known/api-catalog", nota: "linkset RFC 9727" },
|
|
43
|
+
{ path: "/.well-known/agent-card.json", nota: "agent card A2A" },
|
|
44
|
+
{ path: "/.well-known/mcp/server-card.json", nota: "server card MCP" },
|
|
45
|
+
{ path: "/discovery/resources", nota: "lista x402 Bazaar: lo que cobra 402 de verdad" },
|
|
46
|
+
{ path: "/.well-known/ucp", nota: "perfil UCP: qu\xE9 sabe hacer tu negocio" },
|
|
47
|
+
{ path: "/checkout_sessions", nota: "checkout ACP (el de OpenAI)" },
|
|
48
|
+
{ path: "/agentic_commerce/delegate_payment", nota: "delegate payment ACP" },
|
|
49
|
+
{ path: "/developers", nota: "portal de desarrolladores, renderizado con tus precios" },
|
|
50
|
+
{ path: "/.well-known/peaje-indexnow.txt", nota: "clave IndexNow: avisa a Bing y Copilot cuando cambian precios" },
|
|
51
|
+
// Los auditores prueban /docs y /developers; el gateway redirige uno al otro.
|
|
52
|
+
{ path: "/docs", nota: "alias del portal: los auditores prueban ambos" }
|
|
53
|
+
];
|
|
54
|
+
var RUTAS_DINAMICAS = [
|
|
55
|
+
{ path: "/r/:slug", prefijo: "/r/", nota: "links con precio: el 402 en tu dominio" },
|
|
56
|
+
{ path: "/checkout_sessions/:id", prefijo: "/checkout_sessions/", nota: "leer una sesi\xF3n de checkout ACP" }
|
|
57
|
+
];
|
|
58
|
+
var PEAJE_FETCH_HEADER = "x-peaje-fetch";
|
|
59
|
+
function reglasNext(base) {
|
|
60
|
+
return [
|
|
61
|
+
...RUTAS_PROXY.map((r) => ({
|
|
62
|
+
source: r.path,
|
|
63
|
+
destination: `${base}${r.path}`,
|
|
64
|
+
...r.path === "/llms.txt" ? { missing: [{ type: "header", key: PEAJE_FETCH_HEADER }] } : {}
|
|
65
|
+
})),
|
|
66
|
+
...RUTAS_DINAMICAS.map((r) => ({ source: r.path, destination: `${base}${r.path}` }))
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ../shared/src/index.ts
|
|
71
|
+
var TEMPO = {
|
|
72
|
+
mainnet: {
|
|
73
|
+
chainId: 4217,
|
|
74
|
+
rpcUrl: "https://rpc.tempo.xyz",
|
|
75
|
+
explorerUrl: "https://explore.tempo.xyz"
|
|
76
|
+
},
|
|
77
|
+
testnet: {
|
|
78
|
+
chainId: 42431,
|
|
79
|
+
rpcUrl: "https://rpc.moderato.tempo.xyz",
|
|
80
|
+
explorerUrl: "https://explore.testnet.tempo.xyz"
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var TOKENS = {
|
|
84
|
+
pathUsd: "0x20c0000000000000000000000000000000000000",
|
|
85
|
+
usdc: "0x20C000000000000000000000b9537d11c60E8b50"
|
|
86
|
+
};
|
|
87
|
+
var DEFAULT_CURRENCY = TOKENS.pathUsd;
|
|
88
|
+
var NETWORKS = {
|
|
89
|
+
tempo: {
|
|
90
|
+
id: "tempo",
|
|
91
|
+
label: "Tempo",
|
|
92
|
+
token: TOKENS.pathUsd,
|
|
93
|
+
tokenSymbol: "pathUSD",
|
|
94
|
+
decimals: 6,
|
|
95
|
+
mainnet: TEMPO.mainnet,
|
|
96
|
+
testnet: TEMPO.testnet
|
|
97
|
+
},
|
|
98
|
+
arc: {
|
|
99
|
+
id: "arc",
|
|
100
|
+
label: "Arc",
|
|
101
|
+
// Interfaz ERC-20 del USDC nativo de Arc; el gas de la red se paga en ese mismo USDC.
|
|
102
|
+
token: "0x3600000000000000000000000000000000000000",
|
|
103
|
+
tokenSymbol: "USDC",
|
|
104
|
+
decimals: 6,
|
|
105
|
+
// Leído on-chain del contrato: name() = "USDC", version() = "2".
|
|
106
|
+
eip3009: { name: "USDC", version: "2" },
|
|
107
|
+
// Arc no publica direcciones de mainnet todavía (sept 2026).
|
|
108
|
+
mainnet: null,
|
|
109
|
+
testnet: {
|
|
110
|
+
chainId: 5042002,
|
|
111
|
+
rpcUrl: "https://rpc.testnet.arc.io",
|
|
112
|
+
explorerUrl: "https://testnet.arcscan.app"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
arbitrum: {
|
|
116
|
+
id: "arbitrum",
|
|
117
|
+
label: "Arbitrum",
|
|
118
|
+
// USDC de Circle en Arbitrum Sepolia. En Arbitrum One vive en otra dirección,
|
|
119
|
+
// por eso mainnet queda en null hasta que el gateway opere allá.
|
|
120
|
+
token: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d",
|
|
121
|
+
tokenSymbol: "USDC",
|
|
122
|
+
decimals: 6,
|
|
123
|
+
// Leído on-chain: name() = "USD Coin", version() = "2" (distinto al USDC de Arc).
|
|
124
|
+
eip3009: { name: "USD Coin", version: "2" },
|
|
125
|
+
mainnet: null,
|
|
126
|
+
testnet: {
|
|
127
|
+
chainId: 421614,
|
|
128
|
+
rpcUrl: "https://sepolia-rollup.arbitrum.io/rpc",
|
|
129
|
+
explorerUrl: "https://sepolia.arbiscan.io"
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"arbitrum-usdg": {
|
|
133
|
+
id: "arbitrum-usdg",
|
|
134
|
+
label: "Arbitrum \xB7 USDG",
|
|
135
|
+
// Mismo contrato y misma cadena que el riel USDC: cambia el stablecoin.
|
|
136
|
+
// Un riel es (cadena, token), y el saldo del negocio se lleva por token.
|
|
137
|
+
token: "0xFFC95faa3d63Cde504a05B567C600B78C0b41892",
|
|
138
|
+
tokenSymbol: "USDG",
|
|
139
|
+
decimals: 6,
|
|
140
|
+
eip3009: { name: "Global Dollar", version: "1" },
|
|
141
|
+
mainnet: null,
|
|
142
|
+
testnet: {
|
|
143
|
+
chainId: 421614,
|
|
144
|
+
rpcUrl: "https://sepolia-rollup.arbitrum.io/rpc",
|
|
145
|
+
explorerUrl: "https://sepolia.arbiscan.io"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
robinhood: {
|
|
149
|
+
id: "robinhood",
|
|
150
|
+
label: "Robinhood",
|
|
151
|
+
// USDG de Paxos en Robinhood Chain Testnet (el "USDC" de esa testnet es un
|
|
152
|
+
// mock sin EIP-3009). Leído on-chain: dominio "Global Dollar", versión "1".
|
|
153
|
+
token: "0x7E955252E15c84f5768B83c41a71F9eba181802F",
|
|
154
|
+
tokenSymbol: "USDG",
|
|
155
|
+
decimals: 6,
|
|
156
|
+
eip3009: { name: "Global Dollar", version: "1" },
|
|
157
|
+
mainnet: null,
|
|
158
|
+
testnet: {
|
|
159
|
+
chainId: 46630,
|
|
160
|
+
rpcUrl: "https://rpc.testnet.chain.robinhood.com",
|
|
161
|
+
explorerUrl: "https://explorer.testnet.chain.robinhood.com"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
var NETWORK_IDS = Object.keys(NETWORKS);
|
|
166
|
+
|
|
167
|
+
// src/index.ts
|
|
168
|
+
var GATEWAY_POR_DEFECTO = "https://peaje-gateway.up.railway.app";
|
|
169
|
+
function baseDe({ slug, gateway }) {
|
|
170
|
+
const raiz = (gateway ?? process.env.PEAJE_GATEWAY_URL ?? GATEWAY_POR_DEFECTO).replace(/\/+$/, "");
|
|
171
|
+
return `${raiz}/${slug}`;
|
|
172
|
+
}
|
|
173
|
+
function fusionarRewrites(previo, reglas) {
|
|
174
|
+
const objeto = Array.isArray(previo) ? { afterFiles: previo } : { ...previo ?? {} };
|
|
175
|
+
const antes = objeto.beforeFiles ?? [];
|
|
176
|
+
const destinos = new Set(antes.map((r) => r.destination));
|
|
177
|
+
const nuevas = reglas.filter((r) => !destinos.has(r.destination));
|
|
178
|
+
return { ...objeto, beforeFiles: [...nuevas, ...antes] };
|
|
179
|
+
}
|
|
180
|
+
function envolverConfig(config, reglas) {
|
|
181
|
+
const original = config.rewrites;
|
|
182
|
+
return {
|
|
183
|
+
...config,
|
|
184
|
+
async rewrites() {
|
|
185
|
+
const previo = original ? await original.call(config) : void 0;
|
|
186
|
+
return fusionarRewrites(previo, reglas);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function withPeaje(nextConfig, opciones) {
|
|
191
|
+
if (!opciones?.slug) throw new Error("withPeaje: `slug` is required (the business slug from your Peaje dashboard).");
|
|
192
|
+
const reglas = reglasNext(baseDe(opciones));
|
|
193
|
+
if (typeof nextConfig === "function") {
|
|
194
|
+
return async (phase, contexto) => envolverConfig(await nextConfig(phase, contexto), reglas);
|
|
195
|
+
}
|
|
196
|
+
return envolverConfig(nextConfig ?? {}, reglas);
|
|
197
|
+
}
|
|
198
|
+
var src_default = withPeaje;
|
|
199
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
200
|
+
0 && (module.exports = {
|
|
201
|
+
GATEWAY_POR_DEFECTO,
|
|
202
|
+
baseDe,
|
|
203
|
+
fusionarRewrites,
|
|
204
|
+
withPeaje
|
|
205
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
declare const GATEWAY_POR_DEFECTO = "https://peaje-gateway.up.railway.app";
|
|
2
|
+
type OpcionesPeaje = {
|
|
3
|
+
/** El slug del negocio en Peaje (el mismo del dashboard). */
|
|
4
|
+
slug: string;
|
|
5
|
+
/** URL pública del gateway. Por defecto la de producción, o `PEAJE_GATEWAY_URL`. */
|
|
6
|
+
gateway?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Tipos mínimos y locales en vez de importar `NextConfig`: así el paquete
|
|
10
|
+
* compila y se usa sin `next` instalado en tiempo de tipos (peer opcional) y
|
|
11
|
+
* acepta cualquier versión desde 14.
|
|
12
|
+
*/
|
|
13
|
+
type ReglaRewrite = {
|
|
14
|
+
source: string;
|
|
15
|
+
destination: string;
|
|
16
|
+
basePath?: false;
|
|
17
|
+
locale?: false;
|
|
18
|
+
has?: unknown[];
|
|
19
|
+
missing?: unknown[];
|
|
20
|
+
};
|
|
21
|
+
type RewritesObjeto = {
|
|
22
|
+
beforeFiles?: ReglaRewrite[];
|
|
23
|
+
afterFiles?: ReglaRewrite[];
|
|
24
|
+
fallback?: ReglaRewrite[];
|
|
25
|
+
};
|
|
26
|
+
type ResultadoRewrites = ReglaRewrite[] | RewritesObjeto;
|
|
27
|
+
type ConfigConRewrites = {
|
|
28
|
+
rewrites?: () => ResultadoRewrites | Promise<ResultadoRewrites>;
|
|
29
|
+
[clave: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
type ConfigOFuncion<C extends ConfigConRewrites = ConfigConRewrites> = C | ((phase: string, contexto: {
|
|
32
|
+
defaultConfig: unknown;
|
|
33
|
+
}) => C | Promise<C>);
|
|
34
|
+
/** Base `${gateway}/${slug}` sin barra final, con el env como override. */
|
|
35
|
+
declare function baseDe({ slug, gateway }: OpcionesPeaje): string;
|
|
36
|
+
/**
|
|
37
|
+
* Fusiona las reglas de Peaje con lo que devolvía el `rewrites()` original.
|
|
38
|
+
* Un array pasa a `afterFiles`: es lo que Next hace internamente con el array,
|
|
39
|
+
* y así las nuestras siguen ganando en `beforeFiles`.
|
|
40
|
+
*/
|
|
41
|
+
declare function fusionarRewrites(previo: ResultadoRewrites | undefined, reglas: ReglaRewrite[]): RewritesObjeto;
|
|
42
|
+
/**
|
|
43
|
+
* Acepta la config como objeto o como función `(phase, { defaultConfig })`,
|
|
44
|
+
* y un `rewrites()` sync o async que devuelva array u objeto.
|
|
45
|
+
*/
|
|
46
|
+
declare function withPeaje<C extends ConfigConRewrites>(nextConfig: ConfigOFuncion<C>, opciones: OpcionesPeaje): ConfigOFuncion<C>;
|
|
47
|
+
|
|
48
|
+
export { type ConfigConRewrites, type ConfigOFuncion, GATEWAY_POR_DEFECTO, type OpcionesPeaje, type ReglaRewrite, type ResultadoRewrites, type RewritesObjeto, baseDe, withPeaje as default, fusionarRewrites, withPeaje };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
declare const GATEWAY_POR_DEFECTO = "https://peaje-gateway.up.railway.app";
|
|
2
|
+
type OpcionesPeaje = {
|
|
3
|
+
/** El slug del negocio en Peaje (el mismo del dashboard). */
|
|
4
|
+
slug: string;
|
|
5
|
+
/** URL pública del gateway. Por defecto la de producción, o `PEAJE_GATEWAY_URL`. */
|
|
6
|
+
gateway?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Tipos mínimos y locales en vez de importar `NextConfig`: así el paquete
|
|
10
|
+
* compila y se usa sin `next` instalado en tiempo de tipos (peer opcional) y
|
|
11
|
+
* acepta cualquier versión desde 14.
|
|
12
|
+
*/
|
|
13
|
+
type ReglaRewrite = {
|
|
14
|
+
source: string;
|
|
15
|
+
destination: string;
|
|
16
|
+
basePath?: false;
|
|
17
|
+
locale?: false;
|
|
18
|
+
has?: unknown[];
|
|
19
|
+
missing?: unknown[];
|
|
20
|
+
};
|
|
21
|
+
type RewritesObjeto = {
|
|
22
|
+
beforeFiles?: ReglaRewrite[];
|
|
23
|
+
afterFiles?: ReglaRewrite[];
|
|
24
|
+
fallback?: ReglaRewrite[];
|
|
25
|
+
};
|
|
26
|
+
type ResultadoRewrites = ReglaRewrite[] | RewritesObjeto;
|
|
27
|
+
type ConfigConRewrites = {
|
|
28
|
+
rewrites?: () => ResultadoRewrites | Promise<ResultadoRewrites>;
|
|
29
|
+
[clave: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
type ConfigOFuncion<C extends ConfigConRewrites = ConfigConRewrites> = C | ((phase: string, contexto: {
|
|
32
|
+
defaultConfig: unknown;
|
|
33
|
+
}) => C | Promise<C>);
|
|
34
|
+
/** Base `${gateway}/${slug}` sin barra final, con el env como override. */
|
|
35
|
+
declare function baseDe({ slug, gateway }: OpcionesPeaje): string;
|
|
36
|
+
/**
|
|
37
|
+
* Fusiona las reglas de Peaje con lo que devolvía el `rewrites()` original.
|
|
38
|
+
* Un array pasa a `afterFiles`: es lo que Next hace internamente con el array,
|
|
39
|
+
* y así las nuestras siguen ganando en `beforeFiles`.
|
|
40
|
+
*/
|
|
41
|
+
declare function fusionarRewrites(previo: ResultadoRewrites | undefined, reglas: ReglaRewrite[]): RewritesObjeto;
|
|
42
|
+
/**
|
|
43
|
+
* Acepta la config como objeto o como función `(phase, { defaultConfig })`,
|
|
44
|
+
* y un `rewrites()` sync o async que devuelva array u objeto.
|
|
45
|
+
*/
|
|
46
|
+
declare function withPeaje<C extends ConfigConRewrites>(nextConfig: ConfigOFuncion<C>, opciones: OpcionesPeaje): ConfigOFuncion<C>;
|
|
47
|
+
|
|
48
|
+
export { type ConfigConRewrites, type ConfigOFuncion, GATEWAY_POR_DEFECTO, type OpcionesPeaje, type ReglaRewrite, type ResultadoRewrites, type RewritesObjeto, baseDe, withPeaje as default, fusionarRewrites, withPeaje };
|
package/dist/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@peaje/next",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Peaje for Next.js: proxy rewrites and the head block that make your site speak MPP, MCP and OpenAPI on your own domain.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"main": "./dist/index.cjs",
|
|
12
|
+
"module": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"require": {
|
|
21
|
+
"types": "./dist/index.d.cts",
|
|
22
|
+
"default": "./dist/index.cjs"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"./head": {
|
|
26
|
+
"import": {
|
|
27
|
+
"types": "./dist/head.d.ts",
|
|
28
|
+
"default": "./dist/head.js"
|
|
29
|
+
},
|
|
30
|
+
"require": {
|
|
31
|
+
"types": "./dist/head.d.cts",
|
|
32
|
+
"default": "./dist/head.cjs"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"test": "tsx --test test/*.test.ts"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"peaje",
|
|
43
|
+
"next",
|
|
44
|
+
"mpp",
|
|
45
|
+
"x402",
|
|
46
|
+
"mcp",
|
|
47
|
+
"agents"
|
|
48
|
+
],
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"next": ">=14",
|
|
51
|
+
"react": ">=18"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"next": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"react": {
|
|
58
|
+
"optional": true
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@peaje/shared": "workspace:*",
|
|
63
|
+
"@types/node": "^20",
|
|
64
|
+
"@types/react": "^19",
|
|
65
|
+
"next": "16.3.1",
|
|
66
|
+
"react": "19.2.8",
|
|
67
|
+
"tsup": "^8.5.1",
|
|
68
|
+
"tsx": "^4.23.12",
|
|
69
|
+
"typescript": "^5.9.0"
|
|
70
|
+
}
|
|
71
|
+
}
|