mppx 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +1 -1
  2. package/dist/Challenge.d.ts +18 -18
  3. package/dist/Challenge.d.ts.map +1 -1
  4. package/dist/Challenge.js +8 -8
  5. package/dist/Challenge.js.map +1 -1
  6. package/dist/Errors.d.ts +58 -8
  7. package/dist/Errors.d.ts.map +1 -1
  8. package/dist/Errors.js +51 -9
  9. package/dist/Errors.js.map +1 -1
  10. package/dist/Method.d.ts +154 -0
  11. package/dist/Method.d.ts.map +1 -0
  12. package/dist/Method.js +81 -0
  13. package/dist/Method.js.map +1 -0
  14. package/dist/PaymentRequest.d.ts +5 -5
  15. package/dist/PaymentRequest.d.ts.map +1 -1
  16. package/dist/PaymentRequest.js +5 -5
  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 +12 -7
  24. package/dist/client/Mppx.d.ts.map +1 -1
  25. package/dist/client/Mppx.js +10 -5
  26. package/dist/client/Mppx.js.map +1 -1
  27. package/dist/client/internal/Fetch.d.ts +13 -11
  28. package/dist/client/internal/Fetch.d.ts.map +1 -1
  29. package/dist/client/internal/Fetch.js +8 -4
  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 +48 -44
  62. package/dist/stripe/client/Charge.d.ts.map +1 -1
  63. package/dist/stripe/client/Charge.js +22 -17
  64. package/dist/stripe/client/Charge.js.map +1 -1
  65. package/dist/stripe/client/{MethodIntents.d.ts → Methods.d.ts} +25 -24
  66. package/dist/stripe/client/Methods.d.ts.map +1 -0
  67. package/dist/stripe/client/{MethodIntents.js → Methods.js} +4 -4
  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.d.ts.map +1 -1
  113. package/dist/tempo/client/SessionManager.js +10 -5
  114. package/dist/tempo/client/SessionManager.js.map +1 -1
  115. package/dist/tempo/client/index.d.ts +1 -1
  116. package/dist/tempo/client/index.d.ts.map +1 -1
  117. package/dist/tempo/client/index.js +1 -1
  118. package/dist/tempo/client/index.js.map +1 -1
  119. package/dist/tempo/index.d.ts +1 -1
  120. package/dist/tempo/index.d.ts.map +1 -1
  121. package/dist/tempo/index.js +1 -1
  122. package/dist/tempo/index.js.map +1 -1
  123. package/dist/tempo/internal/defaults.d.ts +1 -1
  124. package/dist/tempo/internal/defaults.js +1 -1
  125. package/dist/tempo/server/Charge.d.ts +27 -27
  126. package/dist/tempo/server/Charge.d.ts.map +1 -1
  127. package/dist/tempo/server/Charge.js +3 -3
  128. package/dist/tempo/server/Charge.js.map +1 -1
  129. package/dist/tempo/server/{MethodIntents.d.ts → Methods.d.ts} +73 -69
  130. package/dist/tempo/server/Methods.d.ts.map +1 -0
  131. package/dist/tempo/server/{MethodIntents.js → Methods.js} +4 -4
  132. package/dist/tempo/server/Methods.js.map +1 -0
  133. package/dist/tempo/server/Session.d.ts +51 -47
  134. package/dist/tempo/server/Session.d.ts.map +1 -1
  135. package/dist/tempo/server/Session.js +4 -4
  136. package/dist/tempo/server/Session.js.map +1 -1
  137. package/dist/tempo/server/index.d.ts +6 -0
  138. package/dist/tempo/server/index.d.ts.map +1 -0
  139. package/dist/tempo/server/index.js +6 -0
  140. package/dist/tempo/server/index.js.map +1 -0
  141. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  142. package/dist/tempo/server/internal/transport.js +2 -1
  143. package/dist/tempo/server/internal/transport.js.map +1 -1
  144. package/package.json +1 -1
  145. package/src/Challenge.test-d.ts +3 -3
  146. package/src/Challenge.test.ts +6 -6
  147. package/src/Challenge.ts +34 -34
  148. package/src/Errors.test.ts +75 -21
  149. package/src/Errors.ts +74 -9
  150. package/src/Method.test.ts +76 -0
  151. package/src/Method.ts +228 -0
  152. package/src/PaymentRequest.test.ts +4 -4
  153. package/src/PaymentRequest.ts +9 -9
  154. package/src/cli.test.ts +12 -22
  155. package/src/cli.ts +74 -21
  156. package/src/client/Methods.ts +2 -2
  157. package/src/client/Mppx.test-d.ts +6 -6
  158. package/src/client/Mppx.test.ts +26 -22
  159. package/src/client/Mppx.ts +29 -13
  160. package/src/client/Transport.test.ts +2 -2
  161. package/src/client/internal/Fetch.test.ts +35 -1
  162. package/src/client/internal/Fetch.ts +36 -27
  163. package/src/index.ts +1 -2
  164. package/src/mcp-sdk/client/McpClient.ts +11 -13
  165. package/src/middlewares/elysia.ts +1 -1
  166. package/src/middlewares/express.ts +1 -1
  167. package/src/middlewares/hono.ts +1 -1
  168. package/src/middlewares/internal/mppx.ts +10 -10
  169. package/src/middlewares/nextjs.ts +1 -1
  170. package/src/proxy/Service.ts +2 -2
  171. package/src/server/Methods.ts +2 -2
  172. package/src/server/Mppx.test-d.ts +27 -29
  173. package/src/server/Mppx.test.ts +23 -19
  174. package/src/server/Mppx.ts +43 -43
  175. package/src/server/Transport.test.ts +3 -3
  176. package/src/stripe/Charge.integration.test.ts +4 -1
  177. package/src/stripe/{Intents.test.ts → Methods.test.ts} +12 -12
  178. package/src/stripe/Methods.ts +45 -0
  179. package/src/stripe/client/Charge.test.ts +189 -0
  180. package/src/stripe/client/Charge.ts +40 -31
  181. package/src/stripe/client/{MethodIntents.ts → Methods.ts} +3 -3
  182. package/src/stripe/client/index.ts +1 -1
  183. package/src/stripe/index.ts +1 -1
  184. package/src/stripe/internal/types.ts +22 -0
  185. package/src/stripe/server/Charge.test.ts +241 -0
  186. package/src/stripe/server/Charge.ts +124 -38
  187. package/src/stripe/server/{MethodIntents.ts → Methods.ts} +2 -2
  188. package/src/stripe/server/index.ts +1 -1
  189. package/src/tempo/{Intents.test.ts → Methods.test.ts} +15 -15
  190. package/src/tempo/{Intents.ts → Methods.ts} +77 -22
  191. package/src/tempo/client/ChannelOps.ts +1 -1
  192. package/src/tempo/client/Charge.ts +3 -3
  193. package/src/tempo/client/{MethodIntents.ts → Methods.ts} +2 -2
  194. package/src/tempo/client/Session.ts +4 -4
  195. package/src/tempo/client/SessionManager.ts +11 -5
  196. package/src/tempo/client/index.ts +1 -1
  197. package/src/tempo/index.ts +1 -1
  198. package/src/tempo/internal/defaults.ts +1 -1
  199. package/src/tempo/server/Charge.ts +4 -7
  200. package/src/tempo/server/{MethodIntents.ts → Methods.ts} +3 -3
  201. package/src/tempo/server/Session.test.ts +4 -7
  202. package/src/tempo/server/Session.ts +6 -6
  203. package/src/tempo/server/index.ts +1 -1
  204. package/src/tempo/server/internal/transport.ts +3 -2
  205. package/dist/Intent.d.ts +0 -101
  206. package/dist/Intent.d.ts.map +0 -1
  207. package/dist/Intent.js +0 -83
  208. package/dist/Intent.js.map +0 -1
  209. package/dist/MethodIntent.d.ts +0 -225
  210. package/dist/MethodIntent.d.ts.map +0 -1
  211. package/dist/MethodIntent.js +0 -156
  212. package/dist/MethodIntent.js.map +0 -1
  213. package/dist/stripe/Intents.d.ts.map +0 -1
  214. package/dist/stripe/Intents.js +0 -27
  215. package/dist/stripe/Intents.js.map +0 -1
  216. package/dist/stripe/client/MethodIntents.d.ts.map +0 -1
  217. package/dist/stripe/client/MethodIntents.js.map +0 -1
  218. package/dist/stripe/server/MethodIntents.d.ts.map +0 -1
  219. package/dist/stripe/server/MethodIntents.js.map +0 -1
  220. package/dist/tempo/Intents.d.ts.map +0 -1
  221. package/dist/tempo/Intents.js +0 -81
  222. package/dist/tempo/Intents.js.map +0 -1
  223. package/dist/tempo/client/MethodIntents.d.ts.map +0 -1
  224. package/dist/tempo/client/MethodIntents.js.map +0 -1
  225. package/dist/tempo/server/MethodIntents.d.ts.map +0 -1
  226. package/dist/tempo/server/MethodIntents.js.map +0 -1
  227. package/src/Intent.test.ts +0 -180
  228. package/src/Intent.ts +0 -109
  229. package/src/MethodIntent.test.ts +0 -303
  230. package/src/MethodIntent.ts +0 -388
  231. package/src/stripe/Intents.ts +0 -27
@@ -2,29 +2,32 @@ import { tempo } from 'mppx/server'
2
2
  import { createClient, http } from 'viem'
3
3
  import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
4
4
  import { describe, expectTypeOf, test } from 'vitest'
5
- import * as Intent from '../Intent.js'
6
- import * as MethodIntent from '../MethodIntent.js'
5
+ import * as Method from '../Method.js'
7
6
  import * as z from '../zod.js'
8
7
  import * as Mppx from './Mppx.js'
9
8
 
10
9
  const account = privateKeyToAccount(generatePrivateKey())
11
10
  const getClient = () => createClient({ account, transport: http() })
12
11
 
13
- const fooCharge = MethodIntent.fromIntent(Intent.charge, {
14
- method: 'test',
12
+ const fooCharge = Method.from({
13
+ name: 'test',
14
+ intent: 'charge',
15
15
  schema: {
16
16
  credential: {
17
17
  payload: z.object({ signature: z.string() }),
18
18
  },
19
- request: {
20
- requires: ['recipient'],
21
- },
19
+ request: z.object({
20
+ amount: z.string(),
21
+ currency: z.string(),
22
+ decimals: z.number(),
23
+ recipient: z.string(),
24
+ }),
22
25
  },
23
26
  })
24
27
 
25
28
  describe('Mppx', () => {
26
29
  test('has methods and realm properties', () => {
27
- const method = MethodIntent.toServer(fooCharge, {
30
+ const method = Method.toServer(fooCharge, {
28
31
  async verify() {
29
32
  return {
30
33
  method: 'test',
@@ -45,8 +48,8 @@ describe('Mppx', () => {
45
48
  expectTypeOf(handler.realm).toBeString()
46
49
  })
47
50
 
48
- test('has intent functions matching method intents', () => {
49
- const method = MethodIntent.toServer(fooCharge, {
51
+ test('has method functions matching methods', () => {
52
+ const method = Method.toServer(fooCharge, {
50
53
  async verify() {
51
54
  return {
52
55
  method: 'test',
@@ -66,8 +69,8 @@ describe('Mppx', () => {
66
69
  expectTypeOf(handler.charge).toBeFunction()
67
70
  })
68
71
 
69
- test('intent function options include request', () => {
70
- const method = MethodIntent.toServer(fooCharge, {
72
+ test('method function options include request', () => {
73
+ const method = Method.toServer(fooCharge, {
71
74
  async verify() {
72
75
  return {
73
76
  method: 'test',
@@ -93,8 +96,8 @@ describe('Mppx', () => {
93
96
  })
94
97
  })
95
98
 
96
- test('intent function returns handler that accepts Request', async () => {
97
- const method = MethodIntent.toServer(fooCharge, {
99
+ test('method function returns handler that accepts Request', async () => {
100
+ const method = Method.toServer(fooCharge, {
98
101
  async verify() {
99
102
  return {
100
103
  method: 'test',
@@ -128,10 +131,14 @@ describe('Mppx', () => {
128
131
  }
129
132
  })
130
133
 
131
- test('multiple method intents', () => {
132
- const authorize = Intent.from({
133
- name: 'authorize',
134
+ test('multiple methods', () => {
135
+ const fooAuthorize = Method.from({
136
+ name: 'test',
137
+ intent: 'authorize',
134
138
  schema: {
139
+ credential: {
140
+ payload: z.object({ token: z.string() }),
141
+ },
135
142
  request: z.object({
136
143
  scope: z.string(),
137
144
  duration: z.number(),
@@ -139,16 +146,7 @@ describe('Mppx', () => {
139
146
  },
140
147
  })
141
148
 
142
- const fooAuthorize = MethodIntent.fromIntent(authorize, {
143
- method: 'test',
144
- schema: {
145
- credential: {
146
- payload: z.object({ token: z.string() }),
147
- },
148
- },
149
- })
150
-
151
- const chargeMethod = MethodIntent.toServer(fooCharge, {
149
+ const chargeMethod = Method.toServer(fooCharge, {
152
150
  defaults: {
153
151
  currency: '0x1234',
154
152
  recipient: '0xabc',
@@ -163,7 +161,7 @@ describe('Mppx', () => {
163
161
  },
164
162
  })
165
163
 
166
- const authorizeMethod = MethodIntent.toServer(fooAuthorize, {
164
+ const authorizeMethod = Method.toServer(fooAuthorize, {
167
165
  async verify() {
168
166
  return {
169
167
  method: 'test',
@@ -194,7 +192,7 @@ describe('Mppx', () => {
194
192
  })
195
193
 
196
194
  describe('defaults', () => {
197
- test('defaulted fields are optional in intent options', () => {
195
+ test('defaulted fields are optional in method options', () => {
198
196
  const handler = Mppx.create({
199
197
  methods: [tempo({ currency: '0x1234', recipient: '0xabc', getClient })],
200
198
  realm: 'api.example.com',
@@ -1,4 +1,4 @@
1
- import { Challenge, Credential, Intent, MethodIntent, z } from 'mppx'
1
+ import { Challenge, Credential, Method, z } from 'mppx'
2
2
  import { Mppx, Transport, tempo } from 'mppx/server'
3
3
  import { describe, expect, test } from 'vitest'
4
4
  import * as Http from '~test/Http.js'
@@ -56,8 +56,8 @@ describe('request handler', () => {
56
56
  "detail": "Payment is required for "api.example.com".",
57
57
  "instance": "[instance]",
58
58
  "status": 402,
59
- "title": "PaymentRequiredError",
60
- "type": "https://tempoxyz.github.io/payment-auth-spec/problems/payment-required",
59
+ "title": "Payment Required",
60
+ "type": "https://paymentauth.org/problems/payment-required",
61
61
  }
62
62
  `)
63
63
  })
@@ -88,8 +88,8 @@ describe('request handler', () => {
88
88
  "detail": "Credential is malformed: Invalid base64url or JSON..",
89
89
  "instance": "[instance]",
90
90
  "status": 402,
91
- "title": "MalformedCredentialError",
92
- "type": "https://tempoxyz.github.io/payment-auth-spec/problems/malformed-credential",
91
+ "title": "Malformed Credential",
92
+ "type": "https://paymentauth.org/problems/malformed-credential",
93
93
  }
94
94
  `)
95
95
  })
@@ -132,8 +132,8 @@ describe('request handler', () => {
132
132
  "detail": "Challenge "wrong-id" is invalid: challenge was not issued by this server.",
133
133
  "instance": "[instance]",
134
134
  "status": 402,
135
- "title": "InvalidChallengeError",
136
- "type": "https://tempoxyz.github.io/payment-auth-spec/problems/invalid-challenge",
135
+ "title": "Invalid Challenge",
136
+ "type": "https://paymentauth.org/problems/invalid-challenge",
137
137
  }
138
138
  `)
139
139
  })
@@ -178,8 +178,8 @@ describe('request handler', () => {
178
178
  "detail": "[detail]",
179
179
  "instance": "[instance]",
180
180
  "status": 402,
181
- "title": "InvalidPayloadError",
182
- "type": "https://tempoxyz.github.io/payment-auth-spec/problems/invalid-payload",
181
+ "title": "Invalid Payload",
182
+ "type": "https://paymentauth.org/problems/invalid-payload",
183
183
  }
184
184
  `)
185
185
  expect(body.detail).toContain('Credential payload is invalid')
@@ -218,8 +218,8 @@ describe('request handler (node)', () => {
218
218
  "detail": "Payment is required for "api.example.com".",
219
219
  "instance": "[instance]",
220
220
  "status": 402,
221
- "title": "PaymentRequiredError",
222
- "type": "https://tempoxyz.github.io/payment-auth-spec/problems/payment-required",
221
+ "title": "Payment Required",
222
+ "type": "https://paymentauth.org/problems/payment-required",
223
223
  }
224
224
  `)
225
225
 
@@ -271,8 +271,8 @@ describe('request handler (node)', () => {
271
271
  "detail": "[detail]",
272
272
  "instance": "[instance]",
273
273
  "status": 402,
274
- "title": "VerificationFailedError",
275
- "type": "https://tempoxyz.github.io/payment-auth-spec/problems/verification-failed",
274
+ "title": "Verification Failed",
275
+ "type": "https://paymentauth.org/problems/verification-failed",
276
276
  }
277
277
  `)
278
278
  expect(body.detail).toContain('Payment verification failed')
@@ -283,19 +283,23 @@ describe('request handler (node)', () => {
283
283
 
284
284
  describe('receipt handling', () => {
285
285
  test('returns 200 when verify returns a success receipt', async () => {
286
- const mockCharge = MethodIntent.fromIntent(Intent.charge, {
287
- method: 'mock',
286
+ const mockCharge = Method.from({
287
+ name: 'mock',
288
+ intent: 'charge',
288
289
  schema: {
289
290
  credential: {
290
291
  payload: z.object({ token: z.string() }),
291
292
  },
292
- request: {
293
- requires: ['recipient'],
294
- },
293
+ request: z.object({
294
+ amount: z.string(),
295
+ currency: z.string(),
296
+ decimals: z.number(),
297
+ recipient: z.string(),
298
+ }),
295
299
  },
296
300
  })
297
301
 
298
- const mockMethod = MethodIntent.toServer(mockCharge, {
302
+ const mockMethod = Method.toServer(mockCharge, {
299
303
  async verify() {
300
304
  return {
301
305
  method: 'mock',
@@ -2,14 +2,14 @@ import type { IncomingMessage, ServerResponse } from 'node:http'
2
2
  import * as Challenge from '../Challenge.js'
3
3
  import type * as Credential from '../Credential.js'
4
4
  import * as Errors from '../Errors.js'
5
- import type * as MethodIntent from '../MethodIntent.js'
5
+ import type * as Method from '../Method.js'
6
6
  import type * as Receipt from '../Receipt.js'
7
7
  import type * as z from '../zod.js'
8
8
  import * as NodeListener from './NodeListener.js'
9
9
  import * as Request from './Request.js'
10
10
  import * as Transport from './Transport.js'
11
11
 
12
- export type Methods = readonly (MethodIntent.AnyServer | readonly MethodIntent.AnyServer[])[]
12
+ export type Methods = readonly (Method.AnyServer | readonly Method.AnyServer[])[]
13
13
 
14
14
  /**
15
15
  * Payment handler.
@@ -26,14 +26,14 @@ export type Mppx<
26
26
  transport: transport
27
27
  } & Handlers<FlattenMethods<methods>, transport>
28
28
 
29
- /** Extracts the transport override from a method intent, if any. */
29
+ /** Extracts the transport override from a method, if any. */
30
30
  type TransportOverrideOf<mi> = mi extends { transport?: infer transport }
31
31
  ? Exclude<transport, undefined> extends Transport.AnyTransport
32
32
  ? Exclude<transport, undefined>
33
33
  : never
34
34
  : never
35
35
 
36
- /** Resolves the effective transport for an intent: override if present, else global default. */
36
+ /** Resolves the effective transport for a method: override if present, else global default. */
37
37
  type EffectiveTransportOf<mi, defaultTransport extends Transport.AnyTransport> = [
38
38
  TransportOverrideOf<mi>,
39
39
  ] extends [never]
@@ -41,18 +41,18 @@ type EffectiveTransportOf<mi, defaultTransport extends Transport.AnyTransport> =
41
41
  : TransportOverrideOf<mi>
42
42
 
43
43
  type Handlers<
44
- methods extends readonly MethodIntent.AnyServer[],
44
+ methods extends readonly Method.AnyServer[],
45
45
  transport extends Transport.AnyTransport,
46
46
  > = {
47
- [intent in methods[number]['name']]: IntentFn<
48
- Extract<methods[number], { name: intent }>,
49
- EffectiveTransportOf<Extract<methods[number], { name: intent }>, transport>,
50
- NonNullable<Extract<methods[number], { name: intent }>['defaults']>
47
+ [method_name in methods[number]['intent']]: MethodFn<
48
+ Extract<methods[number], { intent: method_name }>,
49
+ EffectiveTransportOf<Extract<methods[number], { intent: method_name }>, transport>,
50
+ NonNullable<Extract<methods[number], { intent: method_name }>['defaults']>
51
51
  >
52
52
  }
53
53
 
54
54
  /**
55
- * Creates a server-side payment handler from method intents.
55
+ * Creates a server-side payment handler from methods.
56
56
  *
57
57
  * It is highly recommended to set a `secretKey` to bind challenges to their contents,
58
58
  * and allow the server to verify that incoming credentials match challenges it issued.
@@ -82,9 +82,9 @@ export function create<
82
82
  const handlers: Record<string, unknown> = {}
83
83
 
84
84
  for (const mi of methods) {
85
- handlers[mi.name] = createIntentFn({
85
+ handlers[mi.intent] = createMethodFn({
86
86
  defaults: mi.defaults,
87
- intent: mi,
87
+ method: mi,
88
88
  realm,
89
89
  request: mi.request as never,
90
90
  respond: mi.respond as never,
@@ -113,25 +113,25 @@ export declare namespace create {
113
113
  }
114
114
  }
115
115
 
116
- function createIntentFn<
117
- intent extends MethodIntent.MethodIntent,
116
+ function createMethodFn<
117
+ method extends Method.Method,
118
118
  transport extends Transport.AnyTransport,
119
119
  defaults extends Record<string, unknown>,
120
120
  >(
121
- parameters: createIntentFn.Parameters<intent, transport, defaults>,
122
- ): createIntentFn.ReturnType<intent, transport, defaults>
121
+ parameters: createMethodFn.Parameters<method, transport, defaults>,
122
+ ): createMethodFn.ReturnType<method, transport, defaults>
123
123
  // biome-ignore lint/correctness/noUnusedVariables: _
124
- function createIntentFn(parameters: createIntentFn.Parameters): createIntentFn.ReturnType {
125
- const { defaults, intent, realm, respond, secretKey, transport, verify } = parameters
124
+ function createMethodFn(parameters: createMethodFn.Parameters): createMethodFn.ReturnType {
125
+ const { defaults, method, realm, respond, secretKey, transport, verify } = parameters
126
126
 
127
127
  return (options) => {
128
128
  const meta = {
129
- ...intent,
129
+ ...method,
130
130
  ...defaults,
131
131
  ...options,
132
132
  }
133
133
  return Object.assign(
134
- async (input: Transport.InputOf): Promise<IntentFn.Response> => {
134
+ async (input: Transport.InputOf): Promise<MethodFn.Response> => {
135
135
  const { description, ...rest } = options
136
136
  const expires = 'expires' in options ? (options.expires as string | undefined) : undefined
137
137
 
@@ -160,7 +160,7 @@ function createIntentFn(parameters: createIntentFn.Parameters): createIntentFn.R
160
160
  // Recompute challenge from options. The HMAC-bound ID means we don't need to
161
161
  // store challenges server-side—if the client echoes back a credential with
162
162
  // a matching ID, we know it was issued by us with these exact parameters.
163
- const challenge = Challenge.fromIntent(intent, {
163
+ const challenge = Challenge.fromIntent(method, {
164
164
  description,
165
165
  expires,
166
166
  realm,
@@ -202,9 +202,9 @@ function createIntentFn(parameters: createIntentFn.Parameters): createIntentFn.R
202
202
  return { challenge: response, status: 402 }
203
203
  }
204
204
 
205
- // Validate payload structure against intent schema
205
+ // Validate payload structure against method schema
206
206
  try {
207
- intent.schema.credential.payload.parse(credential.payload)
207
+ method.schema.credential.payload.parse(credential.payload)
208
208
  } catch (e) {
209
209
  const response = await transport.respondChallenge({
210
210
  challenge,
@@ -265,50 +265,50 @@ function createIntentFn(parameters: createIntentFn.Parameters): createIntentFn.R
265
265
  }
266
266
  }
267
267
 
268
- declare namespace createIntentFn {
268
+ declare namespace createMethodFn {
269
269
  type Parameters<
270
- intent extends MethodIntent.MethodIntent = MethodIntent.MethodIntent,
270
+ method extends Method.Method = Method.Method,
271
271
  transport extends Transport.AnyTransport = Transport.Http,
272
272
  defaults extends Record<string, unknown> = Record<string, unknown>,
273
273
  > = {
274
274
  defaults?: defaults
275
- intent: intent
275
+ method: method
276
276
  realm: string
277
- request?: MethodIntent.RequestFn<intent>
278
- respond?: MethodIntent.RespondFn<intent>
277
+ request?: Method.RequestFn<method>
278
+ respond?: Method.RespondFn<method>
279
279
  secretKey: string
280
280
  transport: transport
281
- verify: MethodIntent.VerifyFn<intent>
281
+ verify: Method.VerifyFn<method>
282
282
  }
283
283
 
284
284
  type ReturnType<
285
- intent extends MethodIntent.MethodIntent = MethodIntent.MethodIntent,
285
+ method extends Method.Method = Method.Method,
286
286
  transport extends Transport.AnyTransport = Transport.Http,
287
287
  defaults extends Record<string, unknown> = Record<string, unknown>,
288
- > = IntentFn<intent, transport, defaults>
288
+ > = MethodFn<method, transport, defaults>
289
289
  }
290
290
 
291
- export type IntentFn<
292
- intent extends MethodIntent.MethodIntent,
291
+ export type MethodFn<
292
+ method extends Method.Method,
293
293
  transport extends Transport.AnyTransport,
294
294
  defaults extends Record<string, unknown>,
295
295
  > = (
296
- options: IntentFn.Options<intent, defaults>,
297
- ) => (input: Transport.InputOf<transport>) => Promise<IntentFn.Response<transport>>
296
+ options: MethodFn.Options<method, defaults>,
297
+ ) => (input: Transport.InputOf<transport>) => Promise<MethodFn.Response<transport>>
298
298
  /** @internal */
299
- export type AnyIntentFn = (options: any) => (input: any) => Promise<any>
299
+ export type AnyMethodFn = (options: any) => (input: any) => Promise<any>
300
300
 
301
301
  /** @internal */
302
- declare namespace IntentFn {
302
+ declare namespace MethodFn {
303
303
  export type Options<
304
- intent extends MethodIntent.MethodIntent,
304
+ method extends Method.Method,
305
305
  defaults extends Record<string, unknown> = Record<string, unknown>,
306
306
  > = {
307
307
  /** Optional human-readable description of the payment. */
308
308
  description?: string | undefined
309
309
  /** Optional challenge expiration timestamp (ISO 8601). */
310
310
  expires?: string | undefined
311
- } & MethodIntent.WithDefaults<z.input<intent['schema']['request']>, defaults>
311
+ } & Method.WithDefaults<z.input<method['schema']['request']>, defaults>
312
312
 
313
313
  export type Response<transport extends Transport.AnyTransport = Transport.Http> =
314
314
  | {
@@ -346,8 +346,8 @@ declare namespace IntentFn {
346
346
  * ```
347
347
  */
348
348
  export function toNodeListener(
349
- handler: (input: globalThis.Request) => Promise<IntentFn.Response<Transport.Http>>,
350
- ): (req: IncomingMessage, res: ServerResponse) => Promise<IntentFn.Response<Transport.Http>> {
349
+ handler: (input: globalThis.Request) => Promise<MethodFn.Response<Transport.Http>>,
350
+ ): (req: IncomingMessage, res: ServerResponse) => Promise<MethodFn.Response<Transport.Http>> {
351
351
  return async (req, res) => {
352
352
  const result = await handler(Request.fromNodeListener(req, res))
353
353
 
@@ -370,9 +370,9 @@ type FlattenMethods<methods extends Methods> = methods extends readonly [
370
370
  infer head,
371
371
  ...infer tail extends Methods,
372
372
  ]
373
- ? head extends readonly MethodIntent.AnyServer[]
373
+ ? head extends readonly Method.AnyServer[]
374
374
  ? readonly [...head, ...FlattenMethods<tail>]
375
- : head extends MethodIntent.AnyServer
375
+ : head extends Method.AnyServer
376
376
  ? readonly [head, ...FlattenMethods<tail>]
377
377
  : never
378
378
  : readonly []
@@ -1,13 +1,13 @@
1
1
  import { Challenge, Credential, Mcp, Receipt } from 'mppx'
2
2
  import { Transport } from 'mppx/server'
3
- import { MethodIntents as Intents } from 'mppx/tempo'
3
+ import { Methods } from 'mppx/tempo'
4
4
  import { describe, expect, test } from 'vitest'
5
5
  import { BadRequestError, ChannelClosedError } from '../Errors.js'
6
6
 
7
7
  const realm = 'api.example.com'
8
8
  const secretKey = 'test-secret-key'
9
9
 
10
- const challenge = Challenge.fromIntent(Intents.charge, {
10
+ const challenge = Challenge.fromIntent(Methods.charge, {
11
11
  realm,
12
12
  secretKey,
13
13
  request: {
@@ -111,7 +111,7 @@ describe('http', () => {
111
111
 
112
112
  expect(response.status).toBe(400)
113
113
  const body = await response.json()
114
- expect(body.type).toBe('https://tempoxyz.github.io/payment-auth-spec/problems/bad-request')
114
+ expect(body.type).toBe('https://paymentauth.org/problems/bad-request')
115
115
  expect(body.status).toBe(400)
116
116
  })
117
117
 
@@ -87,7 +87,10 @@ describe.skipIf(!stripeSecretKey)('stripe', () => {
87
87
  })
88
88
 
89
89
  const clientCharge = stripe_client.charge({
90
- createSpt: createTestSpt,
90
+ createToken: async (params) => {
91
+ if (!params.paymentMethod) throw new Error('paymentMethod is required')
92
+ return createTestSpt({ ...params, paymentMethod: params.paymentMethod })
93
+ },
91
94
  paymentMethod: 'pm_card_visa',
92
95
  externalId: 'client_order_789',
93
96
  })
@@ -1,22 +1,22 @@
1
- import { MethodIntents } from 'mppx/stripe'
1
+ import { Methods } from 'mppx/stripe'
2
2
  import { describe, expect, expectTypeOf, test } from 'vitest'
3
3
 
4
4
  describe('charge', () => {
5
- test('has correct name and method', () => {
6
- expect(MethodIntents.charge.name).toBe('charge')
7
- expect(MethodIntents.charge.method).toBe('stripe')
5
+ test('has correct name and intent', () => {
6
+ expect(Methods.charge.intent).toBe('charge')
7
+ expect(Methods.charge.name).toBe('stripe')
8
8
  })
9
9
 
10
- test('types: name is literal', () => {
11
- expectTypeOf(MethodIntents.charge.name).toEqualTypeOf<'charge'>()
10
+ test('types: intent is literal', () => {
11
+ expectTypeOf(Methods.charge.intent).toEqualTypeOf<'charge'>()
12
12
  })
13
13
 
14
- test('types: method is literal', () => {
15
- expectTypeOf(MethodIntents.charge.method).toEqualTypeOf<'stripe'>()
14
+ test('types: name is literal', () => {
15
+ expectTypeOf(Methods.charge.name).toEqualTypeOf<'stripe'>()
16
16
  })
17
17
 
18
18
  test('schema: validates valid request', () => {
19
- const result = MethodIntents.charge.schema.request.safeParse({
19
+ const result = Methods.charge.schema.request.safeParse({
20
20
  amount: '1',
21
21
  currency: 'usd',
22
22
  decimals: 2,
@@ -29,14 +29,14 @@ describe('charge', () => {
29
29
  })
30
30
 
31
31
  test('schema: rejects invalid request', () => {
32
- const result = MethodIntents.charge.schema.request.safeParse({
32
+ const result = Methods.charge.schema.request.safeParse({
33
33
  amount: '1',
34
34
  })
35
35
  expect(result.success).toBe(false)
36
36
  })
37
37
 
38
38
  test('schema: validates spt payload', () => {
39
- const result = MethodIntents.charge.schema.credential.payload.safeParse({
39
+ const result = Methods.charge.schema.credential.payload.safeParse({
40
40
  spt: 'spt_test_123',
41
41
  externalId: 'client_order_789',
42
42
  })
@@ -44,7 +44,7 @@ describe('charge', () => {
44
44
  })
45
45
 
46
46
  test('schema: rejects invalid payload', () => {
47
- const result = MethodIntents.charge.schema.credential.payload.safeParse({
47
+ const result = Methods.charge.schema.credential.payload.safeParse({
48
48
  signature: '0x...',
49
49
  })
50
50
  expect(result.success).toBe(false)
@@ -0,0 +1,45 @@
1
+ import { parseUnits } from 'viem'
2
+ import * as Expires from '../Expires.js'
3
+ import * as Method from '../Method.js'
4
+ import * as z from '../zod.js'
5
+
6
+ /**
7
+ * Stripe charge intent for one-time payments via Shared Payment Tokens (SPTs).
8
+ *
9
+ * @see https://github.com/tempoxyz/payment-auth-spec/blob/main/specs/methods/stripe/draft-stripe-charge-00.md
10
+ */
11
+ export const charge = Method.from({
12
+ name: 'stripe',
13
+ intent: 'charge',
14
+ schema: {
15
+ credential: {
16
+ payload: z.object({
17
+ externalId: z.optional(z.string()),
18
+ spt: z.string(),
19
+ }),
20
+ },
21
+ request: z.pipe(
22
+ z.object({
23
+ amount: z.amount(),
24
+ currency: z.string(),
25
+ decimals: z.number(),
26
+ description: z.optional(z.string()),
27
+ expires: z._default(z.datetime(), () => Expires.minutes(5)),
28
+ externalId: z.optional(z.string()),
29
+ metadata: z.optional(z.record(z.string(), z.string())),
30
+ networkId: z.string(),
31
+ paymentMethodTypes: z.array(z.string()).check(z.minLength(1)),
32
+ recipient: z.optional(z.string()),
33
+ }),
34
+ z.transform(({ amount, decimals, metadata, networkId, paymentMethodTypes, ...rest }) => ({
35
+ ...rest,
36
+ amount: parseUnits(amount, decimals).toString(),
37
+ methodDetails: {
38
+ networkId,
39
+ paymentMethodTypes,
40
+ ...(metadata !== undefined && { metadata }),
41
+ },
42
+ })),
43
+ ),
44
+ },
45
+ })