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.
- package/CHANGELOG.md +21 -0
- package/dist/Expires.d.ts +7 -0
- package/dist/Expires.d.ts.map +1 -1
- package/dist/Expires.js +21 -0
- package/dist/Expires.js.map +1 -1
- package/dist/internal/env.d.ts +1 -1
- package/dist/internal/env.d.ts.map +1 -1
- package/dist/internal/env.js +2 -6
- package/dist/internal/env.js.map +1 -1
- package/dist/internal/types.d.ts +23 -0
- package/dist/internal/types.d.ts.map +1 -1
- package/dist/server/Mppx.d.ts +1 -1
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +55 -7
- package/dist/server/Mppx.js.map +1 -1
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js +3 -3
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/tempo/Methods.d.ts +18 -0
- package/dist/tempo/Methods.d.ts.map +1 -1
- package/dist/tempo/Methods.js +28 -3
- package/dist/tempo/Methods.js.map +1 -1
- package/dist/tempo/client/Charge.d.ts +24 -0
- package/dist/tempo/client/Charge.d.ts.map +1 -1
- package/dist/tempo/client/Charge.js +51 -9
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/client/Methods.d.ts +18 -0
- package/dist/tempo/client/Methods.d.ts.map +1 -1
- package/dist/tempo/internal/account.d.ts +5 -11
- package/dist/tempo/internal/account.d.ts.map +1 -1
- package/dist/tempo/internal/charge.d.ts +20 -0
- package/dist/tempo/internal/charge.d.ts.map +1 -0
- package/dist/tempo/internal/charge.js +23 -0
- package/dist/tempo/internal/charge.js.map +1 -0
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js +15 -3
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/internal/proof.d.ts +23 -0
- package/dist/tempo/internal/proof.d.ts.map +1 -0
- package/dist/tempo/internal/proof.js +17 -0
- package/dist/tempo/internal/proof.js.map +1 -0
- package/dist/tempo/server/Charge.d.ts +20 -2
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +180 -103
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +20 -2
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +4 -1
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Session.d.ts +9 -4
- package/dist/tempo/server/Session.d.ts.map +1 -1
- package/dist/tempo/server/Session.js +18 -3
- package/dist/tempo/server/Session.js.map +1 -1
- package/dist/tempo/session/Chain.d.ts +18 -2
- package/dist/tempo/session/Chain.d.ts.map +1 -1
- package/dist/tempo/session/Chain.js +18 -14
- package/dist/tempo/session/Chain.js.map +1 -1
- package/package.json +1 -1
- package/src/Expires.ts +25 -0
- package/src/cli/cli.test.ts +230 -1
- package/src/internal/env.test.ts +12 -12
- package/src/internal/env.ts +2 -6
- package/src/internal/types.ts +25 -0
- package/src/middlewares/elysia.test.ts +127 -4
- package/src/middlewares/express.test.ts +120 -54
- package/src/middlewares/hono.test.ts +73 -34
- package/src/middlewares/nextjs.test.ts +159 -36
- package/src/server/Mppx.test.ts +373 -0
- package/src/server/Mppx.ts +64 -10
- package/src/stripe/server/Charge.ts +3 -7
- package/src/tempo/Methods.test.ts +105 -0
- package/src/tempo/Methods.ts +54 -17
- package/src/tempo/client/Charge.ts +67 -11
- package/src/tempo/internal/account.ts +7 -14
- package/src/tempo/internal/charge.test.ts +66 -0
- package/src/tempo/internal/charge.ts +43 -0
- package/src/tempo/internal/fee-payer.test.ts +33 -14
- package/src/tempo/internal/fee-payer.ts +21 -6
- package/src/tempo/internal/proof.test.ts +36 -0
- package/src/tempo/internal/proof.ts +19 -0
- package/src/tempo/server/Charge.test.ts +593 -1
- package/src/tempo/server/Charge.ts +233 -126
- package/src/tempo/server/Methods.ts +4 -1
- package/src/tempo/server/Session.test.ts +1152 -54
- package/src/tempo/server/Session.ts +26 -17
- package/src/tempo/server/internal/transport.test.ts +32 -0
- package/src/tempo/session/Chain.test.ts +60 -5
- package/src/tempo/session/Chain.ts +30 -14
- 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 {
|
|
9
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
191
|
-
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
})
|