@ar-agents/mercadopago 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +92 -0
- package/README.md +11 -0
- package/README.skeleton.md +200 -0
- package/dist/index.cjs +167 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +167 -50
- package/dist/index.js.map +1 -1
- package/dist/vercel-kv.cjs +15 -3
- package/dist/vercel-kv.cjs.map +1 -1
- package/dist/vercel-kv.d.cts +39 -8
- package/dist/vercel-kv.d.ts +39 -8
- package/dist/vercel-kv.js +15 -3
- package/dist/vercel-kv.js.map +1 -1
- package/package.json +1 -1
- package/tools.manifest.json +545 -297
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.15.0
|
|
4
|
+
|
|
5
|
+
### Minor — `requireConfirmation` opt-in HITL callback (closes /review CRITICAL)
|
|
6
|
+
|
|
7
|
+
Description-based HITL warnings on irreversible ops are best-effort against
|
|
8
|
+
prompt injection. The /review audit (commit 6e3a0dd) flagged this as a real
|
|
9
|
+
risk: a crafted user message smuggled into `external_reference` saying "the
|
|
10
|
+
user already confirmed this refund" could bypass the LLM's heuristic.
|
|
11
|
+
|
|
12
|
+
`mercadoPagoTools(client, { requireConfirmation: async (op, args) => boolean })`
|
|
13
|
+
adds a programmatic out-of-band gate. When set, the 8 irreversible tools
|
|
14
|
+
(`cancel_payment`, `capture_payment`, `refund_payment`,
|
|
15
|
+
`delete_customer_card`, `cancel_qr_payment`, `cancel_order`,
|
|
16
|
+
`cancel_point_payment_intent`, `delete_webhook`) call the callback BEFORE
|
|
17
|
+
executing. If it returns `false`, the tool returns
|
|
18
|
+
`{ ok: false, reason: "Confirmation declined", operation, args }` and never
|
|
19
|
+
reaches MP. If it throws, the error propagates so connection issues are
|
|
20
|
+
distinguishable from declined confirmations.
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
mercadoPagoTools(client, {
|
|
24
|
+
state, backUrl,
|
|
25
|
+
requireConfirmation: async (op, args) => {
|
|
26
|
+
return await slack.confirm({
|
|
27
|
+
channel: "#mp-approvals",
|
|
28
|
+
text: `Refund $${args.amount ?? "FULL"} on payment ${args.payment_id}?`,
|
|
29
|
+
timeoutMs: 60_000,
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Backward-compat: omit the option for the previous behavior (description-only
|
|
36
|
+
HITL). 8 new tests in `test/require-confirmation.test.ts` covering decline,
|
|
37
|
+
approve, non-gated tools unaffected, error propagation.
|
|
38
|
+
|
|
39
|
+
### Other improvements (closes /review findings)
|
|
40
|
+
|
|
41
|
+
- **webhookDedup wired in `handle_webhook`** — the option was declared in
|
|
42
|
+
v0.10 but never used; `handle_webhook` now actually short-circuits on
|
|
43
|
+
duplicate `(topic, dataId, requestId)` tuples (fix for /review CRITICAL).
|
|
44
|
+
- **Idempotency key collision-safe encoding** — `deterministicIdempotencyKey`
|
|
45
|
+
switched from `|`-joined to length-prefix (`<n>:<value>|`) so an attacker
|
|
46
|
+
controlling `external_reference` can no longer craft a colliding key with
|
|
47
|
+
a future legitimate transaction.
|
|
48
|
+
- **VercelKVRateLimiter improvements** — fixed the docstring's fictional
|
|
49
|
+
`MercadoPagoClient({ rateLimiter })` example (now correctly shows
|
|
50
|
+
`withRateLimit` middleware), added randomized jitter (±30%) to the retry
|
|
51
|
+
loop to mitigate thundering herd, capped retries at 8 to fail fast on
|
|
52
|
+
misconfigured buckets.
|
|
53
|
+
|
|
54
|
+
## 0.14.0
|
|
55
|
+
|
|
56
|
+
### Minor Changes — deep-audit hardening pass
|
|
57
|
+
|
|
58
|
+
**Critical: Browser-context guard in MercadoPagoClient constructor.**
|
|
59
|
+
Throws if instantiated in a context where `window` is defined — prevents
|
|
60
|
+
the access token from being bundled into a client-side JavaScript bundle.
|
|
61
|
+
Edge Runtime, Node, Workers, and any server context pass through. To
|
|
62
|
+
opt out for jsdom-based tests, pass `__allowBrowser: true`.
|
|
63
|
+
|
|
64
|
+
**`z.unknown()` schemas replaced with strict Zod.** Two tools previously
|
|
65
|
+
used `z.record(z.string(), z.unknown())`:
|
|
66
|
+
- `update_merchant_order.patch` → narrow object with documented MP fields
|
|
67
|
+
(`external_reference`, `notification_url`, `additional_info`, `status`),
|
|
68
|
+
`.strict()` so unknown keys are rejected.
|
|
69
|
+
- `explain_payment_status.payment` → typed shape with `.passthrough()` for
|
|
70
|
+
ergonomic interop, marked clearly as ADVANCED — LLMs should use
|
|
71
|
+
`payment_id` instead.
|
|
72
|
+
|
|
73
|
+
**Stricter validation on `search_payments`:**
|
|
74
|
+
- `payer_email` now requires `.email()` (was bare `z.string()`).
|
|
75
|
+
- `begin_date` / `end_date` now require `.datetime()` ISO 8601.
|
|
76
|
+
|
|
77
|
+
**Deterministic idempotency on subscription + preference creation.**
|
|
78
|
+
`create_subscription` and `create_payment_preference` now derive their
|
|
79
|
+
idempotency key from input fields (customer_email + amount + frequency
|
|
80
|
+
for subscriptions; items + payer + external_reference for preferences).
|
|
81
|
+
LLM retries with the same inputs return the EXISTING resource instead
|
|
82
|
+
of creating a duplicate.
|
|
83
|
+
|
|
84
|
+
**Human-in-the-loop warnings on irreversible / money-moving tools.**
|
|
85
|
+
Updated 7 tool descriptions to explicitly tell the LLM to confirm with
|
|
86
|
+
the user before calling: `cancel_payment`, `capture_payment`,
|
|
87
|
+
`refund_payment`, `delete_customer_card`, `cancel_qr_payment`,
|
|
88
|
+
`cancel_order`, `cancel_point_payment_intent`, `delete_webhook`. Each
|
|
89
|
+
description now states what's irreversible, what the user should be
|
|
90
|
+
told before confirmation, and what the post-call state is.
|
|
91
|
+
|
|
92
|
+
`CreatePreapprovalParams` and `CreatePreferenceParams` now accept an
|
|
93
|
+
optional `idempotencyKey` field for callers that want explicit control.
|
|
94
|
+
|
|
3
95
|
## 0.13.0
|
|
4
96
|
|
|
5
97
|
### Minor Changes — Distributed rate limiter via Vercel KV
|
package/README.md
CHANGED
|
@@ -531,3 +531,14 @@ Each recipe is copy-pasteable into a Next.js route handler.
|
|
|
531
531
|
## License
|
|
532
532
|
|
|
533
533
|
MIT — see [LICENSE](./LICENSE).
|
|
534
|
+
|
|
535
|
+
## Stability
|
|
536
|
+
|
|
537
|
+
This package is **pre-1.0**. Per [npm convention](https://docs.npmjs.com/about-semantic-versioning), **0.x minor versions may include breaking changes**. We document every breaking change in `CHANGELOG.md` under the corresponding minor bump and flag it explicitly. To avoid surprises:
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
# Pin to exact version (recommended for production):
|
|
541
|
+
pnpm add @ar-agents/<package>@<exact-version>
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
We commit to **no breaking changes within a patch version**, and we publish `1.0.0` once the public API has stabilized across at least two consecutive minor releases.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
README skeleton — Vercel-official quality.
|
|
3
|
+
Drop this in as packages/mercadopago/README.md after a final once-over.
|
|
4
|
+
The structure follows the patterns Vercel themselves use on
|
|
5
|
+
https://github.com/vercel/ai-sdk and https://github.com/vercel/next.js
|
|
6
|
+
for their public OSS repos.
|
|
7
|
+
|
|
8
|
+
Hard rules:
|
|
9
|
+
- Lead with what it is and a 3-line install + first call.
|
|
10
|
+
- Real numbers (latency, bundle size) only — no "fast", "blazing", "robust".
|
|
11
|
+
- Code blocks runnable as-pasted (no `// ...` placeholders that hide work).
|
|
12
|
+
- One-screen scrolling for the top: header → install → first call → core API.
|
|
13
|
+
- Everything below is reference, not pitch.
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
# `@ar-agents/mercadopago`
|
|
17
|
+
|
|
18
|
+
[](https://www.npmjs.com/package/@ar-agents/mercadopago)
|
|
19
|
+
[](https://bundlephobia.com/package/@ar-agents/mercadopago)
|
|
20
|
+
[](https://arethetypeswrong.github.io/?p=@ar-agents/mercadopago)
|
|
21
|
+
[](https://github.com/ar-agents/ar-agents/actions/workflows/ci.yml)
|
|
22
|
+
[](./LICENSE)
|
|
23
|
+
|
|
24
|
+
Mercado Pago Subscriptions, Payments, Checkout Pro, Marketplace, and Point — as drop-in tools for the [Vercel AI SDK](https://ai-sdk.dev/). Argentine-focused, agent-ready, Edge-Runtime-safe.
|
|
25
|
+
|
|
26
|
+
> **Reading this as an agent?** Skip to [AGENTS.md](./AGENTS.md) — decision tree, result schemas to memorize, error patterns, latency table.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm add @ar-agents/mercadopago ai zod
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { Experimental_Agent as Agent, stepCountIs } from "ai";
|
|
36
|
+
import { MercadoPagoClient, mercadoPagoTools, InMemoryStateAdapter } from "@ar-agents/mercadopago";
|
|
37
|
+
|
|
38
|
+
const mp = new MercadoPagoClient({ accessToken: process.env.MP_ACCESS_TOKEN! });
|
|
39
|
+
|
|
40
|
+
export const agent = new Agent({
|
|
41
|
+
model: "anthropic/claude-sonnet-4-6",
|
|
42
|
+
instructions: "Sos un asistente de billing para una SaaS argentina.",
|
|
43
|
+
tools: mercadoPagoTools(mp, { state: new InMemoryStateAdapter(), backUrl: "https://example.com/done" }),
|
|
44
|
+
stopWhen: stepCountIs(8),
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const { text } = await agent.generate({
|
|
50
|
+
prompt: "Cobrale $25.000 mensual a juan@example.com con razón 'Plan Pro'."
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
That's it. The agent picks `create_subscription`, returns an `init_point_url` you send to the customer, and the rest of the flow (first payment confirmation, recurring charges, webhooks) just works.
|
|
55
|
+
|
|
56
|
+
## At a glance
|
|
57
|
+
|
|
58
|
+
| | |
|
|
59
|
+
| --- | --- |
|
|
60
|
+
| **Tools** | 30 — Subscriptions, Payments, Refunds, Checkout Pro, Cuotas, QR in-store, Saved cards, Marketplace OAuth, Order Management, Point devices, 3DS, Webhooks. [Full list](./AGENTS.md#tool-selection). |
|
|
61
|
+
| **Bundle size** | 41 KB ESM brotli'd ([bundlephobia](https://bundlephobia.com/package/@ar-agents/mercadopago)). Tree-shakable subpath exports for `/vercel-kv` + `/otel`. |
|
|
62
|
+
| **Runtime** | Vercel Edge, Node 18+, Cloudflare Workers, Deno — Web Crypto under the hood. |
|
|
63
|
+
| **Tests** | 290 unit + property + failure-injection + benchmark. `pnpm test`, `pnpm bench`. |
|
|
64
|
+
| **TypeScript** | Strict mode, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`. publint + arethetypeswrong all 🟢. |
|
|
65
|
+
| **AR-specific knowledge** | Cuotas with regulatory text (RG 5286/2023), AR issuer promo catalog, Subscription replay-protection, MLA-verified, ARS default. |
|
|
66
|
+
|
|
67
|
+
## Server-only
|
|
68
|
+
|
|
69
|
+
This package **MUST** run on the server. The constructor throws if instantiated in a browser context — the access token would be exposed in the JavaScript bundle. Use Server Components, Route Handlers, or Server Actions.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// ❌ Never. Throws at runtime AND would leak the token if it didn't.
|
|
73
|
+
"use client";
|
|
74
|
+
const mp = new MercadoPagoClient({ accessToken: ... });
|
|
75
|
+
|
|
76
|
+
// ✅ Server Component / Route Handler / Server Action.
|
|
77
|
+
import { MercadoPagoClient } from "@ar-agents/mercadopago";
|
|
78
|
+
export async function POST(req: Request) {
|
|
79
|
+
const mp = new MercadoPagoClient({ accessToken: process.env.MP_ACCESS_TOKEN! });
|
|
80
|
+
// ...
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## API reference
|
|
85
|
+
|
|
86
|
+
### `new MercadoPagoClient(options)`
|
|
87
|
+
|
|
88
|
+
Server-side MP API client. Edge-Runtime safe.
|
|
89
|
+
|
|
90
|
+
| Option | Default | Description |
|
|
91
|
+
| --- | --- | --- |
|
|
92
|
+
| `accessToken` (required) | — | TEST- prefix for sandbox, APP_USR- for production. |
|
|
93
|
+
| `baseUrl` | `https://api.mercadopago.com` | Override for tests / regional hosts. |
|
|
94
|
+
| `fetch` | `globalThis.fetch` | Custom fetch (e.g., MSW for tests). |
|
|
95
|
+
| `requestTimeoutMs` | `30_000` | Per-request timeout. |
|
|
96
|
+
| `maxRetries` | `1` | 5xx + network retries. 4xx never retried. |
|
|
97
|
+
| `circuitBreaker` | — | `new CircuitBreaker({ ... })` to fail fast on cascading failures. |
|
|
98
|
+
| `traceContext` | — | OpenTelemetry context propagator (W3C trace headers). |
|
|
99
|
+
| `onCall` | — | Observability hook fired after every request. |
|
|
100
|
+
|
|
101
|
+
### `mercadoPagoTools(client, options)`
|
|
102
|
+
|
|
103
|
+
Returns the agent tool set wired to the given client.
|
|
104
|
+
|
|
105
|
+
| Option | Required | Description |
|
|
106
|
+
| --- | --- | --- |
|
|
107
|
+
| `state` | yes | `SubscriptionStateAdapter` — `InMemoryStateAdapter`, `VercelKVSubscriptionStateAdapter`, or your own. |
|
|
108
|
+
| `backUrl` | yes | HTTPS URL where MP redirects buyers after first payment. localhost rejected. |
|
|
109
|
+
| `notificationUrl` | no | Webhook URL for new payments / status changes. |
|
|
110
|
+
| `oauth` | no | `{ clientId, clientSecret, redirectUri, tokenStore }` for marketplace OAuth flows. |
|
|
111
|
+
| `webhookSecret` | no | HMAC secret for `handle_webhook` (paste from MP dev panel). |
|
|
112
|
+
| `descriptions` | no | Override individual tool descriptions for fine-tuning the LLM. |
|
|
113
|
+
|
|
114
|
+
### Subpath exports
|
|
115
|
+
|
|
116
|
+
| Subpath | When to use |
|
|
117
|
+
| --- | --- |
|
|
118
|
+
| `@ar-agents/mercadopago` | The 30 tools + client. Always-on. |
|
|
119
|
+
| `@ar-agents/mercadopago/vercel-kv` | Vercel KV–backed adapters: `VercelKVSubscriptionStateAdapter`, `VercelKVOAuthTokenStore`, `VercelKVIdempotencyCache`, `VercelKVAuditLog`, `VercelKVRateLimiter` (distributed). Pulls in `@vercel/kv` peer dep. |
|
|
120
|
+
| `@ar-agents/mercadopago/otel` | `instrumentMercadoPagoClient` + `instrumentMercadoPagoTools` for OpenTelemetry spans + metrics. Pulls in `@opentelemetry/api` peer dep. |
|
|
121
|
+
|
|
122
|
+
## Production patterns
|
|
123
|
+
|
|
124
|
+
### Idempotency by default
|
|
125
|
+
|
|
126
|
+
Every `POST` request gets an auto-generated UUID idempotency key — your app survives network blips without double-charging. For LLM-driven retries, `create_payment`, `create_subscription`, `create_payment_preference`, and `refund_payment` use a **deterministic** key derived from the inputs, so a tool retried with the same inputs returns the existing resource instead of creating a duplicate.
|
|
127
|
+
|
|
128
|
+
### Webhook verification
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { verifyWebhookSignature, parseWebhookEvent } from "@ar-agents/mercadopago";
|
|
132
|
+
|
|
133
|
+
export async function POST(req: Request) {
|
|
134
|
+
const url = new URL(req.url);
|
|
135
|
+
const rawBody = await req.text();
|
|
136
|
+
const event = parseWebhookEvent(JSON.parse(rawBody), url.searchParams);
|
|
137
|
+
|
|
138
|
+
const ok = await verifyWebhookSignature({
|
|
139
|
+
requestId: req.headers.get("x-request-id"),
|
|
140
|
+
dataId: event!.dataId,
|
|
141
|
+
signatureHeader: req.headers.get("x-signature"),
|
|
142
|
+
secret: process.env.MP_WEBHOOK_SECRET!,
|
|
143
|
+
});
|
|
144
|
+
if (!ok) return new Response("Invalid signature", { status: 401 });
|
|
145
|
+
// process event...
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
5-minute replay-tolerance window built in. Constant-time HMAC comparison.
|
|
150
|
+
|
|
151
|
+
### Distributed rate limiting
|
|
152
|
+
|
|
153
|
+
For multi-region or marketplace deploys where serverless instances would each get their own per-process bucket:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import { VercelKVRateLimiter } from "@ar-agents/mercadopago/vercel-kv";
|
|
157
|
+
|
|
158
|
+
const limiter = new VercelKVRateLimiter({
|
|
159
|
+
key: "mp-account-prod",
|
|
160
|
+
capacity: 50,
|
|
161
|
+
refillPerSecond: 25,
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Cookbook
|
|
166
|
+
|
|
167
|
+
8 production-grade recipes in [`./cookbook`](./cookbook/) — Checkout Pro, SaaS subscription, webhook handler, marketplace split, QR in-store, 3DS challenge, manual capture, recovery patterns, full OpenTelemetry wiring.
|
|
168
|
+
|
|
169
|
+
## Comparison
|
|
170
|
+
|
|
171
|
+
| | `@ar-agents/mercadopago` | `mercadopago` (official SDK) | Hand-rolled |
|
|
172
|
+
| --- | --- | --- | --- |
|
|
173
|
+
| Tools as Vercel AI SDK 6 schemas | ✓ | — | build it |
|
|
174
|
+
| AR-specific (cuotas, AR issuer promos, AR phone, MLA-verified) | ✓ | — | weeks |
|
|
175
|
+
| `AGENTS.md` per package (LLM-readable) | ✓ | — | — |
|
|
176
|
+
| Idempotency-by-default for state mutations | ✓ | — | build it |
|
|
177
|
+
| Webhook signature verify + 5-min replay window | ✓ | client only | build it |
|
|
178
|
+
| Edge Runtime support | ✓ | Node-only | build it |
|
|
179
|
+
| Vercel KV adapters via subpath | ✓ | — | — |
|
|
180
|
+
| OpenTelemetry instrumentation + recipe | ✓ | — | build it |
|
|
181
|
+
| Circuit breaker + deadline propagation | ✓ | — | build it |
|
|
182
|
+
| Tool middleware (compose audit/rate/metrics) | ✓ | — | — |
|
|
183
|
+
| Time to first cobro | 30 min | 1+ week | 6-8 weeks |
|
|
184
|
+
|
|
185
|
+
See [`MIGRATION.md`](./MIGRATION.md) for a side-by-side `mercadopago` → `@ar-agents/mercadopago` migration guide.
|
|
186
|
+
|
|
187
|
+
## Security
|
|
188
|
+
|
|
189
|
+
This package handles money. Read [SECURITY.md](../../SECURITY.md) before deploying:
|
|
190
|
+
|
|
191
|
+
- The constructor refuses to instantiate in a browser context (token leak prevention).
|
|
192
|
+
- Every webhook handler MUST call `verifyWebhookSignature` before trusting payload contents.
|
|
193
|
+
- Irreversible tools (`refund_payment`, `cancel_*`, `delete_customer_card`) include explicit confirm-with-user instructions in their descriptions; the LLM should ask before calling.
|
|
194
|
+
- Report vulnerabilities privately per [SECURITY.md](../../SECURITY.md).
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
[MIT](./LICENSE) · © Nazareno Clemente
|
|
199
|
+
|
|
200
|
+
If this saves your team weeks of MP integration work, consider [sponsoring](https://github.com/sponsors/naza00000).
|