mppx 0.1.1 → 0.2.1

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 (221) hide show
  1. package/dist/Challenge.d.ts +18 -18
  2. package/dist/Challenge.d.ts.map +1 -1
  3. package/dist/Challenge.js +8 -8
  4. package/dist/Challenge.js.map +1 -1
  5. package/dist/Errors.d.ts +58 -8
  6. package/dist/Errors.d.ts.map +1 -1
  7. package/dist/Errors.js +51 -9
  8. package/dist/Errors.js.map +1 -1
  9. package/dist/Method.d.ts +154 -0
  10. package/dist/Method.d.ts.map +1 -0
  11. package/dist/Method.js +81 -0
  12. package/dist/Method.js.map +1 -0
  13. package/dist/PaymentRequest.d.ts +5 -5
  14. package/dist/PaymentRequest.d.ts.map +1 -1
  15. package/dist/PaymentRequest.js +11 -6
  16. package/dist/PaymentRequest.js.map +1 -1
  17. package/dist/cli.js +67 -18
  18. package/dist/cli.js.map +1 -1
  19. package/dist/client/Methods.d.ts +2 -2
  20. package/dist/client/Methods.d.ts.map +1 -1
  21. package/dist/client/Methods.js +2 -2
  22. package/dist/client/Methods.js.map +1 -1
  23. package/dist/client/Mppx.d.ts +7 -7
  24. package/dist/client/Mppx.d.ts.map +1 -1
  25. package/dist/client/Mppx.js +3 -3
  26. package/dist/client/Mppx.js.map +1 -1
  27. package/dist/client/internal/Fetch.d.ts +10 -10
  28. package/dist/client/internal/Fetch.d.ts.map +1 -1
  29. package/dist/client/internal/Fetch.js +2 -2
  30. package/dist/client/internal/Fetch.js.map +1 -1
  31. package/dist/index.d.ts +1 -2
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/mcp-sdk/client/McpClient.d.ts +6 -6
  36. package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
  37. package/dist/mcp-sdk/client/McpClient.js +4 -4
  38. package/dist/mcp-sdk/client/McpClient.js.map +1 -1
  39. package/dist/middlewares/elysia.d.ts +1 -1
  40. package/dist/middlewares/express.d.ts +1 -1
  41. package/dist/middlewares/hono.d.ts +1 -1
  42. package/dist/middlewares/internal/mppx.d.ts +7 -7
  43. package/dist/middlewares/internal/mppx.d.ts.map +1 -1
  44. package/dist/middlewares/internal/mppx.js +5 -5
  45. package/dist/middlewares/internal/mppx.js.map +1 -1
  46. package/dist/middlewares/nextjs.d.ts +1 -1
  47. package/dist/proxy/Service.js +2 -2
  48. package/dist/proxy/Service.js.map +1 -1
  49. package/dist/server/Methods.d.ts +2 -2
  50. package/dist/server/Methods.d.ts.map +1 -1
  51. package/dist/server/Methods.js +2 -2
  52. package/dist/server/Methods.js.map +1 -1
  53. package/dist/server/Mppx.d.ts +17 -17
  54. package/dist/server/Mppx.d.ts.map +1 -1
  55. package/dist/server/Mppx.js +9 -9
  56. package/dist/server/Mppx.js.map +1 -1
  57. package/dist/stripe/{Intents.d.ts → Methods.d.ts} +22 -22
  58. package/dist/stripe/Methods.d.ts.map +1 -0
  59. package/dist/stripe/Methods.js +42 -0
  60. package/dist/stripe/Methods.js.map +1 -0
  61. package/dist/stripe/client/Charge.d.ts +40 -27
  62. package/dist/stripe/client/Charge.d.ts.map +1 -1
  63. package/dist/stripe/client/Charge.js +15 -7
  64. package/dist/stripe/client/Charge.js.map +1 -1
  65. package/dist/stripe/client/{MethodIntents.d.ts → Methods.d.ts} +24 -23
  66. package/dist/stripe/client/Methods.d.ts.map +1 -0
  67. package/dist/stripe/client/{MethodIntents.js → Methods.js} +3 -3
  68. package/dist/stripe/client/Methods.js.map +1 -0
  69. package/dist/stripe/client/index.d.ts +1 -1
  70. package/dist/stripe/client/index.d.ts.map +1 -1
  71. package/dist/stripe/client/index.js +1 -1
  72. package/dist/stripe/client/index.js.map +1 -1
  73. package/dist/stripe/index.d.ts +1 -1
  74. package/dist/stripe/index.d.ts.map +1 -1
  75. package/dist/stripe/index.js +1 -1
  76. package/dist/stripe/index.js.map +1 -1
  77. package/dist/stripe/internal/types.d.ts +25 -0
  78. package/dist/stripe/internal/types.d.ts.map +1 -0
  79. package/dist/stripe/internal/types.js +2 -0
  80. package/dist/stripe/internal/types.js.map +1 -0
  81. package/dist/stripe/server/Charge.d.ts +47 -28
  82. package/dist/stripe/server/Charge.d.ts.map +1 -1
  83. package/dist/stripe/server/Charge.js +90 -32
  84. package/dist/stripe/server/Charge.js.map +1 -1
  85. package/dist/stripe/server/{MethodIntents.d.ts → Methods.d.ts} +24 -23
  86. package/dist/stripe/server/Methods.d.ts.map +1 -0
  87. package/dist/stripe/server/{MethodIntents.js → Methods.js} +3 -3
  88. package/dist/stripe/server/Methods.js.map +1 -0
  89. package/dist/stripe/server/index.d.ts +1 -1
  90. package/dist/stripe/server/index.d.ts.map +1 -1
  91. package/dist/stripe/server/index.js +1 -1
  92. package/dist/stripe/server/index.js.map +1 -1
  93. package/dist/tempo/{Intents.d.ts → Methods.d.ts} +72 -69
  94. package/dist/tempo/Methods.d.ts.map +1 -0
  95. package/dist/tempo/Methods.js +118 -0
  96. package/dist/tempo/Methods.js.map +1 -0
  97. package/dist/tempo/client/ChannelOps.d.ts +1 -1
  98. package/dist/tempo/client/ChannelOps.js +1 -1
  99. package/dist/tempo/client/Charge.d.ts +25 -25
  100. package/dist/tempo/client/Charge.d.ts.map +1 -1
  101. package/dist/tempo/client/Charge.js +3 -3
  102. package/dist/tempo/client/Charge.js.map +1 -1
  103. package/dist/tempo/client/{MethodIntents.d.ts → Methods.d.ts} +74 -70
  104. package/dist/tempo/client/Methods.d.ts.map +1 -0
  105. package/dist/tempo/client/{MethodIntents.js → Methods.js} +3 -3
  106. package/dist/tempo/client/Methods.js.map +1 -0
  107. package/dist/tempo/client/Session.d.ts +49 -45
  108. package/dist/tempo/client/Session.d.ts.map +1 -1
  109. package/dist/tempo/client/Session.js +4 -4
  110. package/dist/tempo/client/Session.js.map +1 -1
  111. package/dist/tempo/client/SessionManager.d.ts +1 -1
  112. package/dist/tempo/client/SessionManager.js +1 -1
  113. package/dist/tempo/client/index.d.ts +1 -1
  114. package/dist/tempo/client/index.d.ts.map +1 -1
  115. package/dist/tempo/client/index.js +1 -1
  116. package/dist/tempo/client/index.js.map +1 -1
  117. package/dist/tempo/index.d.ts +1 -1
  118. package/dist/tempo/index.d.ts.map +1 -1
  119. package/dist/tempo/index.js +1 -1
  120. package/dist/tempo/index.js.map +1 -1
  121. package/dist/tempo/server/Charge.d.ts +27 -27
  122. package/dist/tempo/server/Charge.d.ts.map +1 -1
  123. package/dist/tempo/server/Charge.js +3 -3
  124. package/dist/tempo/server/Charge.js.map +1 -1
  125. package/dist/tempo/server/{MethodIntents.d.ts → Methods.d.ts} +73 -69
  126. package/dist/tempo/server/Methods.d.ts.map +1 -0
  127. package/dist/tempo/server/{MethodIntents.js → Methods.js} +4 -4
  128. package/dist/tempo/server/Methods.js.map +1 -0
  129. package/dist/tempo/server/Session.d.ts +51 -47
  130. package/dist/tempo/server/Session.d.ts.map +1 -1
  131. package/dist/tempo/server/Session.js +4 -4
  132. package/dist/tempo/server/Session.js.map +1 -1
  133. package/dist/tempo/server/index.d.ts +6 -0
  134. package/dist/tempo/server/index.d.ts.map +1 -0
  135. package/dist/tempo/server/index.js +6 -0
  136. package/dist/tempo/server/index.js.map +1 -0
  137. package/package.json +2 -1
  138. package/src/Challenge.test-d.ts +3 -3
  139. package/src/Challenge.test.ts +7 -7
  140. package/src/Challenge.ts +34 -34
  141. package/src/Errors.test.ts +75 -21
  142. package/src/Errors.ts +74 -9
  143. package/src/Method.test.ts +76 -0
  144. package/src/Method.ts +228 -0
  145. package/src/PaymentRequest.test.ts +5 -5
  146. package/src/PaymentRequest.ts +15 -10
  147. package/src/cli.test.ts +12 -22
  148. package/src/cli.ts +74 -21
  149. package/src/client/Methods.ts +2 -2
  150. package/src/client/Mppx.test-d.ts +6 -6
  151. package/src/client/Mppx.test.ts +26 -22
  152. package/src/client/Mppx.ts +10 -10
  153. package/src/client/Transport.test.ts +6 -6
  154. package/src/client/internal/Fetch.ts +21 -24
  155. package/src/index.ts +1 -2
  156. package/src/mcp-sdk/client/McpClient.test.ts +1 -1
  157. package/src/mcp-sdk/client/McpClient.ts +11 -13
  158. package/src/middlewares/elysia.ts +1 -1
  159. package/src/middlewares/express.ts +1 -1
  160. package/src/middlewares/hono.ts +1 -1
  161. package/src/middlewares/internal/mppx.ts +10 -10
  162. package/src/middlewares/nextjs.ts +1 -1
  163. package/src/proxy/Service.ts +2 -2
  164. package/src/server/Methods.ts +2 -2
  165. package/src/server/Mppx.test-d.ts +27 -29
  166. package/src/server/Mppx.test.ts +23 -19
  167. package/src/server/Mppx.ts +43 -43
  168. package/src/server/Transport.test.ts +8 -8
  169. package/src/stripe/{Intents.test.ts → Methods.test.ts} +12 -12
  170. package/src/stripe/Methods.ts +45 -0
  171. package/src/stripe/client/Charge.test.ts +189 -0
  172. package/src/stripe/client/Charge.ts +29 -16
  173. package/src/stripe/client/{MethodIntents.ts → Methods.ts} +2 -2
  174. package/src/stripe/client/index.ts +1 -1
  175. package/src/stripe/index.ts +1 -1
  176. package/src/stripe/internal/types.ts +22 -0
  177. package/src/stripe/server/Charge.test.ts +241 -0
  178. package/src/stripe/server/Charge.ts +124 -38
  179. package/src/stripe/server/{MethodIntents.ts → Methods.ts} +2 -2
  180. package/src/stripe/server/index.ts +1 -1
  181. package/src/tempo/{Intents.test.ts → Methods.test.ts} +15 -15
  182. package/src/tempo/{Intents.ts → Methods.ts} +77 -22
  183. package/src/tempo/client/ChannelOps.ts +1 -1
  184. package/src/tempo/client/Charge.ts +3 -3
  185. package/src/tempo/client/{MethodIntents.ts → Methods.ts} +2 -2
  186. package/src/tempo/client/Session.ts +4 -4
  187. package/src/tempo/client/SessionManager.ts +1 -1
  188. package/src/tempo/client/index.ts +1 -1
  189. package/src/tempo/index.ts +1 -1
  190. package/src/tempo/server/Charge.ts +4 -7
  191. package/src/tempo/server/{MethodIntents.ts → Methods.ts} +3 -3
  192. package/src/tempo/server/Session.test.ts +4 -7
  193. package/src/tempo/server/Session.ts +6 -6
  194. package/src/tempo/server/index.ts +1 -1
  195. package/dist/Intent.d.ts +0 -101
  196. package/dist/Intent.d.ts.map +0 -1
  197. package/dist/Intent.js +0 -83
  198. package/dist/Intent.js.map +0 -1
  199. package/dist/MethodIntent.d.ts +0 -225
  200. package/dist/MethodIntent.d.ts.map +0 -1
  201. package/dist/MethodIntent.js +0 -156
  202. package/dist/MethodIntent.js.map +0 -1
  203. package/dist/stripe/Intents.d.ts.map +0 -1
  204. package/dist/stripe/Intents.js +0 -27
  205. package/dist/stripe/Intents.js.map +0 -1
  206. package/dist/stripe/client/MethodIntents.d.ts.map +0 -1
  207. package/dist/stripe/client/MethodIntents.js.map +0 -1
  208. package/dist/stripe/server/MethodIntents.d.ts.map +0 -1
  209. package/dist/stripe/server/MethodIntents.js.map +0 -1
  210. package/dist/tempo/Intents.d.ts.map +0 -1
  211. package/dist/tempo/Intents.js +0 -81
  212. package/dist/tempo/Intents.js.map +0 -1
  213. package/dist/tempo/client/MethodIntents.d.ts.map +0 -1
  214. package/dist/tempo/client/MethodIntents.js.map +0 -1
  215. package/dist/tempo/server/MethodIntents.d.ts.map +0 -1
  216. package/dist/tempo/server/MethodIntents.js.map +0 -1
  217. package/src/Intent.test.ts +0 -180
  218. package/src/Intent.ts +0 -109
  219. package/src/MethodIntent.test.ts +0 -303
  220. package/src/MethodIntent.ts +0 -388
  221. package/src/stripe/Intents.ts +0 -27
package/src/cli.ts CHANGED
@@ -42,9 +42,9 @@ cli
42
42
  .option('-L, --location', 'Follow redirects')
43
43
  .option('-X, --method <method>', 'HTTP method')
44
44
  .option('--channel <id>', 'Reuse existing stream channel ID')
45
+ .option('--confirm', 'Show confirmation prompts')
45
46
  .option('--deposit <amount>', 'Deposit amount for stream payments (human-readable units)')
46
47
  .option('--json <json>', 'Send JSON body (sets Content-Type and Accept, implies POST)')
47
- .option('--yes', 'Skip confirmation prompts')
48
48
  .example(`${name} example.com/content`)
49
49
  .example(`${name} example.com/api --json '{"key":"value"}'`)
50
50
  .action(async (rawUrl: string | undefined, rawOptions: unknown) => {
@@ -52,6 +52,7 @@ cli
52
52
  z.object({
53
53
  account: z.optional(z.string()),
54
54
  channel: z.optional(z.coerce.string()),
55
+ confirm: z.optional(z.boolean()),
55
56
  data: z.optional(z.string()),
56
57
  deposit: z.optional(z.union([z.string(), z.number()])),
57
58
  fail: z.optional(z.boolean()),
@@ -65,7 +66,6 @@ cli
65
66
  silent: z.optional(z.boolean()),
66
67
  userAgent: z.optional(z.string()),
67
68
  verbose: z.optional(z.boolean()),
68
- yes: z.optional(z.boolean()),
69
69
  }),
70
70
  rawOptions,
71
71
  )
@@ -76,7 +76,7 @@ cli
76
76
 
77
77
  const silent = options.silent ?? false
78
78
  const info = silent ? (_msg: string) => {} : (msg: string) => process.stderr.write(msg)
79
- if (silent) options.yes = true
79
+ if (silent) options.confirm = false
80
80
 
81
81
  const accountName = resolveAccountName(options.account)
82
82
  const privateKey = process.env.MPPX_PRIVATE_KEY ?? (await createKeychain(accountName).get())
@@ -266,10 +266,9 @@ cli
266
266
  for (const line of rest) info(`${indent}${line}\n`)
267
267
  }
268
268
  }
269
- info('\n')
270
-
271
- if (!options.yes) {
272
- const ok = await confirm(`Proceed with ${challenge.intent}?`)
269
+ if (options.confirm) {
270
+ info('\n')
271
+ const ok = await confirm(`Proceed with ${challenge.intent}?`, true)
273
272
  if (!ok) {
274
273
  info('Aborted.\n')
275
274
  process.exit(0)
@@ -336,7 +335,7 @@ cli
336
335
  const depositDisplay = depositRaw
337
336
  ? ` ${pc.dim(`(deposit ${depositRaw} ${tokenSymbol})`)}`
338
337
  : ''
339
- info(`${pc.dim(`Channel opened ${parsed.payload.channelId}`)}${depositDisplay}\n`)
338
+ info(`\n${pc.dim(`Channel opened ${parsed.payload.channelId}`)}${depositDisplay}\n`)
340
339
  }
341
340
  }
342
341
 
@@ -385,11 +384,25 @@ cli
385
384
  }
386
385
  info(`\n${pc.bold(pc.green('Payment Receipt'))}\n`)
387
386
  const rows: [string, string][] = []
387
+ const channelId = receiptJson.channelId
388
+ const reference = receiptJson.reference
389
+ const skipReference = channelId && reference && channelId === reference
390
+ const receiptBalanceKeys = new Set(['acceptedCumulative', 'spent'])
388
391
  for (const [key, value] of Object.entries(receiptJson)) {
389
392
  if (value === undefined || shownKeys.has(key)) continue
390
- if (key === 'reference' && typeof value === 'string' && explorerUrl)
393
+ if (key === 'reference' && skipReference) continue
394
+ if (receiptBalanceKeys.has(key) && typeof value === 'string') {
395
+ rows.push([
396
+ key,
397
+ `${value} ${pc.dim(`(${fmtBalance(BigInt(value), tokenSymbol, tokenDecimals)})`)}`,
398
+ ])
399
+ } else if (
400
+ (key === 'reference' || key === 'txHash') &&
401
+ typeof value === 'string' &&
402
+ explorerUrl
403
+ ) {
391
404
  rows.push([key, pc.link(`${explorerUrl}/tx/${value}`, value)])
392
- else rows.push([key, String(value)])
405
+ } else rows.push([key, String(value)])
393
406
  }
394
407
  rows.sort(([a], [b]) => a.localeCompare(b))
395
408
  const pad = Math.max(...rows.map(([k]) => k.length))
@@ -426,7 +439,7 @@ cli
426
439
  : 0n
427
440
  let _voucherSeq = 0
428
441
 
429
- const termBg = await detectTerminalBg()
442
+ const termBg = verbose ? await detectTerminalBg() : undefined
430
443
  const chunkBgs = (() => {
431
444
  if (!termBg || !pc.isColorSupported) return undefined
432
445
  const clamp = (n: number) => Math.max(0, Math.min(255, Math.round(n)))
@@ -513,18 +526,26 @@ cli
513
526
  const receipt = JSON.parse(data) as Record<string, unknown>
514
527
  info(`\n\n${pc.bold(pc.green('Payment Receipt'))}\n`)
515
528
  const rows: [string, string][] = []
529
+ const skipRef =
530
+ receipt.channelId &&
531
+ receipt.reference &&
532
+ receipt.channelId === receipt.reference
516
533
  for (const [key, value] of Object.entries(receipt)) {
517
534
  if (value === undefined || shownKeys.has(key)) continue
518
- if (key === 'channelId' && value === receipt.reference) continue
535
+ if (key === 'reference' && skipRef) continue
519
536
  const receiptBalanceKeys = ['acceptedCumulative', 'spent']
520
537
  if (receiptBalanceKeys.includes(key) && typeof value === 'string') {
521
538
  rows.push([
522
539
  key,
523
540
  `${value} ${pc.dim(`(${fmtBalance(BigInt(value), tokenSymbol, tokenDecimals)})`)}`,
524
541
  ])
525
- } else if (key === 'reference' && typeof value === 'string' && explorerUrl)
542
+ } else if (
543
+ (key === 'reference' || key === 'txHash') &&
544
+ typeof value === 'string' &&
545
+ explorerUrl
546
+ ) {
526
547
  rows.push([key, pc.link(`${explorerUrl}/tx/${value}`, value)])
527
- else rows.push([key, String(value)])
548
+ } else rows.push([key, String(value)])
528
549
  }
529
550
  rows.sort(([a], [b]) => a.localeCompare(b))
530
551
  const rpad = Math.max(...rows.map(([k]) => k.length))
@@ -586,8 +607,23 @@ cli
586
607
  headers: { Authorization: closeCred },
587
608
  })
588
609
  if (closeRes.ok) {
610
+ const closeReceiptHeader = closeRes.headers.get('Payment-Receipt')
611
+ let closeTxHash: string | undefined
612
+ if (closeReceiptHeader) {
613
+ try {
614
+ const r = JSON.parse(Base64.toString(closeReceiptHeader)) as Record<
615
+ string,
616
+ unknown
617
+ >
618
+ if (typeof r.txHash === 'string') closeTxHash = r.txHash
619
+ } catch {}
620
+ }
621
+ const txInfo =
622
+ closeTxHash && explorerUrl
623
+ ? ` ${pc.dim(pc.link(`${explorerUrl}/tx/${closeTxHash}`, closeTxHash))}`
624
+ : ''
589
625
  info(
590
- `\n${pc.dim('Channel closed.')} ${pc.dim(`Spent ${fmtBalance(cumulativeAmount, tokenSymbol, tokenDecimals)}.`)}\n`,
626
+ `\n${pc.dim('Channel closed.')} ${pc.dim(`Spent ${fmtBalance(cumulativeAmount, tokenSymbol, tokenDecimals)}.`)}${txInfo}\n`,
591
627
  )
592
628
  } else {
593
629
  info(
@@ -605,10 +641,10 @@ cli
605
641
  streamChannelId &&
606
642
  streamEscrowContract &&
607
643
  streamChainId
608
- if (shouldClose && !options.yes) {
644
+ if (shouldClose && options.confirm) {
609
645
  info('\n')
610
646
  }
611
- if (shouldClose && !(options.yes || (await confirm('Close channel?')))) {
647
+ if (shouldClose && options.confirm && !(await confirm('Close channel?', true))) {
612
648
  info(`${pc.dim('Kept channel open.')}\n`)
613
649
  } else if (shouldClose) {
614
650
  const signature = await signVoucher(
@@ -638,8 +674,23 @@ cli
638
674
  })
639
675
  if (closeRes.ok) {
640
676
  deleteChannelState(streamChannelId!)
677
+ const closeReceiptHeader = closeRes.headers.get('Payment-Receipt')
678
+ let closeTxHash: string | undefined
679
+ if (closeReceiptHeader) {
680
+ try {
681
+ const r = JSON.parse(Base64.toString(closeReceiptHeader)) as Record<
682
+ string,
683
+ unknown
684
+ >
685
+ if (typeof r.txHash === 'string') closeTxHash = r.txHash
686
+ } catch {}
687
+ }
688
+ const txInfo =
689
+ closeTxHash && explorerUrl
690
+ ? ` ${pc.dim(pc.link(`${explorerUrl}/tx/${closeTxHash}`, closeTxHash))}`
691
+ : ''
641
692
  info(
642
- `${pc.dim('Channel closed.')} ${pc.dim(`Spent ${fmtBalance(streamCumulativeAmount, tokenSymbol, tokenDecimals)}.`)}\n`,
693
+ `\n${pc.dim('Channel closed.')} ${pc.dim(`Spent ${fmtBalance(streamCumulativeAmount, tokenSymbol, tokenDecimals)}.`)}${txInfo}\n`,
643
694
  )
644
695
  } else {
645
696
  const closeBody = await closeRes.text().catch(() => '')
@@ -1097,12 +1148,14 @@ function prompt(message: string): Promise<string | undefined> {
1097
1148
  })
1098
1149
  }
1099
1150
 
1100
- function confirm(prompt: string): Promise<boolean> {
1151
+ function confirm(prompt: string, defaultYes = false): Promise<boolean> {
1101
1152
  const reader = readline.createInterface({ input: process.stdin, output: process.stderr })
1102
1153
  return new Promise((resolve) => {
1103
- reader.question(`${pc.bold(`▸ ${prompt}`)} ${pc.dim('(y/N)')} `, (answer) => {
1154
+ const hint = defaultYes ? '(Y/n)' : '(y/N)'
1155
+ reader.question(`${pc.bold(`▸ ${prompt}`)} ${pc.dim(hint)} `, (answer) => {
1104
1156
  reader.close()
1105
- resolve(answer.trim().toLowerCase() === 'y')
1157
+ const trimmed = answer.trim().toLowerCase()
1158
+ resolve(trimmed === '' ? defaultYes : trimmed === 'y')
1106
1159
  })
1107
1160
  })
1108
1161
  }
@@ -1,3 +1,3 @@
1
- export { stripe } from '../stripe/client/MethodIntents.js'
2
- export { tempo } from '../tempo/client/MethodIntents.js'
1
+ export { stripe } from '../stripe/client/index.js'
2
+ export { tempo } from '../tempo/client/index.js'
3
3
  export { session } from '../tempo/client/Session.js'
@@ -1,8 +1,8 @@
1
1
  import type { Account } from 'viem'
2
2
  import { describe, expectTypeOf, test } from 'vitest'
3
- import * as MethodIntent from '../MethodIntent.js'
3
+ import * as Method from '../Method.js'
4
4
  import { charge } from '../tempo/client/Charge.js'
5
- import * as Intents from '../tempo/Intents.js'
5
+ import * as Methods from '../tempo/Methods.js'
6
6
  import * as z from '../zod.js'
7
7
  import * as Mppx from './Mppx.js'
8
8
 
@@ -13,8 +13,8 @@ describe('Mppx', () => {
13
13
  })
14
14
  const mppx = Mppx.create({ methods: [method] })
15
15
 
16
- expectTypeOf(mppx.methods).toMatchTypeOf<readonly MethodIntent.AnyClient[]>()
17
- expectTypeOf(mppx.methods[0]?.name).toEqualTypeOf<'charge'>()
16
+ expectTypeOf(mppx.methods).toMatchTypeOf<readonly Method.AnyClient[]>()
17
+ expectTypeOf(mppx.methods[0]?.intent).toEqualTypeOf<'charge'>()
18
18
  })
19
19
 
20
20
  test('has createCredential function', () => {
@@ -38,7 +38,7 @@ describe('create.Config', () => {
38
38
 
39
39
  describe('Method.toClient', () => {
40
40
  test('createCredential receives typed challenge', () => {
41
- MethodIntent.toClient(Intents.charge, {
41
+ Method.toClient(Methods.charge, {
42
42
  async createCredential({ challenge }) {
43
43
  expectTypeOf(challenge.method).toBeString()
44
44
  expectTypeOf(challenge.intent).toBeString()
@@ -52,7 +52,7 @@ describe('Method.toClient', () => {
52
52
  })
53
53
 
54
54
  test('createCredential receives typed context when provided', () => {
55
- MethodIntent.toClient(Intents.charge, {
55
+ Method.toClient(Methods.charge, {
56
56
  context: z.object({
57
57
  account: z.custom<Account>(),
58
58
  extra: z.optional(z.string()),
@@ -1,7 +1,7 @@
1
- import { Challenge, Credential, Intent, Mcp, MethodIntent, Receipt } from 'mppx'
1
+ import { Challenge, Credential, Mcp, Method, Receipt } from 'mppx'
2
2
  import { Mppx, Transport, tempo } from 'mppx/client'
3
3
  import { Mppx as Mppx_server, tempo as tempo_server } from 'mppx/server'
4
- import { MethodIntents } from 'mppx/tempo'
4
+ import { Methods } from 'mppx/tempo'
5
5
  import { afterEach, describe, expect, test } from 'vitest'
6
6
  import * as Http from '~test/Http.js'
7
7
  import { accounts, asset, client } from '~test/tempo/viem.js'
@@ -21,10 +21,10 @@ describe('Mppx.create', () => {
21
21
  })
22
22
 
23
23
  expect(mppx.methods).toHaveLength(2)
24
- expect(mppx.methods[0]?.method).toBe('tempo')
25
- expect(mppx.methods[0]?.name).toBe('charge')
26
- expect(mppx.methods[1]?.method).toBe('tempo')
27
- expect(mppx.methods[1]?.name).toBe('session')
24
+ expect(mppx.methods[0]?.name).toBe('tempo')
25
+ expect(mppx.methods[0]?.intent).toBe('charge')
26
+ expect(mppx.methods[1]?.name).toBe('tempo')
27
+ expect(mppx.methods[1]?.intent).toBe('session')
28
28
  expect(mppx.transport.name).toBe('http')
29
29
  expect(typeof mppx.createCredential).toBe('function')
30
30
  expect(typeof mppx.fetch).toBe('function')
@@ -41,15 +41,17 @@ describe('Mppx.create', () => {
41
41
  })
42
42
 
43
43
  test('behavior: with multiple methods', () => {
44
- const stripeCharge = MethodIntent.fromIntent(Intent.charge, {
45
- method: 'stripe',
44
+ const stripeCharge = Method.from({
45
+ name: 'stripe',
46
+ intent: 'charge',
46
47
  schema: {
47
48
  credential: {
48
- payload: MethodIntents.charge.schema.credential.payload,
49
+ payload: Methods.charge.schema.credential.payload,
49
50
  },
51
+ request: Methods.charge.schema.request,
50
52
  },
51
53
  })
52
- const stripeMethod = MethodIntent.toClient(stripeCharge, {
54
+ const stripeMethod = Method.toClient(stripeCharge, {
53
55
  async createCredential({ challenge }) {
54
56
  return Credential.serialize({
55
57
  challenge,
@@ -64,9 +66,9 @@ describe('Mppx.create', () => {
64
66
  })
65
67
 
66
68
  expect(mppx.methods).toHaveLength(3)
67
- expect(mppx.methods[0]?.method).toBe('tempo')
68
- expect(mppx.methods[1]?.method).toBe('tempo')
69
- expect(mppx.methods[2]?.method).toBe('stripe')
69
+ expect(mppx.methods[0]?.name).toBe('tempo')
70
+ expect(mppx.methods[1]?.name).toBe('tempo')
71
+ expect(mppx.methods[2]?.name).toBe('stripe')
70
72
  })
71
73
  })
72
74
 
@@ -77,7 +79,7 @@ describe('createCredential', () => {
77
79
  methods: [tempo({ account: accounts[1], getClient: () => client })],
78
80
  })
79
81
 
80
- const challenge = Challenge.fromIntent(MethodIntents.charge, {
82
+ const challenge = Challenge.fromMethod(Methods.charge, {
81
83
  realm,
82
84
  secretKey,
83
85
  request: {
@@ -127,21 +129,23 @@ describe('createCredential', () => {
127
129
  })
128
130
 
129
131
  await expect(mppx.createCredential(response)).rejects.toThrow(
130
- 'No method intent found for "unknown.charge". Available: tempo.charge, tempo.session',
132
+ 'No method found for "unknown.charge". Available: tempo.charge, tempo.session',
131
133
  )
132
134
  })
133
135
 
134
136
  test('behavior: routes to correct method with multiple methods', async () => {
135
- const stripeCharge = MethodIntent.fromIntent(Intent.charge, {
136
- method: 'stripe',
137
+ const stripeCharge = Method.from({
138
+ name: 'stripe',
139
+ intent: 'charge',
137
140
  schema: {
138
141
  credential: {
139
- payload: MethodIntents.charge.schema.credential.payload,
142
+ payload: Methods.charge.schema.credential.payload,
140
143
  },
144
+ request: Methods.charge.schema.request,
141
145
  },
142
146
  })
143
147
 
144
- const stripe = MethodIntent.toClient(stripeCharge, {
148
+ const stripe = Method.toClient(stripeCharge, {
145
149
  async createCredential({ challenge }) {
146
150
  return Credential.serialize({
147
151
  challenge,
@@ -188,7 +192,7 @@ describe('createCredential', () => {
188
192
  methods: [tempo({ getClient: () => client })],
189
193
  })
190
194
 
191
- const challenge = Challenge.fromIntent(MethodIntents.charge, {
195
+ const challenge = Challenge.fromMethod(Methods.charge, {
192
196
  realm,
193
197
  secretKey,
194
198
  request: {
@@ -220,7 +224,7 @@ describe('createCredential', () => {
220
224
  methods: [tempo({ account: accounts[1], getClient: () => client })],
221
225
  })
222
226
 
223
- const challenge = Challenge.fromIntent(MethodIntents.charge, {
227
+ const challenge = Challenge.fromMethod(Methods.charge, {
224
228
  realm,
225
229
  secretKey,
226
230
  request: {
@@ -251,7 +255,7 @@ describe('createCredential', () => {
251
255
  transport: Transport.mcp(),
252
256
  })
253
257
 
254
- const challenge = Challenge.fromIntent(MethodIntents.charge, {
258
+ const challenge = Challenge.fromMethod(Methods.charge, {
255
259
  realm,
256
260
  secretKey,
257
261
  request: {
@@ -1,10 +1,10 @@
1
1
  import type * as Challenge from '../Challenge.js'
2
- import type * as MethodIntent from '../MethodIntent.js'
2
+ import type * as Method from '../Method.js'
3
3
  import type * as z from '../zod.js'
4
4
  import * as Fetch from './internal/Fetch.js'
5
5
  import * as Transport from './Transport.js'
6
6
 
7
- export type Methods = readonly (MethodIntent.AnyClient | readonly MethodIntent.AnyClient[])[]
7
+ export type Methods = readonly (Method.AnyClient | readonly Method.AnyClient[])[]
8
8
 
9
9
  /**
10
10
  * Client-side payment handler.
@@ -27,7 +27,7 @@ export type Mppx<
27
27
  }
28
28
 
29
29
  /**
30
- * Creates a client-side payment handler from an array of method intents.
30
+ * Creates a client-side payment handler from an array of methods.
31
31
  *
32
32
  * Returns a payment handler with a `fetch` function that automatically handles
33
33
  * 402 Payment Required responses. By default, also polyfills `globalThis.fetch`.
@@ -76,10 +76,10 @@ export function create<
76
76
  async createCredential(response: Transport.ResponseOf<transport>, context?: unknown) {
77
77
  const challenge = transport.getChallenge(response as never) as Challenge.Challenge
78
78
 
79
- const mi = methods.find((m) => m.method === challenge.method && m.name === challenge.intent)
79
+ const mi = methods.find((m) => m.name === challenge.method && m.intent === challenge.intent)
80
80
  if (!mi)
81
81
  throw new Error(
82
- `No method intent found for "${challenge.method}.${challenge.intent}". Available: ${methods.map((m) => `${m.method}.${m.name}`).join(', ')}`,
82
+ `No method found for "${challenge.method}.${challenge.intent}". Available: ${methods.map((m) => `${m.name}.${m.intent}`).join(', ')}`,
83
83
  )
84
84
 
85
85
  const parsedContext =
@@ -128,7 +128,7 @@ export declare namespace create {
128
128
  },
129
129
  ) => Promise<string | undefined>)
130
130
  | undefined
131
- /** Array of method intents to use. Accepts individual clients or tuples (e.g. from `tempo()`). */
131
+ /** Array of methods to use. Accepts individual clients or tuples (e.g. from `tempo()`). */
132
132
  methods: methods
133
133
  /** Whether to polyfill `globalThis.fetch` with the payment-aware wrapper. @default true */
134
134
  polyfill?: boolean | undefined
@@ -141,8 +141,8 @@ export declare namespace create {
141
141
  * Union of all context types from all methods that have context schemas.
142
142
  * @internal
143
143
  */
144
- type AnyContextFor<methods extends readonly MethodIntent.AnyClient[]> = {
145
- [method in keyof methods]: methods[method] extends MethodIntent.Client<any, infer context>
144
+ type AnyContextFor<methods extends readonly Method.AnyClient[]> = {
145
+ [method in keyof methods]: methods[method] extends Method.Client<any, infer context>
146
146
  ? context extends z.ZodMiniType
147
147
  ? z.input<context>
148
148
  : undefined
@@ -157,9 +157,9 @@ type FlattenMethods<methods extends Methods> = methods extends readonly [
157
157
  infer head,
158
158
  ...infer tail extends Methods,
159
159
  ]
160
- ? head extends readonly MethodIntent.AnyClient[]
160
+ ? head extends readonly Method.AnyClient[]
161
161
  ? readonly [...head, ...FlattenMethods<tail>]
162
- : head extends MethodIntent.AnyClient
162
+ : head extends Method.AnyClient
163
163
  ? readonly [head, ...FlattenMethods<tail>]
164
164
  : never
165
165
  : readonly []
@@ -1,12 +1,12 @@
1
1
  import { Challenge, Credential, Mcp } from 'mppx'
2
2
  import { Transport } from 'mppx/client'
3
- import { MethodIntents as Intents } from 'mppx/tempo'
3
+ import { Methods } from 'mppx/tempo'
4
4
  import { describe, expect, test } from 'vitest'
5
5
 
6
6
  const realm = 'api.example.com'
7
7
  const secretKey = 'test-secret-key'
8
8
 
9
- const challenge = Challenge.fromIntent(Intents.charge, {
9
+ const challenge = Challenge.fromMethod(Methods.charge, {
10
10
  realm,
11
11
  secretKey,
12
12
  request: {
@@ -60,7 +60,7 @@ describe('http', () => {
60
60
  expect(transport.getChallenge(response)).toMatchInlineSnapshot(`
61
61
  {
62
62
  "expires": "2025-01-01T00:00:00.000Z",
63
- "id": "EUAHxZRCSFB29SAs5TEcB4cQDS0uVDzl8uSYuA58aVs",
63
+ "id": "wv3vZAjsySM50i4f1sJCZxyOLNry0dLSOwuWDBqrXaw",
64
64
  "intent": "charge",
65
65
  "method": "tempo",
66
66
  "realm": "api.example.com",
@@ -91,7 +91,7 @@ describe('http', () => {
91
91
  const headers = result.headers as Headers
92
92
 
93
93
  expect(headers.get('Authorization')).toMatchInlineSnapshot(
94
- `"Payment eyJjaGFsbGVuZ2UiOnsiZXhwaXJlcyI6IjIwMjUtMDEtMDFUMDA6MDA6MDAuMDAwWiIsImlkIjoiRVVBSHhaUkNTRkIyOVNBczVURWNCNGNRRFMwdVZEemw4dVNZdUE1OGFWcyIsImludGVudCI6ImNoYXJnZSIsIm1ldGhvZCI6InRlbXBvIiwicmVhbG0iOiJhcGkuZXhhbXBsZS5jb20iLCJyZXF1ZXN0IjoiZXlKamRYSnlaVzVqZVNJNklqQjRNakJqTURBd01EQXdNREF3TURBd01EQXdNREF3TURBd01EQXdNREF3TURBd01EQXdNREF3TVNJc0ltVjRjR2x5WlhNaU9pSXlNREkxTFRBeExUQXhWREF3T2pBd09qQXdMakF3TUZvaUxDSnlaV05wY0dsbGJuUWlPaUl3ZURjME1tUXpOVU5qTmpZek5FTXdOVE15T1RJMVlUTmlPRFEwUW1NNVpUYzFPVFZtT0daRk1EQWlMQ0poYlc5MWJuUWlPaUl4TURBd0luMCJ9LCJwYXlsb2FkIjp7InNpZ25hdHVyZSI6IjB4YWJjMTIzIiwidHlwZSI6InRyYW5zYWN0aW9uIn19"`,
94
+ `"Payment eyJjaGFsbGVuZ2UiOnsiZXhwaXJlcyI6IjIwMjUtMDEtMDFUMDA6MDA6MDAuMDAwWiIsImlkIjoid3YzdlpBanN5U001MGk0ZjFzSkNaeHlPTE5yeTBkTFNPd3VXREJxclhhdyIsImludGVudCI6ImNoYXJnZSIsIm1ldGhvZCI6InRlbXBvIiwicmVhbG0iOiJhcGkuZXhhbXBsZS5jb20iLCJyZXF1ZXN0IjoiZXlKaGJXOTFiblFpT2lJeE1EQXdJaXdpWTNWeWNtVnVZM2tpT2lJd2VESXdZekF3TURBd01EQXdNREF3TURBd01EQXdNREF3TURBd01EQXdNREF3TURBd01EQXdNREVpTENKbGVIQnBjbVZ6SWpvaU1qQXlOUzB3TVMwd01WUXdNRG93TURvd01DNHdNREJhSWl3aWNtVmphWEJwWlc1MElqb2lNSGczTkRKa016VkRZelkyTXpSRE1EVXpNamt5TldFellqZzBORUpqT1dVM05UazFaamhtUlRBd0luMCJ9LCJwYXlsb2FkIjp7InNpZ25hdHVyZSI6IjB4YWJjMTIzIiwidHlwZSI6InRyYW5zYWN0aW9uIn19"`,
95
95
  )
96
96
  })
97
97
 
@@ -182,7 +182,7 @@ describe('mcp', () => {
182
182
  expect(transport.getChallenge(response)).toMatchInlineSnapshot(`
183
183
  {
184
184
  "expires": "2025-01-01T00:00:00.000Z",
185
- "id": "EUAHxZRCSFB29SAs5TEcB4cQDS0uVDzl8uSYuA58aVs",
185
+ "id": "wv3vZAjsySM50i4f1sJCZxyOLNry0dLSOwuWDBqrXaw",
186
186
  "intent": "charge",
187
187
  "method": "tempo",
188
188
  "realm": "api.example.com",
@@ -239,7 +239,7 @@ describe('mcp', () => {
239
239
  "org.paymentauth/credential": {
240
240
  "challenge": {
241
241
  "expires": "2025-01-01T00:00:00.000Z",
242
- "id": "EUAHxZRCSFB29SAs5TEcB4cQDS0uVDzl8uSYuA58aVs",
242
+ "id": "wv3vZAjsySM50i4f1sJCZxyOLNry0dLSOwuWDBqrXaw",
243
243
  "intent": "charge",
244
244
  "method": "tempo",
245
245
  "realm": "api.example.com",
@@ -1,5 +1,5 @@
1
1
  import * as Challenge from '../../Challenge.js'
2
- import type * as MethodIntent from '../../MethodIntent.js'
2
+ import type * as Method from '../../Method.js'
3
3
  import type * as z from '../../zod.js'
4
4
 
5
5
  let originalFetch: typeof globalThis.fetch | undefined
@@ -25,7 +25,7 @@ let originalFetch: typeof globalThis.fetch | undefined
25
25
  * ```
26
26
  *
27
27
  */
28
- export function from<const methods extends readonly MethodIntent.AnyClient[]>(
28
+ export function from<const methods extends readonly Method.AnyClient[]>(
29
29
  config: from.Config<methods>,
30
30
  ): from.Fetch<methods> {
31
31
  const { fetch = globalThis.fetch, methods, onChallenge } = config
@@ -38,10 +38,10 @@ export function from<const methods extends readonly MethodIntent.AnyClient[]>(
38
38
 
39
39
  const challenge = Challenge.fromResponse(response)
40
40
 
41
- const mi = methods.find((m) => m.method === challenge.method && m.name === challenge.intent)
41
+ const mi = methods.find((m) => m.name === challenge.method && m.intent === challenge.intent)
42
42
  if (!mi)
43
43
  throw new Error(
44
- `No method intent found for "${challenge.method}.${challenge.intent}". Available: ${methods.map((m) => `${m.method}.${m.name}`).join(', ')}`,
44
+ `No method found for "${challenge.method}.${challenge.intent}". Available: ${methods.map((m) => `${m.name}.${m.intent}`).join(', ')}`,
45
45
  )
46
46
 
47
47
  const onChallengeCredential = onChallenge
@@ -63,8 +63,8 @@ export function from<const methods extends readonly MethodIntent.AnyClient[]>(
63
63
  }
64
64
 
65
65
  /** Union of all context types from all methods that have context schemas. */
66
- type AnyContextFor<methods extends readonly MethodIntent.AnyClient[]> = {
67
- [K in keyof methods]: methods[K] extends MethodIntent.Client<any, infer contextSchema>
66
+ type AnyContextFor<methods extends readonly Method.AnyClient[]> = {
67
+ [K in keyof methods]: methods[K] extends Method.Client<any, infer contextSchema>
68
68
  ? contextSchema extends z.ZodMiniType
69
69
  ? z.input<contextSchema>
70
70
  : undefined
@@ -72,12 +72,10 @@ type AnyContextFor<methods extends readonly MethodIntent.AnyClient[]> = {
72
72
  }[number]
73
73
 
74
74
  export declare namespace from {
75
- type Config<
76
- methods extends readonly MethodIntent.AnyClient[] = readonly MethodIntent.AnyClient[],
77
- > = {
75
+ type Config<methods extends readonly Method.AnyClient[] = readonly Method.AnyClient[]> = {
78
76
  /** Custom fetch function to wrap. Defaults to `globalThis.fetch`. */
79
77
  fetch?: typeof globalThis.fetch
80
- /** Array of method intents to use. */
78
+ /** Array of methods to use. */
81
79
  methods: methods
82
80
  /** Called when a 402 challenge is received, before credential creation. */
83
81
  onChallenge?:
@@ -90,16 +88,16 @@ export declare namespace from {
90
88
  | undefined
91
89
  }
92
90
 
93
- type Fetch<
94
- methods extends readonly MethodIntent.AnyClient[] = readonly MethodIntent.AnyClient[],
95
- > = (input: RequestInfo | URL, init?: RequestInit<methods>) => Promise<Response>
91
+ type Fetch<methods extends readonly Method.AnyClient[] = readonly Method.AnyClient[]> = (
92
+ input: RequestInfo | URL,
93
+ init?: RequestInit<methods>,
94
+ ) => Promise<Response>
96
95
 
97
- type RequestInit<
98
- methods extends readonly MethodIntent.AnyClient[] = readonly MethodIntent.AnyClient[],
99
- > = globalThis.RequestInit & {
100
- /** Context to pass to the method intent's createCredential. */
101
- context?: AnyContextFor<methods>
102
- }
96
+ type RequestInit<methods extends readonly Method.AnyClient[] = readonly Method.AnyClient[]> =
97
+ globalThis.RequestInit & {
98
+ /** Context to pass to the method intent's createCredential. */
99
+ context?: AnyContextFor<methods>
100
+ }
103
101
  }
104
102
 
105
103
  /**
@@ -122,7 +120,7 @@ export declare namespace from {
122
120
  * const res = await fetch('https://api.example.com/resource')
123
121
  * ```
124
122
  */
125
- export function polyfill<const methods extends readonly MethodIntent.AnyClient[]>(
123
+ export function polyfill<const methods extends readonly Method.AnyClient[]>(
126
124
  config: polyfill.Config<methods>,
127
125
  ): void {
128
126
  originalFetch = globalThis.fetch
@@ -130,9 +128,8 @@ export function polyfill<const methods extends readonly MethodIntent.AnyClient[]
130
128
  }
131
129
 
132
130
  export declare namespace polyfill {
133
- type Config<
134
- methods extends readonly MethodIntent.AnyClient[] = readonly MethodIntent.AnyClient[],
135
- > = from.Config<methods>
131
+ type Config<methods extends readonly Method.AnyClient[] = readonly Method.AnyClient[]> =
132
+ from.Config<methods>
136
133
  }
137
134
 
138
135
  /**
@@ -159,7 +156,7 @@ export function restore(): void {
159
156
  /** @internal */
160
157
  async function resolveCredential(
161
158
  challenge: Challenge.Challenge,
162
- mi: MethodIntent.AnyClient,
159
+ mi: Method.AnyClient,
163
160
  context: unknown,
164
161
  ): Promise<string> {
165
162
  const parsedContext = mi.context && context !== undefined ? mi.context.parse(context) : undefined
package/src/index.ts CHANGED
@@ -3,9 +3,8 @@ export * as Challenge from './Challenge.js'
3
3
  export * as Credential from './Credential.js'
4
4
  export * as Errors from './Errors.js'
5
5
  export * as Expires from './Expires.js'
6
- export * as Intent from './Intent.js'
7
6
  export * as Mcp from './Mcp.js'
8
- export * as MethodIntent from './MethodIntent.js'
7
+ export * as Method from './Method.js'
9
8
  export * as PaymentRequest from './PaymentRequest.js'
10
9
  export * as Receipt from './Receipt.js'
11
10
  export * as Store from './Store.js'
@@ -154,7 +154,7 @@ describe('McpClient.wrap', () => {
154
154
  })
155
155
 
156
156
  test('error: throws when method not found', async () => {
157
- const challenge = Challenge.fromIntent(tempo_server.charge({ getClient: () => testClient }), {
157
+ const challenge = Challenge.fromMethod(tempo_server.charge({ getClient: () => testClient }), {
158
158
  realm,
159
159
  secretKey,
160
160
  request: {