@curless/agentbank-mcp-pay 0.1.0 → 0.2.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 +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +15 -4
- package/dist/agent.js.map +1 -1
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +22 -15
- package/dist/backend.js.map +1 -1
- package/dist/paywall.d.ts.map +1 -1
- package/dist/paywall.js +25 -9
- package/dist/paywall.js.map +1 -1
- package/dist/types.d.ts +3 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ import { withPaywall, createHttpBackend } from '@curless/agentbank-mcp-pay';
|
|
|
18
18
|
|
|
19
19
|
const backend = createHttpBackend({
|
|
20
20
|
baseUrl: 'https://api.agentbank…',
|
|
21
|
-
apiKey: process.env.AGENTBANK_KEY!, //
|
|
21
|
+
apiKey: process.env.AGENTBANK_KEY!, // agent:execute; verifies via merchant-scoped /verify
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
server.tool(
|
package/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAyC9C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAEhB,KAAK,EAAE,MAAM,CAAC;IAEd,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB,CAAC;AAKF,eAAO,MAAM,UAAU,GACrB,MAAM,WAAW,EACjB,MAAM,iBAAiB,KACtB,OAAO,CAAC;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAyC9C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAEhB,KAAK,EAAE,MAAM,CAAC;IAEd,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB,CAAC;AAKF,eAAO,MAAM,UAAU,GACrB,MAAM,WAAW,EACjB,MAAM,iBAAiB,KACtB,OAAO,CAAC;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,CA8CrC,CAAC"}
|
package/dist/agent.js
CHANGED
|
@@ -47,7 +47,13 @@ export const payMcpGate = async (gate, opts) => {
|
|
|
47
47
|
'content-type': 'application/json',
|
|
48
48
|
authorization: `Bearer ${opts.token}`,
|
|
49
49
|
};
|
|
50
|
-
|
|
50
|
+
// Include the gate's sku as the MPP reference (both on the challenge and
|
|
51
|
+
// the credential retry) so the payment is bound to this tool/call.
|
|
52
|
+
const body = JSON.stringify({
|
|
53
|
+
amount: gate.payment.amount,
|
|
54
|
+
currency: gate.payment.currency,
|
|
55
|
+
...(gate.payment.sku ? { reference: gate.payment.sku } : {}),
|
|
56
|
+
});
|
|
51
57
|
// 1. Unpaid → 402 + WWW-Authenticate: Payment challenge.
|
|
52
58
|
const challengeRes = await fetchImpl(url, { method: 'POST', headers, body });
|
|
53
59
|
if (challengeRes.status !== 402) {
|
|
@@ -68,10 +74,15 @@ export const payMcpGate = async (gate, opts) => {
|
|
|
68
74
|
headers: { ...headers, 'x-mpp-credential': credential },
|
|
69
75
|
body,
|
|
70
76
|
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
// Check status BEFORE parsing — a non-JSON error body (gateway 502 HTML)
|
|
78
|
+
// must surface as the real status, not a JSON parse error.
|
|
79
|
+
if (paidRes.status !== 200) {
|
|
80
|
+
const text = await paidRes.text().catch(() => '');
|
|
81
|
+
throw new Error(`MPP charge failed (${paidRes.status}): ${text}`);
|
|
74
82
|
}
|
|
83
|
+
const out = (await paidRes.json());
|
|
84
|
+
if (!out.paymentIntentId)
|
|
85
|
+
throw new Error('MPP charge response missing paymentIntentId');
|
|
75
86
|
return { paymentIntentId: out.paymentIntentId };
|
|
76
87
|
};
|
|
77
88
|
//# sourceMappingURL=agent.js.map
|
package/dist/agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGnE,8EAA8E;AAC9E,kEAAkE;AAClE,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,cAAc;AAEd,4DAA4D;AAC5D,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAU,EAAE;IACrC,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACvF,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1C,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC9E,CAAC,CAAC;AAIF,+EAA+E;AAC/E,MAAM,oBAAoB,GAAG,CAAC,MAAc,EAAmB,EAAE;IAC/D,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACnD,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAC7D,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,EAAE,GAAG,CAAC;YAAE,SAAS;QACrB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;aACb,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;aACb,IAAI,EAAE;aACN,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;aACjB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AAC3E,CAAC,CAAC;AAaF,uEAAuE;AACvE,6EAA6E;AAC7E,gCAAgC;AAChC,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAC7B,IAAiB,EACjB,IAAuB,EACe,EAAE;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC;IACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACjF,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;QAClC,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE;KACtC,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
|
package/dist/backend.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAsB,MAAM,yBAAyB,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAcjD,eAAO,MAAM,iBAAiB,GAAI,KAAK;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB,KAAG,cAuCH,CAAC"}
|
package/dist/backend.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { buildUrl, sendJson } from '@curless/agentbank-core';
|
|
2
|
-
// agentbank-backed paywall verification
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
2
|
+
// agentbank-backed paywall verification. Calls the merchant-scoped MPP verify
|
|
3
|
+
// endpoint (`POST /mpp/:merchantId/verify`) — scoped to (merchant, mode), NOT
|
|
4
|
+
// org — so a seller in a different org than the paying agent can still verify.
|
|
5
|
+
// The key needs `agent:execute` (or `agentbank:admin`); it never moves money.
|
|
6
6
|
export const createHttpBackend = (cfg) => {
|
|
7
7
|
const fetchImpl = cfg.fetch ?? fetch;
|
|
8
8
|
const baseUrl = cfg.baseUrl.replace(/\/+$/, '');
|
|
@@ -11,24 +11,31 @@ export const createHttpBackend = (cfg) => {
|
|
|
11
11
|
authorization: `Bearer ${cfg.apiKey}`,
|
|
12
12
|
};
|
|
13
13
|
return {
|
|
14
|
-
async verifyPayment({ paymentIntentId, merchantId, minAmount, currency }) {
|
|
15
|
-
let
|
|
14
|
+
async verifyPayment({ paymentIntentId, merchantId, minAmount, currency, expectedReference }) {
|
|
15
|
+
let v;
|
|
16
16
|
try {
|
|
17
|
-
|
|
17
|
+
v = await sendJson(fetchImpl, buildUrl(baseUrl, `/mpp/${encodeURIComponent(merchantId)}/verify`), 'POST', headers, { paymentIntentId });
|
|
18
18
|
}
|
|
19
19
|
catch (err) {
|
|
20
|
-
|
|
20
|
+
// 404 (wrong merchant/mode/unknown id) or transport error → not verified.
|
|
21
|
+
return { ok: false, reason: `verify failed: ${err.message}` };
|
|
21
22
|
}
|
|
22
|
-
if (
|
|
23
|
-
return { ok: false, reason:
|
|
24
|
-
if (pi.status !== 'captured' && pi.status !== 'settled' && pi.status !== 'reconciled') {
|
|
25
|
-
return { ok: false, reason: `payment not captured (status=${pi.status})` };
|
|
23
|
+
if (v.status !== 'captured' && v.status !== 'settled' && v.status !== 'reconciled') {
|
|
24
|
+
return { ok: false, reason: `payment not captured (status=${v.status})` };
|
|
26
25
|
}
|
|
27
|
-
if (
|
|
26
|
+
if (v.currency !== currency)
|
|
28
27
|
return { ok: false, reason: 'currency_mismatch' };
|
|
29
|
-
if (
|
|
28
|
+
if (v.amount < minAmount)
|
|
30
29
|
return { ok: false, reason: 'insufficient_amount' };
|
|
31
|
-
|
|
30
|
+
if (expectedReference && v.reference !== expectedReference) {
|
|
31
|
+
return { ok: false, reason: 'reference_mismatch' };
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
ok: true,
|
|
35
|
+
amount: v.amount,
|
|
36
|
+
currency: v.currency,
|
|
37
|
+
reference: v.reference ?? undefined,
|
|
38
|
+
};
|
|
32
39
|
},
|
|
33
40
|
};
|
|
34
41
|
};
|
package/dist/backend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,QAAQ,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAW7E,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAC/E,8EAA8E;AAC9E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAIjC,EAAkB,EAAE;IACnB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC;IACrC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG;QACd,cAAc,EAAE,kBAAkB;QAClC,aAAa,EAAE,UAAU,GAAG,CAAC,MAAM,EAAE;KACtC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,aAAa,CAAC,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE;YACzF,IAAI,CAAiB,CAAC;YACtB,IAAI,CAAC;gBACH,CAAC,GAAG,MAAM,QAAQ,CAChB,SAAS,EACT,QAAQ,CAAC,OAAO,EAAE,QAAQ,kBAAkB,CAAC,UAAU,CAAC,SAAS,CAAC,EAClE,MAAM,EACN,OAAO,EACP,EAAE,eAAe,EAAE,CACpB,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,0EAA0E;gBAC1E,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAmB,GAAa,CAAC,OAAO,EAAE,EAAE,CAAC;YAC3E,CAAC;YACD,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;gBACnF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gCAAgC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC;YAC5E,CAAC;YACD,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;YAC/E,IAAI,CAAC,CAAC,MAAM,GAAG,SAAS;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;YAC9E,IAAI,iBAAiB,IAAI,CAAC,CAAC,SAAS,KAAK,iBAAiB,EAAE,CAAC;gBAC3D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;YACrD,CAAC;YACD,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,SAAS;aACpC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/paywall.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paywall.d.ts","sourceRoot":"","sources":["../src/paywall.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EAGd,WAAW,EAEZ,MAAM,YAAY,CAAC;AAGpB,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"paywall.d.ts","sourceRoot":"","sources":["../src/paywall.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EAGd,WAAW,EAEZ,MAAM,YAAY,CAAC;AAGpB,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IAGjB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B,CAAC;AA4DF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrF,SAAS,WAAW,CAAC,CAAC,CAAC,EACvB,MAAM,kBAAkB,KACvB,WAAW,CAAC,CAAC,CAkCf,CAAC"}
|
package/dist/paywall.js
CHANGED
|
@@ -3,9 +3,11 @@ export const PAYMENT_ARG = '_agentbankPayment';
|
|
|
3
3
|
const inMemoryConsumed = () => {
|
|
4
4
|
const seen = new Set();
|
|
5
5
|
return {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
consume: (id) => {
|
|
7
|
+
if (seen.has(id))
|
|
8
|
+
return false;
|
|
8
9
|
seen.add(id);
|
|
10
|
+
return true;
|
|
9
11
|
},
|
|
10
12
|
};
|
|
11
13
|
};
|
|
@@ -35,11 +37,24 @@ const gate = (opts, note) => {
|
|
|
35
37
|
isError: false,
|
|
36
38
|
};
|
|
37
39
|
};
|
|
40
|
+
// Already-paid-and-used: tell the agent the call was already redeemed WITHOUT
|
|
41
|
+
// a payment_required gate, so it doesn't pay again (e.g. if the first
|
|
42
|
+
// response was lost in transit). Not an error.
|
|
43
|
+
const alreadyRedeemed = (paymentIntentId) => ({
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: 'text',
|
|
47
|
+
text: `Payment ${paymentIntentId} was already redeemed for this call — not charging again.`,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
structuredContent: { payment: { paymentIntentId, status: 'already_redeemed' } },
|
|
51
|
+
isError: false,
|
|
52
|
+
});
|
|
38
53
|
// Wrap an MCP tool handler with a per-call paywall. An unpaid call returns a
|
|
39
54
|
// payment gate; once the agent pays (via agentbank MPP) and retries with the
|
|
40
|
-
// PaymentIntent id, the payment is verified +
|
|
41
|
-
//
|
|
42
|
-
//
|
|
55
|
+
// PaymentIntent id, the payment is verified (merchant + amount + currency +
|
|
56
|
+
// the per-tool reference) and atomically consumed (single-use) before the
|
|
57
|
+
// real handler runs. agentbank's ledger + rail did the actual settlement.
|
|
43
58
|
export const withPaywall = (handler, opts) => {
|
|
44
59
|
const consumed = opts.consumed ?? inMemoryConsumed();
|
|
45
60
|
return async (args) => {
|
|
@@ -47,18 +62,19 @@ export const withPaywall = (handler, opts) => {
|
|
|
47
62
|
if (!proof?.paymentIntentId)
|
|
48
63
|
return gate(opts);
|
|
49
64
|
const pi = proof.paymentIntentId;
|
|
50
|
-
if (await consumed.has(pi))
|
|
51
|
-
return gate(opts, `payment ${pi} was already used — pay again`);
|
|
52
65
|
const verdict = await opts.backend.verifyPayment({
|
|
53
66
|
paymentIntentId: pi,
|
|
54
67
|
merchantId: opts.merchantId,
|
|
55
68
|
minAmount: opts.price,
|
|
56
69
|
currency: opts.currency,
|
|
70
|
+
expectedReference: opts.sku,
|
|
57
71
|
});
|
|
58
72
|
if (!verdict.ok)
|
|
59
73
|
return gate(opts, verdict.reason ?? 'payment could not be verified');
|
|
60
|
-
//
|
|
61
|
-
|
|
74
|
+
// Atomic single-use: only the first redemption runs the handler. A replay
|
|
75
|
+
// (e.g. lost response) gets "already redeemed", not a re-payment prompt.
|
|
76
|
+
if (!(await consumed.consume(pi)))
|
|
77
|
+
return alreadyRedeemed(pi);
|
|
62
78
|
const result = await handler(args);
|
|
63
79
|
return {
|
|
64
80
|
...result,
|
package/dist/paywall.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paywall.js","sourceRoot":"","sources":["../src/paywall.ts"],"names":[],"mappings":"AASA,2EAA2E;AAC3E,MAAM,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"paywall.js","sourceRoot":"","sources":["../src/paywall.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -32,15 +32,16 @@ export type PaywallBackend = {
|
|
|
32
32
|
merchantId: string;
|
|
33
33
|
minAmount: number;
|
|
34
34
|
currency: string;
|
|
35
|
+
expectedReference?: string;
|
|
35
36
|
}): Promise<{
|
|
36
37
|
ok: boolean;
|
|
37
38
|
amount?: number;
|
|
38
39
|
currency?: string;
|
|
40
|
+
reference?: string;
|
|
39
41
|
reason?: string;
|
|
40
42
|
}>;
|
|
41
43
|
};
|
|
42
44
|
export type ConsumedStore = {
|
|
43
|
-
|
|
44
|
-
add(id: string): void | Promise<void>;
|
|
45
|
+
consume(id: string): boolean | Promise<boolean>;
|
|
45
46
|
};
|
|
46
47
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IACxF,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CACrD,IAAI,EAAE,CAAC,KACJ,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC;AAKtC,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,KAAK,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAGF,MAAM,MAAM,YAAY,GAAG;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IACxF,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CACrD,IAAI,EAAE,CAAC,KACJ,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC;AAKtC,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,KAAK,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAGF,MAAM,MAAM,YAAY,GAAG;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC;AAMvD,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,CAAC,KAAK,EAAE;QACnB,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,GAAG,OAAO,CAAC;QACV,EAAE,EAAE,OAAO,CAAC;QACZ,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACJ,CAAC;AAOF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACjD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@curless/agentbank-mcp-pay",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Paywall an MCP tool / API so AI agents pay per call. Wrap a tool handler with withPaywall(): unpaid calls return a payment gate, the agent pays via agentbank (MPP/HTTP-402), and the call runs once payment is verified. Settles down to agentbank's ledger + rails (card / stablecoin / Curless).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|