mppx 0.3.13 → 0.3.15

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 (75) hide show
  1. package/dist/Challenge.d.ts +1 -1
  2. package/dist/Challenge.d.ts.map +1 -1
  3. package/dist/Challenge.js +107 -15
  4. package/dist/Challenge.js.map +1 -1
  5. package/dist/bin.d.ts +3 -0
  6. package/dist/bin.d.ts.map +1 -0
  7. package/dist/bin.js +4 -0
  8. package/dist/bin.js.map +1 -0
  9. package/dist/cli.d.ts +26 -2
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +1478 -915
  12. package/dist/cli.js.map +1 -1
  13. package/dist/client/Mppx.d.ts +2 -0
  14. package/dist/client/Mppx.d.ts.map +1 -1
  15. package/dist/client/Mppx.js +2 -0
  16. package/dist/client/Mppx.js.map +1 -1
  17. package/dist/server/Mppx.d.ts.map +1 -1
  18. package/dist/server/Mppx.js +2 -1
  19. package/dist/server/Mppx.js.map +1 -1
  20. package/dist/stripe/Methods.d.ts +0 -3
  21. package/dist/stripe/Methods.d.ts.map +1 -1
  22. package/dist/stripe/Methods.js +0 -2
  23. package/dist/stripe/Methods.js.map +1 -1
  24. package/dist/stripe/client/Charge.d.ts +0 -3
  25. package/dist/stripe/client/Charge.d.ts.map +1 -1
  26. package/dist/stripe/client/Charge.js +2 -2
  27. package/dist/stripe/client/Charge.js.map +1 -1
  28. package/dist/stripe/client/Methods.d.ts +0 -3
  29. package/dist/stripe/client/Methods.d.ts.map +1 -1
  30. package/dist/stripe/server/Charge.d.ts +0 -3
  31. package/dist/stripe/server/Charge.d.ts.map +1 -1
  32. package/dist/stripe/server/Charge.js +2 -2
  33. package/dist/stripe/server/Charge.js.map +1 -1
  34. package/dist/stripe/server/Methods.d.ts +0 -3
  35. package/dist/stripe/server/Methods.d.ts.map +1 -1
  36. package/dist/tempo/Methods.d.ts +0 -3
  37. package/dist/tempo/Methods.d.ts.map +1 -1
  38. package/dist/tempo/Methods.js +3 -3
  39. package/dist/tempo/Methods.js.map +1 -1
  40. package/dist/tempo/client/Charge.d.ts +13 -3
  41. package/dist/tempo/client/Charge.d.ts.map +1 -1
  42. package/dist/tempo/client/Charge.js +18 -1
  43. package/dist/tempo/client/Charge.js.map +1 -1
  44. package/dist/tempo/client/Methods.d.ts +4 -3
  45. package/dist/tempo/client/Methods.d.ts.map +1 -1
  46. package/dist/tempo/server/Charge.d.ts +0 -3
  47. package/dist/tempo/server/Charge.d.ts.map +1 -1
  48. package/dist/tempo/server/Charge.js +2 -1
  49. package/dist/tempo/server/Charge.js.map +1 -1
  50. package/dist/tempo/server/Methods.d.ts +0 -3
  51. package/dist/tempo/server/Methods.d.ts.map +1 -1
  52. package/package.json +4 -4
  53. package/src/Challenge.test.ts +94 -18
  54. package/src/Challenge.ts +118 -15
  55. package/src/PaymentRequest.test.ts +0 -5
  56. package/src/bin.ts +4 -0
  57. package/src/cli.test.ts +180 -252
  58. package/src/cli.ts +1085 -485
  59. package/src/client/Mppx.test-d.ts +9 -0
  60. package/src/client/Mppx.test.ts +83 -5
  61. package/src/client/Mppx.ts +5 -0
  62. package/src/client/Transport.test.ts +5 -8
  63. package/src/client/internal/Fetch.browser.test.ts +135 -0
  64. package/src/client/internal/Fetch.test.ts +0 -88
  65. package/src/mcp-sdk/client/McpClient.test.ts +1 -1
  66. package/src/server/Mppx.ts +3 -1
  67. package/src/server/Transport.test.ts +6 -9
  68. package/src/stripe/Methods.ts +0 -2
  69. package/src/stripe/client/Charge.ts +2 -2
  70. package/src/stripe/server/Charge.ts +2 -2
  71. package/src/tempo/Methods.test.ts +22 -0
  72. package/src/tempo/Methods.ts +3 -3
  73. package/src/tempo/client/Charge.ts +29 -1
  74. package/src/tempo/server/Charge.test.ts +34 -72
  75. package/src/tempo/server/Charge.ts +2 -1
@@ -1,6 +1,5 @@
1
1
  import type { Account } from 'viem'
2
2
  import { parseUnits } from 'viem'
3
- import * as Expires from '../Expires.js'
4
3
  import * as Method from '../Method.js'
5
4
  import * as z from '../zod.js'
6
5
 
@@ -26,7 +25,6 @@ export const charge = Method.from({
26
25
  currency: z.string(),
27
26
  decimals: z.number(),
28
27
  description: z.optional(z.string()),
29
- expires: z._default(z.datetime(), () => Expires.minutes(5)),
30
28
  externalId: z.optional(z.string()),
31
29
  feePayer: z.optional(
32
30
  z.pipe(
@@ -137,7 +135,9 @@ export const session = Method.from({
137
135
  methodDetails: {
138
136
  escrowContract,
139
137
  ...(channelId !== undefined && { channelId }),
140
- ...(minVoucherDelta !== undefined && { minVoucherDelta }),
138
+ ...(minVoucherDelta !== undefined && {
139
+ minVoucherDelta: parseUnits(minVoucherDelta, decimals).toString(),
140
+ }),
141
141
  ...(chainId !== undefined && { chainId }),
142
142
  ...(feePayer !== undefined && { feePayer }),
143
143
  },
@@ -1,6 +1,6 @@
1
1
  import type * as Hex from 'ox/Hex'
2
2
  import type { Address } from 'viem'
3
- import { prepareTransactionRequest, signTransaction } from 'viem/actions'
3
+ import { prepareTransactionRequest, sendCallsSync, signTransaction } from 'viem/actions'
4
4
  import { tempo as tempo_chain } from 'viem/chains'
5
5
  import { Actions } from 'viem/tempo'
6
6
  import * as Credential from '../../Credential.js'
@@ -39,6 +39,7 @@ export function charge(parameters: charge.Parameters = {}) {
39
39
  context: z.object({
40
40
  account: z.optional(z.custom<Account.getResolver.Parameters['account']>()),
41
41
  autoSwap: z.optional(z.custom<charge.AutoSwap>()),
42
+ mode: z.optional(z.enum(['push', 'pull'])),
42
43
  }),
43
44
 
44
45
  async createCredential({ challenge, context }) {
@@ -46,6 +47,9 @@ export function charge(parameters: charge.Parameters = {}) {
46
47
  const client = await getClient({ chainId })
47
48
  const account = getAccount(client, context)
48
49
 
50
+ const mode =
51
+ context?.mode ?? parameters.mode ?? (account.type === 'json-rpc' ? 'push' : 'pull')
52
+
49
53
  const { request } = challenge
50
54
  const { amount, methodDetails } = request
51
55
  const currency = request.currency as Address
@@ -79,6 +83,21 @@ export function charge(parameters: charge.Parameters = {}) {
79
83
 
80
84
  const calls = [...(swapCalls ?? []), transferCall]
81
85
 
86
+ if (mode === 'push') {
87
+ const { receipts } = await sendCallsSync(client, {
88
+ account,
89
+ calls: calls as never,
90
+ experimental_fallback: true,
91
+ })
92
+ const hash = receipts?.[0]?.transactionHash
93
+ if (!hash) throw new Error('No transaction receipt returned.')
94
+ return Credential.serialize({
95
+ challenge,
96
+ payload: { hash, type: 'hash' },
97
+ source: `did:pkh:eip155:${chainId}:${account.address}`,
98
+ })
99
+ }
100
+
82
101
  const prepared = await prepareTransactionRequest(client, {
83
102
  account,
84
103
  calls,
@@ -111,6 +130,15 @@ export declare namespace charge {
111
130
  autoSwap?: AutoSwap | undefined
112
131
  /** Client identifier used to derive the client fingerprint in attribution memos. */
113
132
  clientId?: string | undefined
133
+ /**
134
+ * Controls how the charge transaction is submitted.
135
+ *
136
+ * - `'push'`: Client broadcasts the transaction and sends the tx hash to the server.
137
+ * - `'pull'`: Client signs the transaction and sends the serialized tx to the server for broadcast.
138
+ *
139
+ * @default `'push'` for JSON-RPC accounts, `'pull'` for local accounts.
140
+ */
141
+ mode?: 'push' | 'pull' | undefined
114
142
  } & Account.getResolver.Parameters &
115
143
  Client.getResolver.Parameters
116
144
  }
@@ -30,6 +30,17 @@ const server = Mppx_server.create({
30
30
  describe('tempo', () => {
31
31
  describe('intent: charge; type: hash', () => {
32
32
  test('default', async () => {
33
+ const mppx = Mppx_client.create({
34
+ polyfill: false,
35
+ methods: [
36
+ tempo_client({
37
+ account: accounts[1],
38
+ mode: 'push',
39
+ getClient: () => client,
40
+ }),
41
+ ],
42
+ })
43
+
33
44
  const httpServer = await Http.createServer(async (req, res) => {
34
45
  const result = await Mppx_server.toNodeListener(
35
46
  server.charge({ amount: '1', decimals: 6 }),
@@ -38,43 +49,15 @@ describe('tempo', () => {
38
49
  res.end('OK')
39
50
  })
40
51
 
41
- const response = await fetch(httpServer.url)
42
- expect(response.status).toBe(402)
43
-
44
- const challenge = Challenge.fromResponse(response, {
45
- methods: [tempo_client.charge()],
46
- })
47
- const request = challenge.request
48
- expect(request.methodDetails?.chainId).toBe(chain.id)
49
-
50
- const memo = Attribution.encode({ serverId: challenge.realm })
51
-
52
- const { receipt } = await Actions.token.transferSync(client, {
53
- account: accounts[1],
54
- amount: BigInt(request.amount),
55
- memo,
56
- to: request.recipient as Hex.Hex,
57
- token: request.currency as Hex.Hex,
58
- })
59
- const hash = receipt.transactionHash
60
-
61
- const credential = Credential.from({
62
- challenge,
63
- payload: { hash, type: 'hash' as const },
64
- })
65
-
66
- {
67
- const response = await fetch(httpServer.url, {
68
- headers: { Authorization: Credential.serialize(credential) },
69
- })
70
- expect(response.status).toBe(200)
52
+ const response = await mppx.fetch(httpServer.url)
53
+ expect(response.status).toBe(200)
71
54
 
72
- const receipt = Receipt.fromResponse(response)
73
- expect({
74
- ...receipt,
75
- reference: '[reference]',
76
- timestamp: '[timestamp]',
77
- }).toMatchInlineSnapshot(`
55
+ const receipt = Receipt.fromResponse(response)
56
+ expect({
57
+ ...receipt,
58
+ reference: '[reference]',
59
+ timestamp: '[timestamp]',
60
+ }).toMatchInlineSnapshot(`
78
61
  {
79
62
  "method": "tempo",
80
63
  "reference": "[reference]",
@@ -82,7 +65,6 @@ describe('tempo', () => {
82
65
  "timestamp": "[timestamp]",
83
66
  }
84
67
  `)
85
- }
86
68
 
87
69
  httpServer.close()
88
70
  })
@@ -92,6 +74,17 @@ describe('tempo', () => {
92
74
  const overrideCurrency = asset
93
75
  const overrideExpires = new Date(Date.now() + 60_000).toISOString()
94
76
 
77
+ const mppx = Mppx_client.create({
78
+ polyfill: false,
79
+ methods: [
80
+ tempo_client({
81
+ account: accounts[1],
82
+ mode: 'push',
83
+ getClient: () => client,
84
+ }),
85
+ ],
86
+ })
87
+
95
88
  const httpServer = await Http.createServer(async (req, res) => {
96
89
  const result = await Mppx_server.toNodeListener(
97
90
  server.charge({
@@ -105,42 +98,11 @@ describe('tempo', () => {
105
98
  res.end('OK')
106
99
  })
107
100
 
108
- const response = await fetch(httpServer.url)
109
- expect(response.status).toBe(402)
110
-
111
- const challenge = Challenge.fromResponse(response, {
112
- methods: [tempo_client.charge()],
113
- })
114
- const request = challenge.request
115
- expect(request.recipient).toBe(overrideRecipient)
116
- expect(request.currency).toBe(overrideCurrency)
117
- expect(request.expires).toBe(overrideExpires)
118
-
119
- const memo = Attribution.encode({ serverId: challenge.realm })
120
-
121
- const { receipt } = await Actions.token.transferSync(client, {
122
- account: accounts[1],
123
- amount: BigInt(request.amount),
124
- memo,
125
- to: request.recipient as Hex.Hex,
126
- token: request.currency as Hex.Hex,
127
- })
128
- const hash = receipt.transactionHash
129
-
130
- const credential = Credential.from({
131
- challenge,
132
- payload: { hash, type: 'hash' as const },
133
- })
134
-
135
- {
136
- const response = await fetch(httpServer.url, {
137
- headers: { Authorization: Credential.serialize(credential) },
138
- })
139
- expect(response.status).toBe(200)
101
+ const response = await mppx.fetch(httpServer.url)
102
+ expect(response.status).toBe(200)
140
103
 
141
- const receipt = Receipt.fromResponse(response)
142
- expect(receipt.status).toBe('success')
143
- }
104
+ const receipt = Receipt.fromResponse(response)
105
+ expect(receipt.status).toBe('success')
144
106
 
145
107
  httpServer.close()
146
108
  })
@@ -103,7 +103,8 @@ export function charge<const parameters extends charge.Parameters>(
103
103
  const client = await getClient({ chainId })
104
104
 
105
105
  const { request: challengeRequest } = challenge
106
- const { amount, expires, methodDetails } = challengeRequest
106
+ const { amount, methodDetails } = challengeRequest
107
+ const expires = challenge.expires
107
108
 
108
109
  const currency = challengeRequest.currency as `0x${string}`
109
110
  const recipient = challengeRequest.recipient as `0x${string}`