mppx 0.6.3 → 0.6.6
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 +20 -0
- package/dist/Credential.d.ts +4 -0
- package/dist/Credential.d.ts.map +1 -1
- package/dist/Credential.js +18 -2
- package/dist/Credential.js.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +166 -54
- package/dist/cli/cli.js.map +1 -1
- package/dist/discovery/Discovery.d.ts +234 -18
- package/dist/discovery/Discovery.d.ts.map +1 -1
- package/dist/discovery/Discovery.js +24 -2
- package/dist/discovery/Discovery.js.map +1 -1
- package/dist/discovery/OpenApi.d.ts +1 -1
- package/dist/discovery/OpenApi.d.ts.map +1 -1
- package/dist/discovery/OpenApi.js +2 -1
- package/dist/discovery/OpenApi.js.map +1 -1
- package/dist/discovery/Validate.d.ts.map +1 -1
- package/dist/discovery/Validate.js +2 -1
- package/dist/discovery/Validate.js.map +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/stripe/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/client/Charge.js +1 -1
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/internal/proof.d.ts +6 -2
- package/dist/tempo/internal/proof.d.ts.map +1 -1
- package/dist/tempo/internal/proof.js +7 -4
- package/dist/tempo/internal/proof.js.map +1 -1
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +4 -3
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/server/internal/html.gen.js.map +1 -1
- package/package.json +2 -2
- package/src/Challenge.test.ts +45 -0
- package/src/Credential.test.ts +66 -0
- package/src/Credential.ts +23 -3
- package/src/bin.ts +1 -1
- package/src/cli/cli.ts +194 -58
- package/src/cli/mcp.test.ts +233 -0
- package/src/discovery/Discovery.test.ts +66 -4
- package/src/discovery/Discovery.ts +40 -7
- package/src/discovery/OpenApi.test.ts +61 -33
- package/src/discovery/OpenApi.ts +2 -2
- package/src/discovery/Validate.test.ts +117 -0
- package/src/discovery/Validate.ts +2 -1
- package/src/middlewares/elysia.test.ts +1 -1
- package/src/middlewares/express.test.ts +1 -1
- package/src/middlewares/hono.test.ts +1 -1
- package/src/middlewares/nextjs.test.ts +1 -1
- package/src/proxy/Proxy.test.ts +3 -3
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/client/Charge.ts +1 -1
- package/src/tempo/internal/proof.test.ts +11 -5
- package/src/tempo/internal/proof.ts +7 -4
- package/src/tempo/server/Charge.test.ts +51 -15
- package/src/tempo/server/Charge.ts +5 -3
- package/src/tempo/server/internal/html.gen.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.gen.js","sourceRoot":"","sources":["../../../../src/tempo/server/internal/html.gen.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,IAAI,GAAG,
|
|
1
|
+
{"version":3,"file":"html.gen.js","sourceRoot":"","sources":["../../../../src/tempo/server/internal/html.gen.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,IAAI,GAAG,6wtcAA6wtc,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mppx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.6",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"files": [
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
},
|
|
125
125
|
"dependencies": {
|
|
126
126
|
"incur": "^0.3.25",
|
|
127
|
-
"ox": "0.14.
|
|
127
|
+
"ox": "0.14.18",
|
|
128
128
|
"zod": "^4.3.6"
|
|
129
129
|
},
|
|
130
130
|
"repository": {
|
package/src/Challenge.test.ts
CHANGED
|
@@ -109,6 +109,29 @@ describe('from', () => {
|
|
|
109
109
|
},
|
|
110
110
|
expectedId: 'm39jbWWCIfmfJZSwCfvKFFtBl0Qwf9X4nOmDb21peLA',
|
|
111
111
|
},
|
|
112
|
+
{
|
|
113
|
+
label: 'with opaque',
|
|
114
|
+
params: {
|
|
115
|
+
realm: 'api.example.com',
|
|
116
|
+
method: 'tempo',
|
|
117
|
+
intent: 'charge',
|
|
118
|
+
request: { amount: '1000000' },
|
|
119
|
+
meta: { pi: 'pi_3abc123XYZ' },
|
|
120
|
+
},
|
|
121
|
+
expectedId: 'rxzKZ2qjXvinqCH96RORTZEPs1KXsA-0AUjrCAPFOWc',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
label: 'with opaque and expires',
|
|
125
|
+
params: {
|
|
126
|
+
realm: 'api.example.com',
|
|
127
|
+
method: 'tempo',
|
|
128
|
+
intent: 'charge',
|
|
129
|
+
request: { amount: '1000000' },
|
|
130
|
+
expires: '2025-01-06T12:00:00Z',
|
|
131
|
+
meta: { pi: 'pi_3abc123XYZ' },
|
|
132
|
+
},
|
|
133
|
+
expectedId: 'KAfoMrA4fnzS1DPWN_cUv_b3_yHxCizdp6OhH7gluMY',
|
|
134
|
+
},
|
|
112
135
|
{
|
|
113
136
|
label: 'with description (not in HMAC input)',
|
|
114
137
|
params: {
|
|
@@ -150,6 +173,17 @@ describe('from', () => {
|
|
|
150
173
|
},
|
|
151
174
|
expectedId: 'yLN7yChAejW9WNmb54HpJIWpdb1WWXeA3_aCx4dxmkU',
|
|
152
175
|
},
|
|
176
|
+
{
|
|
177
|
+
label: 'with empty opaque',
|
|
178
|
+
params: {
|
|
179
|
+
realm: 'api.example.com',
|
|
180
|
+
method: 'tempo',
|
|
181
|
+
intent: 'charge',
|
|
182
|
+
request: { amount: '1000000' },
|
|
183
|
+
meta: {},
|
|
184
|
+
},
|
|
185
|
+
expectedId: 'vb4IyH-0LdJ3s7L0QAw8jIzcZkyxksPhIvEfmHmzA9k',
|
|
186
|
+
},
|
|
153
187
|
{
|
|
154
188
|
label: 'different realm',
|
|
155
189
|
params: {
|
|
@@ -180,6 +214,17 @@ describe('from', () => {
|
|
|
180
214
|
},
|
|
181
215
|
expectedId: 'aAY7_IEDzsznNYplhOSE8cERQxvjFcT4Lcn-7FHjLVE',
|
|
182
216
|
},
|
|
217
|
+
{
|
|
218
|
+
label: 'with multi-key opaque',
|
|
219
|
+
params: {
|
|
220
|
+
realm: 'api.example.com',
|
|
221
|
+
method: 'tempo',
|
|
222
|
+
intent: 'charge',
|
|
223
|
+
request: { amount: '1000000' },
|
|
224
|
+
meta: { deposit: 'dep_456', pi: 'pi_3abc123XYZ' },
|
|
225
|
+
},
|
|
226
|
+
expectedId: 'aKskU8sadR5ZuFbUCsIwhO-ENxuVpTw17FdwHEXsJDk',
|
|
227
|
+
},
|
|
183
228
|
] as const
|
|
184
229
|
|
|
185
230
|
test.each(hmacVectors)('hmac: $label', ({ params, expectedId }) => {
|
package/src/Credential.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Challenge, Credential } from 'mppx'
|
|
2
|
+
import { Base64 } from 'ox'
|
|
2
3
|
import { describe, expect, test } from 'vp/test'
|
|
3
4
|
|
|
4
5
|
const challenge = Challenge.from({
|
|
@@ -88,6 +89,28 @@ describe('serialize', () => {
|
|
|
88
89
|
const deserialized = Credential.deserialize(header)
|
|
89
90
|
expect(deserialized.challenge.request).toEqual({ amount: '1000' })
|
|
90
91
|
})
|
|
92
|
+
|
|
93
|
+
test('behavior: serializes opaque as a base64url string', () => {
|
|
94
|
+
const credential = Credential.from({
|
|
95
|
+
challenge: Challenge.from({
|
|
96
|
+
id: 'opaque123',
|
|
97
|
+
intent: 'charge',
|
|
98
|
+
meta: { pi: 'pi_3abc123XYZ' },
|
|
99
|
+
method: 'tempo',
|
|
100
|
+
realm: 'api.example.com',
|
|
101
|
+
request: { amount: '1000' },
|
|
102
|
+
}),
|
|
103
|
+
payload: { signature: '0x1234' },
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const header = Credential.serialize(credential)
|
|
107
|
+
const encoded = header.replace(/^Payment\s+/i, '')
|
|
108
|
+
const parsed = JSON.parse(Base64.toString(encoded)) as {
|
|
109
|
+
challenge: { opaque?: unknown }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
expect(parsed.challenge.opaque).toBe('eyJwaSI6InBpXzNhYmMxMjNYWVoifQ')
|
|
113
|
+
})
|
|
91
114
|
})
|
|
92
115
|
|
|
93
116
|
describe('deserialize', () => {
|
|
@@ -134,6 +157,49 @@ describe('deserialize', () => {
|
|
|
134
157
|
expect(deserialized.source).toBe(original.source)
|
|
135
158
|
})
|
|
136
159
|
|
|
160
|
+
test('behavior: deserializes spec-compliant opaque string credentials', () => {
|
|
161
|
+
const encoded = Base64.fromString(
|
|
162
|
+
JSON.stringify({
|
|
163
|
+
challenge: {
|
|
164
|
+
id: 'opaque123',
|
|
165
|
+
intent: 'charge',
|
|
166
|
+
method: 'tempo',
|
|
167
|
+
opaque: 'eyJwaSI6InBpXzNhYmMxMjNYWVoifQ',
|
|
168
|
+
realm: 'api.example.com',
|
|
169
|
+
request: 'eyJhbW91bnQiOiIxMDAwIn0',
|
|
170
|
+
},
|
|
171
|
+
payload: { signature: '0x1234' },
|
|
172
|
+
}),
|
|
173
|
+
{ pad: false, url: true },
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
const credential = Credential.deserialize(`Payment ${encoded}`)
|
|
177
|
+
|
|
178
|
+
expect(credential.challenge.opaque).toEqual({ pi: 'pi_3abc123XYZ' })
|
|
179
|
+
expect(credential.challenge.request).toEqual({ amount: '1000' })
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test('behavior: preserves legacy object-shaped opaque credentials', () => {
|
|
183
|
+
const encoded = Base64.fromString(
|
|
184
|
+
JSON.stringify({
|
|
185
|
+
challenge: {
|
|
186
|
+
id: 'opaque123',
|
|
187
|
+
intent: 'charge',
|
|
188
|
+
method: 'tempo',
|
|
189
|
+
opaque: { pi: 'pi_3abc123XYZ' },
|
|
190
|
+
realm: 'api.example.com',
|
|
191
|
+
request: 'eyJhbW91bnQiOiIxMDAwIn0',
|
|
192
|
+
},
|
|
193
|
+
payload: { signature: '0x1234' },
|
|
194
|
+
}),
|
|
195
|
+
{ pad: false, url: true },
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
const credential = Credential.deserialize(`Payment ${encoded}`)
|
|
199
|
+
|
|
200
|
+
expect(credential.challenge.opaque).toEqual({ pi: 'pi_3abc123XYZ' })
|
|
201
|
+
})
|
|
202
|
+
|
|
137
203
|
test('error: throws for missing Payment scheme', () => {
|
|
138
204
|
expect(() => Credential.deserialize('Bearer abc123')).toThrow('Missing Payment scheme.')
|
|
139
205
|
})
|
package/src/Credential.ts
CHANGED
|
@@ -44,6 +44,8 @@ export class InvalidCredentialEncodingError extends Error {
|
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Deserializes an Authorization header value to a credential.
|
|
47
|
+
* Accepts the spec-compliant base64url `opaque` string shape and the legacy
|
|
48
|
+
* object-shaped `opaque` form emitted by older mppx versions.
|
|
47
49
|
*
|
|
48
50
|
* @param header - The Authorization header value.
|
|
49
51
|
* @returns The deserialized credential.
|
|
@@ -61,12 +63,26 @@ export function deserialize<payload = unknown>(value: string): Credential<payloa
|
|
|
61
63
|
try {
|
|
62
64
|
const json = Base64.toString(prefixMatch[1])
|
|
63
65
|
const parsed = JSON.parse(json) as {
|
|
64
|
-
challenge: Omit<Challenge.Challenge, 'request'> & {
|
|
66
|
+
challenge: Omit<Challenge.Challenge, 'opaque' | 'request'> & {
|
|
67
|
+
opaque?: Record<string, string> | string
|
|
68
|
+
request: string
|
|
69
|
+
}
|
|
65
70
|
payload: payload
|
|
66
71
|
source?: string
|
|
67
72
|
}
|
|
68
73
|
const challenge = Challenge.Schema.parse({
|
|
69
74
|
...parsed.challenge,
|
|
75
|
+
...(parsed.challenge.opaque !== undefined && {
|
|
76
|
+
// TODO: Drop the legacy object-shaped `opaque` fallback after old mppx
|
|
77
|
+
// clients are no longer in circulation. Older mppx versions echoed
|
|
78
|
+
// `opaque` as an expanded JSON object in credentials, but the Payment
|
|
79
|
+
// auth spec requires clients to return the original base64url string
|
|
80
|
+
// unchanged in the credential challenge object.
|
|
81
|
+
opaque:
|
|
82
|
+
typeof parsed.challenge.opaque === 'string'
|
|
83
|
+
? (PaymentRequest.deserialize(parsed.challenge.opaque) as Record<string, string>)
|
|
84
|
+
: parsed.challenge.opaque,
|
|
85
|
+
}),
|
|
70
86
|
request: PaymentRequest.deserialize(parsed.challenge.request),
|
|
71
87
|
})
|
|
72
88
|
return {
|
|
@@ -140,6 +156,8 @@ export function fromRequest<payload = unknown>(request: Request): Credential<pay
|
|
|
140
156
|
|
|
141
157
|
/**
|
|
142
158
|
* Serializes a credential to the Authorization header format.
|
|
159
|
+
* When present, `challenge.opaque` is encoded as the base64url string required
|
|
160
|
+
* by the Payment auth credential format.
|
|
143
161
|
*
|
|
144
162
|
* @param credential - The credential to serialize.
|
|
145
163
|
* @returns A string suitable for the Authorization header value.
|
|
@@ -153,10 +171,12 @@ export function fromRequest<payload = unknown>(request: Request): Credential<pay
|
|
|
153
171
|
* ```
|
|
154
172
|
*/
|
|
155
173
|
export function serialize(credential: Credential): string {
|
|
174
|
+
const { opaque, request, ...challenge } = credential.challenge
|
|
156
175
|
const wire = {
|
|
157
176
|
challenge: {
|
|
158
|
-
...
|
|
159
|
-
|
|
177
|
+
...challenge,
|
|
178
|
+
...(opaque !== undefined && { opaque: PaymentRequest.serialize(opaque) }),
|
|
179
|
+
request: PaymentRequest.serialize(request),
|
|
160
180
|
},
|
|
161
181
|
payload: credential.payload,
|
|
162
182
|
...(credential.source && { source: credential.source }),
|
package/src/bin.ts
CHANGED