cope-sdk 0.1.0 → 0.1.1
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 +74 -1
- package/README.md +94 -41
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -10
- package/dist/index.d.ts +55 -10
- package/dist/index.global.js +1 -2
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/node.cjs +59 -20
- package/dist/mcp/node.cjs.map +1 -1
- package/dist/mcp/node.js +59 -20
- package/dist/mcp/node.js.map +1 -1
- package/dist/mcp.cjs +59 -20
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +59 -20
- package/dist/mcp.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -26,7 +26,7 @@ declare class CopeCartExpiredError extends CopeError {
|
|
|
26
26
|
readonly state: CartState;
|
|
27
27
|
constructor(state: CartState);
|
|
28
28
|
}
|
|
29
|
-
type ApiErrorCode = '
|
|
29
|
+
type ApiErrorCode = 'unauthorized' | 'invalid_sdk_key' | 'cart_id_mismatch' | 'not_found' | 'validation_error' | 'forbidden_field' | 'business_checkout_hold' | 'cart_not_active' | 'unsupported_currency' | 'unsupported_checkout_locale' | 'checkout_locale_not_allowed' | 'duplicate_line' | 'not_saleable' | 'product_unavailable' | 'insufficient_stock' | 'mixed_seller_cart' | 'mixed_vat_mode_cart' | 'empty_cart' | 'below_minimum_charge' | 'above_maximum_charge' | 'missing_tax_location' | 'cart_not_repriceable' | 'tax_address_invalid' | 'tax_request_rejected' | 'tax_service_unavailable' | 'invalid_redirect_url' | 'embed_origin_not_allowed' | 'price_changed' | 'checkout_expired' | 'checkout_not_cancellable' | 'checkout_payment_in_flight' | 'idempotency_conflict' | 'idempotency_body_mismatch' | 'inactive' | 'not_started' | 'expired' | 'exhausted' | 'no_applicable_items' | 'currency_not_supported' | 'promo_not_supported_for_recurring' | 'offer_sourced_no_promo' | 'promo_locked_during_payment' | 'payload_too_large' | 'rate_limited' | 'upstream_unavailable' | 'gateway_timeout' | 'incomplete_buyer_identity' | 'incomplete_shipping_address' | 'missing_consent' | 'missing_withdrawal_waiver' | 'checkout_not_open' | 'payment_provider_error' | (string & {});
|
|
30
30
|
type CartState = 'active' | 'checkout_in_progress' | 'ordered' | 'expired' | 'abandoned' | 'merged';
|
|
31
31
|
interface OneClickChargeConsentApplicability {
|
|
32
32
|
readonly applicable: boolean;
|
|
@@ -41,7 +41,12 @@ interface Cart {
|
|
|
41
41
|
/** Present only in the `createCart()` response. The SDK persists it to localStorage automatically. */
|
|
42
42
|
readonly cart_secret?: string;
|
|
43
43
|
readonly lines: readonly CartLine[];
|
|
44
|
+
/** Present only on a `setBuyerIdentity()` response that dropped a field, e.g. a malformed phone. */
|
|
45
|
+
readonly field_errors?: readonly FieldError[];
|
|
44
46
|
/**
|
|
47
|
+
* `getCart()` masks the email (`j***n@example.com`); the `setBuyerIdentity()`
|
|
48
|
+
* response carries it as saved.
|
|
49
|
+
*
|
|
45
50
|
* Absent where cope-core does not report it — the reprice and promo-code
|
|
46
51
|
* responses — which is not the same as `null` (no buyer recorded yet).
|
|
47
52
|
*/
|
|
@@ -53,7 +58,8 @@ interface Cart {
|
|
|
53
58
|
readonly one_click_charge_consent?: OneClickChargeConsentApplicability | null;
|
|
54
59
|
}
|
|
55
60
|
interface CartLine {
|
|
56
|
-
|
|
61
|
+
/** The line's id: an integer (the cart API renders `cart_lines.id`, a bigint). */
|
|
62
|
+
readonly id: number;
|
|
57
63
|
readonly cart_id: string;
|
|
58
64
|
readonly product_id: number;
|
|
59
65
|
readonly plan_id: number | null;
|
|
@@ -177,7 +183,7 @@ interface CheckoutCreateResponse {
|
|
|
177
183
|
readonly totals: CartTotals;
|
|
178
184
|
readonly cart_version: number;
|
|
179
185
|
}
|
|
180
|
-
interface
|
|
186
|
+
interface CopeOptions {
|
|
181
187
|
readonly publishableKey: string;
|
|
182
188
|
readonly baseUrl?: string;
|
|
183
189
|
readonly checkoutBaseUrl?: string;
|
|
@@ -199,6 +205,8 @@ interface CopeCartOptions {
|
|
|
199
205
|
readonly secret: string;
|
|
200
206
|
};
|
|
201
207
|
}
|
|
208
|
+
/** @deprecated Use `CopeOptions`. */
|
|
209
|
+
type CopeCartOptions = CopeOptions;
|
|
202
210
|
interface CheckoutOptions {
|
|
203
211
|
/**
|
|
204
212
|
* Sent as the Idempotency-Key. The cart API replays its stored answer to a
|
|
@@ -256,6 +264,13 @@ interface UpdateBuyerIdentityPayload {
|
|
|
256
264
|
readonly vat_id?: string;
|
|
257
265
|
readonly billing_address?: Partial<Address>;
|
|
258
266
|
readonly shipping_address?: Partial<Address>;
|
|
267
|
+
/**
|
|
268
|
+
* Not blocking: a malformed phone is dropped and the rest of the identity is
|
|
269
|
+
* saved, and the response says so in `field_errors`.
|
|
270
|
+
*/
|
|
271
|
+
readonly phone?: string;
|
|
272
|
+
/** The buyer's checkout language; a locale the business has not enabled is ignored. */
|
|
273
|
+
readonly locale?: string;
|
|
259
274
|
readonly consents?: ReadonlyArray<{
|
|
260
275
|
readonly type: string;
|
|
261
276
|
}>;
|
|
@@ -264,7 +279,14 @@ interface CheckoutPayload {
|
|
|
264
279
|
readonly success_url?: string;
|
|
265
280
|
readonly cancel_url?: string;
|
|
266
281
|
readonly embed_origin?: string;
|
|
267
|
-
|
|
282
|
+
/**
|
|
283
|
+
* Recorded on the checkout when sent; not required to create it. When the
|
|
284
|
+
* buyer's payment session is created, `buyer_tos` is required, and so is
|
|
285
|
+
* `withdrawal_waiver` for a cart holding a product that does not ship (a digital
|
|
286
|
+
* product). The hosted checkout page asks the buyer for both; send them here
|
|
287
|
+
* only when the buyer has already given them on your page.
|
|
288
|
+
*/
|
|
289
|
+
readonly consents?: ReadonlyArray<{
|
|
268
290
|
readonly type: string;
|
|
269
291
|
readonly version?: string;
|
|
270
292
|
}>;
|
|
@@ -334,6 +356,12 @@ interface PrefilledCheckoutBaseInput {
|
|
|
334
356
|
*/
|
|
335
357
|
readonly metadata?: CartMetadata;
|
|
336
358
|
readonly intendedPaymentMethod?: string;
|
|
359
|
+
/**
|
|
360
|
+
* Let the hosted checkout page collect the buyer's email, country and postal
|
|
361
|
+
* code instead of requiring them in `buyerIdentity`. Only with
|
|
362
|
+
* `intendedPaymentMethod: 'hosted'`; the API refuses it otherwise.
|
|
363
|
+
*/
|
|
364
|
+
readonly collectBuyerIdentityAtCheckout?: boolean;
|
|
337
365
|
readonly buyerIdentity: UpdateBuyerIdentityPayload;
|
|
338
366
|
readonly checkout: CheckoutPayload;
|
|
339
367
|
}
|
|
@@ -361,6 +389,14 @@ interface PrefilledCheckoutResult {
|
|
|
361
389
|
readonly expiresAt: string;
|
|
362
390
|
readonly totals: CartTotals;
|
|
363
391
|
readonly intendedPaymentMethod?: string;
|
|
392
|
+
/** Non-blocking notices, e.g. a malformed phone that was dropped. Absent when there are none. */
|
|
393
|
+
readonly fieldErrors?: readonly FieldError[];
|
|
394
|
+
}
|
|
395
|
+
/** A non-blocking notice the API attaches to a successful response. */
|
|
396
|
+
interface FieldError {
|
|
397
|
+
readonly code: string;
|
|
398
|
+
readonly message: string;
|
|
399
|
+
readonly field: string;
|
|
364
400
|
}
|
|
365
401
|
declare const CHECKOUT_EMBED_ERROR_CODES: readonly ["not_found", "load_failed", "embed_not_allowed", "confirm_failed"];
|
|
366
402
|
type CheckoutEmbedErrorCode = (typeof CHECKOUT_EMBED_ERROR_CODES)[number];
|
|
@@ -509,7 +545,7 @@ interface MountedCheckout {
|
|
|
509
545
|
*
|
|
510
546
|
* Usage:
|
|
511
547
|
* ```ts
|
|
512
|
-
* const cope = new
|
|
548
|
+
* const cope = new Cope({ publishableKey: 'cope_pk_...' })
|
|
513
549
|
* const cart = await cope.createCart({ currency: 'EUR' })
|
|
514
550
|
* await cope.addLine(cart.id, { product_id: 'uuid-123' })
|
|
515
551
|
* await cope.reprice(cart.id)
|
|
@@ -517,7 +553,7 @@ interface MountedCheckout {
|
|
|
517
553
|
* cope.redirectToCheckout(checkout)
|
|
518
554
|
* ```
|
|
519
555
|
*/
|
|
520
|
-
declare class
|
|
556
|
+
declare class Cope {
|
|
521
557
|
private readonly publishableKey;
|
|
522
558
|
private readonly baseUrl;
|
|
523
559
|
private readonly checkoutBaseUrl;
|
|
@@ -528,13 +564,15 @@ declare class CopeCart {
|
|
|
528
564
|
private cachedCartId;
|
|
529
565
|
/** The active cart ID from localStorage, or null if no cart exists. */
|
|
530
566
|
get currentCartId(): string | null;
|
|
531
|
-
constructor(options:
|
|
567
|
+
constructor(options: CopeOptions);
|
|
532
568
|
createCart(payload: CreateCartPayload): Promise<Cart>;
|
|
533
569
|
getProduct(productUuid: string): Promise<SdkProduct>;
|
|
534
570
|
getCart(cartId: string): Promise<Cart>;
|
|
535
571
|
addLine(cartId: string, payload: AddLinePayload): Promise<Cart>;
|
|
536
|
-
|
|
537
|
-
|
|
572
|
+
/** `lineId` is the line's `id`, an integer; a string of its digits is accepted too. */
|
|
573
|
+
updateLine(cartId: string, lineId: number | string, payload: UpdateLinePayload): Promise<Cart>;
|
|
574
|
+
/** `lineId` is the line's `id`, an integer; a string of its digits is accepted too. */
|
|
575
|
+
removeLine(cartId: string, lineId: number | string): Promise<Cart>;
|
|
538
576
|
setBuyerIdentity(cartId: string, payload: UpdateBuyerIdentityPayload): Promise<Cart>;
|
|
539
577
|
reprice(cartId: string): Promise<Cart>;
|
|
540
578
|
applyPromoCode(cartId: string, code: string): Promise<Cart>;
|
|
@@ -572,5 +610,12 @@ declare class CopeCart {
|
|
|
572
610
|
private persistToStorage;
|
|
573
611
|
private clearStorage;
|
|
574
612
|
}
|
|
613
|
+
/**
|
|
614
|
+
* The 0.1.0 name of {@link Cope}: the same class, so `instanceof` agrees across both names.
|
|
615
|
+
* @deprecated Use `Cope`. `CopeCart` stays exported for code written against 0.1.0.
|
|
616
|
+
*/
|
|
617
|
+
declare const CopeCart: typeof Cope;
|
|
618
|
+
/** @deprecated Use `Cope`. */
|
|
619
|
+
type CopeCart = Cope;
|
|
575
620
|
|
|
576
|
-
export { type AddLinePayload, type Address, type ApiErrorCode, type BuyerIdentity, CHECKOUT_EMBED_ERROR_CODES, CHECKOUT_EMBED_TERMINAL_STATUSES, type Cart, type CartAttribution, type CartLine, type CartMetadata, type CartMetadataValue, type CartState, type CartTotals, type CheckoutCreateEmbedPolicy, type CheckoutCreateResponse, type CheckoutEmbedErrorCode, type CheckoutEmbedErrorPayload, type CheckoutEmbedEvent, type CheckoutEmbedTerminalPayload, type CheckoutEmbedTerminalStatus, type CheckoutMountMessage, type CheckoutOptions, type CheckoutPayload, type CheckoutResult, type CheckoutStatus, type Consent, CopeApiError, CopeCart, CopeCartExpiredError, type CopeCartOptions, CopeError, CopeNetworkError, type CreateCartPayload, type MountCheckoutOptions, type MountableCheckout, type MountedCheckout, type PostPurchaseChargeStatus, type PostPurchaseDecisionPayload, type PostPurchaseDecisionStatus, type PostPurchaseOffer, type PostPurchaseOfferPayload, type PostPurchaseOfferStepKind, type PostPurchaseOutcome, type PostPurchaseTerminalPayload, type PostPurchaseTerminalStatus, type PrefilledCheckoutInput, type PrefilledCheckoutLineInput, type PrefilledCheckoutResult, type PriceSnapshot, type SdkPaymentPlan, type SdkProduct, type SdkProductImage, type SdkVanityPrice, type TotalsFinality, type UpdateBuyerIdentityPayload, type UpdateLinePayload };
|
|
621
|
+
export { type AddLinePayload, type Address, type ApiErrorCode, type BuyerIdentity, CHECKOUT_EMBED_ERROR_CODES, CHECKOUT_EMBED_TERMINAL_STATUSES, type Cart, type CartAttribution, type CartLine, type CartMetadata, type CartMetadataValue, type CartState, type CartTotals, type CheckoutCreateEmbedPolicy, type CheckoutCreateResponse, type CheckoutEmbedErrorCode, type CheckoutEmbedErrorPayload, type CheckoutEmbedEvent, type CheckoutEmbedTerminalPayload, type CheckoutEmbedTerminalStatus, type CheckoutMountMessage, type CheckoutOptions, type CheckoutPayload, type CheckoutResult, type CheckoutStatus, type Consent, Cope, CopeApiError, CopeCart, CopeCartExpiredError, type CopeCartOptions, CopeError, CopeNetworkError, type CopeOptions, type CreateCartPayload, type FieldError, type MountCheckoutOptions, type MountableCheckout, type MountedCheckout, type PostPurchaseChargeStatus, type PostPurchaseDecisionPayload, type PostPurchaseDecisionStatus, type PostPurchaseOffer, type PostPurchaseOfferPayload, type PostPurchaseOfferStepKind, type PostPurchaseOutcome, type PostPurchaseTerminalPayload, type PostPurchaseTerminalStatus, type PrefilledCheckoutInput, type PrefilledCheckoutLineInput, type PrefilledCheckoutResult, type PriceSnapshot, type SdkPaymentPlan, type SdkProduct, type SdkProductImage, type SdkVanityPrice, type TotalsFinality, type UpdateBuyerIdentityPayload, type UpdateLinePayload };
|
package/dist/index.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ declare class CopeCartExpiredError extends CopeError {
|
|
|
26
26
|
readonly state: CartState;
|
|
27
27
|
constructor(state: CartState);
|
|
28
28
|
}
|
|
29
|
-
type ApiErrorCode = '
|
|
29
|
+
type ApiErrorCode = 'unauthorized' | 'invalid_sdk_key' | 'cart_id_mismatch' | 'not_found' | 'validation_error' | 'forbidden_field' | 'business_checkout_hold' | 'cart_not_active' | 'unsupported_currency' | 'unsupported_checkout_locale' | 'checkout_locale_not_allowed' | 'duplicate_line' | 'not_saleable' | 'product_unavailable' | 'insufficient_stock' | 'mixed_seller_cart' | 'mixed_vat_mode_cart' | 'empty_cart' | 'below_minimum_charge' | 'above_maximum_charge' | 'missing_tax_location' | 'cart_not_repriceable' | 'tax_address_invalid' | 'tax_request_rejected' | 'tax_service_unavailable' | 'invalid_redirect_url' | 'embed_origin_not_allowed' | 'price_changed' | 'checkout_expired' | 'checkout_not_cancellable' | 'checkout_payment_in_flight' | 'idempotency_conflict' | 'idempotency_body_mismatch' | 'inactive' | 'not_started' | 'expired' | 'exhausted' | 'no_applicable_items' | 'currency_not_supported' | 'promo_not_supported_for_recurring' | 'offer_sourced_no_promo' | 'promo_locked_during_payment' | 'payload_too_large' | 'rate_limited' | 'upstream_unavailable' | 'gateway_timeout' | 'incomplete_buyer_identity' | 'incomplete_shipping_address' | 'missing_consent' | 'missing_withdrawal_waiver' | 'checkout_not_open' | 'payment_provider_error' | (string & {});
|
|
30
30
|
type CartState = 'active' | 'checkout_in_progress' | 'ordered' | 'expired' | 'abandoned' | 'merged';
|
|
31
31
|
interface OneClickChargeConsentApplicability {
|
|
32
32
|
readonly applicable: boolean;
|
|
@@ -41,7 +41,12 @@ interface Cart {
|
|
|
41
41
|
/** Present only in the `createCart()` response. The SDK persists it to localStorage automatically. */
|
|
42
42
|
readonly cart_secret?: string;
|
|
43
43
|
readonly lines: readonly CartLine[];
|
|
44
|
+
/** Present only on a `setBuyerIdentity()` response that dropped a field, e.g. a malformed phone. */
|
|
45
|
+
readonly field_errors?: readonly FieldError[];
|
|
44
46
|
/**
|
|
47
|
+
* `getCart()` masks the email (`j***n@example.com`); the `setBuyerIdentity()`
|
|
48
|
+
* response carries it as saved.
|
|
49
|
+
*
|
|
45
50
|
* Absent where cope-core does not report it — the reprice and promo-code
|
|
46
51
|
* responses — which is not the same as `null` (no buyer recorded yet).
|
|
47
52
|
*/
|
|
@@ -53,7 +58,8 @@ interface Cart {
|
|
|
53
58
|
readonly one_click_charge_consent?: OneClickChargeConsentApplicability | null;
|
|
54
59
|
}
|
|
55
60
|
interface CartLine {
|
|
56
|
-
|
|
61
|
+
/** The line's id: an integer (the cart API renders `cart_lines.id`, a bigint). */
|
|
62
|
+
readonly id: number;
|
|
57
63
|
readonly cart_id: string;
|
|
58
64
|
readonly product_id: number;
|
|
59
65
|
readonly plan_id: number | null;
|
|
@@ -177,7 +183,7 @@ interface CheckoutCreateResponse {
|
|
|
177
183
|
readonly totals: CartTotals;
|
|
178
184
|
readonly cart_version: number;
|
|
179
185
|
}
|
|
180
|
-
interface
|
|
186
|
+
interface CopeOptions {
|
|
181
187
|
readonly publishableKey: string;
|
|
182
188
|
readonly baseUrl?: string;
|
|
183
189
|
readonly checkoutBaseUrl?: string;
|
|
@@ -199,6 +205,8 @@ interface CopeCartOptions {
|
|
|
199
205
|
readonly secret: string;
|
|
200
206
|
};
|
|
201
207
|
}
|
|
208
|
+
/** @deprecated Use `CopeOptions`. */
|
|
209
|
+
type CopeCartOptions = CopeOptions;
|
|
202
210
|
interface CheckoutOptions {
|
|
203
211
|
/**
|
|
204
212
|
* Sent as the Idempotency-Key. The cart API replays its stored answer to a
|
|
@@ -256,6 +264,13 @@ interface UpdateBuyerIdentityPayload {
|
|
|
256
264
|
readonly vat_id?: string;
|
|
257
265
|
readonly billing_address?: Partial<Address>;
|
|
258
266
|
readonly shipping_address?: Partial<Address>;
|
|
267
|
+
/**
|
|
268
|
+
* Not blocking: a malformed phone is dropped and the rest of the identity is
|
|
269
|
+
* saved, and the response says so in `field_errors`.
|
|
270
|
+
*/
|
|
271
|
+
readonly phone?: string;
|
|
272
|
+
/** The buyer's checkout language; a locale the business has not enabled is ignored. */
|
|
273
|
+
readonly locale?: string;
|
|
259
274
|
readonly consents?: ReadonlyArray<{
|
|
260
275
|
readonly type: string;
|
|
261
276
|
}>;
|
|
@@ -264,7 +279,14 @@ interface CheckoutPayload {
|
|
|
264
279
|
readonly success_url?: string;
|
|
265
280
|
readonly cancel_url?: string;
|
|
266
281
|
readonly embed_origin?: string;
|
|
267
|
-
|
|
282
|
+
/**
|
|
283
|
+
* Recorded on the checkout when sent; not required to create it. When the
|
|
284
|
+
* buyer's payment session is created, `buyer_tos` is required, and so is
|
|
285
|
+
* `withdrawal_waiver` for a cart holding a product that does not ship (a digital
|
|
286
|
+
* product). The hosted checkout page asks the buyer for both; send them here
|
|
287
|
+
* only when the buyer has already given them on your page.
|
|
288
|
+
*/
|
|
289
|
+
readonly consents?: ReadonlyArray<{
|
|
268
290
|
readonly type: string;
|
|
269
291
|
readonly version?: string;
|
|
270
292
|
}>;
|
|
@@ -334,6 +356,12 @@ interface PrefilledCheckoutBaseInput {
|
|
|
334
356
|
*/
|
|
335
357
|
readonly metadata?: CartMetadata;
|
|
336
358
|
readonly intendedPaymentMethod?: string;
|
|
359
|
+
/**
|
|
360
|
+
* Let the hosted checkout page collect the buyer's email, country and postal
|
|
361
|
+
* code instead of requiring them in `buyerIdentity`. Only with
|
|
362
|
+
* `intendedPaymentMethod: 'hosted'`; the API refuses it otherwise.
|
|
363
|
+
*/
|
|
364
|
+
readonly collectBuyerIdentityAtCheckout?: boolean;
|
|
337
365
|
readonly buyerIdentity: UpdateBuyerIdentityPayload;
|
|
338
366
|
readonly checkout: CheckoutPayload;
|
|
339
367
|
}
|
|
@@ -361,6 +389,14 @@ interface PrefilledCheckoutResult {
|
|
|
361
389
|
readonly expiresAt: string;
|
|
362
390
|
readonly totals: CartTotals;
|
|
363
391
|
readonly intendedPaymentMethod?: string;
|
|
392
|
+
/** Non-blocking notices, e.g. a malformed phone that was dropped. Absent when there are none. */
|
|
393
|
+
readonly fieldErrors?: readonly FieldError[];
|
|
394
|
+
}
|
|
395
|
+
/** A non-blocking notice the API attaches to a successful response. */
|
|
396
|
+
interface FieldError {
|
|
397
|
+
readonly code: string;
|
|
398
|
+
readonly message: string;
|
|
399
|
+
readonly field: string;
|
|
364
400
|
}
|
|
365
401
|
declare const CHECKOUT_EMBED_ERROR_CODES: readonly ["not_found", "load_failed", "embed_not_allowed", "confirm_failed"];
|
|
366
402
|
type CheckoutEmbedErrorCode = (typeof CHECKOUT_EMBED_ERROR_CODES)[number];
|
|
@@ -509,7 +545,7 @@ interface MountedCheckout {
|
|
|
509
545
|
*
|
|
510
546
|
* Usage:
|
|
511
547
|
* ```ts
|
|
512
|
-
* const cope = new
|
|
548
|
+
* const cope = new Cope({ publishableKey: 'cope_pk_...' })
|
|
513
549
|
* const cart = await cope.createCart({ currency: 'EUR' })
|
|
514
550
|
* await cope.addLine(cart.id, { product_id: 'uuid-123' })
|
|
515
551
|
* await cope.reprice(cart.id)
|
|
@@ -517,7 +553,7 @@ interface MountedCheckout {
|
|
|
517
553
|
* cope.redirectToCheckout(checkout)
|
|
518
554
|
* ```
|
|
519
555
|
*/
|
|
520
|
-
declare class
|
|
556
|
+
declare class Cope {
|
|
521
557
|
private readonly publishableKey;
|
|
522
558
|
private readonly baseUrl;
|
|
523
559
|
private readonly checkoutBaseUrl;
|
|
@@ -528,13 +564,15 @@ declare class CopeCart {
|
|
|
528
564
|
private cachedCartId;
|
|
529
565
|
/** The active cart ID from localStorage, or null if no cart exists. */
|
|
530
566
|
get currentCartId(): string | null;
|
|
531
|
-
constructor(options:
|
|
567
|
+
constructor(options: CopeOptions);
|
|
532
568
|
createCart(payload: CreateCartPayload): Promise<Cart>;
|
|
533
569
|
getProduct(productUuid: string): Promise<SdkProduct>;
|
|
534
570
|
getCart(cartId: string): Promise<Cart>;
|
|
535
571
|
addLine(cartId: string, payload: AddLinePayload): Promise<Cart>;
|
|
536
|
-
|
|
537
|
-
|
|
572
|
+
/** `lineId` is the line's `id`, an integer; a string of its digits is accepted too. */
|
|
573
|
+
updateLine(cartId: string, lineId: number | string, payload: UpdateLinePayload): Promise<Cart>;
|
|
574
|
+
/** `lineId` is the line's `id`, an integer; a string of its digits is accepted too. */
|
|
575
|
+
removeLine(cartId: string, lineId: number | string): Promise<Cart>;
|
|
538
576
|
setBuyerIdentity(cartId: string, payload: UpdateBuyerIdentityPayload): Promise<Cart>;
|
|
539
577
|
reprice(cartId: string): Promise<Cart>;
|
|
540
578
|
applyPromoCode(cartId: string, code: string): Promise<Cart>;
|
|
@@ -572,5 +610,12 @@ declare class CopeCart {
|
|
|
572
610
|
private persistToStorage;
|
|
573
611
|
private clearStorage;
|
|
574
612
|
}
|
|
613
|
+
/**
|
|
614
|
+
* The 0.1.0 name of {@link Cope}: the same class, so `instanceof` agrees across both names.
|
|
615
|
+
* @deprecated Use `Cope`. `CopeCart` stays exported for code written against 0.1.0.
|
|
616
|
+
*/
|
|
617
|
+
declare const CopeCart: typeof Cope;
|
|
618
|
+
/** @deprecated Use `Cope`. */
|
|
619
|
+
type CopeCart = Cope;
|
|
575
620
|
|
|
576
|
-
export { type AddLinePayload, type Address, type ApiErrorCode, type BuyerIdentity, CHECKOUT_EMBED_ERROR_CODES, CHECKOUT_EMBED_TERMINAL_STATUSES, type Cart, type CartAttribution, type CartLine, type CartMetadata, type CartMetadataValue, type CartState, type CartTotals, type CheckoutCreateEmbedPolicy, type CheckoutCreateResponse, type CheckoutEmbedErrorCode, type CheckoutEmbedErrorPayload, type CheckoutEmbedEvent, type CheckoutEmbedTerminalPayload, type CheckoutEmbedTerminalStatus, type CheckoutMountMessage, type CheckoutOptions, type CheckoutPayload, type CheckoutResult, type CheckoutStatus, type Consent, CopeApiError, CopeCart, CopeCartExpiredError, type CopeCartOptions, CopeError, CopeNetworkError, type CreateCartPayload, type MountCheckoutOptions, type MountableCheckout, type MountedCheckout, type PostPurchaseChargeStatus, type PostPurchaseDecisionPayload, type PostPurchaseDecisionStatus, type PostPurchaseOffer, type PostPurchaseOfferPayload, type PostPurchaseOfferStepKind, type PostPurchaseOutcome, type PostPurchaseTerminalPayload, type PostPurchaseTerminalStatus, type PrefilledCheckoutInput, type PrefilledCheckoutLineInput, type PrefilledCheckoutResult, type PriceSnapshot, type SdkPaymentPlan, type SdkProduct, type SdkProductImage, type SdkVanityPrice, type TotalsFinality, type UpdateBuyerIdentityPayload, type UpdateLinePayload };
|
|
621
|
+
export { type AddLinePayload, type Address, type ApiErrorCode, type BuyerIdentity, CHECKOUT_EMBED_ERROR_CODES, CHECKOUT_EMBED_TERMINAL_STATUSES, type Cart, type CartAttribution, type CartLine, type CartMetadata, type CartMetadataValue, type CartState, type CartTotals, type CheckoutCreateEmbedPolicy, type CheckoutCreateResponse, type CheckoutEmbedErrorCode, type CheckoutEmbedErrorPayload, type CheckoutEmbedEvent, type CheckoutEmbedTerminalPayload, type CheckoutEmbedTerminalStatus, type CheckoutMountMessage, type CheckoutOptions, type CheckoutPayload, type CheckoutResult, type CheckoutStatus, type Consent, Cope, CopeApiError, CopeCart, CopeCartExpiredError, type CopeCartOptions, CopeError, CopeNetworkError, type CopeOptions, type CreateCartPayload, type FieldError, type MountCheckoutOptions, type MountableCheckout, type MountedCheckout, type PostPurchaseChargeStatus, type PostPurchaseDecisionPayload, type PostPurchaseDecisionStatus, type PostPurchaseOffer, type PostPurchaseOfferPayload, type PostPurchaseOfferStepKind, type PostPurchaseOutcome, type PostPurchaseTerminalPayload, type PostPurchaseTerminalStatus, type PrefilledCheckoutInput, type PrefilledCheckoutLineInput, type PrefilledCheckoutResult, type PriceSnapshot, type SdkPaymentPlan, type SdkProduct, type SdkProductImage, type SdkVanityPrice, type TotalsFinality, type UpdateBuyerIdentityPayload, type UpdateLinePayload };
|
package/dist/index.global.js
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
var CopeCart=(function(exports){'use strict';var i=class extends Error{constructor(e){super(e),this.name="CopeError";}},b=class extends i{code;status;field;requestId;retryAfter;errors;constructor(e,r,n,o){let a=r[0];super(a?.message??`API error ${e}`),this.name="CopeApiError",this.status=e,this.code=a?.code??"unknown",this.field=a?.field,this.requestId=n??null,this.retryAfter=o??null,this.errors=r;}},E=class extends i{constructor(e){super(e),this.name="CopeNetworkError";}},S=class extends i{state;constructor(e){super(`Cart is ${e} and cannot be used`),this.name="CopeCartExpiredError",this.state=e;}},U=["not_found","load_failed","embed_not_allowed","confirm_failed"],v=["expired","completed","already_completed","cancelled","processing"];var $=new Set(["ordered","expired","abandoned","merged"]),H="https://app.cope.com",x="cope_sdk_cart",N=8e3,B=500,z=5e3,V="cope.checkout",G=1,F="copecart.checkout.mount",j=1,Y=250,W=20,X=8e3,J=new Set(["oto-v1"]);function d(t){return encodeURIComponent(t)}function u(t){return typeof t=="object"&&t!==null}function Q(t){try{let e=new URL(t);return e.pathname==="/"&&!e.search&&!e.hash&&!e.username&&!e.password?e.origin:null}catch{return null}}var Z={payload_too_large:"Request body is too large",rate_limited:"Too many requests",upstream_unavailable:"The checkout service is unavailable",gateway_timeout:"The checkout service did not answer in time",not_found:"Not found"};function ee(t){return u(t)?Array.isArray(t.errors)&&t.errors.length>0&&t.errors.every(te)?t.errors:typeof t.error=="string"&&t.error.length>0?/^[a-z][a-z0-9_]*$/.test(t.error)?[{code:t.error,message:Z[t.error]??t.error}]:[{code:"unknown",message:t.error}]:null:null}function te(t){return u(t)&&typeof t.code=="string"&&typeof t.message=="string"}function re(t){if(t===null||t.trim()==="")return null;if(/^\d+$/.test(t.trim()))return Number(t.trim());let e=Date.parse(t);return Number.isNaN(e)?null:Math.max(0,Math.ceil((e-Date.now())/1e3))}function ne(t){return u(t)&&typeof t.request_id=="string"?t.request_id:null}function oe(t){if(!u(t))return {applicable:false,terms_version:null};let e=t.terms_version;return t.applicable!==true||typeof e!="string"||!J.has(e)?{applicable:false,terms_version:null}:{applicable:true,terms_version:e}}function g(t){return {...t,one_click_charge_consent:oe(t.one_click_charge_consent)}}var ae=new Set(U),ie=new Set(v);function se(t){return ae.has(t)}function le(t){return ie.has(t)}function ce(t){return t==="upsell"||t==="downsell"}function ue(t){return t==="accepted"||t==="declined"||t==="failed_not_charged"||t==="requires_action"}function de(t){return t==="not_charged"||t==="charged"||t==="requires_action"||t==="failed"}function ye(t){return t==="completed"||t==="declined"||t==="expired"||t==="unavailable"}function pe(){let t=window.location;if(t.origin)return t.origin;let e=t.host||[t.hostname,t.port].filter(Boolean).join(":");return new URL(`${t.protocol}//${e}`).origin}function he(t){let e=new URL(t),r=new URL(t),n=e.pathname.match(/^\/checkout\/embed\/([^/]+)$/),o=e.pathname.match(/^\/checkout\/([^/]+)$/);if(n)return e.pathname=`/checkout/${n[1]}`,r.pathname=`/checkout/embed/${n[1]}`,{checkoutUrl:e.toString(),embedCheckoutUrl:r.toString()};if(o)return e.pathname=`/checkout/${o[1]}`,r.pathname=`/checkout/embed/${o[1]}`,{checkoutUrl:e.toString(),embedCheckoutUrl:r.toString()};throw new i("Checkout URL path cannot be mapped to COPE checkout routes")}function D(t){let r=new URL(t).pathname.match(/^\/checkout\/embed\/([^/]+)$/);if(!r)throw new i("Checkout embed URL path cannot be mapped to COPE checkout embed route");return decodeURIComponent(r[1])}function me(t){let e=t.embed;if(u(e)&&e.allowed===true&&typeof e.parent_origin=="string")try{return new URL(e.parent_origin).origin===e.parent_origin?e.parent_origin:void 0}catch{return}}function ge(t){if(!u(t)||t.source!==V||t.version!==G)return null;let e={...typeof t.messageId=="string"?{messageId:t.messageId}:{},...typeof t.timestamp=="string"?{timestamp:t.timestamp}:{}};if(t.type==="ready")return {type:"ready",...e};if(t.type==="resize"){if(!u(t.payload))return null;let{height:r}=t.payload;return typeof r!="number"||!Number.isFinite(r)||r<=0?null:{type:"resize",payload:{height:Math.ceil(r)},...e}}if(t.type==="error"){if(!u(t.payload))return null;let{code:r,retryable:n}=t.payload;return typeof r!="string"||!se(r)||typeof n!="boolean"?null:{type:"error",payload:{code:r,retryable:n},...e}}if(t.type==="terminal"){if(!u(t.payload))return null;let{status:r}=t.payload;return typeof r!="string"||!le(r)?null:{type:"terminal",payload:{status:r},...e}}if(t.type==="post_purchase_offer"){if(!u(t.payload))return null;let{offerRef:r,stepKind:n,title:o,priceGrossMinorUnits:a,currency:y}=t.payload;return typeof r!="string"||!r||typeof n!="string"||!ce(n)||typeof o!="string"||!o||typeof a!="number"||!Number.isFinite(a)||a<0||typeof y!="string"||!y?null:{type:"post_purchase_offer",payload:{offerRef:r,stepKind:n,title:o,priceGrossMinorUnits:a,currency:y},...e}}if(t.type==="post_purchase_decision"){if(!u(t.payload))return null;let{offerRef:r,status:n,chargeStatus:o}=t.payload;return typeof r!="string"||!r||typeof n!="string"||!ue(n)||typeof o!="string"||!de(o)?null:{type:"post_purchase_decision",payload:{offerRef:r,status:n,chargeStatus:o},...e}}if(t.type==="post_purchase_terminal"){if(!u(t.payload))return null;let{status:r}=t.payload;return typeof r!="string"||!ye(r)?null:{type:"post_purchase_terminal",payload:{status:r},...e}}return null}var A=class{publishableKey;baseUrl;checkoutBaseUrl;persistence;abortController;mountCleanups=new Set;cachedSecret=null;cachedCartId=null;get currentCartId(){return this.cachedCartId}constructor(e){if(!e.publishableKey?.startsWith("cope_pk_"))throw new i('Invalid publishableKey. Must start with "cope_pk_".');if(typeof window<"u"&&window.location?.protocol==="http:"&&window.location.hostname!=="localhost")throw new i("CopeCart SDK requires HTTPS. Refusing to operate on an insecure page.");this.publishableKey=e.publishableKey;let r=Q(e.baseUrl??H);if(r===null)throw new i('Invalid baseUrl. Pass an origin such as "https://app.cope.com"; the SDK adds /api/cart/v1 itself.');this.baseUrl=r,this.checkoutBaseUrl=e.checkoutBaseUrl?e.checkoutBaseUrl.replace(/\/+$/,""):new URL(this.baseUrl).origin,this.abortController=new AbortController,this.persistence=e.cart?"none":e.persistence??"localStorage",e.cart?(this.cachedCartId=e.cart.id,this.cachedSecret=e.cart.secret):this.hydrateFromStorage();}async createCart(e){return this.createCartRequest(e,{skipAuth:true})}async getProduct(e){return this.get(`/products/${d(e)}`,{skipAuth:true})}async getCart(e){let r=g(await this.get(`/carts/${d(e)}`));if($.has(r.state))throw this.clearStorage(),new S(r.state);return r}async addLine(e,r){return g(await this.post(`/carts/${d(e)}/lines`,r))}async updateLine(e,r,n){return g(await this.patch(`/carts/${d(e)}/lines/${d(r)}`,n))}async removeLine(e,r){return g(await this.del(`/carts/${d(e)}/lines/${d(r)}`))}async setBuyerIdentity(e,r){return g(await this.patch(`/carts/${d(e)}/buyer-identity`,r))}async reprice(e){return g(await this.post(`/carts/${d(e)}/reprice`,{}))}async applyPromoCode(e,r){return g(await this.post(`/carts/${d(e)}/promo_code`,{code:r}))}async removePromoCode(e){return g(await this.del(`/carts/${d(e)}/promo_code`))}async checkout(e,r,n={}){return this.createCheckoutResult(e,r,n.idempotencyKey?{idempotencyKey:n.idempotencyKey}:void 0)}async createPrefilledCheckout(e){let r=this.normalizePrefilledLines(e),n=await this.post("/prefilled-checkouts",{external_reference:e.externalReference,currency:e.currency,...e.locale!=null?{locale:e.locale}:{},...e.attribution?{attribution:e.attribution}:{},...e.intendedPaymentMethod!=null?{intended_payment_method:e.intendedPaymentMethod}:{},...e.metadata?{metadata:e.metadata}:{},lines:r.map(a=>({product_id:a.productId,...a.planId!==void 0?{plan_id:a.planId}:{},...a.quantity!==void 0?{quantity:a.quantity}:{}})),buyer_identity:e.buyerIdentity,checkout:e.checkout},{skipAuth:true,idempotencyKey:await this.prefilledIdempotencyKey(e.externalReference)}),o=this.normalizeCheckoutResult(n);return {cartId:n.cart_id,cartVersion:n.cart_version,checkoutId:o.checkoutId,checkoutToken:n.checkout_token??D(o.embedCheckoutUrl),checkoutUrl:o.checkoutUrl,embedCheckoutUrl:o.embedCheckoutUrl,...o.embedOrigin?{embedOrigin:o.embedOrigin}:{},status:o.status,expiresAt:o.expiresAt,totals:o.totals,...e.intendedPaymentMethod!=null?{intendedPaymentMethod:e.intendedPaymentMethod}:{}}}async cancelCheckout(e){await this.requestVoid("POST",`/checkouts/${d(e)}/cancel`);}redirectToCheckout(e){this.abortController.signal.aborted||typeof window<"u"&&(window.location.href=e.checkoutUrl);}mountCheckout(e,r,n={}){if(this.abortController.signal.aborted)throw new i("SDK destroyed");if(typeof window>"u"||typeof document>"u")throw new i("mountCheckout requires a browser environment");let{checkout:o,options:a}=this.normalizeMountCheckoutArgs(e,r,n),y=this.checkoutOrigin();if(this.assertCopeOrigin(o.embedCheckoutUrl,y,"Checkout embed URL"),!o.embedOrigin)throw new i("mountCheckout requires checkout.embedOrigin \u2014 send embed_origin on checkout() or on create-offer, and register the origin in dashboard Settings");let w;if(a.fallback==="redirect"){if(!o.checkoutUrl)throw new i("mountCheckout with fallback: 'redirect' requires checkout.checkoutUrl \u2014 for an offer, pass its public_url");this.assertCopeOrigin(o.checkoutUrl,y,"Checkout URL"),w=o.checkoutUrl;}let T=this.resolveMountTarget(a.target),l=document.createElement("iframe"),f=new URL(o.embedCheckoutUrl).origin,C={type:F,version:j,token:D(o.embedCheckoutUrl)},R=pe(),p=false,P=false,s=0,h,k;if(o.embedOrigin!==R)throw new i(`Checkout embed origin ${o.embedOrigin} does not match current origin ${R}`);l.src=o.embedCheckoutUrl,l.title=a.title??"COPE checkout",l.setAttribute("allow","payment *"),l.referrerPolicy="no-referrer",l.style.border="0",l.style.width="100%",l.style.minHeight="720px",a.className&&(l.className=a.className);let m=()=>{h!==void 0&&(window.clearInterval(h),h=void 0);},_=()=>{k!==void 0&&(window.clearTimeout(k),k=void 0);},O=()=>{p||(p=true,m(),_(),window.removeEventListener("message",q),l.removeEventListener("load",K),l.remove(),this.mountCleanups.delete(O));},I=()=>{if(!(p||P)){if(s>=W){m();return}s+=1,l.contentWindow?.postMessage(C,f);}},L=()=>{p||(s=0,m(),I(),h=window.setInterval(I,Y));},K=()=>{p||(P=false,L());},q=M=>{if(p||M.origin!==f||M.source!==l.contentWindow)return;let c=ge(M.data);c&&(a.onMessage?.(c),c.type==="ready"?(P=true,m(),_(),a.onReady?.()):c.type==="resize"?(l.style.height=`${c.payload.height}px`,a.onResize?.(c.payload)):c.type==="error"?(m(),_(),a.onError?.(c.payload)):c.type==="terminal"?(m(),_(),a.onTerminal?.(c.payload),c.payload.status==="completed"?a.onSuccess?.():c.payload.status==="cancelled"&&a.onCancel?.()):c.type==="post_purchase_offer"?a.onPostPurchaseOffer?.(c.payload):c.type==="post_purchase_decision"?a.onPostPurchaseDecision?.(c.payload):c.type==="post_purchase_terminal"&&a.onPostPurchaseTerminal?.(c.payload));};window.addEventListener("message",q),l.addEventListener("load",K),this.mountCleanups.add(O);try{T.appendChild(l),L(),k=window.setTimeout(()=>{if(!(p||P)){if(a.fallback==="redirect"){a.onFallbackRedirect?.(),window.location.href=w;return}a.onError?.({code:"load_failed",retryable:!0});}},a.readyTimeoutMs??X);}catch(M){throw O(),M}return {iframe:l,destroy:O}}destroy(){for(let e of Array.from(this.mountCleanups))e();this.abortController.abort(),this.clearStorage();}async createCartRequest(e,r){let n=await this.post("/carts",e,r),o=g({...n,lines:n.lines??[],buyer_identity:n.buyer_identity??null});return o.cart_secret&&(this.cachedCartId=o.id,this.cachedSecret=o.cart_secret,this.persistToStorage()),o}async createCheckoutResult(e,r,n){let o=await this.post(`/carts/${d(e)}/checkout`,r,n);return this.normalizeCheckoutResult(o)}normalizeCheckoutResult(e){let r=e.checkout_url.startsWith("http")?e.checkout_url:`${this.checkoutBaseUrl}${e.checkout_url}`;this.assertCopeOrigin(r,this.checkoutOrigin(),"Checkout URL");let n=he(r);return {checkoutId:e.checkout_id,checkoutUrl:n.checkoutUrl,embedCheckoutUrl:n.embedCheckoutUrl,embedOrigin:me(e),status:e.status,expiresAt:e.expires_at,totals:e.totals}}async requestVoid(e,r,n){await this.request(e,r,n);}async get(e,r){return this.request("GET",e,void 0,r)}async post(e,r,n){return this.request("POST",e,r,n)}async patch(e,r){return this.request("PATCH",e,r)}async del(e){return this.request("DELETE",e)}async request(e,r,n,o){if(this.abortController.signal.aborted)throw new i("SDK destroyed");let a=`${this.baseUrl}/api/cart/v1${r}`,y={Accept:"application/json","X-Cope-Key":this.publishableKey};n!==void 0&&(y["Content-Type"]="application/json"),!o?.skipAuth&&this.cachedSecret&&(y.Authorization=`CartSecret ${this.cachedSecret}`);let w=e==="POST"?o?.idempotencyKey??crypto.randomUUID():void 0;w&&(y["Idempotency-Key"]=w);let T=e==="GET"||e==="POST"&&this.isRetryablePath(r)?2:1,l=this.isReplaySafe(e,r),f;for(let C=0;C<T;C++){if(C>0){let s=this.calculateRetryDelay(C-1);await this.sleep(s);}let R=new AbortController,p=setTimeout(()=>R.abort(),N),P=AbortSignal.any([this.abortController.signal,R.signal]);try{let s=await fetch(a,{method:e,headers:y,body:n!==void 0?JSON.stringify(n):void 0,signal:P});if(s.ok)return s.status===204?void 0:await s.json();let h=await s.json().catch(()=>null),k=ee(h)??[{code:"unknown",message:s.statusText}],m=s.headers.get("X-Request-Id")??ne(h),_=re(s.headers.get("Retry-After"));if(this.shouldRetry(s.status)&&C<T-1&&(l||s.status===429)){f=new b(s.status,k,m,_);continue}throw new b(s.status,k,m,_)}catch(s){if(s instanceof b||s instanceof S)throw s;if(this.abortController.signal.aborted)throw new i("SDK destroyed");if(C<T-1&&l){f=s;continue}let h=s instanceof Error?s.message:"Network error";throw new E(h)}finally{clearTimeout(p);}}throw f instanceof Error?f:new E("Request failed")}shouldRetry(e){return e===429||e>=500}isRetryablePath(e){return !e.includes("/checkout")}isReplaySafe(e,r){return e==="GET"||e==="POST"&&r==="/prefilled-checkouts"}calculateRetryDelay(e){let r=B*Math.pow(2,e);return Math.min(r,z)*(.5+Math.random()*.5)}sleep(e){return new Promise(r=>setTimeout(r,e))}normalizePrefilledLines(e){if(!u(e))throw new i("createPrefilledCheckout requires an input object");if(!e.externalReference)throw new i("createPrefilledCheckout requires externalReference for backend idempotency");if(e.line!=null&&e.lines!=null)throw new i("Use either line or lines for createPrefilledCheckout, not both");if(e.line!=null)return [e.line];if(e.lines==null||e.lines.length===0)throw new i("createPrefilledCheckout requires at least one line");return e.lines}async prefilledIdempotencyKey(e){if(/^[A-Za-z0-9._:-]{1,120}$/.test(e))return `prefilled:${e}:cart`;let r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e));return `prefilled#${Array.from(new Uint8Array(r),o=>o.toString(16).padStart(2,"0")).join("")}:cart`}checkoutOrigin(){return new URL(this.checkoutBaseUrl).origin}assertCopeOrigin(e,r,n){let o=new URL(e).origin;if(o!==r)throw new i(`${n} origin ${o} does not match expected ${r}`)}resolveMountTarget(e){if(e==null)throw new i("mountCheckout requires options.target");if(typeof e!="string")return e;let r=document.querySelector(e);if(r instanceof HTMLElement)return r;throw new i(`mountCheckout target "${e}" was not found`)}normalizeMountCheckoutArgs(e,r,n){if(this.isMountableCheckout(e))return {checkout:e,options:r};if(!this.isMountableCheckout(r))throw new i("mountCheckout requires a checkout with embedCheckoutUrl");return {checkout:r,options:{...n,target:e}}}isMountableCheckout(e){return u(e)?typeof e.embedCheckoutUrl=="string":false}get storageEnabled(){return this.persistence==="localStorage"&&typeof localStorage<"u"}hydrateFromStorage(){if(this.storageEnabled)try{let e=localStorage.getItem(x);if(e){let r=JSON.parse(e);this.cachedCartId=r.cartId??null,this.cachedSecret=r.secret??null;}}catch{}}persistToStorage(){if(this.storageEnabled)try{localStorage.setItem(x,JSON.stringify({cartId:this.cachedCartId,secret:this.cachedSecret}));}catch{}}clearStorage(){if(this.cachedCartId=null,this.cachedSecret=null,!!this.storageEnabled)try{localStorage.removeItem(x);}catch{}}};
|
|
2
|
-
exports.CHECKOUT_EMBED_ERROR_CODES=U;exports.CHECKOUT_EMBED_TERMINAL_STATUSES=v;exports.CopeApiError=b;exports.CopeCart=A;exports.CopeCartExpiredError=S;exports.CopeError=i;exports.CopeNetworkError=E;return exports;})({});//# sourceMappingURL=index.global.js.map
|
|
1
|
+
"use strict";var CopeCart=(()=>{var A=Object.defineProperty;var H=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var z=Object.prototype.hasOwnProperty;var F=(t,e)=>{for(var r in e)A(t,r,{get:e[r],enumerable:!0})},V=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of B(e))!z.call(t,o)&&o!==r&&A(t,o,{get:()=>e[o],enumerable:!(n=H(e,o))||n.enumerable});return t};var G=t=>V(A({},"__esModule",{value:!0}),t);var Re={};F(Re,{CHECKOUT_EMBED_ERROR_CODES:()=>x,CHECKOUT_EMBED_TERMINAL_STATUSES:()=>U,Cope:()=>w,CopeApiError:()=>b,CopeCart:()=>$,CopeCartExpiredError:()=>T,CopeError:()=>i,CopeNetworkError:()=>S});var i=class extends Error{constructor(e){super(e),this.name="CopeError"}},b=class extends i{code;status;field;requestId;retryAfter;errors;constructor(e,r,n,o){let a=r[0];super(a?.message??`API error ${e}`),this.name="CopeApiError",this.status=e,this.code=a?.code??"unknown",this.field=a?.field,this.requestId=n??null,this.retryAfter=o??null,this.errors=r}},S=class extends i{constructor(e){super(e),this.name="CopeNetworkError"}},T=class extends i{state;constructor(e){super(`Cart is ${e} and cannot be used`),this.name="CopeCartExpiredError",this.state=e}},x=["not_found","load_failed","embed_not_allowed","confirm_failed"],U=["expired","completed","already_completed","cancelled","processing"];var j=new Set(["ordered","expired","abandoned","merged"]),Y="https://app.cope.com",I="cope_sdk_cart",J=8e3,W=500,X=5e3,Z="cope.checkout",Q=1,ee="copecart.checkout.mount",te=1,re=250,ne=20,oe=8e3,ae=new Set(["oto-v1"]);function y(t){return encodeURIComponent(String(t))}function u(t){return typeof t=="object"&&t!==null}function ie(t){try{let e=new URL(t);return e.pathname==="/"&&!e.search&&!e.hash&&!e.username&&!e.password?e.origin:null}catch{return null}}var se={payload_too_large:"Request body is too large",rate_limited:"Too many requests",upstream_unavailable:"The checkout service is unavailable",gateway_timeout:"The checkout service did not answer in time",not_found:"Not found"};function le(t){return u(t)?Array.isArray(t.errors)&&t.errors.length>0&&t.errors.every(ce)?t.errors:typeof t.error=="string"&&t.error.length>0?/^[a-z][a-z0-9_]*$/.test(t.error)?[{code:t.error,message:se[t.error]??t.error}]:[{code:"unknown",message:t.error}]:null:null}function ce(t){return u(t)&&typeof t.code=="string"&&typeof t.message=="string"}var de=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],ue=/^[A-Z][a-z]{2} ([A-Z][a-z]{2}) ([ \d]\d) (\d{2}):(\d{2}):(\d{2}) (\d{4})$/;function ye([,t,e,r,n,o,a]){let c=[Number(a),de.indexOf(t??""),Number((e??"").trim()),Number(r),Number(n),Number(o)],k=Date.UTC(c[0],c[1],c[2],c[3],c[4],c[5]),p=new Date(k);return[p.getUTCFullYear(),p.getUTCMonth(),p.getUTCDate(),p.getUTCHours(),p.getUTCMinutes(),p.getUTCSeconds()].every((m,h)=>m===c[h])?k:Number.NaN}function pe(t){if(t===null)return null;let e=t.trim();if(/^\d+$/.test(e))return Number(e);let r=ue.exec(e),n=r?ye(r):/ GMT$/.test(e)?Date.parse(e):Number.NaN;return Number.isNaN(n)?null:Math.max(0,Math.ceil((n-Date.now())/1e3))}function he(t){return u(t)&&typeof t.request_id=="string"?t.request_id:null}function me(t){if(!u(t))return{applicable:!1,terms_version:null};let e=t.terms_version;return t.applicable!==!0||typeof e!="string"||!ae.has(e)?{applicable:!1,terms_version:null}:{applicable:!0,terms_version:e}}function _(t){return{...t,one_click_charge_consent:me(t.one_click_charge_consent)}}var ge=new Set(x),Ce=new Set(U);function fe(t){return ge.has(t)}function _e(t){return Ce.has(t)}function ke(t){return t==="upsell"||t==="downsell"}function be(t){return t==="accepted"||t==="declined"||t==="failed_not_charged"||t==="requires_action"}function Pe(t){return t==="not_charged"||t==="charged"||t==="requires_action"||t==="failed"}function Ee(t){return t==="completed"||t==="declined"||t==="expired"||t==="unavailable"}function Se(){let t=window.location;if(t.origin)return t.origin;let e=t.host||[t.hostname,t.port].filter(Boolean).join(":");return new URL(`${t.protocol}//${e}`).origin}function Te(t){let e=new URL(t),r=new URL(t),n=e.pathname.match(/^\/checkout\/embed\/([^/]+)$/),o=e.pathname.match(/^\/checkout\/([^/]+)$/);if(n)return e.pathname=`/checkout/${n[1]}`,r.pathname=`/checkout/embed/${n[1]}`,{checkoutUrl:e.toString(),embedCheckoutUrl:r.toString()};if(o)return e.pathname=`/checkout/${o[1]}`,r.pathname=`/checkout/embed/${o[1]}`,{checkoutUrl:e.toString(),embedCheckoutUrl:r.toString()};throw new i("Checkout URL path cannot be mapped to COPE checkout routes")}function N(t){let r=new URL(t).pathname.match(/^\/checkout\/embed\/([^/]+)$/);if(!r)throw new i("Checkout embed URL path cannot be mapped to COPE checkout embed route");return decodeURIComponent(r[1])}function we(t){let e=t.embed;if(u(e)&&e.allowed===!0&&typeof e.parent_origin=="string")try{return new URL(e.parent_origin).origin===e.parent_origin?e.parent_origin:void 0}catch{return}}function Me(t){if(!u(t)||t.source!==Z||t.version!==Q)return null;let e={...typeof t.messageId=="string"?{messageId:t.messageId}:{},...typeof t.timestamp=="string"?{timestamp:t.timestamp}:{}};if(t.type==="ready")return{type:"ready",...e};if(t.type==="resize"){if(!u(t.payload))return null;let{height:r}=t.payload;return typeof r!="number"||!Number.isFinite(r)||r<=0?null:{type:"resize",payload:{height:Math.ceil(r)},...e}}if(t.type==="error"){if(!u(t.payload))return null;let{code:r,retryable:n}=t.payload;return typeof r!="string"||!fe(r)||typeof n!="boolean"?null:{type:"error",payload:{code:r,retryable:n},...e}}if(t.type==="terminal"){if(!u(t.payload))return null;let{status:r}=t.payload;return typeof r!="string"||!_e(r)?null:{type:"terminal",payload:{status:r},...e}}if(t.type==="post_purchase_offer"){if(!u(t.payload))return null;let{offerRef:r,stepKind:n,title:o,priceGrossMinorUnits:a,currency:c}=t.payload;return typeof r!="string"||!r||typeof n!="string"||!ke(n)||typeof o!="string"||!o||typeof a!="number"||!Number.isFinite(a)||a<0||typeof c!="string"||!c?null:{type:"post_purchase_offer",payload:{offerRef:r,stepKind:n,title:o,priceGrossMinorUnits:a,currency:c},...e}}if(t.type==="post_purchase_decision"){if(!u(t.payload))return null;let{offerRef:r,status:n,chargeStatus:o}=t.payload;return typeof r!="string"||!r||typeof n!="string"||!be(n)||typeof o!="string"||!Pe(o)?null:{type:"post_purchase_decision",payload:{offerRef:r,status:n,chargeStatus:o},...e}}if(t.type==="post_purchase_terminal"){if(!u(t.payload))return null;let{status:r}=t.payload;return typeof r!="string"||!Ee(r)?null:{type:"post_purchase_terminal",payload:{status:r},...e}}return null}var w=class{publishableKey;baseUrl;checkoutBaseUrl;persistence;abortController;mountCleanups=new Set;cachedSecret=null;cachedCartId=null;get currentCartId(){return this.cachedCartId}constructor(e){if(!e.publishableKey?.startsWith("cope_pk_"))throw new i('Invalid publishableKey. Must start with "cope_pk_".');if(typeof window<"u"&&window.location?.protocol==="http:"&&window.location.hostname!=="localhost")throw new i("COPE SDK requires HTTPS. Refusing to operate on an insecure page.");this.publishableKey=e.publishableKey;let r=ie(e.baseUrl??Y);if(r===null)throw new i('Invalid baseUrl. Pass an origin such as "https://app.cope.com"; the SDK adds /api/cart/v1 itself.');this.baseUrl=r,this.checkoutBaseUrl=e.checkoutBaseUrl?e.checkoutBaseUrl.replace(/\/+$/,""):new URL(this.baseUrl).origin,this.abortController=new AbortController,this.persistence=e.cart?"none":e.persistence??"localStorage",e.cart?(this.cachedCartId=e.cart.id,this.cachedSecret=e.cart.secret):this.hydrateFromStorage()}async createCart(e){return this.createCartRequest(e,{skipAuth:!0})}async getProduct(e){return this.get(`/products/${y(e)}`,{skipAuth:!0})}async getCart(e){let r=_(await this.get(`/carts/${y(e)}`));if(j.has(r.state))throw this.clearStorage(),new T(r.state);return r}async addLine(e,r){return _(await this.post(`/carts/${y(e)}/lines`,r))}async updateLine(e,r,n){return _(await this.patch(`/carts/${y(e)}/lines/${y(r)}`,n))}async removeLine(e,r){return _(await this.del(`/carts/${y(e)}/lines/${y(r)}`))}async setBuyerIdentity(e,r){return _(await this.patch(`/carts/${y(e)}/buyer-identity`,r))}async reprice(e){return _(await this.post(`/carts/${y(e)}/reprice`,{}))}async applyPromoCode(e,r){return _(await this.post(`/carts/${y(e)}/promo_code`,{code:r}))}async removePromoCode(e){return _(await this.del(`/carts/${y(e)}/promo_code`))}async checkout(e,r,n={}){return this.createCheckoutResult(e,r,n.idempotencyKey?{idempotencyKey:n.idempotencyKey}:void 0)}async createPrefilledCheckout(e){let r=this.normalizePrefilledLines(e),n=await this.post("/prefilled-checkouts",{external_reference:e.externalReference,currency:e.currency,...e.locale!=null?{locale:e.locale}:{},...e.attribution?{attribution:e.attribution}:{},...e.intendedPaymentMethod!=null?{intended_payment_method:e.intendedPaymentMethod}:{},...e.metadata?{metadata:e.metadata}:{},...e.collectBuyerIdentityAtCheckout!=null?{collect_buyer_identity_at_checkout:e.collectBuyerIdentityAtCheckout}:{},lines:r.map(a=>({product_id:a.productId,...a.planId!==void 0?{plan_id:a.planId}:{},...a.quantity!==void 0?{quantity:a.quantity}:{}})),buyer_identity:e.buyerIdentity,checkout:e.checkout},{skipAuth:!0,idempotencyKey:await this.prefilledIdempotencyKey(e.externalReference)}),o=this.normalizeCheckoutResult(n);return{cartId:n.cart_id,cartVersion:n.cart_version,checkoutId:o.checkoutId,checkoutToken:n.checkout_token??N(o.embedCheckoutUrl),checkoutUrl:o.checkoutUrl,embedCheckoutUrl:o.embedCheckoutUrl,...o.embedOrigin?{embedOrigin:o.embedOrigin}:{},status:o.status,expiresAt:o.expiresAt,totals:o.totals,...e.intendedPaymentMethod!=null?{intendedPaymentMethod:e.intendedPaymentMethod}:{},...n.field_errors?.length?{fieldErrors:n.field_errors}:{}}}async cancelCheckout(e){await this.requestVoid("POST",`/checkouts/${y(e)}/cancel`)}redirectToCheckout(e){this.abortController.signal.aborted||typeof window<"u"&&(window.location.href=e.checkoutUrl)}mountCheckout(e,r,n={}){if(this.abortController.signal.aborted)throw new i("SDK destroyed");if(typeof window>"u"||typeof document>"u")throw new i("mountCheckout requires a browser environment");let{checkout:o,options:a}=this.normalizeMountCheckoutArgs(e,r,n),c=this.checkoutOrigin();if(this.assertCopeOrigin(o.embedCheckoutUrl,c,"Checkout embed URL"),!o.embedOrigin)throw new i("mountCheckout requires checkout.embedOrigin \u2014 send embed_origin on checkout() or on create-offer, and register the origin in dashboard Settings");let k;if(a.fallback==="redirect"){if(!o.checkoutUrl)throw new i("mountCheckout with fallback: 'redirect' requires checkout.checkoutUrl \u2014 for an offer, pass its public_url");this.assertCopeOrigin(o.checkoutUrl,c,"Checkout URL"),k=o.checkoutUrl}let p=this.resolveMountTarget(a.target),l=document.createElement("iframe"),m=new URL(o.embedCheckoutUrl).origin,h={type:ee,version:te,token:N(o.embedCheckoutUrl)},R=Se(),g=!1,M=!1,s=0,C,P;if(o.embedOrigin!==R)throw new i(`Checkout embed origin ${o.embedOrigin} does not match current origin ${R}`);l.src=o.embedCheckoutUrl,l.title=a.title??"COPE checkout",l.setAttribute("allow","payment *"),l.referrerPolicy="no-referrer",l.style.border="0",l.style.width="100%",l.style.minHeight="720px",a.className&&(l.className=a.className);let f=()=>{C!==void 0&&(window.clearInterval(C),C=void 0)},E=()=>{P!==void 0&&(window.clearTimeout(P),P=void 0)},v=()=>{g||(g=!0,f(),E(),window.removeEventListener("message",D),l.removeEventListener("load",q),l.remove(),this.mountCleanups.delete(v))},L=()=>{if(!(g||M)){if(s>=ne){f();return}s+=1,l.contentWindow?.postMessage(h,m)}},K=()=>{g||(s=0,f(),L(),C=window.setInterval(L,re))},q=()=>{g||(M=!1,K())},D=O=>{if(g||O.origin!==m||O.source!==l.contentWindow)return;let d=Me(O.data);d&&(a.onMessage?.(d),d.type==="ready"?(M=!0,f(),E(),a.onReady?.()):d.type==="resize"?(l.style.height=`${d.payload.height}px`,a.onResize?.(d.payload)):d.type==="error"?(f(),E(),a.onError?.(d.payload)):d.type==="terminal"?(f(),E(),a.onTerminal?.(d.payload),d.payload.status==="completed"?a.onSuccess?.():d.payload.status==="cancelled"&&a.onCancel?.()):d.type==="post_purchase_offer"?a.onPostPurchaseOffer?.(d.payload):d.type==="post_purchase_decision"?a.onPostPurchaseDecision?.(d.payload):d.type==="post_purchase_terminal"&&a.onPostPurchaseTerminal?.(d.payload))};window.addEventListener("message",D),l.addEventListener("load",q),this.mountCleanups.add(v);try{p.appendChild(l),K(),P=window.setTimeout(()=>{if(!(g||M)){if(a.fallback==="redirect"){a.onFallbackRedirect?.(),window.location.href=k;return}a.onError?.({code:"load_failed",retryable:!0})}},a.readyTimeoutMs??oe)}catch(O){throw v(),O}return{iframe:l,destroy:v}}destroy(){for(let e of Array.from(this.mountCleanups))e();this.abortController.abort(),this.clearStorage()}async createCartRequest(e,r){let n=await this.post("/carts",e,r),o=_({...n,lines:n.lines??[],buyer_identity:n.buyer_identity??null});return o.cart_secret&&(this.cachedCartId=o.id,this.cachedSecret=o.cart_secret,this.persistToStorage()),o}async createCheckoutResult(e,r,n){let o=await this.post(`/carts/${y(e)}/checkout`,r,n);return this.normalizeCheckoutResult(o)}normalizeCheckoutResult(e){let r=e.checkout_url.startsWith("http")?e.checkout_url:`${this.checkoutBaseUrl}${e.checkout_url}`;this.assertCopeOrigin(r,this.checkoutOrigin(),"Checkout URL");let n=Te(r);return{checkoutId:e.checkout_id,checkoutUrl:n.checkoutUrl,embedCheckoutUrl:n.embedCheckoutUrl,embedOrigin:we(e),status:e.status,expiresAt:e.expires_at,totals:e.totals}}async requestVoid(e,r,n){await this.request(e,r,n)}async get(e,r){return this.request("GET",e,void 0,r)}async post(e,r,n){return this.request("POST",e,r,n)}async patch(e,r){return this.request("PATCH",e,r)}async del(e){return this.request("DELETE",e)}async request(e,r,n,o){if(this.abortController.signal.aborted)throw new i("SDK destroyed");let a=`${this.baseUrl}/api/cart/v1${r}`,c={Accept:"application/json","X-Cope-Key":this.publishableKey};n!==void 0&&(c["Content-Type"]="application/json"),!o?.skipAuth&&this.cachedSecret&&(c.Authorization=`CartSecret ${this.cachedSecret}`);let k=e==="POST"?o?.idempotencyKey??crypto.randomUUID():void 0;k&&(c["Idempotency-Key"]=k);let p=e==="GET"||e==="POST"&&this.isRetryablePath(r)?2:1,l=this.isReplaySafe(e,r),m;for(let h=0;h<p;h++){if(h>0){let s=this.calculateRetryDelay(h-1);await this.sleep(s)}let R=new AbortController,g=setTimeout(()=>R.abort(),J),M=AbortSignal.any([this.abortController.signal,R.signal]);try{let s=await fetch(a,{method:e,headers:c,body:n!==void 0?JSON.stringify(n):void 0,signal:M});if(s.ok)return s.status===204?void 0:await s.json();let C=await s.json().catch(()=>null),P=le(C)??[{code:"unknown",message:s.statusText}],f=s.headers.get("X-Request-Id")??he(C),E=pe(s.headers.get("Retry-After"));if(this.shouldRetry(s.status)&&h<p-1&&(l||s.status===429)){m=new b(s.status,P,f,E);continue}throw new b(s.status,P,f,E)}catch(s){if(s instanceof b||s instanceof T)throw s;if(this.abortController.signal.aborted)throw new i("SDK destroyed");if(h<p-1&&l){m=s;continue}let C=s instanceof Error?s.message:"Network error";throw new S(C)}finally{clearTimeout(g)}}throw m instanceof Error?m:new S("Request failed")}shouldRetry(e){return e===429||e>=500}isRetryablePath(e){return!e.includes("/checkout")}isReplaySafe(e,r){return e==="GET"||e==="POST"&&r==="/prefilled-checkouts"}calculateRetryDelay(e){let r=W*Math.pow(2,e);return Math.min(r,X)*(.5+Math.random()*.5)}sleep(e){return new Promise(r=>setTimeout(r,e))}normalizePrefilledLines(e){if(!u(e))throw new i("createPrefilledCheckout requires an input object");if(!e.externalReference)throw new i("createPrefilledCheckout requires externalReference for backend idempotency");if(e.line!=null&&e.lines!=null)throw new i("Use either line or lines for createPrefilledCheckout, not both");if(e.line!=null)return[e.line];if(e.lines==null||e.lines.length===0)throw new i("createPrefilledCheckout requires at least one line");return e.lines}async prefilledIdempotencyKey(e){if(/^[A-Za-z0-9._:-]{1,120}$/.test(e))return`prefilled:${e}:cart`;let r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e));return`prefilled#${Array.from(new Uint8Array(r),o=>o.toString(16).padStart(2,"0")).join("")}:cart`}checkoutOrigin(){return new URL(this.checkoutBaseUrl).origin}assertCopeOrigin(e,r,n){let o=new URL(e).origin;if(o!==r)throw new i(`${n} origin ${o} does not match expected ${r}`)}resolveMountTarget(e){if(e==null)throw new i("mountCheckout requires options.target");if(typeof e!="string")return e;let r=document.querySelector(e);if(r instanceof HTMLElement)return r;throw new i(`mountCheckout target "${e}" was not found`)}normalizeMountCheckoutArgs(e,r,n){if(this.isMountableCheckout(e))return{checkout:e,options:r};if(!this.isMountableCheckout(r))throw new i("mountCheckout requires a checkout with embedCheckoutUrl");return{checkout:r,options:{...n,target:e}}}isMountableCheckout(e){return u(e)?typeof e.embedCheckoutUrl=="string":!1}get storageEnabled(){return this.persistence==="localStorage"&&typeof localStorage<"u"}hydrateFromStorage(){if(this.storageEnabled)try{let e=localStorage.getItem(I);if(e){let r=JSON.parse(e);this.cachedCartId=r.cartId??null,this.cachedSecret=r.secret??null}}catch{}}persistToStorage(){if(this.storageEnabled)try{localStorage.setItem(I,JSON.stringify({cartId:this.cachedCartId,secret:this.cachedSecret}))}catch{}}clearStorage(){if(this.cachedCartId=null,this.cachedSecret=null,!!this.storageEnabled)try{localStorage.removeItem(I)}catch{}}},$=w;globalThis.Cope=w;return G(Re);})();
|
|
3
2
|
//# sourceMappingURL=index.global.js.map
|