@routedock/routedock 0.1.0 → 0.1.2
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/README.md +61 -22
- package/dist/index.cjs +106 -44
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +95 -33
- package/dist/provider.cjs +106 -44
- package/dist/provider.d.cts +3 -1
- package/dist/provider.d.ts +3 -1
- package/dist/provider.js +95 -33
- package/dist/{routedockMiddleware-Beqan6QS.d.cts → routedockMiddleware-B7WTB3LT.d.cts} +4 -0
- package/dist/{routedockMiddleware-CqnyHjhO.d.ts → routedockMiddleware-DRgdrycG.d.ts} +4 -0
- package/package.json +1 -1
- package/src/provider/MppSessionHandler.ts +22 -1
- package/src/provider/routedockMiddleware.ts +6 -0
- package/src/provider/x402Handler.ts +88 -36
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Request, Response, NextFunction, RequestHandler } from 'express'
|
|
2
2
|
import { Keypair } from '@stellar/stellar-sdk'
|
|
3
3
|
import { ExactStellarScheme as ExactStellarFacilitatorScheme } from '@x402/stellar/exact/facilitator'
|
|
4
|
+
import { ExactStellarScheme as ExactStellarServerScheme } from '@x402/stellar/exact/server'
|
|
5
|
+
import { HTTPFacilitatorClient, x402ResourceServer } from '@x402/core/server'
|
|
4
6
|
import { createEd25519Signer } from '@x402/stellar'
|
|
5
7
|
import {
|
|
6
8
|
decodePaymentSignatureHeader,
|
|
@@ -17,6 +19,8 @@ const CAIP2: Record<Network, X402Network> = {
|
|
|
17
19
|
mainnet: 'stellar:pubnet',
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
const OZ_FACILITATOR_URL = 'https://channels.openzeppelin.com/x402'
|
|
23
|
+
|
|
20
24
|
export interface X402HandlerOptions {
|
|
21
25
|
payeeSecretKey: string
|
|
22
26
|
network: Network
|
|
@@ -32,10 +36,29 @@ export function createX402Handler(opts: X402HandlerOptions): RequestHandler {
|
|
|
32
36
|
const payeeKeypair = Keypair.fromSecret(opts.payeeSecretKey)
|
|
33
37
|
const signer = createEd25519Signer(opts.payeeSecretKey, caip2)
|
|
34
38
|
|
|
35
|
-
const
|
|
39
|
+
const useOzFacilitator = opts.network === 'mainnet' && opts.facilitatorApiKey
|
|
40
|
+
|
|
41
|
+
// Mainnet: OZ hosted facilitator via x402ResourceServer
|
|
42
|
+
// Testnet: local ExactStellarFacilitatorScheme (OZ facilitator does not serve testnet)
|
|
43
|
+
const localFacilitator = new ExactStellarFacilitatorScheme([signer], {
|
|
36
44
|
areFeesSponsored: true,
|
|
37
45
|
})
|
|
38
46
|
|
|
47
|
+
let ozServer: x402ResourceServer | null = null
|
|
48
|
+
if (useOzFacilitator) {
|
|
49
|
+
const apiKey = opts.facilitatorApiKey!
|
|
50
|
+
const facilitator = new HTTPFacilitatorClient({
|
|
51
|
+
url: OZ_FACILITATOR_URL,
|
|
52
|
+
createAuthHeaders: async () => ({
|
|
53
|
+
verify: { Authorization: `Bearer ${apiKey}` },
|
|
54
|
+
settle: { Authorization: `Bearer ${apiKey}` },
|
|
55
|
+
supported: { Authorization: `Bearer ${apiKey}` },
|
|
56
|
+
}),
|
|
57
|
+
})
|
|
58
|
+
ozServer = new x402ResourceServer(facilitator)
|
|
59
|
+
ozServer.register(caip2, new ExactStellarServerScheme())
|
|
60
|
+
}
|
|
61
|
+
|
|
39
62
|
const amountInBaseUnits = String(Math.round(parseFloat(opts.amount) * 1e7))
|
|
40
63
|
const requirements = {
|
|
41
64
|
scheme: 'exact' as const,
|
|
@@ -46,7 +69,7 @@ export function createX402Handler(opts: X402HandlerOptions): RequestHandler {
|
|
|
46
69
|
maxTimeoutSeconds: 60,
|
|
47
70
|
extra: {
|
|
48
71
|
areFeesSponsored: true,
|
|
49
|
-
facilitatorAddresses: [payeeKeypair.publicKey()],
|
|
72
|
+
...(useOzFacilitator ? {} : { facilitatorAddresses: [payeeKeypair.publicKey()] }),
|
|
50
73
|
},
|
|
51
74
|
}
|
|
52
75
|
|
|
@@ -55,54 +78,83 @@ export function createX402Handler(opts: X402HandlerOptions): RequestHandler {
|
|
|
55
78
|
const paymentHeader = (req.headers['payment-signature'] ?? req.headers['x-payment']) as string | undefined
|
|
56
79
|
|
|
57
80
|
if (!paymentHeader) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
resource: {
|
|
81
|
+
if (ozServer) {
|
|
82
|
+
const resourceInfo = {
|
|
61
83
|
url: `${req.protocol}://${req.get('host') ?? ''}${req.originalUrl}`,
|
|
62
84
|
description: opts.manifest.name,
|
|
63
|
-
}
|
|
64
|
-
|
|
85
|
+
}
|
|
86
|
+
const paymentRequired = await ozServer.createPaymentRequiredResponse(
|
|
87
|
+
[requirements],
|
|
88
|
+
resourceInfo,
|
|
89
|
+
)
|
|
90
|
+
res
|
|
91
|
+
.status(402)
|
|
92
|
+
.setHeader('Content-Type', 'application/json')
|
|
93
|
+
.setHeader('X-Payment-Requirements', encodePaymentRequiredHeader(paymentRequired))
|
|
94
|
+
.json({ error: 'Payment Required' })
|
|
95
|
+
} else {
|
|
96
|
+
const x402Response = {
|
|
97
|
+
x402Version: 2,
|
|
98
|
+
resource: {
|
|
99
|
+
url: `${req.protocol}://${req.get('host') ?? ''}${req.originalUrl}`,
|
|
100
|
+
description: opts.manifest.name,
|
|
101
|
+
},
|
|
102
|
+
accepts: [requirements],
|
|
103
|
+
}
|
|
104
|
+
res
|
|
105
|
+
.status(402)
|
|
106
|
+
.setHeader('Content-Type', 'application/json')
|
|
107
|
+
.setHeader('X-Payment-Requirements', encodePaymentRequiredHeader(x402Response))
|
|
108
|
+
.json({ error: 'Payment Required' })
|
|
65
109
|
}
|
|
66
|
-
res
|
|
67
|
-
.status(402)
|
|
68
|
-
.setHeader('Content-Type', 'application/json')
|
|
69
|
-
.setHeader('X-Payment-Requirements', encodePaymentRequiredHeader(x402Response))
|
|
70
|
-
.json({ error: 'Payment Required' })
|
|
71
110
|
return
|
|
72
111
|
}
|
|
73
112
|
|
|
74
113
|
const payload = decodePaymentSignatureHeader(paymentHeader)
|
|
75
|
-
|
|
76
|
-
payload as Parameters<typeof facilitatorScheme.verify>[0],
|
|
77
|
-
requirements,
|
|
78
|
-
)
|
|
114
|
+
let txHash: string | null = null
|
|
79
115
|
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
116
|
+
if (ozServer) {
|
|
117
|
+
const settleResult = await ozServer.settlePayment(payload, requirements)
|
|
118
|
+
txHash = (settleResult as { transaction?: string }).transaction ?? null
|
|
119
|
+
if (settleResult) {
|
|
120
|
+
res.setHeader(
|
|
121
|
+
'X-Payment-Response',
|
|
122
|
+
encodePaymentResponseHeader(
|
|
123
|
+
settleResult as Parameters<typeof encodePaymentResponseHeader>[0],
|
|
124
|
+
),
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
const verifyResult = await localFacilitator.verify(
|
|
129
|
+
payload as Parameters<typeof localFacilitator.verify>[0],
|
|
130
|
+
requirements,
|
|
131
|
+
)
|
|
132
|
+
if (!verifyResult.isValid) {
|
|
133
|
+
res.status(401).json({
|
|
134
|
+
error: 'Payment verification failed',
|
|
135
|
+
reason: (verifyResult as { invalidReason?: string }).invalidReason,
|
|
136
|
+
})
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
const settleResult = await localFacilitator.settle(
|
|
140
|
+
payload as Parameters<typeof localFacilitator.settle>[0],
|
|
141
|
+
requirements,
|
|
142
|
+
)
|
|
143
|
+
txHash = (settleResult as { transaction?: string }).transaction ?? null
|
|
144
|
+
if (settleResult) {
|
|
145
|
+
res.setHeader(
|
|
146
|
+
'X-Payment-Response',
|
|
147
|
+
encodePaymentResponseHeader(
|
|
148
|
+
settleResult as Parameters<typeof encodePaymentResponseHeader>[0],
|
|
149
|
+
),
|
|
150
|
+
)
|
|
151
|
+
}
|
|
86
152
|
}
|
|
87
153
|
|
|
88
|
-
const settleResult = await facilitatorScheme.settle(
|
|
89
|
-
payload as Parameters<typeof facilitatorScheme.settle>[0],
|
|
90
|
-
requirements,
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
const txHash = (settleResult as { transaction?: string }).transaction ?? null
|
|
94
154
|
if (txHash && opts.onSettled) {
|
|
95
155
|
await opts.onSettled(txHash, opts.amount, 'x402')
|
|
96
156
|
}
|
|
97
157
|
|
|
98
|
-
if (settleResult) {
|
|
99
|
-
res.setHeader(
|
|
100
|
-
'X-Payment-Response',
|
|
101
|
-
encodePaymentResponseHeader(
|
|
102
|
-
settleResult as Parameters<typeof encodePaymentResponseHeader>[0],
|
|
103
|
-
),
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
158
|
next()
|
|
107
159
|
} catch (err) {
|
|
108
160
|
console.error('[x402] Settlement error:', err)
|