mppx 0.4.11 → 0.5.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 (89) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/Expires.d.ts +7 -0
  3. package/dist/Expires.d.ts.map +1 -1
  4. package/dist/Expires.js +21 -0
  5. package/dist/Expires.js.map +1 -1
  6. package/dist/internal/env.d.ts +1 -1
  7. package/dist/internal/env.d.ts.map +1 -1
  8. package/dist/internal/env.js +2 -6
  9. package/dist/internal/env.js.map +1 -1
  10. package/dist/internal/types.d.ts +23 -0
  11. package/dist/internal/types.d.ts.map +1 -1
  12. package/dist/server/Mppx.d.ts +1 -1
  13. package/dist/server/Mppx.d.ts.map +1 -1
  14. package/dist/server/Mppx.js +55 -7
  15. package/dist/server/Mppx.js.map +1 -1
  16. package/dist/stripe/server/Charge.d.ts.map +1 -1
  17. package/dist/stripe/server/Charge.js +3 -3
  18. package/dist/stripe/server/Charge.js.map +1 -1
  19. package/dist/tempo/Methods.d.ts +18 -0
  20. package/dist/tempo/Methods.d.ts.map +1 -1
  21. package/dist/tempo/Methods.js +28 -3
  22. package/dist/tempo/Methods.js.map +1 -1
  23. package/dist/tempo/client/Charge.d.ts +24 -0
  24. package/dist/tempo/client/Charge.d.ts.map +1 -1
  25. package/dist/tempo/client/Charge.js +51 -9
  26. package/dist/tempo/client/Charge.js.map +1 -1
  27. package/dist/tempo/client/Methods.d.ts +18 -0
  28. package/dist/tempo/client/Methods.d.ts.map +1 -1
  29. package/dist/tempo/internal/account.d.ts +5 -11
  30. package/dist/tempo/internal/account.d.ts.map +1 -1
  31. package/dist/tempo/internal/charge.d.ts +20 -0
  32. package/dist/tempo/internal/charge.d.ts.map +1 -0
  33. package/dist/tempo/internal/charge.js +23 -0
  34. package/dist/tempo/internal/charge.js.map +1 -0
  35. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  36. package/dist/tempo/internal/fee-payer.js +15 -3
  37. package/dist/tempo/internal/fee-payer.js.map +1 -1
  38. package/dist/tempo/internal/proof.d.ts +23 -0
  39. package/dist/tempo/internal/proof.d.ts.map +1 -0
  40. package/dist/tempo/internal/proof.js +17 -0
  41. package/dist/tempo/internal/proof.js.map +1 -0
  42. package/dist/tempo/server/Charge.d.ts +20 -2
  43. package/dist/tempo/server/Charge.d.ts.map +1 -1
  44. package/dist/tempo/server/Charge.js +180 -103
  45. package/dist/tempo/server/Charge.js.map +1 -1
  46. package/dist/tempo/server/Methods.d.ts +20 -2
  47. package/dist/tempo/server/Methods.d.ts.map +1 -1
  48. package/dist/tempo/server/Methods.js +4 -1
  49. package/dist/tempo/server/Methods.js.map +1 -1
  50. package/dist/tempo/server/Session.d.ts +9 -4
  51. package/dist/tempo/server/Session.d.ts.map +1 -1
  52. package/dist/tempo/server/Session.js +18 -3
  53. package/dist/tempo/server/Session.js.map +1 -1
  54. package/dist/tempo/session/Chain.d.ts +18 -2
  55. package/dist/tempo/session/Chain.d.ts.map +1 -1
  56. package/dist/tempo/session/Chain.js +18 -14
  57. package/dist/tempo/session/Chain.js.map +1 -1
  58. package/package.json +1 -1
  59. package/src/Expires.ts +25 -0
  60. package/src/cli/cli.test.ts +230 -1
  61. package/src/internal/env.test.ts +12 -12
  62. package/src/internal/env.ts +2 -6
  63. package/src/internal/types.ts +25 -0
  64. package/src/middlewares/elysia.test.ts +127 -4
  65. package/src/middlewares/express.test.ts +120 -54
  66. package/src/middlewares/hono.test.ts +73 -34
  67. package/src/middlewares/nextjs.test.ts +159 -36
  68. package/src/server/Mppx.test.ts +373 -0
  69. package/src/server/Mppx.ts +64 -10
  70. package/src/stripe/server/Charge.ts +3 -7
  71. package/src/tempo/Methods.test.ts +105 -0
  72. package/src/tempo/Methods.ts +54 -17
  73. package/src/tempo/client/Charge.ts +67 -11
  74. package/src/tempo/internal/account.ts +7 -14
  75. package/src/tempo/internal/charge.test.ts +66 -0
  76. package/src/tempo/internal/charge.ts +43 -0
  77. package/src/tempo/internal/fee-payer.test.ts +33 -14
  78. package/src/tempo/internal/fee-payer.ts +21 -6
  79. package/src/tempo/internal/proof.test.ts +36 -0
  80. package/src/tempo/internal/proof.ts +19 -0
  81. package/src/tempo/server/Charge.test.ts +593 -1
  82. package/src/tempo/server/Charge.ts +233 -126
  83. package/src/tempo/server/Methods.ts +4 -1
  84. package/src/tempo/server/Session.test.ts +1152 -54
  85. package/src/tempo/server/Session.ts +26 -17
  86. package/src/tempo/server/internal/transport.test.ts +32 -0
  87. package/src/tempo/session/Chain.test.ts +60 -5
  88. package/src/tempo/session/Chain.ts +30 -14
  89. package/src/tempo/session/Sse.test.ts +31 -0
@@ -2,11 +2,14 @@ import * as http from 'node:http'
2
2
 
3
3
  import { Elysia } from 'elysia'
4
4
  import { Receipt } from 'mppx'
5
- import { Mppx as Mppx_client, tempo as tempo_client } from 'mppx/client'
5
+ import { Mppx as Mppx_client, session as sessionIntent, tempo as tempo_client } from 'mppx/client'
6
6
  import { Mppx, discovery } from 'mppx/elysia'
7
7
  import { tempo as tempo_server } from 'mppx/server'
8
- import { describe, expect, test } from 'vp/test'
9
- import { accounts, asset, client } from '~test/tempo/viem.js'
8
+ import type { Address } from 'viem'
9
+ import { Addresses } from 'viem/tempo'
10
+ import { beforeAll, describe, expect, test } from 'vp/test'
11
+ import { deployEscrow } from '~test/tempo/session.js'
12
+ import { accounts, asset, client, fundAccount } from '~test/tempo/viem.js'
10
13
 
11
14
  function createServer(app: Elysia<any, any, any, any, any, any, any>) {
12
15
  return new Promise<{ url: string; close: () => void }>((resolve) => {
@@ -34,13 +37,14 @@ function createServer(app: Elysia<any, any, any, any, any, any, any>) {
34
37
 
35
38
  const secretKey = 'test-secret-key'
36
39
 
37
- describe('charge', () => {
40
+ function createChargeHarness(feePayer: boolean) {
38
41
  const mppx = Mppx.create({
39
42
  methods: [
40
43
  tempo_server.charge({
41
44
  getClient: () => client,
42
45
  currency: asset,
43
46
  recipient: accounts[0].address,
47
+ ...(feePayer ? { feePayer: true } : {}),
44
48
  }),
45
49
  ],
46
50
  secretKey,
@@ -56,7 +60,13 @@ describe('charge', () => {
56
60
  ],
57
61
  })
58
62
 
63
+ return { fetch, mppx }
64
+ }
65
+
66
+ describe('charge', () => {
59
67
  test('returns 402 when no credential', async () => {
68
+ const { mppx } = createChargeHarness(false)
69
+
60
70
  const app = new Elysia().guard({ beforeHandle: mppx.charge({ amount: '1' }) }, (app) =>
61
71
  app.get('/', () => ({ fortune: 'You will be rich' })),
62
72
  )
@@ -70,6 +80,8 @@ describe('charge', () => {
70
80
  })
71
81
 
72
82
  test('returns 200 with receipt on valid payment', async () => {
83
+ const { fetch, mppx } = createChargeHarness(false)
84
+
73
85
  const app = new Elysia().guard({ beforeHandle: mppx.charge({ amount: '1' }) }, (app) =>
74
86
  app.get('/', () => ({ fortune: 'You will be rich' })),
75
87
  )
@@ -88,7 +100,24 @@ describe('charge', () => {
88
100
  server.close()
89
101
  })
90
102
 
103
+ test('fee payer: returns 200 with receipt on valid payment', async () => {
104
+ const { fetch, mppx } = createChargeHarness(true)
105
+
106
+ const app = new Elysia().guard({ beforeHandle: mppx.charge({ amount: '1' }) }, (app) =>
107
+ app.get('/', () => ({ fortune: 'You will be rich' })),
108
+ )
109
+
110
+ const server = await createServer(app)
111
+ const response = await fetch(server.url)
112
+ expect(response.status).toBe(200)
113
+ expect(Receipt.fromResponse(response).status).toBe('success')
114
+
115
+ server.close()
116
+ })
117
+
91
118
  test('serves /openapi.json from discovery plugin', async () => {
119
+ const { mppx } = createChargeHarness(false)
120
+
92
121
  const app = new Elysia().use(
93
122
  discovery(mppx, {
94
123
  info: { title: 'Elysia API', version: '1.0.0' },
@@ -113,3 +142,97 @@ describe('charge', () => {
113
142
  server.close()
114
143
  })
115
144
  })
145
+
146
+ describe('session', () => {
147
+ let escrowContract: Address
148
+
149
+ function createSessionHarness(feePayer: boolean) {
150
+ const mppx = Mppx.create({
151
+ methods: [
152
+ tempo_server.session({
153
+ getClient: () => client,
154
+ account: accounts[0],
155
+ currency: asset,
156
+ escrowContract,
157
+ ...(feePayer ? { feePayer: accounts[1] } : {}),
158
+ } as any),
159
+ ],
160
+ secretKey,
161
+ })
162
+
163
+ const { fetch } = Mppx_client.create({
164
+ polyfill: false,
165
+ methods: [
166
+ sessionIntent({
167
+ account: accounts[2],
168
+ deposit: '10',
169
+ getClient: () => client,
170
+ }),
171
+ ],
172
+ })
173
+
174
+ return { fetch, mppx }
175
+ }
176
+
177
+ beforeAll(async () => {
178
+ escrowContract = await deployEscrow()
179
+ await fundAccount({ address: accounts[1].address, token: Addresses.pathUsd })
180
+ await fundAccount({ address: accounts[1].address, token: asset })
181
+ await fundAccount({ address: accounts[2].address, token: Addresses.pathUsd })
182
+ await fundAccount({ address: accounts[2].address, token: asset })
183
+ })
184
+
185
+ test('returns 402 when no credential', async () => {
186
+ const { mppx } = createSessionHarness(false)
187
+
188
+ const app = new Elysia().guard(
189
+ { beforeHandle: mppx.session({ amount: '1', currency: asset, unitType: 'token' }) },
190
+ (app) => app.get('/', () => ({ data: 'streamed' })),
191
+ )
192
+
193
+ const server = await createServer(app)
194
+ const response = await globalThis.fetch(server.url)
195
+ expect(response.status).toBe(402)
196
+ expect(response.headers.get('WWW-Authenticate')).toContain('Payment')
197
+
198
+ server.close()
199
+ })
200
+
201
+ test('returns 200 with receipt on valid payment', async () => {
202
+ const { fetch, mppx } = createSessionHarness(false)
203
+
204
+ const app = new Elysia().guard(
205
+ { beforeHandle: mppx.session({ amount: '1', currency: asset, unitType: 'token' }) },
206
+ (app) => app.get('/', () => ({ data: 'streamed' })),
207
+ )
208
+
209
+ const server = await createServer(app)
210
+ const response = await fetch(server.url)
211
+ expect(response.status).toBe(200)
212
+
213
+ const body = await response.json()
214
+ expect(body).toEqual({ data: 'streamed' })
215
+
216
+ const receipt = Receipt.fromResponse(response)
217
+ expect(receipt.status).toBe('success')
218
+ expect(receipt.method).toBe('tempo')
219
+
220
+ server.close()
221
+ })
222
+
223
+ test('fee payer: returns 200 with receipt on valid payment', async () => {
224
+ const { fetch, mppx } = createSessionHarness(true)
225
+
226
+ const app = new Elysia().guard(
227
+ { beforeHandle: mppx.session({ amount: '1', currency: asset, unitType: 'token' }) },
228
+ (app) => app.get('/', () => ({ data: 'streamed' })),
229
+ )
230
+
231
+ const server = await createServer(app)
232
+ const response = await fetch(server.url)
233
+ expect(response.status).toBe(200)
234
+ expect(Receipt.fromResponse(response).status).toBe('success')
235
+
236
+ server.close()
237
+ })
238
+ })
@@ -23,13 +23,14 @@ function createServer(app: express.Express) {
23
23
 
24
24
  const secretKey = 'test-secret-key'
25
25
 
26
- describe('charge', () => {
26
+ function createChargeHarness(feePayer: boolean) {
27
27
  const mppx = Mppx.create({
28
28
  methods: [
29
29
  tempo_server({
30
30
  getClient: () => client,
31
31
  currency: asset,
32
32
  account: accounts[0],
33
+ ...(feePayer ? { feePayer: true } : {}),
33
34
  }),
34
35
  ],
35
36
  secretKey,
@@ -45,7 +46,39 @@ describe('charge', () => {
45
46
  ],
46
47
  })
47
48
 
49
+ return { fetch, mppx }
50
+ }
51
+
52
+ function createCoreChargeHarness(feePayer: boolean) {
53
+ const mppx = Mppx_server.create({
54
+ methods: [
55
+ tempo_server({
56
+ getClient: () => client,
57
+ currency: asset,
58
+ account: accounts[0],
59
+ ...(feePayer ? { feePayer: true } : {}),
60
+ }),
61
+ ],
62
+ secretKey,
63
+ })
64
+
65
+ const { fetch } = Mppx_client.create({
66
+ polyfill: false,
67
+ methods: [
68
+ tempo_client({
69
+ account: accounts[1],
70
+ getClient: () => client,
71
+ }),
72
+ ],
73
+ })
74
+
75
+ return { fetch, mppx }
76
+ }
77
+
78
+ describe('charge', () => {
48
79
  test('returns 402 when no credential', async () => {
80
+ const { mppx } = createChargeHarness(false)
81
+
49
82
  const app = express()
50
83
  app.get('/', mppx.charge({ amount: '1' }), (_req, res) => {
51
84
  res.json({ fortune: 'You will be rich' })
@@ -60,6 +93,8 @@ describe('charge', () => {
60
93
  })
61
94
 
62
95
  test('returns 200 with receipt on valid payment', async () => {
96
+ const { fetch, mppx } = createChargeHarness(false)
97
+
63
98
  const app = express()
64
99
  app.get('/', mppx.charge({ amount: '1' }), (_req, res) => {
65
100
  res.json({ fortune: 'You will be rich' })
@@ -82,7 +117,25 @@ describe('charge', () => {
82
117
  server.close()
83
118
  })
84
119
 
120
+ test('fee payer: returns 200 with receipt on valid payment', async () => {
121
+ const { fetch, mppx } = createChargeHarness(true)
122
+
123
+ const app = express()
124
+ app.get('/', mppx.charge({ amount: '1' }), (_req, res) => {
125
+ res.json({ fortune: 'You will be rich' })
126
+ })
127
+
128
+ const server = await createServer(app)
129
+ const response = await fetch(server.url)
130
+ expect(response.status).toBe(200)
131
+ expect(Receipt.fromResponse(response).status).toBe('success')
132
+
133
+ server.close()
134
+ })
135
+
85
136
  test('serves /openapi.json from a handler-derived route config', async () => {
137
+ const { mppx } = createChargeHarness(false)
138
+
86
139
  const app = express()
87
140
  const pay = mppx.charge({ amount: '1' })
88
141
  app.get('/', pay, (_req, res) => {
@@ -114,13 +167,7 @@ describe('charge', () => {
114
167
  describe('session', () => {
115
168
  let escrowContract: Address
116
169
 
117
- beforeAll(async () => {
118
- escrowContract = await deployEscrow()
119
- await fundAccount({ address: accounts[2].address, token: Addresses.pathUsd })
120
- await fundAccount({ address: accounts[2].address, token: asset })
121
- })
122
-
123
- test('returns 402 when no credential', async () => {
170
+ function createSessionHarness(feePayer: boolean) {
124
171
  const mppx = Mppx.create({
125
172
  methods: [
126
173
  tempo_server.session({
@@ -128,13 +175,39 @@ describe('session', () => {
128
175
  account: accounts[0],
129
176
  currency: asset,
130
177
  escrowContract,
131
- }),
178
+ ...(feePayer ? { feePayer: accounts[1] } : {}),
179
+ } as any),
132
180
  ],
133
181
  secretKey,
134
182
  })
135
183
 
184
+ const { fetch } = Mppx_client.create({
185
+ polyfill: false,
186
+ methods: [
187
+ sessionIntent({
188
+ account: accounts[2],
189
+ deposit: '10',
190
+ getClient: () => client,
191
+ }),
192
+ ],
193
+ })
194
+
195
+ return { fetch, mppx }
196
+ }
197
+
198
+ beforeAll(async () => {
199
+ escrowContract = await deployEscrow()
200
+ await fundAccount({ address: accounts[1].address, token: Addresses.pathUsd })
201
+ await fundAccount({ address: accounts[1].address, token: asset })
202
+ await fundAccount({ address: accounts[2].address, token: Addresses.pathUsd })
203
+ await fundAccount({ address: accounts[2].address, token: asset })
204
+ })
205
+
206
+ test('returns 402 when no credential', async () => {
207
+ const { mppx } = createSessionHarness(false)
208
+
136
209
  const app = express()
137
- app.get('/', mppx.session({ amount: '1', unitType: 'token' }), (_req, res) => {
210
+ app.get('/', mppx.session({ amount: '1', currency: asset, unitType: 'token' }), (_req, res) => {
138
211
  res.json({ data: 'streamed' })
139
212
  })
140
213
 
@@ -147,32 +220,10 @@ describe('session', () => {
147
220
  })
148
221
 
149
222
  test('returns 200 with receipt on valid payment', async () => {
150
- const mppx = Mppx.create({
151
- methods: [
152
- tempo_server.session({
153
- getClient: () => client,
154
- account: accounts[0],
155
- currency: asset,
156
- escrowContract,
157
- feePayer: true,
158
- }),
159
- ],
160
- secretKey,
161
- })
162
-
163
- const { fetch } = Mppx_client.create({
164
- polyfill: false,
165
- methods: [
166
- sessionIntent({
167
- account: accounts[2],
168
- deposit: '10',
169
- getClient: () => client,
170
- }),
171
- ],
172
- })
223
+ const { fetch, mppx } = createSessionHarness(false)
173
224
 
174
225
  const app = express()
175
- app.get('/', mppx.session({ amount: '1', unitType: 'token' }), (_req, res) => {
226
+ app.get('/', mppx.session({ amount: '1', currency: asset, unitType: 'token' }), (_req, res) => {
176
227
  res.json({ data: 'streamed' })
177
228
  })
178
229
 
@@ -185,31 +236,28 @@ describe('session', () => {
185
236
 
186
237
  server.close()
187
238
  })
188
- })
189
239
 
190
- describe('payment', () => {
191
- const mppx = Mppx_server.create({
192
- methods: [
193
- tempo_server({
194
- getClient: () => client,
195
- currency: asset,
196
- account: accounts[0],
197
- }),
198
- ],
199
- secretKey,
200
- })
240
+ test('fee payer: returns 200 with receipt on valid payment', async () => {
241
+ const { fetch, mppx } = createSessionHarness(true)
201
242
 
202
- const { fetch } = Mppx_client.create({
203
- polyfill: false,
204
- methods: [
205
- tempo_client({
206
- account: accounts[1],
207
- getClient: () => client,
208
- }),
209
- ],
243
+ const app = express()
244
+ app.get('/', mppx.session({ amount: '1', currency: asset, unitType: 'token' }), (_req, res) => {
245
+ res.json({ data: 'streamed' })
246
+ })
247
+
248
+ const server = await createServer(app)
249
+ const response = await fetch(server.url)
250
+ expect(response.status).toBe(200)
251
+ expect(Receipt.fromResponse(response).status).toBe('success')
252
+
253
+ server.close()
210
254
  })
255
+ })
211
256
 
257
+ describe('payment', () => {
212
258
  test('returns 402 when no credential', async () => {
259
+ const { mppx } = createCoreChargeHarness(false)
260
+
213
261
  const app = express()
214
262
  app.get('/', payment(mppx.charge, { amount: '1' }), (_req, res) => {
215
263
  res.json({ fortune: 'You will be rich' })
@@ -224,6 +272,8 @@ describe('payment', () => {
224
272
  })
225
273
 
226
274
  test('returns 200 with receipt on valid payment', async () => {
275
+ const { fetch, mppx } = createCoreChargeHarness(false)
276
+
227
277
  const app = express()
228
278
  app.get('/', payment(mppx.charge, { amount: '1' }), (_req, res) => {
229
279
  res.json({ fortune: 'You will be rich' })
@@ -245,4 +295,20 @@ describe('payment', () => {
245
295
 
246
296
  server.close()
247
297
  })
298
+
299
+ test('fee payer: returns 200 with receipt on valid payment', async () => {
300
+ const { fetch, mppx } = createCoreChargeHarness(true)
301
+
302
+ const app = express()
303
+ app.get('/', payment(mppx.charge, { amount: '1' }), (_req, res) => {
304
+ res.json({ fortune: 'You will be rich' })
305
+ })
306
+
307
+ const server = await createServer(app)
308
+ const response = await fetch(server.url)
309
+ expect(response.status).toBe(200)
310
+ expect(Receipt.fromResponse(response).status).toBe('success')
311
+
312
+ server.close()
313
+ })
248
314
  })
@@ -23,13 +23,14 @@ function createServer(app: Hono) {
23
23
 
24
24
  const secretKey = 'test-secret-key'
25
25
 
26
- describe('charge', () => {
26
+ function createChargeHarness(feePayer: boolean) {
27
27
  const mppx = Mppx.create({
28
28
  methods: [
29
29
  tempo_server.charge({
30
30
  getClient: () => client,
31
31
  currency: asset,
32
32
  account: accounts[0],
33
+ ...(feePayer ? { feePayer: true } : {}),
33
34
  }),
34
35
  ],
35
36
  secretKey,
@@ -45,7 +46,13 @@ describe('charge', () => {
45
46
  ],
46
47
  })
47
48
 
49
+ return { fetch, mppx }
50
+ }
51
+
52
+ describe('charge', () => {
48
53
  test('returns 402 when no credential', async () => {
54
+ const { mppx } = createChargeHarness(false)
55
+
49
56
  const app = new Hono()
50
57
  app.get('/', mppx.charge({ amount: '1' }), (c) => c.json({ fortune: 'You will be rich' }))
51
58
 
@@ -58,6 +65,8 @@ describe('charge', () => {
58
65
  })
59
66
 
60
67
  test('returns 200 with receipt on valid payment', async () => {
68
+ const { fetch, mppx } = createChargeHarness(false)
69
+
61
70
  const app = new Hono()
62
71
  app.get('/', mppx.charge({ amount: '1' }), (c) => c.json({ fortune: 'You will be rich' }))
63
72
 
@@ -75,7 +84,23 @@ describe('charge', () => {
75
84
  server.close()
76
85
  })
77
86
 
87
+ test('fee payer: returns 200 with receipt on valid payment', async () => {
88
+ const { fetch, mppx } = createChargeHarness(true)
89
+
90
+ const app = new Hono()
91
+ app.get('/', mppx.charge({ amount: '1' }), (c) => c.json({ fortune: 'You will be rich' }))
92
+
93
+ const server = await createServer(app)
94
+ const response = await fetch(server.url)
95
+ expect(response.status).toBe(200)
96
+ expect(Receipt.fromResponse(response).status).toBe('success')
97
+
98
+ server.close()
99
+ })
100
+
78
101
  test('serves /openapi.json via auto discovery', async () => {
102
+ const { mppx } = createChargeHarness(false)
103
+
79
104
  const app = new Hono()
80
105
  app.get('/', mppx.charge({ amount: '1' }), (c) => c.json({ fortune: 'You will be rich' }))
81
106
  discovery(app, mppx, { auto: true, info: { title: 'Auto API', version: '2.0.0' } })
@@ -101,13 +126,7 @@ describe('charge', () => {
101
126
  describe('session', () => {
102
127
  let escrowContract: Address
103
128
 
104
- beforeAll(async () => {
105
- escrowContract = await deployEscrow()
106
- await fundAccount({ address: accounts[2].address, token: Addresses.pathUsd })
107
- await fundAccount({ address: accounts[2].address, token: asset })
108
- })
109
-
110
- test('returns 402 when no credential', async () => {
129
+ function createSessionHarness(feePayer: boolean) {
111
130
  const mppx = Mppx.create({
112
131
  methods: [
113
132
  tempo_server.session({
@@ -115,13 +134,39 @@ describe('session', () => {
115
134
  account: accounts[0],
116
135
  currency: asset,
117
136
  escrowContract,
118
- }),
137
+ ...(feePayer ? { feePayer: accounts[1] } : {}),
138
+ } as any),
119
139
  ],
120
140
  secretKey,
121
141
  })
122
142
 
143
+ const { fetch } = Mppx_client.create({
144
+ polyfill: false,
145
+ methods: [
146
+ sessionIntent({
147
+ account: accounts[2],
148
+ deposit: '10',
149
+ getClient: () => client,
150
+ }),
151
+ ],
152
+ })
153
+
154
+ return { fetch, mppx }
155
+ }
156
+
157
+ beforeAll(async () => {
158
+ escrowContract = await deployEscrow()
159
+ await fundAccount({ address: accounts[1].address, token: Addresses.pathUsd })
160
+ await fundAccount({ address: accounts[1].address, token: asset })
161
+ await fundAccount({ address: accounts[2].address, token: Addresses.pathUsd })
162
+ await fundAccount({ address: accounts[2].address, token: asset })
163
+ })
164
+
165
+ test('returns 402 when no credential', async () => {
166
+ const { mppx } = createSessionHarness(false)
167
+
123
168
  const app = new Hono()
124
- app.get('/', mppx.session({ amount: '1', unitType: 'token' }), (c) =>
169
+ app.get('/', mppx.session({ amount: '1', currency: asset, unitType: 'token' }), (c) =>
125
170
  c.json({ data: 'streamed' }),
126
171
  )
127
172
 
@@ -134,32 +179,10 @@ describe('session', () => {
134
179
  })
135
180
 
136
181
  test('returns 200 with receipt on valid payment', async () => {
137
- const mppx = Mppx.create({
138
- methods: [
139
- tempo_server.session({
140
- getClient: () => client,
141
- account: accounts[0],
142
- currency: asset,
143
- escrowContract,
144
- feePayer: true,
145
- }),
146
- ],
147
- secretKey,
148
- })
149
-
150
- const { fetch } = Mppx_client.create({
151
- polyfill: false,
152
- methods: [
153
- sessionIntent({
154
- account: accounts[2],
155
- deposit: '10',
156
- getClient: () => client,
157
- }),
158
- ],
159
- })
182
+ const { fetch, mppx } = createSessionHarness(false)
160
183
 
161
184
  const app = new Hono()
162
- app.get('/', mppx.session({ amount: '1', unitType: 'token' }), (c) =>
185
+ app.get('/', mppx.session({ amount: '1', currency: asset, unitType: 'token' }), (c) =>
163
186
  c.json({ data: 'streamed' }),
164
187
  )
165
188
 
@@ -172,4 +195,20 @@ describe('session', () => {
172
195
 
173
196
  server.close()
174
197
  })
198
+
199
+ test('fee payer: returns 200 with receipt on valid payment', async () => {
200
+ const { fetch, mppx } = createSessionHarness(true)
201
+
202
+ const app = new Hono()
203
+ app.get('/', mppx.session({ amount: '1', currency: asset, unitType: 'token' }), (c) =>
204
+ c.json({ data: 'streamed' }),
205
+ )
206
+
207
+ const server = await createServer(app)
208
+ const response = await fetch(server.url)
209
+ expect(response.status).toBe(200)
210
+ expect(Receipt.fromResponse(response).status).toBe('success')
211
+
212
+ server.close()
213
+ })
175
214
  })