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/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 = 'rate_limited' | 'cart_not_active' | 'duplicate_line' | 'not_saleable' | 'empty_cart' | 'incomplete_buyer_identity' | 'incomplete_shipping_address' | 'missing_consent' | 'below_minimum_charge' | 'invalid_redirect_url' | 'checkout_expired' | 'checkout_not_open' | 'checkout_not_cancellable' | 'inactive' | 'not_started' | 'expired' | 'exhausted' | 'no_applicable_items' | 'currency_not_supported' | 'promo_not_supported_for_recurring' | 'missing_code' | 'missing_tax_location' | 'tax_service_unavailable' | 'payment_provider_error' | 'unauthorized' | 'not_found' | 'validation_error' | 'cart_id_mismatch' | 'payload_too_large' | 'upstream_unavailable' | 'gateway_timeout' | (string & {});
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
- readonly id: string;
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 CopeCartOptions {
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
- readonly consents: ReadonlyArray<{
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 CopeCart({ publishableKey: 'cope_pk_...' })
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 CopeCart {
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: CopeCartOptions);
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
- updateLine(cartId: string, lineId: string, payload: UpdateLinePayload): Promise<Cart>;
537
- removeLine(cartId: string, lineId: string): Promise<Cart>;
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 = 'rate_limited' | 'cart_not_active' | 'duplicate_line' | 'not_saleable' | 'empty_cart' | 'incomplete_buyer_identity' | 'incomplete_shipping_address' | 'missing_consent' | 'below_minimum_charge' | 'invalid_redirect_url' | 'checkout_expired' | 'checkout_not_open' | 'checkout_not_cancellable' | 'inactive' | 'not_started' | 'expired' | 'exhausted' | 'no_applicable_items' | 'currency_not_supported' | 'promo_not_supported_for_recurring' | 'missing_code' | 'missing_tax_location' | 'tax_service_unavailable' | 'payment_provider_error' | 'unauthorized' | 'not_found' | 'validation_error' | 'cart_id_mismatch' | 'payload_too_large' | 'upstream_unavailable' | 'gateway_timeout' | (string & {});
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
- readonly id: string;
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 CopeCartOptions {
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
- readonly consents: ReadonlyArray<{
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 CopeCart({ publishableKey: 'cope_pk_...' })
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 CopeCart {
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: CopeCartOptions);
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
- updateLine(cartId: string, lineId: string, payload: UpdateLinePayload): Promise<Cart>;
537
- removeLine(cartId: string, lineId: string): Promise<Cart>;
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 };
@@ -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