mppx 0.3.4 → 0.3.6

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.
Files changed (64) hide show
  1. package/README.md +0 -52
  2. package/dist/Challenge.d.ts +8 -0
  3. package/dist/Challenge.d.ts.map +1 -1
  4. package/dist/Challenge.js +20 -4
  5. package/dist/Challenge.js.map +1 -1
  6. package/dist/cli.js +193 -66
  7. package/dist/cli.js.map +1 -1
  8. package/dist/internal/types.d.ts +10 -0
  9. package/dist/internal/types.d.ts.map +1 -1
  10. package/dist/proxy/internal/Headers.d.ts +2 -0
  11. package/dist/proxy/internal/Headers.d.ts.map +1 -1
  12. package/dist/proxy/internal/Headers.js +2 -0
  13. package/dist/proxy/internal/Headers.js.map +1 -1
  14. package/dist/proxy/internal/Route.d.ts +4 -0
  15. package/dist/proxy/internal/Route.d.ts.map +1 -1
  16. package/dist/proxy/internal/Route.js +4 -0
  17. package/dist/proxy/internal/Route.js.map +1 -1
  18. package/dist/server/Mppx.d.ts +2 -0
  19. package/dist/server/Mppx.d.ts.map +1 -1
  20. package/dist/server/Mppx.js +4 -3
  21. package/dist/server/Mppx.js.map +1 -1
  22. package/dist/server/NodeListener.d.ts +6 -0
  23. package/dist/server/NodeListener.d.ts.map +1 -1
  24. package/dist/server/NodeListener.js +6 -0
  25. package/dist/server/NodeListener.js.map +1 -1
  26. package/dist/server/Response.d.ts +17 -0
  27. package/dist/server/Response.d.ts.map +1 -1
  28. package/dist/server/Response.js +17 -0
  29. package/dist/server/Response.js.map +1 -1
  30. package/dist/tempo/client/ChannelOps.js.map +1 -1
  31. package/dist/tempo/internal/defaults.d.ts +34 -8
  32. package/dist/tempo/internal/defaults.d.ts.map +1 -1
  33. package/dist/tempo/internal/defaults.js +30 -8
  34. package/dist/tempo/internal/defaults.js.map +1 -1
  35. package/dist/tempo/server/Charge.js +2 -2
  36. package/dist/tempo/server/Charge.js.map +1 -1
  37. package/dist/tempo/server/Session.d.ts.map +1 -1
  38. package/dist/tempo/server/Session.js +8 -3
  39. package/dist/tempo/server/Session.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/Challenge.test.ts +201 -11
  42. package/src/Challenge.ts +34 -4
  43. package/src/Store.test.ts +93 -0
  44. package/src/cli.test.ts +233 -37
  45. package/src/cli.ts +229 -79
  46. package/src/client/Transport.test.ts +4 -4
  47. package/src/internal/env.test.ts +42 -0
  48. package/src/internal/types.ts +11 -0
  49. package/src/proxy/internal/Headers.ts +2 -0
  50. package/src/proxy/internal/Route.ts +4 -0
  51. package/src/server/Mppx.test.ts +173 -0
  52. package/src/server/Mppx.ts +6 -3
  53. package/src/server/NodeListener.ts +6 -0
  54. package/src/server/Response.ts +17 -0
  55. package/src/server/Transport.test.ts +5 -5
  56. package/src/tempo/client/ChannelOps.ts +1 -1
  57. package/src/tempo/internal/defaults.test.ts +94 -0
  58. package/src/tempo/internal/defaults.ts +41 -8
  59. package/src/tempo/server/Charge.test.ts +150 -0
  60. package/src/tempo/server/Charge.ts +2 -2
  61. package/src/tempo/server/Session.test.ts +241 -1
  62. package/src/tempo/server/Session.ts +8 -3
  63. package/src/tempo/server/internal/transport.test.ts +285 -0
  64. package/src/tempo/session/Voucher.test.ts +46 -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
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"Challenge.d.ts","sourceRoot":"","sources":["../src/Challenge.ts"],"names":[],"mappings":"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"}
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);
@@ -1 +1 @@
1
- {"version":3,"file":"Challenge.js","sourceRoot":"","sources":["../src/Challenge.ts"],"names":[],"mappings":"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"}
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('--channel <id>', 'Reuse existing session channel ID')
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 tokenInfo = currency
163
- ? await fetchTokenInfo(client, currency, account.address).catch(() => undefined)
164
- : undefined;
165
- const tokenSymbol = tokenInfo?.symbol ?? currency ?? '';
166
- const tokenDecimals = tokenInfo?.decimals ?? challengeRequest.decimals ?? 6;
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
- const mppx = Mppx.create({
270
- methods: tempo({
271
- account,
272
- getClient: () => client,
273
- deposit: (() => {
274
- if (challenge.intent !== 'session')
275
- return undefined;
276
- const suggestedDeposit = challenge.request
277
- .suggestedDeposit;
278
- const cliDeposit = options.deposit !== undefined ? String(options.deposit) : undefined;
279
- const resolved = suggestedDeposit ?? cliDeposit ?? (isTestnet(client.chain) ? '10' : undefined);
280
- if (!resolved) {
281
- console.error('Session payment requires a deposit. Use --deposit <amount> or connect to testnet.');
282
- process.exit(1);
283
- }
284
- return resolved;
285
- })(),
286
- }),
287
- polyfill: false,
288
- });
289
- const credential = await mppx.createCredential(challengeResponse, (() => {
290
- if (!options.channel)
291
- return undefined;
292
- const idx = process.argv.indexOf('--channel');
293
- const channelId = idx !== -1 ? process.argv[idx + 1] : String(options.channel);
294
- const saved = readChannelCumulative(channelId);
295
- return {
296
- channelId,
297
- ...(saved !== undefined && { cumulativeAmountRaw: saved.toString() }),
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.chain?.id ?? 0;
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 ?? options.deposit;
411
+ const depositRaw = challengeRequest.suggestedDeposit;
314
412
  const depositDisplay = depositRaw
315
413
  ? ` ${pc.dim(`(deposit ${depositRaw} ${tokenSymbol})`)}`
316
414
  : '';
317
- info(`\n${pc.dim(`Channel opened ${parsed.payload.channelId}`)}${depositDisplay}\n`);
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.chain?.id ?? 0;
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
- info(`\n${pc.dim('Channel closed.')} ${pc.dim(`Spent ${fmtBalance(sessionCumulativeAmount, tokenSymbol, tokenDecimals)}.`)}${txInfo}\n`);
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(`${pc.dim(pc.yellow('Channel close failed'))} ${pc.dim(`(${closeRes.status})`)}\n`);
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.address}`)}\n` +
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 usdcE = '0x20C000000000000000000000b9537d11c60E8b50';
1201
- const mainnetTokens = [pathUsd, usdcE];
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
- [usdcE]: 'USDC.e',
1355
+ [usdc]: 'USDC',
1229
1356
  };
1230
1357
  const symbol = knownSymbols[token] ?? metadata.symbol;
1231
1358
  const decimals = 'decimals' in metadata ? metadata.decimals : 6;