checkout-intents 0.2.0 → 0.3.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 +14 -0
- package/README.md +55 -2
- package/client.d.mts.map +1 -1
- package/client.d.ts.map +1 -1
- package/client.js +18 -1
- package/client.js.map +1 -1
- package/client.mjs +18 -1
- package/client.mjs.map +1 -1
- package/package.json +1 -1
- package/resources/checkout-intents.d.mts +124 -1
- package/resources/checkout-intents.d.mts.map +1 -1
- package/resources/checkout-intents.d.ts +124 -1
- package/resources/checkout-intents.d.ts.map +1 -1
- package/resources/checkout-intents.js +160 -0
- package/resources/checkout-intents.js.map +1 -1
- package/resources/checkout-intents.mjs +160 -0
- package/resources/checkout-intents.mjs.map +1 -1
- package/src/client.ts +23 -1
- package/src/resources/checkout-intents.ts +222 -0
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
|
@@ -5,6 +5,23 @@ import * as CheckoutIntentsAPI from './checkout-intents';
|
|
|
5
5
|
import { APIPromise } from '../core/api-promise';
|
|
6
6
|
import { RequestOptions } from '../internal/request-options';
|
|
7
7
|
import { path } from '../internal/utils/path';
|
|
8
|
+
import { sleep } from '../internal/utils/sleep';
|
|
9
|
+
import { buildHeaders } from '../internal/headers';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Options for polling operations.
|
|
13
|
+
*/
|
|
14
|
+
export interface PollOptions {
|
|
15
|
+
/**
|
|
16
|
+
* The interval in milliseconds between polling attempts.
|
|
17
|
+
*/
|
|
18
|
+
pollIntervalMs?: number;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The maximum number of polling attempts before timing out.
|
|
22
|
+
*/
|
|
23
|
+
maxAttempts?: number;
|
|
24
|
+
}
|
|
8
25
|
|
|
9
26
|
export class CheckoutIntentsResource extends APIResource {
|
|
10
27
|
/**
|
|
@@ -96,6 +113,210 @@ export class CheckoutIntentsResource extends APIResource {
|
|
|
96
113
|
): APIPromise<CheckoutIntent> {
|
|
97
114
|
return this._client.post(path`/api/v1/checkout-intents/${id}/confirm`, { body, ...options });
|
|
98
115
|
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* A helper to poll a checkout intent until a specific condition is met.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* // Poll until completed or failed
|
|
123
|
+
* const checkoutIntent = await client.checkoutIntents.pollUntil(
|
|
124
|
+
* 'id',
|
|
125
|
+
* (intent) => intent.state === 'completed' || intent.state === 'failed'
|
|
126
|
+
* );
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
private async pollUntil<T extends CheckoutIntent = CheckoutIntent>(
|
|
130
|
+
id: string,
|
|
131
|
+
condition: (intent: CheckoutIntent) => intent is T,
|
|
132
|
+
options?: RequestOptions & PollOptions,
|
|
133
|
+
): Promise<T> {
|
|
134
|
+
const maxAttempts = options?.maxAttempts ?? 120; // Default: 120 attempts
|
|
135
|
+
const pollIntervalMs = options?.pollIntervalMs ?? 5000; // Default: 5 seconds
|
|
136
|
+
let attempts = 0;
|
|
137
|
+
|
|
138
|
+
const headers = buildHeaders([
|
|
139
|
+
options?.headers,
|
|
140
|
+
{
|
|
141
|
+
'X-Stainless-Poll-Helper': 'true',
|
|
142
|
+
'X-Stainless-Custom-Poll-Interval': pollIntervalMs.toString(),
|
|
143
|
+
},
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
while (attempts < maxAttempts) {
|
|
147
|
+
const { data: intent, response } = await this.retrieve(id, {
|
|
148
|
+
...options,
|
|
149
|
+
headers: { ...options?.headers, ...headers.values },
|
|
150
|
+
}).withResponse();
|
|
151
|
+
|
|
152
|
+
// Check if condition is met
|
|
153
|
+
if (condition(intent)) {
|
|
154
|
+
return intent;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
attempts++;
|
|
158
|
+
|
|
159
|
+
// If we've reached max attempts, throw an error
|
|
160
|
+
if (attempts >= maxAttempts) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Polling timeout: condition not met after ${maxAttempts} attempts (${
|
|
163
|
+
(maxAttempts * pollIntervalMs) / 1000
|
|
164
|
+
}s)`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Check if server suggests a polling interval
|
|
169
|
+
let sleepInterval = pollIntervalMs;
|
|
170
|
+
const headerInterval = response.headers.get('retry-after-ms');
|
|
171
|
+
if (headerInterval) {
|
|
172
|
+
const headerIntervalMs = parseInt(headerInterval);
|
|
173
|
+
if (!isNaN(headerIntervalMs)) {
|
|
174
|
+
sleepInterval = headerIntervalMs;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
await sleep(sleepInterval);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// This should never be reached due to the throw above, but TypeScript needs it
|
|
182
|
+
throw new Error(`Polling timeout: condition not met after ${maxAttempts} attempts`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* A helper to poll a checkout intent until it reaches a completed state
|
|
187
|
+
* (completed or failed).
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* const checkoutIntent = await client.checkoutIntents.pollUntilCompleted('id');
|
|
192
|
+
* if (checkoutIntent.state === 'completed') {
|
|
193
|
+
* console.log('Order placed successfully!');
|
|
194
|
+
* } else if (checkoutIntent.state === 'failed') {
|
|
195
|
+
* console.log('Order failed:', checkoutIntent.failureReason);
|
|
196
|
+
* }
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
async pollUntilCompleted(
|
|
200
|
+
id: string,
|
|
201
|
+
options?: RequestOptions & PollOptions,
|
|
202
|
+
): Promise<CheckoutIntent.CompletedCheckoutIntent | CheckoutIntent.FailedCheckoutIntent> {
|
|
203
|
+
return this.pollUntil(
|
|
204
|
+
id,
|
|
205
|
+
(intent): intent is CheckoutIntent.CompletedCheckoutIntent | CheckoutIntent.FailedCheckoutIntent =>
|
|
206
|
+
intent.state === 'completed' || intent.state === 'failed',
|
|
207
|
+
options,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* A helper to poll a checkout intent until it's ready for confirmation
|
|
213
|
+
* (awaiting_confirmation state) or has failed. This is typically used after
|
|
214
|
+
* creating a checkout intent to wait for the offer to be retrieved from the merchant.
|
|
215
|
+
*
|
|
216
|
+
* The intent can reach awaiting_confirmation (success - ready to confirm) or failed
|
|
217
|
+
* (offer retrieval failed). Always check the state after polling.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* const intent = await client.checkoutIntents.pollUntilAwaitingConfirmation('id');
|
|
222
|
+
*
|
|
223
|
+
* if (intent.state === 'awaiting_confirmation') {
|
|
224
|
+
* // Review the offer before confirming
|
|
225
|
+
* console.log('Total:', intent.offer.cost.total);
|
|
226
|
+
* } else if (intent.state === 'failed') {
|
|
227
|
+
* // Handle failure (e.g., offer retrieval failed, product out of stock)
|
|
228
|
+
* console.log('Failed:', intent.failureReason);
|
|
229
|
+
* }
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
async pollUntilAwaitingConfirmation(
|
|
233
|
+
id: string,
|
|
234
|
+
options?: RequestOptions & PollOptions,
|
|
235
|
+
): Promise<CheckoutIntent.AwaitingConfirmationCheckoutIntent | CheckoutIntent.FailedCheckoutIntent> {
|
|
236
|
+
return this.pollUntil(
|
|
237
|
+
id,
|
|
238
|
+
(
|
|
239
|
+
intent,
|
|
240
|
+
): intent is CheckoutIntent.AwaitingConfirmationCheckoutIntent | CheckoutIntent.FailedCheckoutIntent =>
|
|
241
|
+
intent.state === 'awaiting_confirmation' || intent.state === 'failed',
|
|
242
|
+
options,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* A helper to create a checkout intent and poll until it's ready for confirmation.
|
|
248
|
+
* This follows the Rye documented flow: create → poll until awaiting_confirmation.
|
|
249
|
+
*
|
|
250
|
+
* After this method completes, you should review the offer (pricing, shipping, taxes)
|
|
251
|
+
* with the user before calling confirm().
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* // Phase 1: Create and wait for offer
|
|
256
|
+
* const intent = await client.checkoutIntents.createAndPoll({
|
|
257
|
+
* buyer: {
|
|
258
|
+
* address1: '123 Main St',
|
|
259
|
+
* city: 'New York',
|
|
260
|
+
* country: 'United States',
|
|
261
|
+
* email: 'john.doe@example.com',
|
|
262
|
+
* firstName: 'John',
|
|
263
|
+
* lastName: 'Doe',
|
|
264
|
+
* phone: '+1234567890',
|
|
265
|
+
* postalCode: '10001',
|
|
266
|
+
* province: 'NY',
|
|
267
|
+
* },
|
|
268
|
+
* productUrl: 'https://example.com/product',
|
|
269
|
+
* quantity: 1,
|
|
270
|
+
* });
|
|
271
|
+
*
|
|
272
|
+
* // Review the offer with the user
|
|
273
|
+
* console.log('Total:', intent.offer.cost.total);
|
|
274
|
+
*
|
|
275
|
+
* // Phase 2: Confirm with payment
|
|
276
|
+
* const completed = await client.checkoutIntents.confirmAndPoll(intent.id, {
|
|
277
|
+
* paymentMethod: { type: 'stripe_token', stripeToken: 'tok_visa' }
|
|
278
|
+
* });
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
async createAndPoll(
|
|
282
|
+
body: CheckoutIntentCreateParams,
|
|
283
|
+
options?: RequestOptions & PollOptions,
|
|
284
|
+
): Promise<CheckoutIntent.AwaitingConfirmationCheckoutIntent | CheckoutIntent.FailedCheckoutIntent> {
|
|
285
|
+
const intent = await this.create(body, options);
|
|
286
|
+
return this.pollUntilAwaitingConfirmation(intent.id, options);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* A helper to confirm a checkout intent and poll until it reaches a completed state
|
|
291
|
+
* (completed or failed).
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```ts
|
|
295
|
+
* const checkoutIntent = await client.checkoutIntents.confirmAndPoll(
|
|
296
|
+
* 'id',
|
|
297
|
+
* {
|
|
298
|
+
* paymentMethod: {
|
|
299
|
+
* stripeToken: 'tok_1RkrWWHGDlstla3f1Fc7ZrhH',
|
|
300
|
+
* type: 'stripe_token',
|
|
301
|
+
* },
|
|
302
|
+
* }
|
|
303
|
+
* );
|
|
304
|
+
*
|
|
305
|
+
* if (checkoutIntent.state === 'completed') {
|
|
306
|
+
* console.log('Order placed successfully!');
|
|
307
|
+
* } else if (checkoutIntent.state === 'failed') {
|
|
308
|
+
* console.log('Order failed:', checkoutIntent.failureReason);
|
|
309
|
+
* }
|
|
310
|
+
* ```
|
|
311
|
+
*/
|
|
312
|
+
async confirmAndPoll(
|
|
313
|
+
id: string,
|
|
314
|
+
body: CheckoutIntentConfirmParams,
|
|
315
|
+
options?: RequestOptions & PollOptions,
|
|
316
|
+
): Promise<CheckoutIntent.CompletedCheckoutIntent | CheckoutIntent.FailedCheckoutIntent> {
|
|
317
|
+
const intent = await this.confirm(id, body, options);
|
|
318
|
+
return this.pollUntilCompleted(intent.id, options);
|
|
319
|
+
}
|
|
99
320
|
}
|
|
100
321
|
|
|
101
322
|
export interface BaseCheckoutIntent {
|
|
@@ -301,6 +522,7 @@ export declare namespace CheckoutIntentsResource {
|
|
|
301
522
|
type Money as Money,
|
|
302
523
|
type Offer as Offer,
|
|
303
524
|
type PaymentMethod as PaymentMethod,
|
|
525
|
+
type PollOptions as PollOptions,
|
|
304
526
|
type VariantSelection as VariantSelection,
|
|
305
527
|
type CheckoutIntentCreateParams as CheckoutIntentCreateParams,
|
|
306
528
|
type CheckoutIntentAddPaymentParams as CheckoutIntentAddPaymentParams,
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.3.0'; // x-release-please-version
|
package/version.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.3.0";
|
|
2
2
|
//# sourceMappingURL=version.d.mts.map
|
package/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.3.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/version.js
CHANGED
package/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.3.0'; // x-release-please-version
|
|
2
2
|
//# sourceMappingURL=version.mjs.map
|