mppx 0.3.4 → 0.3.5
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 +0 -52
- package/dist/Challenge.d.ts +8 -0
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +20 -4
- package/dist/Challenge.js.map +1 -1
- package/dist/cli.js +193 -66
- package/dist/cli.js.map +1 -1
- package/dist/server/Mppx.d.ts +2 -0
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +4 -3
- package/dist/server/Mppx.js.map +1 -1
- package/package.json +1 -1
- package/src/Challenge.test.ts +201 -11
- package/src/Challenge.ts +34 -4
- package/src/Store.test.ts +93 -0
- package/src/cli.test.ts +233 -37
- package/src/cli.ts +229 -79
- package/src/client/Transport.test.ts +4 -4
- package/src/internal/env.test.ts +42 -0
- package/src/server/Mppx.test.ts +173 -0
- package/src/server/Mppx.ts +6 -3
- package/src/server/Transport.test.ts +5 -5
- package/src/tempo/server/Session.test.ts +52 -0
- package/src/tempo/server/internal/transport.test.ts +285 -0
package/README.md
CHANGED
|
@@ -78,58 +78,6 @@ mppx account create
|
|
|
78
78
|
mppx example.com
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
<details>
|
|
82
|
-
<summary><code>mppx --help</code></summary>
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
mppx/0.1.0
|
|
86
|
-
|
|
87
|
-
Usage:
|
|
88
|
-
$ mppx [url]
|
|
89
|
-
|
|
90
|
-
Commands:
|
|
91
|
-
[url] Make HTTP request with automatic payment
|
|
92
|
-
account [action] Manage accounts (create, default, delete, fund, list, view)
|
|
93
|
-
|
|
94
|
-
For more info, run any command with the `--help` flag:
|
|
95
|
-
$ mppx --help
|
|
96
|
-
$ mppx account --help
|
|
97
|
-
|
|
98
|
-
Actions:
|
|
99
|
-
create Create new account
|
|
100
|
-
default Set default account
|
|
101
|
-
delete Delete account
|
|
102
|
-
fund Fund account with testnet tokens
|
|
103
|
-
list List all accounts
|
|
104
|
-
view View account address
|
|
105
|
-
|
|
106
|
-
Options:
|
|
107
|
-
-a, --account <name> Account name (env: MPPX_ACCOUNT)
|
|
108
|
-
-d, --data <data> Send request body (implies POST unless -X is set)
|
|
109
|
-
-f, --fail Fail silently on HTTP errors (exit 22)
|
|
110
|
-
-i, --include Include response headers in output
|
|
111
|
-
-k, --insecure Skip TLS certificate verification (true for localhost/.local)
|
|
112
|
-
-r, --rpc-url <url> RPC endpoint, defaults to public RPC for chain (env: MPPX_RPC_URL)
|
|
113
|
-
-s, --silent Silent mode (suppress progress and info)
|
|
114
|
-
-v, --verbose Show request/response headers
|
|
115
|
-
-A, --user-agent <ua> Set User-Agent header
|
|
116
|
-
-H, --header <header> Add header (repeatable)
|
|
117
|
-
-L, --location Follow redirects
|
|
118
|
-
-X, --method <method> HTTP method
|
|
119
|
-
--channel <id> Reuse existing stream channel ID
|
|
120
|
-
--deposit <amount> Deposit amount for stream payments (human-readable units)
|
|
121
|
-
--json <json> Send JSON body (sets Content-Type and Accept, implies POST)
|
|
122
|
-
--yes Skip confirmation prompts
|
|
123
|
-
-V, --version Display version number
|
|
124
|
-
-h, --help Display this message
|
|
125
|
-
|
|
126
|
-
Examples:
|
|
127
|
-
mppx example.com/content
|
|
128
|
-
mppx example.com/api --json '{"key":"value"}'
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
</details>
|
|
132
|
-
|
|
133
81
|
You can also install globally to use the `mppx` CLI from anywhere:
|
|
134
82
|
|
|
135
83
|
```bash
|
package/dist/Challenge.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export declare const Schema: z.ZodMiniObject<{
|
|
|
25
25
|
intent: z.ZodMiniString<string>;
|
|
26
26
|
/** Payment method (e.g., "tempo", "stripe"). */
|
|
27
27
|
method: z.ZodMiniString<string>;
|
|
28
|
+
/** Optional server-defined correlation data. Flat string-to-string map; clients MUST NOT modify. */
|
|
29
|
+
opaque: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniString<string>>>;
|
|
28
30
|
/** Server realm (e.g., hostname). */
|
|
29
31
|
realm: z.ZodMiniString<string>;
|
|
30
32
|
/** Method-specific request data. */
|
|
@@ -113,6 +115,8 @@ export declare namespace from {
|
|
|
113
115
|
expires?: string | undefined;
|
|
114
116
|
/** Intent type (e.g., "charge", "session"). */
|
|
115
117
|
intent: string;
|
|
118
|
+
/** Optional server-defined correlation data (serialized as `opaque` on the challenge). Flat string-to-string map; clients MUST NOT modify. */
|
|
119
|
+
meta?: Record<string, string> | undefined;
|
|
116
120
|
/** Payment method (e.g., "tempo", "stripe"). */
|
|
117
121
|
method: string;
|
|
118
122
|
/** Server realm (e.g., hostname). */
|
|
@@ -169,6 +173,8 @@ export declare namespace fromMethod {
|
|
|
169
173
|
digest?: string | undefined;
|
|
170
174
|
/** Optional expiration timestamp (ISO 8601). */
|
|
171
175
|
expires?: string | undefined;
|
|
176
|
+
/** Optional server-defined correlation data (serialized as `opaque` on the challenge). Flat string-to-string map; clients MUST NOT modify. */
|
|
177
|
+
meta?: Record<string, string> | undefined;
|
|
172
178
|
/** Server realm (e.g., hostname). */
|
|
173
179
|
realm: string;
|
|
174
180
|
/** Method-specific request data. */
|
|
@@ -268,4 +274,6 @@ export declare namespace verify {
|
|
|
268
274
|
secretKey: string;
|
|
269
275
|
};
|
|
270
276
|
}
|
|
277
|
+
/** Alias for `challenge.opaque`. Extracts server-defined correlation data from a challenge. */
|
|
278
|
+
export declare function meta(challenge: Challenge): Record<string, string> | undefined;
|
|
271
279
|
//# sourceMappingURL=Challenge.d.ts.map
|
package/dist/Challenge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Challenge.d.ts","sourceRoot":"","sources":["../src/Challenge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,KAAK,MAAM,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAE7B;;;;;;;;;GASG;AACH,eAAO,MAAM,MAAM;IACjB,0DAA0D;;IAE1D,0EAA0E;;IAE1E,gDAAgD;;IAEhD,gDAAgD;;IAEhD,+CAA+C;;IAE/C,gDAAgD;;IAEhD,qCAAqC;;IAErC,oCAAoC;;iBAEpC,CAAA;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,SAAS,CACnB,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,MAAM,SAAS,MAAM,GAAG,MAAM,IAC5B,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC,GAAG;IAClE,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,OAAO,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,IAAI;KACjE,MAAM,IAAI,MAAM,OAAO,GAAG,SAAS,CAClC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,EAC9C,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EACzB,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CACxB;CACF,CAAC,MAAM,CAAC,CAAA;AAET;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,IAAI,CAClB,KAAK,CAAC,UAAU,SAAS,IAAI,CAAC,UAAU,EACxC,KAAK,CAAC,OAAO,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,SAAS,GAAG,SAAS,EACtE,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"Challenge.d.ts","sourceRoot":"","sources":["../src/Challenge.ts"],"names":[],"mappings":"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"}
|
package/dist/Challenge.js
CHANGED
|
@@ -24,6 +24,8 @@ export const Schema = z.object({
|
|
|
24
24
|
intent: z.string(),
|
|
25
25
|
/** Payment method (e.g., "tempo", "stripe"). */
|
|
26
26
|
method: z.string(),
|
|
27
|
+
/** Optional server-defined correlation data. Flat string-to-string map; clients MUST NOT modify. */
|
|
28
|
+
opaque: z.optional(z.record(z.string(), z.string())),
|
|
27
29
|
/** Server realm (e.g., hostname). */
|
|
28
30
|
realm: z.string(),
|
|
29
31
|
/** Method-specific request data. */
|
|
@@ -67,10 +69,10 @@ export const Schema = z.object({
|
|
|
67
69
|
*/
|
|
68
70
|
export function from(parameters, options) {
|
|
69
71
|
void options;
|
|
70
|
-
const { description, digest, method: methodName, intent, realm, request, secretKey } = parameters;
|
|
72
|
+
const { description, digest, meta, method: methodName, intent, realm, request, secretKey, } = parameters;
|
|
71
73
|
const expires = (parameters.expires ?? request.expires);
|
|
72
74
|
const id = secretKey
|
|
73
|
-
? computeId({ ...parameters, expires }, { secretKey })
|
|
75
|
+
? computeId({ ...parameters, expires, ...(meta && { opaque: meta }) }, { secretKey })
|
|
74
76
|
: parameters.id;
|
|
75
77
|
return Schema.parse({
|
|
76
78
|
id,
|
|
@@ -81,6 +83,7 @@ export function from(parameters, options) {
|
|
|
81
83
|
...(description && { description }),
|
|
82
84
|
...(digest && { digest }),
|
|
83
85
|
...(expires && { expires }),
|
|
86
|
+
...(meta && { opaque: meta }),
|
|
84
87
|
});
|
|
85
88
|
}
|
|
86
89
|
/**
|
|
@@ -117,7 +120,7 @@ export function from(parameters, options) {
|
|
|
117
120
|
*/
|
|
118
121
|
export function fromMethod(method, parameters) {
|
|
119
122
|
const { name: methodName, intent } = method;
|
|
120
|
-
const { description, digest, expires, id, realm, secretKey } = parameters;
|
|
123
|
+
const { description, digest, expires, id, meta, realm, secretKey } = parameters;
|
|
121
124
|
const request = PaymentRequest.fromMethod(method, parameters.request);
|
|
122
125
|
return from({
|
|
123
126
|
...(id ? { id } : { secretKey }),
|
|
@@ -128,6 +131,7 @@ export function fromMethod(method, parameters) {
|
|
|
128
131
|
description,
|
|
129
132
|
digest,
|
|
130
133
|
expires,
|
|
134
|
+
meta,
|
|
131
135
|
});
|
|
132
136
|
}
|
|
133
137
|
/**
|
|
@@ -158,6 +162,8 @@ export function serialize(challenge) {
|
|
|
158
162
|
parts.push(`digest="${challenge.digest}"`);
|
|
159
163
|
if (challenge.expires !== undefined)
|
|
160
164
|
parts.push(`expires="${challenge.expires}"`);
|
|
165
|
+
if (challenge.opaque !== undefined)
|
|
166
|
+
parts.push(`opaque="${PaymentRequest.serialize(challenge.opaque)}"`);
|
|
161
167
|
return `Payment ${parts.join(', ')}`;
|
|
162
168
|
}
|
|
163
169
|
/**
|
|
@@ -192,12 +198,13 @@ export function deserialize(value, options) {
|
|
|
192
198
|
result[key] = value;
|
|
193
199
|
}
|
|
194
200
|
}
|
|
195
|
-
const { request, ...rest } = result;
|
|
201
|
+
const { request, opaque, ...rest } = result;
|
|
196
202
|
if (!request)
|
|
197
203
|
throw new Error('Missing request parameter.');
|
|
198
204
|
return from({
|
|
199
205
|
...rest,
|
|
200
206
|
request: PaymentRequest.deserialize(request),
|
|
207
|
+
...(opaque && { meta: PaymentRequest.deserialize(opaque) }),
|
|
201
208
|
}, options);
|
|
202
209
|
}
|
|
203
210
|
/**
|
|
@@ -265,8 +272,16 @@ export function verify(challenge, options) {
|
|
|
265
272
|
const expectedId = computeId(challenge, options);
|
|
266
273
|
return constantTimeEqual(challenge.id, expectedId);
|
|
267
274
|
}
|
|
275
|
+
/** Alias for `challenge.opaque`. Extracts server-defined correlation data from a challenge. */
|
|
276
|
+
export function meta(challenge) {
|
|
277
|
+
return challenge.opaque;
|
|
278
|
+
}
|
|
268
279
|
/** @internal Computes HMAC-SHA256 challenge ID from parameters. */
|
|
269
280
|
function computeId(challenge, options) {
|
|
281
|
+
// Each field occupies a fixed positional slot joined by '|'. Optional fields
|
|
282
|
+
// use an empty string when absent so the slot count is stable — this avoids
|
|
283
|
+
// ambiguity between e.g. (expires set, no digest) vs (no expires, digest set)
|
|
284
|
+
// and means adding a new optional field changes all HMACs exactly once.
|
|
270
285
|
const input = [
|
|
271
286
|
challenge.realm,
|
|
272
287
|
challenge.method,
|
|
@@ -274,6 +289,7 @@ function computeId(challenge, options) {
|
|
|
274
289
|
PaymentRequest.serialize(challenge.request),
|
|
275
290
|
challenge.expires ?? '',
|
|
276
291
|
challenge.digest ?? '',
|
|
292
|
+
challenge.opaque ? PaymentRequest.serialize(challenge.opaque) : '',
|
|
277
293
|
].join('|');
|
|
278
294
|
const key = Bytes.fromString(options.secretKey);
|
|
279
295
|
const data = Bytes.fromString(input);
|
package/dist/Challenge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Challenge.js","sourceRoot":"","sources":["../src/Challenge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAGxC,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAE7B;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,0DAA0D;IAC1D,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACnC,0EAA0E;IAC1E,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC,CAAC;IACnF,gDAAgD;IAChD,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACjC,gDAAgD;IAChD,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,+CAA+C;IAC/C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,gDAAgD;IAChD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,qCAAqC;IACrC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,oCAAoC;IACpC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;CAC3C,CAAC,CAAA;AAuCF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,UAAU,IAAI,CAGlB,UAAsB,EAAE,OAA+B;IACvD,KAAK,OAAO,CAAA;IACZ,MAAM,
|
|
1
|
+
{"version":3,"file":"Challenge.js","sourceRoot":"","sources":["../src/Challenge.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -14,6 +14,7 @@ import { z } from 'zod/mini';
|
|
|
14
14
|
import * as Challenge from './Challenge.js';
|
|
15
15
|
import * as Credential from './Credential.js';
|
|
16
16
|
import * as Mppx from './client/Mppx.js';
|
|
17
|
+
import { stripe } from './stripe/client/index.js';
|
|
17
18
|
import { tempo } from './tempo/client/index.js';
|
|
18
19
|
import { signVoucher } from './tempo/session/Voucher.js';
|
|
19
20
|
const require = createRequire(import.meta.url);
|
|
@@ -33,19 +34,16 @@ cli
|
|
|
33
34
|
.option('-H, --header <header>', 'Add header (repeatable)')
|
|
34
35
|
.option('-L, --location', 'Follow redirects')
|
|
35
36
|
.option('-X, --method <method>', 'HTTP method')
|
|
36
|
-
.option('--
|
|
37
|
+
.option('-M, --method-opt <opt>', 'Method-specific option (key=value, repeatable)')
|
|
37
38
|
.option('--confirm', 'Show confirmation prompts')
|
|
38
|
-
.option('--deposit <amount>', 'Deposit amount for session payments (human-readable units)')
|
|
39
39
|
.option('--json <json>', 'Send JSON body (sets Content-Type and Accept, implies POST)')
|
|
40
40
|
.example(`${name} example.com/content`)
|
|
41
41
|
.example(`${name} example.com/api --json '{"key":"value"}'`)
|
|
42
42
|
.action(async (rawUrl, rawOptions) => {
|
|
43
43
|
const options = parseOptions(z.object({
|
|
44
44
|
account: z.optional(z.string()),
|
|
45
|
-
channel: z.optional(z.coerce.string()),
|
|
46
45
|
confirm: z.optional(z.boolean()),
|
|
47
46
|
data: z.optional(z.string()),
|
|
48
|
-
deposit: z.optional(z.union([z.string(), z.number()])),
|
|
49
47
|
fail: z.optional(z.boolean()),
|
|
50
48
|
header: z.optional(z.union([z.string(), z.array(z.string())])),
|
|
51
49
|
include: z.optional(z.boolean()),
|
|
@@ -53,11 +51,13 @@ cli
|
|
|
53
51
|
json: z.optional(z.string()),
|
|
54
52
|
location: z.optional(z.boolean()),
|
|
55
53
|
method: z.optional(z.string()),
|
|
54
|
+
methodOpt: z.optional(z.union([z.string(), z.array(z.string())])),
|
|
56
55
|
rpcUrl: z.optional(z.string()),
|
|
57
56
|
silent: z.optional(z.boolean()),
|
|
58
57
|
userAgent: z.optional(z.string()),
|
|
59
58
|
verbose: z.optional(z.boolean()),
|
|
60
59
|
}), rawOptions);
|
|
60
|
+
const methodOpts = parseMethodOpts(options.methodOpt);
|
|
61
61
|
if (!rawUrl) {
|
|
62
62
|
cli.outputHelp();
|
|
63
63
|
return;
|
|
@@ -67,14 +67,6 @@ cli
|
|
|
67
67
|
if (silent)
|
|
68
68
|
options.confirm = false;
|
|
69
69
|
const accountName = resolveAccountName(options.account);
|
|
70
|
-
const privateKey = process.env.MPPX_PRIVATE_KEY || (await createKeychain(accountName).get());
|
|
71
|
-
if (!privateKey) {
|
|
72
|
-
if (options.account)
|
|
73
|
-
console.log(`Account "${accountName}" not found.`);
|
|
74
|
-
else
|
|
75
|
-
console.log(`No account found.`);
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
78
70
|
const headers = {};
|
|
79
71
|
if (options.header) {
|
|
80
72
|
const headerList = Array.isArray(options.header) ? options.header : [options.header];
|
|
@@ -148,22 +140,39 @@ cli
|
|
|
148
140
|
console.log((await challengeResponse.text()).replace(/\n+$/, ''));
|
|
149
141
|
return;
|
|
150
142
|
}
|
|
151
|
-
const account = privateKeyToAccount(privateKey);
|
|
152
|
-
const rpcUrl = options.rpcUrl ?? (process.env.MPPX_RPC_URL || undefined);
|
|
153
|
-
const client = createClient({
|
|
154
|
-
chain: await resolveChain({ ...options, rpcUrl }),
|
|
155
|
-
transport: http(rpcUrl),
|
|
156
|
-
});
|
|
157
143
|
const challenge = Challenge.fromResponse(challengeResponse);
|
|
158
|
-
const explorerUrl = client.chain?.blockExplorers?.default?.url;
|
|
159
|
-
const shownKeys = new Set();
|
|
160
144
|
const challengeRequest = challenge.request;
|
|
161
145
|
const currency = challengeRequest.currency;
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
146
|
+
const shownKeys = new Set();
|
|
147
|
+
let tokenSymbol = challenge.method === 'stripe' ? (currency?.toUpperCase() ?? '') : (currency ?? '');
|
|
148
|
+
let tokenDecimals = challengeRequest.decimals ?? (challenge.method === 'stripe' ? 2 : 6);
|
|
149
|
+
let explorerUrl;
|
|
150
|
+
// Tempo-specific setup (private key, viem account/client, token info)
|
|
151
|
+
let account;
|
|
152
|
+
let client;
|
|
153
|
+
if (challenge.method === 'tempo') {
|
|
154
|
+
const privateKey = process.env.MPPX_PRIVATE_KEY ?? (await createKeychain(accountName).get());
|
|
155
|
+
if (!privateKey) {
|
|
156
|
+
if (options.account)
|
|
157
|
+
console.error(`Account "${accountName}" not found.`);
|
|
158
|
+
else
|
|
159
|
+
console.error(`No account found.`);
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
account = privateKeyToAccount(privateKey);
|
|
163
|
+
const rpcUrl = options.rpcUrl ?? process.env.RPC_URL;
|
|
164
|
+
client = createClient({
|
|
165
|
+
chain: await resolveChain({ ...options, rpcUrl }),
|
|
166
|
+
transport: http(rpcUrl),
|
|
167
|
+
});
|
|
168
|
+
explorerUrl = client.chain?.blockExplorers?.default?.url;
|
|
169
|
+
const tokenInfo = currency
|
|
170
|
+
? await fetchTokenInfo(client, currency, account.address).catch(() => undefined)
|
|
171
|
+
: undefined;
|
|
172
|
+
tokenSymbol = tokenInfo?.symbol ?? currency ?? '';
|
|
173
|
+
tokenDecimals =
|
|
174
|
+
tokenInfo?.decimals ?? challengeRequest.decimals ?? 6;
|
|
175
|
+
}
|
|
167
176
|
{
|
|
168
177
|
printResponseHeaders(challengeResponse);
|
|
169
178
|
const request = challengeRequest;
|
|
@@ -266,37 +275,126 @@ cli
|
|
|
266
275
|
}
|
|
267
276
|
}
|
|
268
277
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
};
|
|
299
|
-
|
|
278
|
+
let credential;
|
|
279
|
+
if (challenge.method === 'tempo') {
|
|
280
|
+
if (!account || !client) {
|
|
281
|
+
console.error('Tempo requires a configured account.');
|
|
282
|
+
process.exit(1);
|
|
283
|
+
}
|
|
284
|
+
const tempoOpts = parseOptions(z.object({
|
|
285
|
+
channel: z.optional(z.coerce.string()),
|
|
286
|
+
deposit: z.optional(z.union([z.string(), z.number()])),
|
|
287
|
+
}), methodOpts);
|
|
288
|
+
const mppx = Mppx.create({
|
|
289
|
+
methods: tempo({
|
|
290
|
+
account,
|
|
291
|
+
getClient: () => client,
|
|
292
|
+
deposit: (() => {
|
|
293
|
+
if (challenge.intent !== 'session')
|
|
294
|
+
return undefined;
|
|
295
|
+
const suggestedDeposit = challenge.request
|
|
296
|
+
.suggestedDeposit;
|
|
297
|
+
const cliDeposit = tempoOpts.deposit !== undefined ? String(tempoOpts.deposit) : undefined;
|
|
298
|
+
const resolved = suggestedDeposit ?? cliDeposit ?? (isTestnet(client.chain) ? '10' : undefined);
|
|
299
|
+
if (!resolved) {
|
|
300
|
+
console.error('Session payment requires a deposit. Use -M deposit=<amount> or connect to testnet.');
|
|
301
|
+
process.exit(1);
|
|
302
|
+
}
|
|
303
|
+
return resolved;
|
|
304
|
+
})(),
|
|
305
|
+
}),
|
|
306
|
+
polyfill: false,
|
|
307
|
+
});
|
|
308
|
+
credential = await mppx.createCredential(challengeResponse, (() => {
|
|
309
|
+
if (!tempoOpts.channel)
|
|
310
|
+
return undefined;
|
|
311
|
+
const channelId = tempoOpts.channel;
|
|
312
|
+
const saved = readChannelCumulative(channelId);
|
|
313
|
+
return {
|
|
314
|
+
channelId,
|
|
315
|
+
...(saved !== undefined && { cumulativeAmountRaw: saved.toString() }),
|
|
316
|
+
};
|
|
317
|
+
})());
|
|
318
|
+
}
|
|
319
|
+
else if (challenge.method === 'stripe') {
|
|
320
|
+
const stripeOpts = parseOptions(z.object({
|
|
321
|
+
paymentMethod: z.string(),
|
|
322
|
+
}), methodOpts);
|
|
323
|
+
const stripeSecretKey = process.env.MPPX_STRIPE_SECRET_KEY;
|
|
324
|
+
if (!stripeSecretKey) {
|
|
325
|
+
console.error('\nMPPX_STRIPE_SECRET_KEY environment variable is required for Stripe payments.');
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
if (!stripeSecretKey.startsWith('sk_test_')) {
|
|
329
|
+
console.error('\nStripe CLI payments are currently only supported in test mode (sk_test_... keys).');
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
|
332
|
+
const mppx = Mppx.create({
|
|
333
|
+
methods: [
|
|
334
|
+
stripe.charge({
|
|
335
|
+
paymentMethod: stripeOpts.paymentMethod,
|
|
336
|
+
createToken: async ({ paymentMethod, amount, currency, networkId, expiresAt, metadata, }) => {
|
|
337
|
+
const body = new URLSearchParams({
|
|
338
|
+
payment_method: paymentMethod,
|
|
339
|
+
'usage_limits[currency]': currency,
|
|
340
|
+
'usage_limits[max_amount]': amount,
|
|
341
|
+
'usage_limits[expires_at]': expiresAt.toString(),
|
|
342
|
+
});
|
|
343
|
+
if (networkId)
|
|
344
|
+
body.set('seller_details[network_id]', networkId);
|
|
345
|
+
if (metadata) {
|
|
346
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
347
|
+
body.set(`metadata[${key}]`, value);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const sptUrl = process.env.MPPX_STRIPE_SPT_URL ??
|
|
351
|
+
'https://api.stripe.com/v1/test_helpers/shared_payment/granted_tokens';
|
|
352
|
+
const sptHeaders = {
|
|
353
|
+
Authorization: `Basic ${btoa(`${stripeSecretKey}:`)}`,
|
|
354
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
355
|
+
};
|
|
356
|
+
let response = await globalThis.fetch(sptUrl, {
|
|
357
|
+
method: 'POST',
|
|
358
|
+
headers: sptHeaders,
|
|
359
|
+
body,
|
|
360
|
+
});
|
|
361
|
+
if (!response.ok) {
|
|
362
|
+
const errorBody = (await response.json());
|
|
363
|
+
if ((metadata || networkId) &&
|
|
364
|
+
errorBody.error.message.includes('Received unknown parameter')) {
|
|
365
|
+
const fallbackBody = new URLSearchParams({
|
|
366
|
+
payment_method: paymentMethod,
|
|
367
|
+
'usage_limits[currency]': currency,
|
|
368
|
+
'usage_limits[max_amount]': amount,
|
|
369
|
+
'usage_limits[expires_at]': expiresAt.toString(),
|
|
370
|
+
});
|
|
371
|
+
response = await globalThis.fetch(sptUrl, {
|
|
372
|
+
method: 'POST',
|
|
373
|
+
headers: sptHeaders,
|
|
374
|
+
body: fallbackBody,
|
|
375
|
+
});
|
|
376
|
+
if (!response.ok) {
|
|
377
|
+
const fallbackError = (await response.json());
|
|
378
|
+
throw new Error(`Failed to create SPT: ${fallbackError.error.message}`);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
throw new Error(`Failed to create SPT: ${errorBody.error.message}`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const { id } = (await response.json());
|
|
386
|
+
return id;
|
|
387
|
+
},
|
|
388
|
+
}),
|
|
389
|
+
],
|
|
390
|
+
polyfill: false,
|
|
391
|
+
});
|
|
392
|
+
credential = await mppx.createCredential(challengeResponse);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
console.error(`Unsupported payment method: ${challenge.method}`);
|
|
396
|
+
process.exit(1);
|
|
397
|
+
}
|
|
300
398
|
const sessionMd = challenge.request.methodDetails;
|
|
301
399
|
let sessionChannelId;
|
|
302
400
|
let sessionEscrowContract;
|
|
@@ -305,16 +403,21 @@ cli
|
|
|
305
403
|
if (challenge.intent === 'session') {
|
|
306
404
|
const parsed = Credential.deserialize(credential);
|
|
307
405
|
sessionChannelId = parsed.payload.channelId;
|
|
308
|
-
sessionChainId = sessionMd?.chainId ?? client
|
|
406
|
+
sessionChainId = sessionMd?.chainId ?? client?.chain?.id ?? 0;
|
|
309
407
|
sessionEscrowContract = sessionMd?.escrowContract;
|
|
310
408
|
if ('cumulativeAmount' in parsed.payload && parsed.payload.cumulativeAmount)
|
|
311
409
|
sessionCumulativeAmount = BigInt(parsed.payload.cumulativeAmount);
|
|
312
410
|
if (parsed.payload.action === 'open') {
|
|
313
|
-
const depositRaw = challengeRequest.suggestedDeposit
|
|
411
|
+
const depositRaw = challengeRequest.suggestedDeposit;
|
|
314
412
|
const depositDisplay = depositRaw
|
|
315
413
|
? ` ${pc.dim(`(deposit ${depositRaw} ${tokenSymbol})`)}`
|
|
316
414
|
: '';
|
|
317
|
-
|
|
415
|
+
const prefix = options.confirm ? '' : '\n';
|
|
416
|
+
info(`${prefix}${pc.dim(`Channel opened ${parsed.payload.channelId}`)}${depositDisplay}\n`);
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
const prefix = options.confirm ? '' : '\n';
|
|
420
|
+
info(`${prefix}${pc.dim(`Channel reused ${parsed.payload.channelId}`)}\n`);
|
|
318
421
|
}
|
|
319
422
|
}
|
|
320
423
|
const credentialFetchInit = {
|
|
@@ -381,6 +484,14 @@ cli
|
|
|
381
484
|
explorerUrl) {
|
|
382
485
|
rows.push([key, pc.link(`${explorerUrl}/tx/${value}`, value)]);
|
|
383
486
|
}
|
|
487
|
+
else if (key === 'reference' &&
|
|
488
|
+
typeof value === 'string' &&
|
|
489
|
+
challenge.method === 'stripe' &&
|
|
490
|
+
value.startsWith('pi_')) {
|
|
491
|
+
const isTest = process.env.MPPX_STRIPE_SECRET_KEY?.startsWith('sk_test_');
|
|
492
|
+
const dashboardUrl = `https://dashboard.stripe.com${isTest ? '/test' : ''}/payments/${value}`;
|
|
493
|
+
rows.push([key, pc.link(dashboardUrl, value)]);
|
|
494
|
+
}
|
|
384
495
|
else
|
|
385
496
|
rows.push([key, String(value)]);
|
|
386
497
|
}
|
|
@@ -407,7 +518,7 @@ cli
|
|
|
407
518
|
: undefined;
|
|
408
519
|
const channelId = sessionCred?.payload.channelId;
|
|
409
520
|
const md = challenge.request.methodDetails;
|
|
410
|
-
const sessionChainId = md?.chainId ?? client
|
|
521
|
+
const sessionChainId = md?.chainId ?? client?.chain?.id ?? 0;
|
|
411
522
|
const escrowContract = md?.escrowContract;
|
|
412
523
|
let cumulativeAmount = sessionCred?.payload &&
|
|
413
524
|
'cumulativeAmount' in sessionCred.payload &&
|
|
@@ -636,16 +747,17 @@ cli
|
|
|
636
747
|
const txInfo = closeTxHash && explorerUrl
|
|
637
748
|
? ` ${pc.dim(pc.link(`${explorerUrl}/tx/${closeTxHash}`, closeTxHash))}`
|
|
638
749
|
: '';
|
|
639
|
-
|
|
750
|
+
const closePrefix = options.confirm ? '' : '\n';
|
|
751
|
+
info(`${closePrefix}${pc.dim('Channel closed.')} ${pc.dim(`Spent ${fmtBalance(sessionCumulativeAmount, tokenSymbol, tokenDecimals)}.`)}${txInfo}\n`);
|
|
640
752
|
}
|
|
641
753
|
else {
|
|
642
754
|
const closeBody = await closeRes.text().catch(() => '');
|
|
643
|
-
info(
|
|
755
|
+
info(`\n${pc.dim(pc.yellow('Channel close failed'))} ${pc.dim(`(${closeRes.status})`)}\n`);
|
|
644
756
|
info(`${pc.dim(` channelId: ${sessionChannelId}`)}\n` +
|
|
645
757
|
`${pc.dim(` cumulativeAmount: ${sessionCumulativeAmount}`)}\n` +
|
|
646
758
|
`${pc.dim(` escrowContract: ${sessionEscrowContract}`)}\n` +
|
|
647
759
|
`${pc.dim(` chainId: ${sessionChainId}`)}\n` +
|
|
648
|
-
`${pc.dim(` account: ${account
|
|
760
|
+
`${pc.dim(` account: ${account?.address}`)}\n` +
|
|
649
761
|
`${pc.dim(` response: ${closeBody || '(empty)'}`)}\n`);
|
|
650
762
|
}
|
|
651
763
|
}
|
|
@@ -919,6 +1031,21 @@ catch (err) {
|
|
|
919
1031
|
process.exit(1);
|
|
920
1032
|
}
|
|
921
1033
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
1034
|
+
function parseMethodOpts(raw) {
|
|
1035
|
+
if (!raw)
|
|
1036
|
+
return {};
|
|
1037
|
+
const list = Array.isArray(raw) ? raw : [raw];
|
|
1038
|
+
const result = {};
|
|
1039
|
+
for (const item of list) {
|
|
1040
|
+
const idx = item.indexOf('=');
|
|
1041
|
+
if (idx === -1) {
|
|
1042
|
+
console.error(`Invalid method option format: ${item} (expected key=value)`);
|
|
1043
|
+
process.exit(1);
|
|
1044
|
+
}
|
|
1045
|
+
result[item.slice(0, idx)] = item.slice(idx + 1);
|
|
1046
|
+
}
|
|
1047
|
+
return result;
|
|
1048
|
+
}
|
|
922
1049
|
function parseOptions(schema, rawOptions) {
|
|
923
1050
|
const result = schema.safeParse(rawOptions ?? {});
|
|
924
1051
|
if (result.success)
|
|
@@ -1197,8 +1324,8 @@ function chainName(chain) {
|
|
|
1197
1324
|
return chainNames[chain.id] ?? chain.name;
|
|
1198
1325
|
}
|
|
1199
1326
|
const pathUsd = '0x20c0000000000000000000000000000000000000';
|
|
1200
|
-
const
|
|
1201
|
-
const mainnetTokens = [pathUsd,
|
|
1327
|
+
const usdc = '0x20C000000000000000000000b9537d11c60E8b50';
|
|
1328
|
+
const mainnetTokens = [pathUsd, usdc];
|
|
1202
1329
|
const testnetTokens = [
|
|
1203
1330
|
'0x20c0000000000000000000000000000000000000',
|
|
1204
1331
|
'0x20c0000000000000000000000000000000000001',
|
|
@@ -1225,7 +1352,7 @@ async function fetchTokenInfo(client, token, account) {
|
|
|
1225
1352
|
]);
|
|
1226
1353
|
const knownSymbols = {
|
|
1227
1354
|
[pathUsd]: 'PathUSD',
|
|
1228
|
-
[
|
|
1355
|
+
[usdc]: 'USDC',
|
|
1229
1356
|
};
|
|
1230
1357
|
const symbol = knownSymbols[token] ?? metadata.symbol;
|
|
1231
1358
|
const decimals = 'decimals' in metadata ? metadata.decimals : 6;
|