mppx 0.8.12 → 0.8.14
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 +34 -0
- package/README.md +16 -1
- package/dist/Errors.d.ts +10 -0
- package/dist/Errors.d.ts.map +1 -1
- package/dist/Errors.js +11 -2
- package/dist/Errors.js.map +1 -1
- package/dist/Method.d.ts +105 -3
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +102 -2
- package/dist/Method.js.map +1 -1
- package/dist/cli/account.d.ts +88 -0
- package/dist/cli/account.d.ts.map +1 -1
- package/dist/cli/account.js +39 -9
- package/dist/cli/account.js.map +1 -1
- package/dist/cli/cli.d.ts +2 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +59 -2
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/sessions/Manager.d.ts +31 -0
- package/dist/cli/sessions/Manager.d.ts.map +1 -0
- package/dist/cli/sessions/Manager.js +56 -0
- package/dist/cli/sessions/Manager.js.map +1 -0
- package/dist/cli/sessions/commands.d.ts +36 -0
- package/dist/cli/sessions/commands.d.ts.map +1 -0
- package/dist/cli/sessions/commands.js +407 -0
- package/dist/cli/sessions/commands.js.map +1 -0
- package/dist/cli/sessions/request.d.ts +35 -0
- package/dist/cli/sessions/request.d.ts.map +1 -0
- package/dist/cli/sessions/request.js +271 -0
- package/dist/cli/sessions/request.js.map +1 -0
- package/dist/cli/sessions/store.d.ts +134 -0
- package/dist/cli/sessions/store.d.ts.map +1 -0
- package/dist/cli/sessions/store.js +723 -0
- package/dist/cli/sessions/store.js.map +1 -0
- package/dist/cli/utils.d.ts +2 -0
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js +12 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/cli/validate/index.d.ts.map +1 -1
- package/dist/cli/validate/index.js +12 -6
- package/dist/cli/validate/index.js.map +1 -1
- package/dist/cli/validate/messages.d.ts +2 -0
- package/dist/cli/validate/messages.d.ts.map +1 -0
- package/dist/cli/validate/messages.js +8 -0
- package/dist/cli/validate/messages.js.map +1 -0
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +12 -2
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/client/internal/MethodChallenge.d.ts +17 -0
- package/dist/client/internal/MethodChallenge.d.ts.map +1 -0
- package/dist/client/internal/MethodChallenge.js +11 -0
- package/dist/client/internal/MethodChallenge.js.map +1 -0
- package/dist/client/node.d.ts +29 -0
- package/dist/client/node.d.ts.map +1 -0
- package/dist/client/node.js +177 -0
- package/dist/client/node.js.map +1 -0
- package/dist/internal/types.d.ts +24 -0
- package/dist/internal/types.d.ts.map +1 -1
- package/dist/server/Mppx.d.ts +23 -4
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +91 -82
- package/dist/server/Mppx.js.map +1 -1
- package/dist/stripe/server/Charge.d.ts +8 -4
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.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/Methods.d.ts +2 -1
- package/dist/tempo/client/Methods.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts +1 -0
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js +7 -2
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/internal/types.d.ts +10 -1
- package/dist/tempo/internal/types.d.ts.map +1 -1
- package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -1
- package/dist/tempo/legacy/client/ChannelOps.js +2 -1
- package/dist/tempo/legacy/client/ChannelOps.js.map +1 -1
- package/dist/tempo/legacy/client/Session.d.ts +2 -2
- package/dist/tempo/legacy/server/Session.d.ts +3 -3
- package/dist/tempo/legacy/server/Session.d.ts.map +1 -1
- package/dist/tempo/legacy/server/Session.js.map +1 -1
- package/dist/tempo/server/Charge.d.ts +40 -78
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +289 -209
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +13 -23
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +6 -2
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Relay.d.ts +48 -0
- package/dist/tempo/server/Relay.d.ts.map +1 -0
- package/dist/tempo/server/Relay.js +177 -0
- package/dist/tempo/server/Relay.js.map +1 -0
- package/dist/tempo/server/SponsorBudget.d.ts +59 -0
- package/dist/tempo/server/SponsorBudget.d.ts.map +1 -0
- package/dist/tempo/server/SponsorBudget.js +144 -0
- package/dist/tempo/server/SponsorBudget.js.map +1 -0
- package/dist/tempo/server/Subscription.d.ts +3 -2
- package/dist/tempo/server/Subscription.d.ts.map +1 -1
- package/dist/tempo/server/Subscription.js.map +1 -1
- package/dist/tempo/server/index.d.ts +1 -1
- package/dist/tempo/server/index.d.ts.map +1 -1
- package/dist/tempo/server/index.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/dist/tempo/session/Snapshot.d.ts +9 -0
- package/dist/tempo/session/Snapshot.d.ts.map +1 -1
- package/dist/tempo/session/Snapshot.js +6 -0
- package/dist/tempo/session/Snapshot.js.map +1 -1
- package/dist/tempo/session/client/ChannelOps.d.ts +7 -1
- package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -1
- package/dist/tempo/session/client/ChannelOps.js +17 -3
- package/dist/tempo/session/client/ChannelOps.js.map +1 -1
- package/dist/tempo/session/client/CredentialState.d.ts +26 -2
- package/dist/tempo/session/client/CredentialState.d.ts.map +1 -1
- package/dist/tempo/session/client/CredentialState.js +99 -16
- package/dist/tempo/session/client/CredentialState.js.map +1 -1
- package/dist/tempo/session/client/Runtime.d.ts +8 -0
- package/dist/tempo/session/client/Runtime.d.ts.map +1 -1
- package/dist/tempo/session/client/Runtime.js +17 -0
- package/dist/tempo/session/client/Runtime.js.map +1 -1
- package/dist/tempo/session/client/Session.d.ts +16 -6
- package/dist/tempo/session/client/Session.d.ts.map +1 -1
- package/dist/tempo/session/client/Session.js +93 -36
- package/dist/tempo/session/client/Session.js.map +1 -1
- package/dist/tempo/session/client/SessionManager.d.ts +10 -3
- package/dist/tempo/session/client/SessionManager.d.ts.map +1 -1
- package/dist/tempo/session/client/SessionManager.js +176 -50
- package/dist/tempo/session/client/SessionManager.js.map +1 -1
- package/dist/tempo/session/client/Transports.d.ts +18 -7
- package/dist/tempo/session/client/Transports.d.ts.map +1 -1
- package/dist/tempo/session/client/Transports.js +81 -33
- package/dist/tempo/session/client/Transports.js.map +1 -1
- package/dist/tempo/session/client/internal/SessionManager.d.ts +19 -0
- package/dist/tempo/session/client/internal/SessionManager.d.ts.map +1 -0
- package/dist/tempo/session/client/internal/SessionManager.js +13 -0
- package/dist/tempo/session/client/internal/SessionManager.js.map +1 -0
- package/dist/tempo/session/precompile/Chain.d.ts.map +1 -1
- package/dist/tempo/session/precompile/Chain.js +109 -12
- package/dist/tempo/session/precompile/Chain.js.map +1 -1
- package/dist/tempo/session/precompile/Channel.d.ts +2 -0
- package/dist/tempo/session/precompile/Channel.d.ts.map +1 -1
- package/dist/tempo/session/precompile/Channel.js +4 -0
- package/dist/tempo/session/precompile/Channel.js.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.d.ts +3 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.js +14 -0
- package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
- package/dist/tempo/session/server/MeteredStream.d.ts +7 -1
- package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -1
- package/dist/tempo/session/server/MeteredStream.js +5 -4
- package/dist/tempo/session/server/MeteredStream.js.map +1 -1
- package/dist/tempo/session/server/RequestState.d.ts +5 -1
- package/dist/tempo/session/server/RequestState.d.ts.map +1 -1
- package/dist/tempo/session/server/RequestState.js +13 -5
- package/dist/tempo/session/server/RequestState.js.map +1 -1
- package/dist/tempo/session/server/Session.d.ts +21 -6
- package/dist/tempo/session/server/Session.d.ts.map +1 -1
- package/dist/tempo/session/server/Session.js +4 -1
- package/dist/tempo/session/server/Session.js.map +1 -1
- package/dist/tempo/session/server/Settlement.d.ts +20 -0
- package/dist/tempo/session/server/Settlement.d.ts.map +1 -1
- package/dist/tempo/session/server/Settlement.js +20 -0
- package/dist/tempo/session/server/Settlement.js.map +1 -1
- package/dist/tempo/session/server/Ws.d.ts +2 -0
- package/dist/tempo/session/server/Ws.d.ts.map +1 -1
- package/dist/tempo/session/server/Ws.js.map +1 -1
- package/dist/tempo/session/server/index.d.ts +1 -1
- package/dist/tempo/session/server/index.d.ts.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.d.ts +21 -21
- package/dist/validation/core.d.ts.map +1 -1
- package/dist/validation/core.js +6 -2
- package/dist/validation/core.js.map +1 -1
- package/dist/viem/Client.d.ts.map +1 -1
- package/dist/viem/Client.js +24 -17
- package/dist/viem/Client.js.map +1 -1
- package/package.json +6 -1
- package/src/Errors.test.ts +23 -0
- package/src/Errors.ts +21 -2
- package/src/Method.test.ts +102 -1
- package/src/Method.ts +241 -5
- package/src/cli/account.ts +45 -10
- package/src/cli/cli.test.ts +165 -70
- package/src/cli/cli.ts +67 -2
- package/src/cli/mcp.test.ts +11 -0
- package/src/cli/sessions/Manager.test.ts +249 -0
- package/src/cli/sessions/Manager.ts +93 -0
- package/src/cli/sessions/commands.ts +444 -0
- package/src/cli/sessions/request.test.ts +51 -0
- package/src/cli/sessions/request.ts +353 -0
- package/src/cli/sessions/store.test.ts +581 -0
- package/src/cli/sessions/store.ts +940 -0
- package/src/cli/utils.test.ts +23 -0
- package/src/cli/utils.ts +10 -0
- package/src/cli/validate/index.ts +12 -14
- package/src/cli/validate/messages.ts +7 -0
- package/src/cli/validate.test.ts +38 -5
- package/src/client/Mppx.test-d.ts +3 -3
- package/src/client/internal/Fetch.ts +16 -7
- package/src/client/internal/MethodChallenge.ts +30 -0
- package/src/client/node.test.ts +115 -0
- package/src/client/node.ts +247 -0
- package/src/internal/types.test-d.ts +21 -0
- package/src/internal/types.ts +33 -0
- package/src/server/Mppx.test-d.ts +44 -0
- package/src/server/Mppx.test.ts +205 -0
- package/src/server/Mppx.ts +167 -103
- package/src/stripe/Methods.test.ts +10 -0
- package/src/stripe/server/Charge.test-d.ts +66 -0
- package/src/stripe/server/Charge.ts +8 -5
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/PublicExports.test-d.ts +20 -0
- package/src/tempo/internal/fee-payer.ts +7 -3
- package/src/tempo/internal/types.ts +13 -2
- package/src/tempo/legacy/client/ChannelOps.test.ts +7 -0
- package/src/tempo/legacy/client/ChannelOps.ts +2 -1
- package/src/tempo/legacy/server/Defaults.test-d.ts +9 -0
- package/src/tempo/legacy/server/Session.ts +6 -5
- package/src/tempo/server/Charge.test.ts +337 -63
- package/src/tempo/server/Charge.ts +440 -270
- package/src/tempo/server/Methods.ts +16 -4
- package/src/tempo/server/Relay.test.ts +523 -0
- package/src/tempo/server/Relay.ts +288 -0
- package/src/tempo/server/SponsorBudget.test.ts +125 -0
- package/src/tempo/server/SponsorBudget.ts +213 -0
- package/src/tempo/server/Subscription.ts +6 -4
- package/src/tempo/server/index.ts +5 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/session/README.md +201 -0
- package/src/tempo/session/Snapshot.ts +21 -0
- package/src/tempo/session/client/ChannelOps.test.ts +55 -0
- package/src/tempo/session/client/ChannelOps.ts +21 -3
- package/src/tempo/session/client/CredentialState.test.ts +2 -2
- package/src/tempo/session/client/CredentialState.ts +159 -16
- package/src/tempo/session/client/Runtime.test.ts +12 -0
- package/src/tempo/session/client/Runtime.ts +22 -0
- package/src/tempo/session/client/Session.test.ts +238 -5
- package/src/tempo/session/client/Session.ts +130 -41
- package/src/tempo/session/client/SessionManager.test.ts +239 -8
- package/src/tempo/session/client/SessionManager.ts +204 -54
- package/src/tempo/session/client/Transports.test.ts +181 -8
- package/src/tempo/session/client/Transports.ts +127 -45
- package/src/tempo/session/client/internal/SessionManager.ts +36 -0
- package/src/tempo/session/precompile/Chain.integration.test.ts +19 -1
- package/src/tempo/session/precompile/Chain.test.ts +223 -10
- package/src/tempo/session/precompile/Chain.ts +119 -12
- package/src/tempo/session/precompile/Channel.test.ts +9 -0
- package/src/tempo/session/precompile/Channel.ts +5 -0
- package/src/tempo/session/server/CredentialVerification.ts +18 -1
- package/src/tempo/session/server/MeteredStream.ts +12 -5
- package/src/tempo/session/server/RequestState.test.ts +47 -4
- package/src/tempo/session/server/RequestState.ts +15 -8
- package/src/tempo/session/server/Session.test.ts +461 -0
- package/src/tempo/session/server/Session.ts +31 -8
- package/src/tempo/session/server/Settlement.ts +45 -0
- package/src/tempo/session/server/Ws.test.ts +113 -0
- package/src/tempo/session/server/Ws.ts +2 -0
- package/src/tempo/session/server/index.ts +2 -0
- package/src/validation/core.ts +7 -1
- package/src/viem/Client.test.ts +44 -1
- package/src/viem/Client.ts +31 -17
package/src/Method.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type * as Challenge from './Challenge.js'
|
|
2
|
-
import
|
|
2
|
+
import * as Constants from './Constants.js'
|
|
3
|
+
import * as Credential from './Credential.js'
|
|
4
|
+
import * as Errors from './Errors.js'
|
|
5
|
+
import * as Expires from './Expires.js'
|
|
3
6
|
import type { ExactPartial, LooseOmit, MaybePromise } from './internal/types.js'
|
|
4
7
|
import type * as Receipt from './Receipt.js'
|
|
5
8
|
import type * as Html from './server/internal/html/config.js'
|
|
@@ -117,12 +120,72 @@ export type VerifyContext<method extends Method> = {
|
|
|
117
120
|
request: z.input<method['schema']['request']>
|
|
118
121
|
}
|
|
119
122
|
|
|
123
|
+
/** Validation hook parameters for a single method. */
|
|
124
|
+
export type ValidateContext<method extends Method> = VerifyContext<method>
|
|
125
|
+
|
|
120
126
|
/** Response hook parameters for a single method. */
|
|
121
127
|
export type RespondContext<method extends Method> = VerifyContext<method> & {
|
|
122
128
|
input: globalThis.Request
|
|
123
129
|
receipt: Receipt.Receipt
|
|
124
130
|
}
|
|
125
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Non-mutating method-specific validation result.
|
|
134
|
+
*
|
|
135
|
+
* Returned by {@link ValidateFn} and exposed from `mppx.validateCredential()`.
|
|
136
|
+
* This confirms that a credential is currently acceptable to the payment
|
|
137
|
+
* method; it does not settle, reserve, or otherwise consume the payment.
|
|
138
|
+
*/
|
|
139
|
+
export type Validation<method extends Method = Method, details = unknown> = Readonly<{
|
|
140
|
+
/**
|
|
141
|
+
* The challenge echoed by the credential and accepted by the method.
|
|
142
|
+
*
|
|
143
|
+
* Callers using `Mppx.validateCredential()` receive a challenge whose HMAC,
|
|
144
|
+
* expiry, route binding, and method identity have already been checked.
|
|
145
|
+
* Lower-level `Method.validateCredential()` callers must verify challenge
|
|
146
|
+
* issuance and route binding themselves.
|
|
147
|
+
*/
|
|
148
|
+
challenge: Challenge.Challenge<
|
|
149
|
+
z.output<method['schema']['request']>,
|
|
150
|
+
method['intent'],
|
|
151
|
+
method['name']
|
|
152
|
+
>
|
|
153
|
+
/**
|
|
154
|
+
* The submitted credential with its method-specific payload parsed by the
|
|
155
|
+
* selected method schema. This is the exact credential validation examined.
|
|
156
|
+
*/
|
|
157
|
+
credential: Credential.Credential<
|
|
158
|
+
z.output<method['schema']['credential']['payload']>,
|
|
159
|
+
Challenge.Challenge<z.output<method['schema']['request']>, method['intent'], method['name']>
|
|
160
|
+
>
|
|
161
|
+
/**
|
|
162
|
+
* Method-defined, non-mutating validation data.
|
|
163
|
+
*
|
|
164
|
+
* Its shape is intentionally method-specific—for example, a recovered payer
|
|
165
|
+
* address or a simulation result. Consumers must not assume a particular
|
|
166
|
+
* shape or use it as a settlement receipt.
|
|
167
|
+
*/
|
|
168
|
+
details: details
|
|
169
|
+
/** The validated payment intent, repeated for convenient dispatch. */
|
|
170
|
+
intent: method['intent']
|
|
171
|
+
/** The validated payment method, repeated for convenient dispatch. */
|
|
172
|
+
method: method['name']
|
|
173
|
+
/**
|
|
174
|
+
* The validated method request after the method's schema transforms.
|
|
175
|
+
*
|
|
176
|
+
* For `Mppx.validateCredential()` with route options, this is the
|
|
177
|
+
* authoritative route request after defaults and request-hook transforms.
|
|
178
|
+
*/
|
|
179
|
+
request: z.output<method['schema']['request']>
|
|
180
|
+
/**
|
|
181
|
+
* Optional payer identity declared by the credential.
|
|
182
|
+
*
|
|
183
|
+
* This is an asserted identity, not independent proof of control; methods
|
|
184
|
+
* that rely on it must validate the relationship to the credential payload.
|
|
185
|
+
*/
|
|
186
|
+
source?: string | undefined
|
|
187
|
+
}>
|
|
188
|
+
|
|
126
189
|
/**
|
|
127
190
|
* A server-side configured method with verification logic.
|
|
128
191
|
*/
|
|
@@ -141,8 +204,15 @@ export type Server<
|
|
|
141
204
|
preflight?: PreflightFn<method> | undefined
|
|
142
205
|
request?: RequestFn<method> | undefined
|
|
143
206
|
respond?: RespondFn<method> | undefined
|
|
207
|
+
broadcast?: BroadcastFn<method> | undefined
|
|
144
208
|
stableBinding?: StableBindingFn<method> | undefined
|
|
145
209
|
transport?: transportOverride | undefined
|
|
210
|
+
validate?: ValidateFn<method> | undefined
|
|
211
|
+
/**
|
|
212
|
+
* @deprecated Use `validate` for the non-mutating pre-check and `broadcast`
|
|
213
|
+
* for settlement. `verify` combines both operations and may consume payment
|
|
214
|
+
* state, so it cannot support a safe pre-check endpoint.
|
|
215
|
+
*/
|
|
146
216
|
verify: VerifyFn<method>
|
|
147
217
|
}
|
|
148
218
|
export type AnyServer = Server<any, any, any, any, any>
|
|
@@ -221,11 +291,148 @@ export type StableBindingFn<method extends Method> = (
|
|
|
221
291
|
request: z.output<method['schema']['request']>,
|
|
222
292
|
) => Record<string, unknown>
|
|
223
293
|
|
|
224
|
-
/**
|
|
294
|
+
/**
|
|
295
|
+
* Legacy combined validation and settlement function for a single method.
|
|
296
|
+
*
|
|
297
|
+
* @deprecated Implement `validate` and `broadcast` instead. `validate` must
|
|
298
|
+
* be non-mutating; `broadcast` performs the terminal payment operation. This
|
|
299
|
+
* hook remains only for existing methods that cannot yet split those phases.
|
|
300
|
+
*/
|
|
225
301
|
export type VerifyFn<method extends Method> = (
|
|
226
302
|
parameters: VerifyContext<method>,
|
|
227
303
|
) => Promise<Receipt.Receipt>
|
|
228
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Non-mutating validation function for a single method.
|
|
307
|
+
*
|
|
308
|
+
* @returns A {@link Validation} record describing the credential that was
|
|
309
|
+
* accepted. It must not settle, reserve, or otherwise consume payment state.
|
|
310
|
+
*/
|
|
311
|
+
export type ValidateFn<method extends Method> = (
|
|
312
|
+
parameters: ValidateContext<method>,
|
|
313
|
+
) => Promise<Validation<method>>
|
|
314
|
+
|
|
315
|
+
/** Terminal payment function for a single method. */
|
|
316
|
+
export type BroadcastFn<method extends Method> = (
|
|
317
|
+
parameters: VerifyContext<method>,
|
|
318
|
+
) => Promise<Receipt.Receipt>
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Validates a credential against one of the configured methods.
|
|
322
|
+
*
|
|
323
|
+
* This checks credential structure, challenge expiry, and method-specific
|
|
324
|
+
* validation. It does not prove that the challenge was issued by a particular
|
|
325
|
+
* server; hosts that issue challenges must verify that binding separately.
|
|
326
|
+
*/
|
|
327
|
+
export async function validateCredential<const methods extends readonly AnyServer[]>(
|
|
328
|
+
methods: methods,
|
|
329
|
+
input: string | Credential.Credential,
|
|
330
|
+
): Promise<Validation<methods[number]>> {
|
|
331
|
+
const prepared = prepareCredential(methods, input)
|
|
332
|
+
if (!prepared.method.validate)
|
|
333
|
+
throw new Errors.VerificationFailedError({
|
|
334
|
+
details: { intent: prepared.method.intent, method: prepared.method.name },
|
|
335
|
+
reason: `${prepared.method.name}/${prepared.method.intent} does not support non-mutating credential validation`,
|
|
336
|
+
})
|
|
337
|
+
return prepared.method.validate({
|
|
338
|
+
credential: prepared.credential,
|
|
339
|
+
request: prepared.request,
|
|
340
|
+
} as never) as Promise<Validation<methods[number]>>
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Re-validates and performs the terminal payment operation for a credential.
|
|
345
|
+
*
|
|
346
|
+
* This does not prove that the challenge was issued by a particular server;
|
|
347
|
+
* hosts that issue challenges must verify that binding separately.
|
|
348
|
+
*/
|
|
349
|
+
export async function broadcastCredential<const methods extends readonly AnyServer[]>(
|
|
350
|
+
methods: methods,
|
|
351
|
+
input: string | Credential.Credential,
|
|
352
|
+
): Promise<Receipt.Receipt> {
|
|
353
|
+
const prepared = prepareCredential(methods, input)
|
|
354
|
+
const { method } = prepared
|
|
355
|
+
|
|
356
|
+
if (method.broadcast && method.validate)
|
|
357
|
+
await method.validate({ credential: prepared.credential, request: prepared.request } as never)
|
|
358
|
+
|
|
359
|
+
const broadcast = method.broadcast ?? method.verify
|
|
360
|
+
return broadcast({ credential: prepared.credential, request: prepared.request } as never)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Parses a submitted credential into the inputs required for method execution.
|
|
365
|
+
*
|
|
366
|
+
* Dispatch is based on the challenge method and intent. When more than one
|
|
367
|
+
* server method handles the same wire identity, session protocol details select
|
|
368
|
+
* the appropriate implementation. The helper then asserts challenge expiry and
|
|
369
|
+
* parses the method-specific credential payload before returning the selected
|
|
370
|
+
* method and the unmodified challenge request.
|
|
371
|
+
*
|
|
372
|
+
* This intentionally does not verify that the challenge was issued by a
|
|
373
|
+
* particular host, authorize the caller or requested resource, validate the
|
|
374
|
+
* method request, or invoke method lifecycle hooks. Hosts that issue challenges
|
|
375
|
+
* must verify their challenge binding before accepting the credential.
|
|
376
|
+
*/
|
|
377
|
+
function prepareCredential(
|
|
378
|
+
methods: readonly AnyServer[],
|
|
379
|
+
input: string | Credential.Credential,
|
|
380
|
+
): {
|
|
381
|
+
credential: Credential.Credential
|
|
382
|
+
method: AnyServer
|
|
383
|
+
request: Record<string, unknown>
|
|
384
|
+
} {
|
|
385
|
+
const credential = typeof input === 'string' ? Credential.deserialize(input) : input
|
|
386
|
+
const candidates = methods.filter(
|
|
387
|
+
(method) =>
|
|
388
|
+
method.name === credential.challenge.method && method.intent === credential.challenge.intent,
|
|
389
|
+
)
|
|
390
|
+
const method = selectServerMethod(candidates, credential.challenge)
|
|
391
|
+
if (!method)
|
|
392
|
+
throw new Errors.InvalidChallengeError({
|
|
393
|
+
id: credential.challenge.id,
|
|
394
|
+
reason: `no registered method for ${credential.challenge.method}/${credential.challenge.intent}`,
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
Expires.assert(credential.challenge.expires, credential.challenge.id)
|
|
398
|
+
|
|
399
|
+
let payload: unknown
|
|
400
|
+
try {
|
|
401
|
+
payload = method.schema.credential.payload.parse(credential.payload)
|
|
402
|
+
} catch (error) {
|
|
403
|
+
throw new Errors.InvalidPayloadError(error instanceof Error ? { reason: error.message } : {})
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return {
|
|
407
|
+
credential: { ...credential, payload },
|
|
408
|
+
method,
|
|
409
|
+
request: credential.challenge.request,
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/** @internal */
|
|
414
|
+
export function selectServerMethod(
|
|
415
|
+
methods: readonly AnyServer[],
|
|
416
|
+
challenge: Challenge.Challenge,
|
|
417
|
+
): AnyServer | undefined {
|
|
418
|
+
if (methods.length <= 1) return methods[0]
|
|
419
|
+
if (
|
|
420
|
+
challenge.method !== Constants.Methods.tempo ||
|
|
421
|
+
challenge.intent !== Constants.Intents.session
|
|
422
|
+
)
|
|
423
|
+
return methods[0]
|
|
424
|
+
|
|
425
|
+
const sessionProtocol = Constants.getMethodDetail(
|
|
426
|
+
challenge.request.methodDetails,
|
|
427
|
+
Constants.MethodDetailKeys.sessionProtocol,
|
|
428
|
+
)
|
|
429
|
+
if (sessionProtocol === undefined || sessionProtocol === Constants.SessionProtocols.v1)
|
|
430
|
+
return methods.find((method) => method.alias === 'sessionLegacy') ?? methods[0]
|
|
431
|
+
if (sessionProtocol === Constants.SessionProtocols.v2)
|
|
432
|
+
return methods.find((method) => method.alias === undefined) ?? methods[0]
|
|
433
|
+
return undefined
|
|
434
|
+
}
|
|
435
|
+
|
|
229
436
|
/**
|
|
230
437
|
* Optional respond function for a server-side method.
|
|
231
438
|
*
|
|
@@ -336,10 +543,22 @@ export function toServer<
|
|
|
336
543
|
preflight,
|
|
337
544
|
request,
|
|
338
545
|
respond,
|
|
546
|
+
broadcast,
|
|
339
547
|
stableBinding,
|
|
340
548
|
transport,
|
|
549
|
+
validate,
|
|
341
550
|
verify,
|
|
342
551
|
} = options
|
|
552
|
+
const effectiveVerify =
|
|
553
|
+
verify ??
|
|
554
|
+
(async (parameters: VerifyContext<method>) => {
|
|
555
|
+
if (validate) await validate(parameters)
|
|
556
|
+
if (!broadcast)
|
|
557
|
+
throw new Errors.VerificationFailedError({
|
|
558
|
+
reason: `${method.name}/${method.intent} does not support credential broadcast`,
|
|
559
|
+
})
|
|
560
|
+
return broadcast(parameters)
|
|
561
|
+
})
|
|
343
562
|
return {
|
|
344
563
|
...method,
|
|
345
564
|
alias,
|
|
@@ -350,9 +569,11 @@ export function toServer<
|
|
|
350
569
|
preflight,
|
|
351
570
|
request,
|
|
352
571
|
respond,
|
|
572
|
+
broadcast,
|
|
353
573
|
stableBinding,
|
|
354
574
|
transport,
|
|
355
|
-
|
|
575
|
+
validate,
|
|
576
|
+
verify: effectiveVerify,
|
|
356
577
|
} as Server<method, defaults, transportOverride, extensions, toServer.Alias<options>>
|
|
357
578
|
}
|
|
358
579
|
|
|
@@ -376,6 +597,21 @@ export declare namespace toServer {
|
|
|
376
597
|
respond?: RespondFn<method> | undefined
|
|
377
598
|
stableBinding?: StableBindingFn<method> | undefined
|
|
378
599
|
transport?: transportOverride | Transport.AnyTransport | undefined
|
|
379
|
-
|
|
380
|
-
|
|
600
|
+
} & (
|
|
601
|
+
| {
|
|
602
|
+
broadcast: BroadcastFn<method>
|
|
603
|
+
validate?: ValidateFn<method> | undefined
|
|
604
|
+
verify?: undefined
|
|
605
|
+
}
|
|
606
|
+
| {
|
|
607
|
+
broadcast?: undefined
|
|
608
|
+
validate?: undefined
|
|
609
|
+
/**
|
|
610
|
+
* @deprecated Use `validate` and `broadcast` for new methods. This
|
|
611
|
+
* combined hook may mutate payment state and cannot power a safe
|
|
612
|
+
* validation-only endpoint.
|
|
613
|
+
*/
|
|
614
|
+
verify: VerifyFn<method>
|
|
615
|
+
}
|
|
616
|
+
)
|
|
381
617
|
}
|
package/src/cli/account.ts
CHANGED
|
@@ -5,6 +5,8 @@ import * as path from 'node:path'
|
|
|
5
5
|
|
|
6
6
|
import { Errors } from 'incur'
|
|
7
7
|
|
|
8
|
+
import { isTempoAccount } from './utils.js'
|
|
9
|
+
|
|
8
10
|
const SERVICE_NAME = 'mppx'
|
|
9
11
|
const defaultCommandTimeoutMs = 10_000
|
|
10
12
|
|
|
@@ -203,6 +205,48 @@ export function createKeychain(account = 'main') {
|
|
|
203
205
|
}
|
|
204
206
|
}
|
|
205
207
|
|
|
208
|
+
/** Resolves a local CLI signer together with its durable account reference. */
|
|
209
|
+
export async function resolveLocalAccount(name?: string) {
|
|
210
|
+
const { privateKeyToAccount } = await import('viem/accounts')
|
|
211
|
+
|
|
212
|
+
const envKey = process.env.MPPX_PRIVATE_KEY?.trim()
|
|
213
|
+
if (envKey)
|
|
214
|
+
return {
|
|
215
|
+
account: privateKeyToAccount(envKey as `0x${string}`),
|
|
216
|
+
source: 'environment' as const,
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const accountName = resolveAccountName(name)
|
|
220
|
+
const key = await createKeychain(accountName).get()
|
|
221
|
+
if (key)
|
|
222
|
+
return {
|
|
223
|
+
account: privateKeyToAccount(key as `0x${string}`),
|
|
224
|
+
accountName,
|
|
225
|
+
source: 'keychain' as const,
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
throw new Error(`Account "${accountName}" not found.`)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Resolves an account supported by persistent CLI sessions. */
|
|
232
|
+
export async function resolvePersistentAccount(name?: string) {
|
|
233
|
+
const accountName = resolveAccountName(name)
|
|
234
|
+
if (!process.env.MPPX_PRIVATE_KEY?.trim() && isTempoAccount(accountName))
|
|
235
|
+
throw new Errors.IncurError({
|
|
236
|
+
code: 'UNSUPPORTED_ACCOUNT',
|
|
237
|
+
message: 'Persistent sessions require an mppx account or MPPX_PRIVATE_KEY.',
|
|
238
|
+
exitCode: 2,
|
|
239
|
+
})
|
|
240
|
+
return resolveLocalAccount(name).catch((cause: unknown) => {
|
|
241
|
+
throw new Errors.IncurError({
|
|
242
|
+
code: 'ACCOUNT_NOT_FOUND',
|
|
243
|
+
message: cause instanceof Error ? cause.message : 'No account found.',
|
|
244
|
+
exitCode: 69,
|
|
245
|
+
...(cause instanceof Error && { cause }),
|
|
246
|
+
})
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
|
|
206
250
|
/**
|
|
207
251
|
* Resolve a CLI account to a viem `LocalAccount`.
|
|
208
252
|
*
|
|
@@ -221,14 +265,5 @@ export function createKeychain(account = 'main') {
|
|
|
221
265
|
* ```
|
|
222
266
|
*/
|
|
223
267
|
export async function resolveAccount(name?: string) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const envKey = process.env.MPPX_PRIVATE_KEY?.trim()
|
|
227
|
-
if (envKey) return privateKeyToAccount(envKey as `0x${string}`)
|
|
228
|
-
|
|
229
|
-
const accountName = resolveAccountName(name)
|
|
230
|
-
const key = await createKeychain(accountName).get()
|
|
231
|
-
if (key) return privateKeyToAccount(key as `0x${string}`)
|
|
232
|
-
|
|
233
|
-
throw new Error(`Account "${accountName}" not found.`)
|
|
268
|
+
return (await resolveLocalAccount(name)).account
|
|
234
269
|
}
|