@@ -40,21 +40,32 @@ export type PreparedPayment<
4040 ) => Transport . RequestOf < transport >
4141} >
4242
43- /** A payment challenge prepared together with the exact HTTP request that produced it. */
44- export type PreparedRequest < methods extends readonly Method . AnyClient [ ] > = Readonly <
45- PreparedPayment < methods , Transport . Transport < RequestInit , Response > > & {
46- /** Exact request that returned the selected payment challenge. */
47- request : Request
48- /** Payment-required response returned for {@link request}. */
49- response : Response
50- /** Redirects followed before receiving the payment challenge. */
51- redirects : readonly PreparedRequest . Redirect [ ]
52- /** Creates and sends a credential to the prepared request without following redirects. */
53- pay : ( context ?: AnyContextFor < methods > | undefined ) => Promise < Response >
54- }
55- >
43+ /** An HTTP request prepared together with its response and optional payment. */
44+ export type PreparedRequest <
45+ methods extends readonly Method . AnyClient [ ] ,
46+ requirePayment extends boolean = false ,
47+ > = Readonly < {
48+ /** Exact request that produced {@link response}. */
49+ request : Request
50+ /** Response returned for {@link request}. */
51+ response : Response
52+ /** Redirects followed before receiving {@link response}. */
53+ redirects : readonly PreparedRequest . Redirect [ ]
54+ /** Selected payment when the response requires payment. */
55+ payment : requirePayment extends true
56+ ? PreparedRequest . Payment < methods >
57+ : PreparedRequest . Payment < methods > | undefined
58+ } >
5659
5760export declare namespace PreparedRequest {
61+ /** A request-bound payment that can be inspected or paid. */
62+ type Payment < methods extends readonly Method . AnyClient [ ] > = Readonly <
63+ PreparedPayment < methods , Transport . Transport < RequestInit , Response > > & {
64+ /** Creates and sends a credential to the prepared request without following redirects. */
65+ pay : ( context ?: AnyContextFor < methods > | undefined ) => Promise < Response >
66+ }
67+ >
68+
5869 /** A redirect followed while discovering a payment challenge. */
5970 type Redirect = Readonly < {
6071 from : string
@@ -96,16 +107,26 @@ export type Mppx<
96107 options ?: preparePayment . Options < FlattenMethods < methods > , transport > | undefined ,
97108 ) => Promise < PreparedPayment < FlattenMethods < methods > , transport > >
98109 /**
99- * Follows safe pre-payment redirects and prepares the challenge with the exact request that
100- * produced it. Credential-bearing requests never follow redirects. Requires a runtime that
101- * exposes manual redirect responses; browsers return opaque redirects and are not supported.
110+ * Follows safe pre-payment redirects and returns the response with its exact request. When the
111+ * response requires payment, prepares its selected challenge without creating a credential.
112+ * Credential-bearing requests never follow redirects. Requires a runtime that exposes manual
113+ * redirect responses; browsers return opaque redirects and are not supported.
102114 */
103115 prepareRequest : transport extends Transport . Transport < RequestInit , Response >
104- ? (
105- input : RequestInfo | URL ,
106- init ?: RequestInit | undefined ,
107- options ?: prepareRequest . Options < FlattenMethods < methods > > | undefined ,
108- ) => Promise < PreparedRequest < FlattenMethods < methods > > >
116+ ? {
117+ < const requirePayment extends boolean > (
118+ input : RequestInfo | URL ,
119+ init : RequestInit | undefined ,
120+ options : prepareRequest . Options < FlattenMethods < methods > , requirePayment > & {
121+ requirePayment : requirePayment
122+ } ,
123+ ) : Promise < PreparedRequest < FlattenMethods < methods > , requirePayment > >
124+ (
125+ input : RequestInfo | URL ,
126+ init ?: RequestInit | undefined ,
127+ options ?: prepareRequest . Options < FlattenMethods < methods > > | undefined ,
128+ ) : Promise < PreparedRequest < FlattenMethods < methods > > >
129+ }
109130 : never
110131 /** Creates a credential from a payment-required response by routing to the correct method. */
111132 createCredential : (
@@ -376,9 +397,9 @@ export function create<
376397 async function prepareRequest (
377398 input : RequestInfo | URL ,
378399 init ?: RequestInit ,
379- options ?: prepareRequest . Options < FlattenMethods < methods > > ,
380- ) : Promise < PreparedRequest < FlattenMethods < methods > > > {
381- const { maxRedirects = 20 , ...paymentOptions } = options ?? { }
400+ options ?: prepareRequest . Options < FlattenMethods < methods > , boolean > ,
401+ ) : Promise < PreparedRequest < FlattenMethods < methods > , boolean > > {
402+ const { maxRedirects = 20 , requirePayment = false , ...paymentOptions } = options ?? { }
382403 const preparedHttp = await prepareHttpRequest ( {
383404 acceptPayment : acceptPayment . header ,
384405 acceptPaymentPolicy,
@@ -389,8 +410,17 @@ export function create<
389410 signer : attestationSigner ,
390411 } )
391412 const requestInit = requestToInit ( preparedHttp . replayRequest , preparedHttp . body )
392- if ( ! ( await transport . isPaymentRequired ( preparedHttp . response as never , requestInit as never ) ) )
393- throw new Error ( 'Response does not require payment.' )
413+ if (
414+ ! ( await transport . isPaymentRequired ( preparedHttp . response as never , requestInit as never ) )
415+ ) {
416+ if ( requirePayment ) throw new Error ( 'Response does not require payment.' )
417+ return Object . freeze ( {
418+ payment : undefined ,
419+ request : preparedHttp . request ,
420+ response : preparedHttp . response ,
421+ redirects : preparedHttp . redirects ,
422+ } )
423+ }
394424
395425 const payment = ( await preparePayment ( preparedHttp . response as never , {
396426 ...paymentOptions ,
@@ -412,12 +442,9 @@ export function create<
412442 return payment . createCredential ( context )
413443 } )
414444
415- return Object . freeze ( {
445+ const preparedPayment = Object . freeze ( {
416446 ...payment ,
417447 createCredential : createRequestCredential ,
418- request : preparedHttp . request ,
419- response : preparedHttp . response ,
420- redirects : preparedHttp . redirects ,
421448 async pay ( context ?: AnyContextFor < FlattenMethods < methods > > ) {
422449 const credential = await createRequestCredential ( context )
423450 const paidInit = payment . setCredential (
@@ -430,6 +457,12 @@ export function create<
430457 } )
431458 } ,
432459 } )
460+ return Object . freeze ( {
461+ payment : preparedPayment ,
462+ request : preparedHttp . request ,
463+ response : preparedHttp . response ,
464+ redirects : preparedHttp . redirects ,
465+ } )
433466 }
434467
435468 return {
@@ -465,12 +498,17 @@ export declare namespace preparePayment {
465498
466499export declare namespace prepareRequest {
467500 /** Options for preparing a request-bound payment. */
468- type Options < methods extends readonly Method . AnyClient [ ] = readonly Method . AnyClient [ ] > = Omit <
501+ type Options <
502+ methods extends readonly Method . AnyClient [ ] = readonly Method . AnyClient [ ] ,
503+ requirePayment extends boolean = false ,
504+ > = Omit <
469505 preparePayment . Options < methods , Transport . Transport < RequestInit , Response > > ,
470506 'request'
471507 > & {
472508 /** Maximum redirects followed before rejecting the request. @default 20 */
473509 maxRedirects ?: number | undefined
510+ /** Throw when the response does not require payment. @default false */
511+ requirePayment ?: requirePayment | undefined
474512 }
475513}
476514
0 commit comments