@402flow/sdk 0.1.0-alpha.6 → 0.1.0-alpha.8
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 +5 -3
- package/dist/challenge-detection.d.ts +7 -5
- package/dist/challenge-detection.js +54 -102
- package/dist/challenge-detection.js.map +1 -1
- package/dist/contracts.d.ts +148 -260
- package/dist/contracts.js +2 -4
- package/dist/contracts.js.map +1 -1
- package/dist/index.d.ts +22 -5
- package/dist/index.js +104 -16
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/challenge-types.d.ts +0 -57
- package/dist/challenge-types.js +0 -111
- package/dist/challenge-types.js.map +0 -1
- package/dist/x402-v1.d.ts +0 -4
- package/dist/x402-v1.js +0 -53
- package/dist/x402-v1.js.map +0 -1
- package/dist/x402-v2.d.ts +0 -4
- package/dist/x402-v2.js +0 -52
- package/dist/x402-v2.js.map +0 -1
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@ import { AgentPayClient } from '@402flow/sdk';
|
|
|
17
17
|
|
|
18
18
|
const client = new AgentPayClient({
|
|
19
19
|
controlPlaneBaseUrl: 'https://402flow.ai',
|
|
20
|
+
organization: 'acme-labs',
|
|
21
|
+
agent: 'reporting-worker',
|
|
20
22
|
auth: {
|
|
21
23
|
type: 'bootstrapKey',
|
|
22
24
|
bootstrapKey: process.env.AGENT_PAY_BOOTSTRAP_KEY ?? '',
|
|
@@ -24,11 +26,13 @@ const client = new AgentPayClient({
|
|
|
24
26
|
});
|
|
25
27
|
```
|
|
26
28
|
|
|
29
|
+
|
|
30
|
+
Create one `AgentPayClient` per agent identity. The client binds the organization and agent selectors up front, and `fetchPaid()` only carries request-specific context.
|
|
27
31
|
For most SDK integrations, `bootstrapKey` is the recommended auth mode. The SDK exchanges it for a short-lived runtime token, caches that token, and refreshes it automatically before expiry.
|
|
28
32
|
|
|
29
33
|
### fetchPaid()
|
|
30
34
|
|
|
31
|
-
Call `fetchPaid()` with the merchant URL, the outgoing request, and
|
|
35
|
+
Call `fetchPaid()` with the merchant URL, the outgoing request, and request-specific control-plane context.
|
|
32
36
|
|
|
33
37
|
```ts
|
|
34
38
|
try {
|
|
@@ -44,8 +48,6 @@ try {
|
|
|
44
48
|
}),
|
|
45
49
|
},
|
|
46
50
|
{
|
|
47
|
-
organization: 'acme-labs',
|
|
48
|
-
agent: 'reporting-worker',
|
|
49
51
|
paymentRail: 'base-usdc',
|
|
50
52
|
description: 'sync daily paid report',
|
|
51
53
|
idempotencyKey: 'daily-report-2026-03-25',
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type { PaidRequestProtocol } from './contracts.js';
|
|
2
|
+
export type DetectedChallenge = {
|
|
3
|
+
protocol: PaidRequestProtocol;
|
|
4
|
+
headers: Record<string, string>;
|
|
5
|
+
body?: unknown;
|
|
6
|
+
};
|
|
7
|
+
export declare function detectChallengeFromResponse(response: Response): Promise<DetectedChallenge | undefined>;
|
|
@@ -1,123 +1,75 @@
|
|
|
1
|
-
import { createParsedChallenge, getX402PaymentRequired, } from './challenge-types.js';
|
|
2
|
-
import { parseX402V1BodyChallenge, parseX402V1HeaderChallenge, parseX402V1PaymentResponseHeader, } from './x402-v1.js';
|
|
3
|
-
import { parseX402V2BodyChallenge, parseX402V2HeaderChallenge, parseX402V2PaymentResponseHeader, } from './x402-v2.js';
|
|
4
|
-
import { monetaryAmountToMinorUnits, normalizedMoneySchema } from './contracts.js';
|
|
5
1
|
export async function detectChallengeFromResponse(response) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
try {
|
|
23
|
-
const payload = await response.clone().json();
|
|
24
|
-
return parseBodyChallenge(payload);
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return undefined;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
export function parseX402PaymentResponseFromHeaders(headers) {
|
|
31
|
-
const headerMap = headers instanceof Headers ? headers : new Headers(headers);
|
|
32
|
-
const v2Header = headerMap.get('payment-response');
|
|
33
|
-
if (v2Header) {
|
|
34
|
-
return parseX402V2PaymentResponseHeader(v2Header);
|
|
35
|
-
}
|
|
36
|
-
const v1Header = headerMap.get('x-payment-response');
|
|
37
|
-
if (v1Header) {
|
|
38
|
-
return parseX402V1PaymentResponseHeader(v1Header);
|
|
2
|
+
const headers = captureHeaders(response.headers);
|
|
3
|
+
const protocol = sniffProtocolFromHeaders(headers);
|
|
4
|
+
if (protocol) {
|
|
5
|
+
const body = await tryReadJsonBody(response);
|
|
6
|
+
return body !== undefined
|
|
7
|
+
? { protocol, headers, body }
|
|
8
|
+
: { protocol, headers };
|
|
9
|
+
}
|
|
10
|
+
const body = await tryReadJsonBody(response);
|
|
11
|
+
if (body !== undefined) {
|
|
12
|
+
const bodyProtocol = sniffProtocolFromBody(body);
|
|
13
|
+
if (bodyProtocol) {
|
|
14
|
+
return { protocol: bodyProtocol, headers, body };
|
|
15
|
+
}
|
|
39
16
|
}
|
|
40
17
|
return undefined;
|
|
41
18
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
19
|
+
function captureHeaders(source) {
|
|
20
|
+
const headers = {};
|
|
21
|
+
source.forEach((value, key) => {
|
|
22
|
+
headers[key] = value;
|
|
23
|
+
});
|
|
24
|
+
return headers;
|
|
45
25
|
}
|
|
46
|
-
function
|
|
47
|
-
if (
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
const
|
|
51
|
-
if (
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const attributeName = match[1];
|
|
60
|
-
const attributeValue = match[2];
|
|
61
|
-
if (attributeName && attributeValue) {
|
|
62
|
-
attributes[attributeName.toLowerCase()] = attributeValue;
|
|
26
|
+
function sniffProtocolFromHeaders(headers) {
|
|
27
|
+
if (headers['payment-required']) {
|
|
28
|
+
return 'x402';
|
|
29
|
+
}
|
|
30
|
+
const paymentProtocol = headers['x-payment-protocol']?.toLowerCase();
|
|
31
|
+
if (paymentProtocol === 'x402' || paymentProtocol === 'l402') {
|
|
32
|
+
return paymentProtocol;
|
|
33
|
+
}
|
|
34
|
+
const authenticate = headers['www-authenticate'];
|
|
35
|
+
if (authenticate) {
|
|
36
|
+
const match = authenticate.match(/\b(x402|l402)\b/i);
|
|
37
|
+
if (match) {
|
|
38
|
+
return match[1].toLowerCase();
|
|
63
39
|
}
|
|
64
|
-
match = attributePattern.exec(headerValue);
|
|
65
|
-
}
|
|
66
|
-
if (!attributes.amount || !attributes.asset) {
|
|
67
|
-
return undefined;
|
|
68
40
|
}
|
|
69
|
-
return
|
|
70
|
-
protocol,
|
|
71
|
-
money: normalizedMoneySchema.parse({
|
|
72
|
-
asset: attributes.asset,
|
|
73
|
-
amount: attributes.amount,
|
|
74
|
-
amountMinor: monetaryAmountToMinorUnits(attributes.amount, Number(attributes.precision ?? '6')),
|
|
75
|
-
precision: Number(attributes.precision ?? '6'),
|
|
76
|
-
unit: 'minor',
|
|
77
|
-
}),
|
|
78
|
-
payee: attributes.payee,
|
|
79
|
-
raw: {
|
|
80
|
-
authenticate: headerValue,
|
|
81
|
-
},
|
|
82
|
-
});
|
|
41
|
+
return undefined;
|
|
83
42
|
}
|
|
84
|
-
function
|
|
43
|
+
function sniffProtocolFromBody(payload) {
|
|
85
44
|
if (!payload || typeof payload !== 'object') {
|
|
86
45
|
return undefined;
|
|
87
46
|
}
|
|
88
|
-
const candidate = 'challenge' in payload &&
|
|
47
|
+
const candidate = 'challenge' in payload &&
|
|
48
|
+
payload.challenge &&
|
|
49
|
+
typeof payload.challenge === 'object'
|
|
89
50
|
? payload.challenge
|
|
90
51
|
: payload;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return v2Challenge;
|
|
52
|
+
if ('x402Version' in candidate) {
|
|
53
|
+
return 'x402';
|
|
94
54
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
55
|
+
if ('protocol' in candidate && typeof candidate.protocol === 'string') {
|
|
56
|
+
const protocol = candidate.protocol.toLowerCase();
|
|
57
|
+
if (protocol === 'x402' || protocol === 'l402') {
|
|
58
|
+
return protocol;
|
|
59
|
+
}
|
|
98
60
|
}
|
|
99
|
-
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
async function tryReadJsonBody(response) {
|
|
64
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
65
|
+
if (!contentType.includes('application/json')) {
|
|
100
66
|
return undefined;
|
|
101
67
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const payee = 'payee' in candidate && typeof candidate.payee === 'string'
|
|
107
|
-
? candidate.payee
|
|
108
|
-
: undefined;
|
|
109
|
-
const raw = 'raw' in candidate && candidate.raw && typeof candidate.raw === 'object'
|
|
110
|
-
? candidate.raw
|
|
111
|
-
: undefined;
|
|
112
|
-
if ((protocol !== 'x402' && protocol !== 'l402') || !money) {
|
|
68
|
+
try {
|
|
69
|
+
return await response.clone().json();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
113
72
|
return undefined;
|
|
114
73
|
}
|
|
115
|
-
return createParsedChallenge({
|
|
116
|
-
protocol,
|
|
117
|
-
money: normalizedMoneySchema.parse(money),
|
|
118
|
-
payee,
|
|
119
|
-
raw: raw ?? candidate,
|
|
120
|
-
});
|
|
121
74
|
}
|
|
122
|
-
export { getX402PaymentRequired };
|
|
123
75
|
//# sourceMappingURL=challenge-detection.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"challenge-detection.js","sourceRoot":"","sources":["../src/challenge-detection.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"challenge-detection.js","sourceRoot":"","sources":["../src/challenge-detection.ts"],"names":[],"mappings":"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"}
|