@payment-kit-js/vanilla 0.5.17 → 0.5.18

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.
Files changed (45) hide show
  1. package/dist/{bnpl-shared-DGs1YzS9.mjs → bnpl-shared-CL900HFN.mjs} +2 -2
  2. package/dist/{bnpl-shared-DGs1YzS9.mjs.map → bnpl-shared-CL900HFN.mjs.map} +1 -1
  3. package/dist/{bnpl-shared-BQwCBD45.d.mts → bnpl-shared-D-Kd58Qz.d.mts} +2 -2
  4. package/dist/{bnpl-shared-BQwCBD45.d.mts.map → bnpl-shared-D-Kd58Qz.d.mts.map} +1 -1
  5. package/dist/cdn/paymentkit.js +186 -51
  6. package/dist/cdn/paymentkit.js.map +3 -3
  7. package/dist/cdn/paymentkit.min.js +24 -24
  8. package/dist/cdn/paymentkit.min.js.map +3 -3
  9. package/dist/connect-card-CZhzK_Tp.d.mts.map +1 -1
  10. package/dist/index.d.mts +2 -2
  11. package/dist/index.mjs +11 -4
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/{next-action-handlers-CLOt1wzO.mjs → next-action-handlers-BZ5gynXe.mjs} +18 -18
  14. package/dist/next-action-handlers-BZ5gynXe.mjs.map +1 -0
  15. package/dist/payment-methods/affirm.d.mts +2 -2
  16. package/dist/payment-methods/affirm.mjs +2 -2
  17. package/dist/payment-methods/afterpay.d.mts +2 -2
  18. package/dist/payment-methods/afterpay.mjs +2 -2
  19. package/dist/payment-methods/apple-pay.d.mts +2 -2
  20. package/dist/payment-methods/apple-pay.d.mts.map +1 -1
  21. package/dist/payment-methods/apple-pay.mjs +2 -2
  22. package/dist/payment-methods/apple-pay.mjs.map +1 -1
  23. package/dist/payment-methods/bnpl-shared.d.mts +2 -2
  24. package/dist/payment-methods/bnpl-shared.mjs +2 -2
  25. package/dist/payment-methods/card.d.mts +1 -1
  26. package/dist/payment-methods/card.d.mts.map +1 -1
  27. package/dist/payment-methods/card.mjs +8 -4
  28. package/dist/payment-methods/card.mjs.map +1 -1
  29. package/dist/payment-methods/google-pay.d.mts +25 -3
  30. package/dist/payment-methods/google-pay.d.mts.map +1 -1
  31. package/dist/payment-methods/google-pay.mjs +131 -10
  32. package/dist/payment-methods/google-pay.mjs.map +1 -1
  33. package/dist/payment-methods/klarna.d.mts +2 -2
  34. package/dist/payment-methods/klarna.mjs +2 -2
  35. package/dist/payment-methods/next-action-handlers.mjs +1 -1
  36. package/dist/payment-methods/paypal.d.mts +1 -1
  37. package/dist/payment-methods/paypal.mjs +1 -1
  38. package/dist/{types-B3mjYfOm.d.mts → types-Cjcc3xak.d.mts} +6 -9
  39. package/dist/types-Cjcc3xak.d.mts.map +1 -0
  40. package/dist/{utils-Dc6zwOe1.mjs → utils-DIqrx4XF.mjs} +10 -7
  41. package/dist/utils-DIqrx4XF.mjs.map +1 -0
  42. package/package.json +2 -2
  43. package/dist/next-action-handlers-CLOt1wzO.mjs.map +0 -1
  44. package/dist/types-B3mjYfOm.d.mts.map +0 -1
  45. package/dist/utils-Dc6zwOe1.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { r as PaymentMethod } from "../types-B3mjYfOm.mjs";
1
+ import { i as PaymentMethod } from "../types-Cjcc3xak.mjs";
2
2
  import "../connect-card-CZhzK_Tp.mjs";
3
3
  import "../connect-tunnel-x-BKtMfoGh.mjs";
4
4
  import { a as GooglePayEncryptedToken } from "../airwallex-google-pay-adapter-D-AxVLLq.mjs";
@@ -72,11 +72,33 @@ type GooglePayConfirmResponse = {
72
72
  card_exp_year?: number;
73
73
  };
74
74
  type GooglePaySubmitOptions = {
75
- processorId: string;
75
+ /** Processor external ID — optional when using auto-prepare (SDK fetches from checkout session) */
76
+ processorId?: string;
76
77
  customerInfo: GooglePayCustomerInfo;
77
78
  mockScenario?: GooglePayMockScenario;
78
79
  };
79
- declare const GooglePayPaymentMethod: PaymentMethod<{}, "google_pay">;
80
+ declare const GooglePayPaymentMethod: PaymentMethod<{
81
+ /**
82
+ * Register a callback to be notified when Google Pay becomes ready (or stops being ready).
83
+ * Fires immediately with the current state, then on every state change.
84
+ * Multiple registrations are all notified — none are silently overwritten.
85
+ *
86
+ * @example
87
+ * paymentKit.google_pay.onGooglePayReady((isReady) => {
88
+ * googlePayButton.disabled = !isReady;
89
+ * });
90
+ */
91
+ onGooglePayReady: (callback: (isReady: boolean) => void) => void;
92
+ /**
93
+ * Notify the SDK that the payment amount has changed (e.g. coupon applied).
94
+ * The SDK will disable Google Pay, re-prepare with the new amount, then re-enable.
95
+ * The returned promise resolves when re-prepare is fully complete.
96
+ *
97
+ * @example
98
+ * await paymentKit.google_pay.notifyAmountChanged();
99
+ */
100
+ notifyAmountChanged: () => Promise<void>;
101
+ }, "google_pay">;
80
102
  //#endregion
81
103
  export { Airwallex3dsNextAction, GooglePayConfirmRequest, GooglePayConfirmResponse, GooglePayCustomerInfo, GooglePayMockScenario, GooglePayStartRequest, GooglePayStartResponse, GooglePaySubmitOptions, GooglePayPaymentMethod as default };
82
104
  //# sourceMappingURL=google-pay.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"google-pay.d.mts","names":[],"sources":["../../src/payment-methods/google-pay.ts"],"sourcesContent":[],"mappings":";;;;;;;KAYY,qBAAA;;;;;AAAA,KAMA,qBAAA,GANqB;EAMrB,YAAA,EAAA,MAAA;EAWA,aAAA,EATK,qBASiB;EAuBtB,cAAA,EAAA;IAOA,SAAA,CAAA,EAAA,MAAA;IAOA,WAAA,CAAA,EAAA;MAuBA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAsB;IAmhB5B,CAAA;;;;;;;KA/kBM,sBAAA;;;;;;;;;;;;;;KAuBA,uBAAA;qBACS;;;;KAMT,sBAAA;;;;;;KAOA,wBAAA;;;;;;;;;gBASI;;;;;;;;;;;;;KAcJ,sBAAA;;gBAEI;iBACC;;cAghBX,wBASJ"}
1
+ {"version":3,"file":"google-pay.d.mts","names":[],"sources":["../../src/payment-methods/google-pay.ts"],"sourcesContent":[],"mappings":";;;;;;;KAYY,qBAAA;;;;;AAAA,KAMA,qBAAA,GANqB;EAMrB,YAAA,EAAA,MAAA;EAWA,aAAA,EATK,qBASiB;EAuBtB,cAAA,EAAA;IAOA,SAAA,CAAA,EAAA,MAAA;IAOA,WAAA,CAAA,EAAA;MAuBA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAsB;IA2lB5B,CAAA;;;;;;;KAvpBM,sBAAA;;;;;;;;;;;;;;KAuBA,uBAAA;qBACS;;;;KAMT,sBAAA;;;;;;KAOA,wBAAA;;;;;;;;;gBASI;;;;;;;;;;;;;KAcJ,sBAAA;;;gBAGI;iBACC;;cAulBX,wBAsHgC;;;;;;;;;;;;;;;;;;;;6BAAP"}
@@ -1,6 +1,6 @@
1
- import { i as definePaymentMethod, n as collectFraudMetadata, o as getOrCreateCheckoutRequestId } from "../utils-Dc6zwOe1.mjs";
1
+ import { i as definePaymentMethod, n as collectFraudMetadata, o as getOrCreateCheckoutRequestId } from "../utils-DIqrx4XF.mjs";
2
2
  import { n as AirwallexGooglePayMockScenario, t as AirwallexGooglePayAdapter } from "../airwallex-google-pay-adapter-BvlROwj_.mjs";
3
- import { t as handleNextAction } from "../next-action-handlers-CLOt1wzO.mjs";
3
+ import { t as handleNextAction } from "../next-action-handlers-BZ5gynXe.mjs";
4
4
  import { n as StripeGooglePayAdapter, t as GooglePayMockScenario } from "../stripe-google-pay-adapter-B346KXt4.mjs";
5
5
 
6
6
  //#region src/payment-methods/google-pay.ts
@@ -22,10 +22,42 @@ async function apiCall(url, options, checkoutRequestId) {
22
22
  }
23
23
  return { data: await response.json() };
24
24
  }
25
- function validateOptions(options) {
26
- if (!options?.processorId) return { processor_id: "Processor ID is required" };
25
+ function validateOptions(options, autoPrepareConfig) {
26
+ if (!options?.processorId && !autoPrepareConfig?.processorId) return { processor_id: "Processor ID is required" };
27
27
  return null;
28
28
  }
29
+ /**
30
+ * Check if Google Pay is available on this device/browser.
31
+ * Uses the Google Pay API's isReadyToPay() method.
32
+ */
33
+ async function checkGooglePayAvailability() {
34
+ if (!window.google?.payments?.api?.PaymentsClient) {
35
+ console.log("[GooglePay] Google Pay API not loaded");
36
+ return false;
37
+ }
38
+ try {
39
+ return (await new window.google.payments.api.PaymentsClient({ environment: "TEST" }).isReadyToPay({
40
+ apiVersion: 2,
41
+ apiVersionMinor: 0,
42
+ allowedPaymentMethods: [{
43
+ type: "CARD",
44
+ parameters: {
45
+ allowedAuthMethods: ["PAN_ONLY", "CRYPTOGRAM_3DS"],
46
+ allowedCardNetworks: [
47
+ "VISA",
48
+ "MASTERCARD",
49
+ "AMEX",
50
+ "DISCOVER",
51
+ "JCB"
52
+ ]
53
+ }
54
+ }]
55
+ })).result;
56
+ } catch (error) {
57
+ console.error("[GooglePay] availability check error:", error);
58
+ return false;
59
+ }
60
+ }
29
61
  function getMockScenarioStr(mockScenario) {
30
62
  return mockScenario && mockScenario !== GooglePayMockScenario.None ? mockScenario : void 0;
31
63
  }
@@ -241,17 +273,22 @@ async function confirmAirwallexGooglePay(apiBaseUrl, secureToken, googlePayToken
241
273
  if (userActionCount >= MAX_USER_ACTIONS) return { errors: { google_pay: "Too many authentication attempts. Please try again." } };
242
274
  return toGooglePayResult(response, secureToken);
243
275
  }
244
- const defSubmitPayment = (states) => {
276
+ const defSubmitPayment = (states, getAutoPrepareConfig) => {
245
277
  const submitPayment = async (_fields, options) => {
246
278
  const { apiBaseUrl, secureToken, environment } = states;
247
279
  const gpayOptions = options;
248
- const validationError = validateOptions(gpayOptions);
280
+ const autoPrepareConfig = getAutoPrepareConfig();
281
+ const validationError = validateOptions(gpayOptions, autoPrepareConfig);
249
282
  if (validationError) return { errors: validationError };
283
+ const effectiveOptions = {
284
+ ...gpayOptions,
285
+ processorId: gpayOptions.processorId || autoPrepareConfig?.processorId || ""
286
+ };
250
287
  try {
251
288
  const mockScenarioStr = getMockScenarioStr(gpayOptions.mockScenario);
252
289
  const checkoutRequestId = getOrCreateCheckoutRequestId(environment);
253
290
  console.log(`[GooglePay] Using checkout_request_id: ${checkoutRequestId}`);
254
- const startResult = await callStartEndpoint(apiBaseUrl, secureToken, gpayOptions, mockScenarioStr, checkoutRequestId);
291
+ const startResult = await callStartEndpoint(apiBaseUrl, secureToken, effectiveOptions, mockScenarioStr, checkoutRequestId);
255
292
  if (startResult.error || !startResult.data) return { errors: { google_pay: startResult.error || "Failed to start Google Pay" } };
256
293
  const startData = startResult.data;
257
294
  if (startData.processor === "stripe") {
@@ -273,12 +310,96 @@ const defSubmitPayment = (states) => {
273
310
  return submitPayment;
274
311
  };
275
312
  const GooglePayPaymentMethod = definePaymentMethod((paymentKitStates) => {
313
+ const { apiBaseUrl, secureToken, environment } = paymentKitStates;
314
+ let autoPrepareConfig = null;
315
+ let onGooglePayReadyCallbacks = [];
316
+ let isGooglePayReadyState = false;
317
+ let autoPrepareInProgress = false;
318
+ let cleanupGeneration = 0;
319
+ let pendingAutoPrepareArgs = null;
320
+ let pendingPrepareResolvers = [];
321
+ function instanceSetGooglePayReady(ready) {
322
+ isGooglePayReadyState = ready;
323
+ for (const cb of onGooglePayReadyCallbacks) cb(ready);
324
+ }
325
+ function instanceClearPreparedGooglePay() {
326
+ instanceSetGooglePayReady(false);
327
+ }
328
+ async function instanceAutoPrepare(apBase, sToken, env) {
329
+ if (autoPrepareInProgress) {
330
+ pendingAutoPrepareArgs = {
331
+ apiBaseUrl: apBase,
332
+ secureToken: sToken,
333
+ environment: env
334
+ };
335
+ return new Promise((resolve) => pendingPrepareResolvers.push(resolve));
336
+ }
337
+ autoPrepareInProgress = true;
338
+ const capturedGeneration = cleanupGeneration;
339
+ instanceSetGooglePayReady(false);
340
+ try {
341
+ const result = await apiCall(`${apBase}/api/checkout-sessions/token/${sToken}`, { method: "GET" });
342
+ if (cleanupGeneration !== capturedGeneration) return;
343
+ if (result.error || !result.data) {
344
+ console.warn("[GooglePay] Auto-prepare: failed to fetch session config:", result.error);
345
+ return;
346
+ }
347
+ const processorId = result.data.express_checkout_processor_id;
348
+ if (!processorId) {
349
+ console.log("[GooglePay] Auto-prepare: no express checkout processor configured");
350
+ return;
351
+ }
352
+ const processorTypeRaw = result.data.express_checkout_processor_type;
353
+ autoPrepareConfig = {
354
+ processorId,
355
+ processorType: processorTypeRaw === "airwallex" || processorTypeRaw === "stripe" ? processorTypeRaw : void 0
356
+ };
357
+ const isAvailable = await checkGooglePayAvailability();
358
+ if (cleanupGeneration !== capturedGeneration) return;
359
+ instanceSetGooglePayReady(isAvailable);
360
+ } catch (err) {
361
+ if (cleanupGeneration === capturedGeneration) console.error("[GooglePay] Auto-prepare failed:", err);
362
+ } finally {
363
+ autoPrepareInProgress = false;
364
+ const stale = cleanupGeneration !== capturedGeneration;
365
+ const pending = pendingAutoPrepareArgs;
366
+ const resolvers = pendingPrepareResolvers.splice(0);
367
+ if (!stale && pending) {
368
+ pendingAutoPrepareArgs = null;
369
+ instanceAutoPrepare(pending.apiBaseUrl, pending.secureToken, pending.environment).then(() => {
370
+ for (const r of resolvers) r();
371
+ });
372
+ } else {
373
+ pendingAutoPrepareArgs = null;
374
+ for (const r of resolvers) r();
375
+ }
376
+ }
377
+ }
378
+ instanceAutoPrepare(apiBaseUrl, secureToken, environment).catch((err) => console.error("[GooglePay] Unhandled init error:", err));
276
379
  return {
277
380
  name: "google_pay",
278
- externalFuncs: {},
381
+ externalFuncs: {
382
+ onGooglePayReady: (callback) => {
383
+ onGooglePayReadyCallbacks.push(callback);
384
+ callback(isGooglePayReadyState);
385
+ },
386
+ notifyAmountChanged: () => {
387
+ instanceClearPreparedGooglePay();
388
+ autoPrepareConfig = null;
389
+ return instanceAutoPrepare(apiBaseUrl, secureToken, environment);
390
+ }
391
+ },
279
392
  internalFuncs: {
280
- submitPayment: defSubmitPayment(paymentKitStates),
281
- cleanup: () => {}
393
+ submitPayment: defSubmitPayment(paymentKitStates, () => autoPrepareConfig),
394
+ cleanup: () => {
395
+ cleanupGeneration++;
396
+ onGooglePayReadyCallbacks = [];
397
+ isGooglePayReadyState = false;
398
+ autoPrepareConfig = null;
399
+ pendingAutoPrepareArgs = null;
400
+ pendingPrepareResolvers = [];
401
+ autoPrepareInProgress = false;
402
+ }
282
403
  }
283
404
  };
284
405
  });
@@ -1 +1 @@
1
- {"version":3,"file":"google-pay.mjs","names":["airwallexMockScenario: AirwallexGooglePayMockScenario","config: AirwallexGooglePayConfig","requestBody: GooglePayConfirmRequest","submitPayment: TInternalFuncs[\"submitPayment\"]"],"sources":["../../src/payment-methods/google-pay.ts"],"sourcesContent":["import type { PaymentKitErrors, PaymentKitStates, TInternalFuncs } from \"../types\";\nimport { collectFraudMetadata, definePaymentMethod, getOrCreateCheckoutRequestId } from \"../utils\";\nimport {\n AirwallexGooglePayAdapter,\n type AirwallexGooglePayConfig,\n AirwallexGooglePayMockScenario,\n type GooglePayEncryptedToken,\n} from \"./airwallex-google-pay-adapter\";\nimport { handleNextAction } from \"./next-action-handlers\";\nimport { GooglePayMockScenario, StripeGooglePayAdapter } from \"./stripe-google-pay-adapter\";\n\n// Google Pay-specific types\nexport type GooglePayCustomerInfo = {\n first_name: string;\n last_name: string;\n email?: string;\n};\n\nexport type GooglePayStartRequest = {\n processor_id: string;\n customer_info: GooglePayCustomerInfo;\n fraud_metadata: {\n ipAddress?: string;\n browserInfo?: { [key: string]: unknown };\n processorFraudInfo?: { [key: string]: unknown };\n };\n mock_scenario?: string;\n};\n\nexport type GooglePayStartResponse = {\n checkout_attempt_id: string;\n amount: number;\n amount_display: string; // Formatted for Google Pay (e.g., \"100.00\" for USD, \"1000\" for JPY)\n currency: string;\n country: string;\n\n // Processor discriminator\n processor: \"stripe\" | \"airwallex\";\n\n // Environment flag\n is_sandbox?: boolean;\n\n // Stripe-specific fields (when processor=\"stripe\")\n client_secret?: string;\n stripe_pk?: string;\n\n // Airwallex-specific fields (when processor=\"airwallex\")\n merchant_name?: string;\n airwallex_account_id?: string;\n google_merchant_id?: string; // Google-assigned merchant ID for production (BCR2DN...)\n};\n\nexport type GooglePayConfirmRequest = {\n google_pay_token?: GooglePayEncryptedToken; // Required for Airwallex\n payer_email?: string; // Email from payment sheet (Stripe Google Pay)\n mock_scenario?: string;\n};\n\n// Airwallex 3DS next action type (matches backend snake_case response)\nexport type Airwallex3dsNextAction = {\n type: \"airwallex_3ds\";\n url: string;\n method: string;\n payment_intent_id: string;\n};\n\nexport type GooglePayConfirmResponse = {\n charge_status: \"success\" | \"fail\" | \"pending\";\n transaction_id?: string;\n error_code?: string;\n error_message?: string;\n error_message_for_customer?: string;\n error_message_for_debug?: string;\n checkout_attempt_id: string;\n checkout_session_id?: string;\n next_action?: Airwallex3dsNextAction; // Present when charge_status=\"pending\" for 3DS\n payment_intent_id?: string;\n customer_id?: string;\n payment_method_id?: string;\n processor_used?: string;\n subscription_id?: string;\n invoice_id?: string;\n invoice_number?: number;\n card_brand?: string;\n card_last4?: string;\n card_exp_month?: number;\n card_exp_year?: number;\n};\n\nexport type GooglePaySubmitOptions = {\n processorId: string;\n customerInfo: GooglePayCustomerInfo;\n mockScenario?: GooglePayMockScenario;\n};\n\ntype GooglePayResult =\n | { data: { [key: string]: unknown }; errors?: never }\n | { data?: never; errors: PaymentKitErrors };\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\nasync function apiCall<T>(\n url: string,\n options: RequestInit,\n checkoutRequestId?: string,\n): Promise<{ data?: T; error?: string }> {\n // Add x-request-id header if provided\n const headers = new Headers(options.headers);\n if (checkoutRequestId) {\n headers.set(\"x-request-id\", checkoutRequestId);\n }\n\n const response = await fetch(url, { ...options, headers });\n if (!response.ok) {\n let errorMessage = `Request failed (${response.status})`;\n try {\n const errorData = await response.json();\n errorMessage = errorData.detail || errorMessage;\n } catch {\n errorMessage = response.statusText || errorMessage;\n }\n return { error: errorMessage };\n }\n return { data: await response.json() };\n}\n\nfunction validateOptions(options: GooglePaySubmitOptions): PaymentKitErrors | null {\n if (!options?.processorId) {\n return { processor_id: \"Processor ID is required\" };\n }\n // Customer name is optional — Google Pay collects it from the payment sheet\n return null;\n}\n\nfunction getMockScenarioStr(mockScenario?: GooglePayMockScenario): string | undefined {\n return mockScenario && mockScenario !== GooglePayMockScenario.None ? mockScenario : undefined;\n}\n\nasync function callStartEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n options: GooglePaySubmitOptions,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n): Promise<{ data?: GooglePayStartResponse; error?: string }> {\n return apiCall<GooglePayStartResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/start`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n processor_id: options.processorId,\n customer_info: options.customerInfo,\n fraud_metadata: collectFraudMetadata(),\n mock_scenario: mockScenarioStr,\n } as GooglePayStartRequest),\n },\n checkoutRequestId,\n );\n}\n\n// =============================================================================\n// Stripe Flow\n// =============================================================================\n\nfunction initializeStripeAdapter(\n stripePk: string,\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): { adapter?: StripeGooglePayAdapter; error?: string } {\n const adapter = new StripeGooglePayAdapter(mockScenario);\n\n if (!adapter.initialize(stripePk)) {\n return { error: 'Stripe.js not loaded. Add <script src=\"https://js.stripe.com/v3/\"></script> to your page.' };\n }\n\n const prConfig = {\n country: startData.country,\n currency: startData.currency.toLowerCase(),\n total: { label: \"Total\", amount: startData.amount },\n requestPayerName: true,\n requestPayerEmail: true,\n };\n adapter.createPaymentRequest(prConfig);\n return { adapter };\n}\n\nasync function runStripeFlow(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): Promise<{ success: boolean; error?: string; payerEmail?: string }> {\n if (!startData.stripe_pk || !startData.client_secret) {\n return { success: false, error: \"Stripe credentials not provided\" };\n }\n\n // Initialize Stripe adapter\n const { adapter, error: adapterError } = initializeStripeAdapter(startData.stripe_pk, startData, mockScenario);\n if (!adapter) {\n return { success: false, error: adapterError };\n }\n\n // Check availability\n const isAvailable = await adapter.canMakePayment();\n\n if (!isAvailable) {\n return { success: false, error: \"Google Pay not available on this device\" };\n }\n\n // Show payment sheet\n const paymentResult = await adapter.showPaymentSheet();\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { success: false, error: \"Google Pay cancelled by user\" };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { success: false, error: errorMessage };\n }\n\n // Confirm with Stripe SDK\n const confirmResult = await adapter.confirmCardSetup(startData.client_secret, paymentResult.paymentMethodId);\n\n if (!confirmResult.success) {\n paymentResult.complete(\"fail\");\n return { success: false, error: \"error\" in confirmResult ? confirmResult.error : \"Card setup failed\" };\n }\n\n paymentResult.complete(\"success\");\n return { success: true, payerEmail: paymentResult.payerEmail };\n}\n\n// =============================================================================\n// Airwallex Flow\n// =============================================================================\n\nfunction initializeAirwallexAdapter(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): {\n adapter?: AirwallexGooglePayAdapter;\n error?: string;\n} {\n if (!startData.merchant_name || !startData.airwallex_account_id) {\n return { error: \"Airwallex Google Pay credentials not provided\" };\n }\n\n // Convert GooglePayMockScenario to AirwallexGooglePayMockScenario\n let airwallexMockScenario: AirwallexGooglePayMockScenario = AirwallexGooglePayMockScenario.None;\n if (mockScenario === GooglePayMockScenario.Success) {\n airwallexMockScenario = AirwallexGooglePayMockScenario.Success;\n } else if (mockScenario === GooglePayMockScenario.Cancelled) {\n airwallexMockScenario = AirwallexGooglePayMockScenario.Cancelled;\n }\n\n const adapter = new AirwallexGooglePayAdapter(airwallexMockScenario);\n\n const config: AirwallexGooglePayConfig = {\n merchantId: startData.merchant_name,\n gatewayMerchantId: startData.airwallex_account_id,\n amountDisplay: startData.amount_display,\n currency: startData.currency,\n country: startData.country,\n isProduction: startData.is_sandbox === false,\n googleMerchantId: startData.google_merchant_id,\n };\n\n if (!adapter.initialize(config)) {\n return {\n error:\n 'Google Pay API not loaded. Add <script src=\"https://pay.google.com/gp/p/js/pay.js\"></script> to your page.',\n };\n }\n\n return { adapter };\n}\n\nasync function runAirwallexFlow(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): Promise<{ success: boolean; token?: GooglePayEncryptedToken; payerEmail?: string; error?: string }> {\n // Initialize Airwallex adapter\n const { adapter, error: adapterError } = initializeAirwallexAdapter(startData, mockScenario);\n if (!adapter) {\n return { success: false, error: adapterError };\n }\n\n // Check availability\n const isAvailable = await adapter.canMakePayment();\n\n if (!isAvailable) {\n return { success: false, error: \"Google Pay not available on this device\" };\n }\n\n // Show payment sheet\n const paymentResult = await adapter.showPaymentSheet();\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { success: false, error: \"Google Pay cancelled by user\" };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { success: false, error: errorMessage };\n }\n\n // Return the token and payer email for passing to backend\n return { success: true, token: paymentResult.token, payerEmail: paymentResult.payerEmail };\n}\n\n// =============================================================================\n// Confirm & Verify Endpoints\n// =============================================================================\n\n/**\n * Call /confirm endpoint - processes Google Pay token (Airwallex) or records setup (Stripe).\n * For Airwallex, may return next_action if 3DS is required.\n */\nasync function callConfirmEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n googlePayToken?: GooglePayEncryptedToken,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayConfirmResponse> {\n const requestBody: GooglePayConfirmRequest = {\n mock_scenario: mockScenarioStr,\n };\n\n if (googlePayToken) {\n requestBody.google_pay_token = googlePayToken;\n }\n\n if (payerEmail) {\n requestBody.payer_email = payerEmail;\n }\n\n const result = await apiCall<GooglePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/confirm`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(requestBody),\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return {\n charge_status: \"fail\",\n error_message: result.error || \"Failed to confirm payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\n/**\n * Call /verify endpoint - verifies 3DS completion for Airwallex.\n * Called after user completes 3DS challenge. May return another next_action for retry.\n */\nasync function callVerifyEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n checkoutRequestId?: string,\n): Promise<GooglePayConfirmResponse> {\n const result = await apiCall<GooglePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/verify`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return {\n charge_status: \"fail\",\n error_message: result.error || \"Failed to verify payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\n/**\n * Convert GooglePayConfirmResponse to GooglePayResult for return to caller.\n */\nfunction toGooglePayResult(response: GooglePayConfirmResponse, secureToken: string): GooglePayResult {\n if (response.charge_status === \"success\") {\n return {\n data: {\n id: response.transaction_id,\n checkoutAttemptId: response.checkout_attempt_id,\n checkoutSessionId: response.checkout_session_id ?? secureToken,\n state: \"checkout_succeeded\",\n paymentIntentId: response.payment_intent_id,\n customerId: response.customer_id,\n paymentMethodId: response.payment_method_id,\n processorUsed: response.processor_used,\n subscriptionId: response.subscription_id,\n invoiceId: response.invoice_id,\n invoiceNumber: response.invoice_number,\n cardBrand: response.card_brand,\n cardLast4: response.card_last4,\n cardExpMonth: response.card_exp_month,\n cardExpYear: response.card_exp_year,\n errorCode: response.error_code,\n errorMessageForCustomer: response.error_message_for_customer,\n errorMessageForDebug: response.error_message_for_debug,\n nextAction: response.next_action,\n },\n };\n }\n return {\n errors: {\n google_pay:\n response.error_message_for_customer ||\n response.error_message_for_debug ||\n response.error_message ||\n \"Payment failed\",\n },\n };\n}\n\n// =============================================================================\n// Stripe Confirm (Simple - No 3DS Loop)\n// =============================================================================\n\n/**\n * Confirm Stripe Google Pay - simple flow without 3DS loop.\n * Stripe.js handles 3DS internally during confirmCardSetup().\n */\nasync function confirmStripeGooglePay(\n apiBaseUrl: string,\n secureToken: string,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayResult> {\n const response = await callConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n undefined,\n mockScenarioStr,\n checkoutRequestId,\n payerEmail,\n );\n return toGooglePayResult(response, secureToken);\n}\n\n// =============================================================================\n// Airwallex Confirm with 3DS Loop\n// =============================================================================\n\nconst MAX_USER_ACTIONS = 5;\n\n/**\n * Confirm Airwallex Google Pay with 3DS loop support.\n *\n * Flow:\n * 1. Call /confirm with token → may return next_action (3DS)\n * 2. If next_action: handle 3DS, then call /verify\n * 3. Loop if /verify returns another next_action (3DS retry)\n * 4. Return final result\n *\n * This mirrors the card.ts pattern for consistency.\n */\nasync function confirmAirwallexGooglePay(\n apiBaseUrl: string,\n secureToken: string,\n googlePayToken: GooglePayEncryptedToken,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayResult> {\n let userActionCount = 0;\n\n // Step 1: Initial confirm with token\n let response = await callConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n googlePayToken,\n mockScenarioStr,\n checkoutRequestId,\n payerEmail,\n );\n\n // Step 2: Handle 3DS loop (if required)\n while (response.charge_status === \"pending\" && response.next_action && userActionCount < MAX_USER_ACTIONS) {\n userActionCount++;\n\n // Handle 3DS challenge\n const actionResult = await handleNextAction(response.next_action);\n\n // Always call verify endpoint so backend can conclude properly\n // (even if 3DS failed, backend needs to know)\n const verifyResponse = await callVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId);\n\n // Check if another 3DS action is required (retry scenario)\n if (verifyResponse.charge_status === \"pending\" && verifyResponse.next_action) {\n if (!actionResult.success) {\n console.log(\"[GooglePay:Airwallex] 3DS failed but retry available, continuing loop...\");\n }\n response = verifyResponse;\n continue;\n }\n\n // No more actions - check final result\n if (!actionResult.success) {\n // 3DS failed and no retry available\n return {\n errors: {\n google_pay: verifyResponse.error_message || actionResult.error || \"3DS authentication failed\",\n },\n };\n }\n\n // 3DS succeeded - return verify result\n return toGooglePayResult(verifyResponse, secureToken);\n }\n\n // Check for max attempts exceeded\n if (userActionCount >= MAX_USER_ACTIONS) {\n return { errors: { google_pay: \"Too many authentication attempts. Please try again.\" } };\n }\n\n // No 3DS required - return initial confirm result\n return toGooglePayResult(response, secureToken);\n}\n\n// =============================================================================\n// Main Submit Function\n// =============================================================================\n\nconst defSubmitPayment = (states: PaymentKitStates) => {\n const submitPayment: TInternalFuncs[\"submitPayment\"] = async (_fields, options) => {\n const { apiBaseUrl, secureToken, environment } = states;\n const gpayOptions = options as GooglePaySubmitOptions;\n\n // Validate options\n const validationError = validateOptions(gpayOptions);\n if (validationError) {\n return { errors: validationError };\n }\n\n try {\n const mockScenarioStr = getMockScenarioStr(gpayOptions.mockScenario);\n\n // Get or create checkout request ID for correlating all API calls\n const checkoutRequestId = getOrCreateCheckoutRequestId(environment);\n console.log(`[GooglePay] Using checkout_request_id: ${checkoutRequestId}`);\n\n // Step 1: Start Google Pay flow - backend selects processor\n const startResult = await callStartEndpoint(\n apiBaseUrl,\n secureToken,\n gpayOptions,\n mockScenarioStr,\n checkoutRequestId,\n );\n if (startResult.error || !startResult.data) {\n return { errors: { google_pay: startResult.error || \"Failed to start Google Pay\" } };\n }\n\n const startData = startResult.data;\n\n // Step 2 & 3: Run processor-specific flow and confirm\n if (startData.processor === \"stripe\") {\n // Stripe flow: Uses Stripe.js PaymentRequest API (handles 3DS internally)\n const stripeResult = await runStripeFlow(startData, gpayOptions.mockScenario);\n if (!stripeResult.success) {\n return { errors: { google_pay: stripeResult.error } };\n }\n // Confirm with backend (no token needed, Stripe handled it)\n return await confirmStripeGooglePay(\n apiBaseUrl,\n secureToken,\n mockScenarioStr,\n checkoutRequestId,\n stripeResult.payerEmail,\n );\n }\n\n if (startData.processor === \"airwallex\") {\n // Airwallex flow: Uses Google Pay API directly, may need 3DS\n const airwallexResult = await runAirwallexFlow(startData, gpayOptions.mockScenario);\n if (!airwallexResult.success) {\n return { errors: { google_pay: airwallexResult.error } };\n }\n if (!airwallexResult.token) {\n return { errors: { google_pay: \"Google Pay token not received\" } };\n }\n // Confirm with 3DS loop support\n return await confirmAirwallexGooglePay(\n apiBaseUrl,\n secureToken,\n airwallexResult.token,\n mockScenarioStr,\n checkoutRequestId,\n airwallexResult.payerEmail,\n );\n }\n\n return { errors: { google_pay: `Unsupported processor: ${startData.processor}` } };\n } catch (error) {\n return { errors: { google_pay: `Google Pay error: ${error}` } };\n }\n };\n\n return submitPayment;\n};\n\n// =============================================================================\n// Payment Method Definition\n// =============================================================================\n\nconst GooglePayPaymentMethod = definePaymentMethod((paymentKitStates) => {\n return {\n name: \"google_pay\",\n externalFuncs: {},\n internalFuncs: {\n submitPayment: defSubmitPayment(paymentKitStates),\n cleanup: () => {},\n },\n };\n});\n\nexport { GooglePayMockScenario };\n\nexport default GooglePayPaymentMethod;\n"],"mappings":"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"}
1
+ {"version":3,"file":"google-pay.mjs","names":["airwallexMockScenario: AirwallexGooglePayMockScenario","config: AirwallexGooglePayConfig","requestBody: GooglePayConfirmRequest","submitPayment: TInternalFuncs[\"submitPayment\"]","effectiveOptions: GooglePaySubmitOptions","autoPrepareConfig: AutoPrepareConfig | null","onGooglePayReadyCallbacks: ((isReady: boolean) => void)[]","pendingAutoPrepareArgs: { apiBaseUrl: string; secureToken: string; environment: string } | null","pendingPrepareResolvers: (() => void)[]"],"sources":["../../src/payment-methods/google-pay.ts"],"sourcesContent":["import type { PaymentKitErrors, PaymentKitStates, TInternalFuncs } from \"../types\";\nimport { collectFraudMetadata, definePaymentMethod, getOrCreateCheckoutRequestId } from \"../utils\";\nimport {\n AirwallexGooglePayAdapter,\n type AirwallexGooglePayConfig,\n AirwallexGooglePayMockScenario,\n type GooglePayEncryptedToken,\n} from \"./airwallex-google-pay-adapter\";\nimport { handleNextAction } from \"./next-action-handlers\";\nimport { GooglePayMockScenario, StripeGooglePayAdapter } from \"./stripe-google-pay-adapter\";\n\n// Google Pay-specific types\nexport type GooglePayCustomerInfo = {\n first_name: string;\n last_name: string;\n email?: string;\n};\n\nexport type GooglePayStartRequest = {\n processor_id: string;\n customer_info: GooglePayCustomerInfo;\n fraud_metadata: {\n ipAddress?: string;\n browserInfo?: { [key: string]: unknown };\n processorFraudInfo?: { [key: string]: unknown };\n };\n mock_scenario?: string;\n};\n\nexport type GooglePayStartResponse = {\n checkout_attempt_id: string;\n amount: number;\n amount_display: string; // Formatted for Google Pay (e.g., \"100.00\" for USD, \"1000\" for JPY)\n currency: string;\n country: string;\n\n // Processor discriminator\n processor: \"stripe\" | \"airwallex\";\n\n // Environment flag\n is_sandbox?: boolean;\n\n // Stripe-specific fields (when processor=\"stripe\")\n client_secret?: string;\n stripe_pk?: string;\n\n // Airwallex-specific fields (when processor=\"airwallex\")\n merchant_name?: string;\n airwallex_account_id?: string;\n google_merchant_id?: string; // Google-assigned merchant ID for production (BCR2DN...)\n};\n\nexport type GooglePayConfirmRequest = {\n google_pay_token?: GooglePayEncryptedToken; // Required for Airwallex\n payer_email?: string; // Email from payment sheet (Stripe Google Pay)\n mock_scenario?: string;\n};\n\n// Airwallex 3DS next action type (matches backend snake_case response)\nexport type Airwallex3dsNextAction = {\n type: \"airwallex_3ds\";\n url: string;\n method: string;\n payment_intent_id: string;\n};\n\nexport type GooglePayConfirmResponse = {\n charge_status: \"success\" | \"fail\" | \"pending\";\n transaction_id?: string;\n error_code?: string;\n error_message?: string;\n error_message_for_customer?: string;\n error_message_for_debug?: string;\n checkout_attempt_id: string;\n checkout_session_id?: string;\n next_action?: Airwallex3dsNextAction; // Present when charge_status=\"pending\" for 3DS\n payment_intent_id?: string;\n customer_id?: string;\n payment_method_id?: string;\n processor_used?: string;\n subscription_id?: string;\n invoice_id?: string;\n invoice_number?: number;\n card_brand?: string;\n card_last4?: string;\n card_exp_month?: number;\n card_exp_year?: number;\n};\n\nexport type GooglePaySubmitOptions = {\n /** Processor external ID — optional when using auto-prepare (SDK fetches from checkout session) */\n processorId?: string;\n customerInfo: GooglePayCustomerInfo;\n mockScenario?: GooglePayMockScenario;\n};\n\ntype GooglePayResult =\n | { data: { [key: string]: unknown }; errors?: never }\n | { data?: never; errors: PaymentKitErrors };\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\nasync function apiCall<T>(\n url: string,\n options: RequestInit,\n checkoutRequestId?: string,\n): Promise<{ data?: T; error?: string }> {\n // Add x-request-id header if provided\n const headers = new Headers(options.headers);\n if (checkoutRequestId) {\n headers.set(\"x-request-id\", checkoutRequestId);\n }\n\n const response = await fetch(url, { ...options, headers });\n if (!response.ok) {\n let errorMessage = `Request failed (${response.status})`;\n try {\n const errorData = await response.json();\n errorMessage = errorData.detail || errorMessage;\n } catch {\n errorMessage = response.statusText || errorMessage;\n }\n return { error: errorMessage };\n }\n return { data: await response.json() };\n}\n\nfunction validateOptions(\n options: GooglePaySubmitOptions,\n autoPrepareConfig: AutoPrepareConfig | null,\n): PaymentKitErrors | null {\n // processorId is optional when autoPrepareConfig provides it\n if (!options?.processorId && !autoPrepareConfig?.processorId) {\n return { processor_id: \"Processor ID is required\" };\n }\n // Customer name is optional — Google Pay collects it from the payment sheet\n return null;\n}\n\n// =============================================================================\n// Auto-Prepare Types\n// =============================================================================\n\ntype CheckoutSessionConfig = {\n express_checkout_processor_id?: string | null;\n express_checkout_processor_type?: string | null;\n};\n\ntype AutoPrepareConfig = {\n processorId: string;\n processorType?: \"stripe\" | \"airwallex\";\n};\n\n/**\n * Check if Google Pay is available on this device/browser.\n * Uses the Google Pay API's isReadyToPay() method.\n */\nasync function checkGooglePayAvailability(): Promise<boolean> {\n // Check if Google Pay API is loaded\n if (!window.google?.payments?.api?.PaymentsClient) {\n console.log(\"[GooglePay] Google Pay API not loaded\");\n return false;\n }\n\n try {\n // Per Google Pay docs, TEST mode is appropriate for isReadyToPay() availability checks.\n // The actual payment flow uses the production environment configured in submit().\n const client = new window.google.payments.api.PaymentsClient({\n environment: \"TEST\",\n });\n\n const request = {\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: [\n {\n type: \"CARD\" as const,\n parameters: {\n allowedAuthMethods: [\"PAN_ONLY\", \"CRYPTOGRAM_3DS\"] as (\"PAN_ONLY\" | \"CRYPTOGRAM_3DS\")[],\n allowedCardNetworks: [\"VISA\", \"MASTERCARD\", \"AMEX\", \"DISCOVER\", \"JCB\"] as (\n | \"VISA\"\n | \"MASTERCARD\"\n | \"AMEX\"\n | \"DISCOVER\"\n | \"JCB\"\n )[],\n },\n },\n ],\n };\n\n const response = await client.isReadyToPay(request);\n return response.result;\n } catch (error) {\n console.error(\"[GooglePay] availability check error:\", error);\n return false;\n }\n}\n\nfunction getMockScenarioStr(mockScenario?: GooglePayMockScenario): string | undefined {\n return mockScenario && mockScenario !== GooglePayMockScenario.None ? mockScenario : undefined;\n}\n\nasync function callStartEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n options: GooglePaySubmitOptions,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n): Promise<{ data?: GooglePayStartResponse; error?: string }> {\n return apiCall<GooglePayStartResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/start`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n processor_id: options.processorId,\n customer_info: options.customerInfo,\n fraud_metadata: collectFraudMetadata(),\n mock_scenario: mockScenarioStr,\n } as GooglePayStartRequest),\n },\n checkoutRequestId,\n );\n}\n\n// =============================================================================\n// Stripe Flow\n// =============================================================================\n\nfunction initializeStripeAdapter(\n stripePk: string,\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): { adapter?: StripeGooglePayAdapter; error?: string } {\n const adapter = new StripeGooglePayAdapter(mockScenario);\n\n if (!adapter.initialize(stripePk)) {\n return { error: 'Stripe.js not loaded. Add <script src=\"https://js.stripe.com/v3/\"></script> to your page.' };\n }\n\n const prConfig = {\n country: startData.country,\n currency: startData.currency.toLowerCase(),\n total: { label: \"Total\", amount: startData.amount },\n requestPayerName: true,\n requestPayerEmail: true,\n };\n adapter.createPaymentRequest(prConfig);\n return { adapter };\n}\n\nasync function runStripeFlow(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): Promise<{ success: boolean; error?: string; payerEmail?: string }> {\n if (!startData.stripe_pk || !startData.client_secret) {\n return { success: false, error: \"Stripe credentials not provided\" };\n }\n\n // Initialize Stripe adapter\n const { adapter, error: adapterError } = initializeStripeAdapter(startData.stripe_pk, startData, mockScenario);\n if (!adapter) {\n return { success: false, error: adapterError };\n }\n\n // Check availability\n const isAvailable = await adapter.canMakePayment();\n\n if (!isAvailable) {\n return { success: false, error: \"Google Pay not available on this device\" };\n }\n\n // Show payment sheet\n const paymentResult = await adapter.showPaymentSheet();\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { success: false, error: \"Google Pay cancelled by user\" };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { success: false, error: errorMessage };\n }\n\n // Confirm with Stripe SDK\n const confirmResult = await adapter.confirmCardSetup(startData.client_secret, paymentResult.paymentMethodId);\n\n if (!confirmResult.success) {\n paymentResult.complete(\"fail\");\n return { success: false, error: \"error\" in confirmResult ? confirmResult.error : \"Card setup failed\" };\n }\n\n paymentResult.complete(\"success\");\n return { success: true, payerEmail: paymentResult.payerEmail };\n}\n\n// =============================================================================\n// Airwallex Flow\n// =============================================================================\n\nfunction initializeAirwallexAdapter(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): {\n adapter?: AirwallexGooglePayAdapter;\n error?: string;\n} {\n if (!startData.merchant_name || !startData.airwallex_account_id) {\n return { error: \"Airwallex Google Pay credentials not provided\" };\n }\n\n // Convert GooglePayMockScenario to AirwallexGooglePayMockScenario\n let airwallexMockScenario: AirwallexGooglePayMockScenario = AirwallexGooglePayMockScenario.None;\n if (mockScenario === GooglePayMockScenario.Success) {\n airwallexMockScenario = AirwallexGooglePayMockScenario.Success;\n } else if (mockScenario === GooglePayMockScenario.Cancelled) {\n airwallexMockScenario = AirwallexGooglePayMockScenario.Cancelled;\n }\n\n const adapter = new AirwallexGooglePayAdapter(airwallexMockScenario);\n\n const config: AirwallexGooglePayConfig = {\n merchantId: startData.merchant_name,\n gatewayMerchantId: startData.airwallex_account_id,\n amountDisplay: startData.amount_display,\n currency: startData.currency,\n country: startData.country,\n isProduction: startData.is_sandbox === false,\n googleMerchantId: startData.google_merchant_id,\n };\n\n if (!adapter.initialize(config)) {\n return {\n error:\n 'Google Pay API not loaded. Add <script src=\"https://pay.google.com/gp/p/js/pay.js\"></script> to your page.',\n };\n }\n\n return { adapter };\n}\n\nasync function runAirwallexFlow(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): Promise<{ success: boolean; token?: GooglePayEncryptedToken; payerEmail?: string; error?: string }> {\n // Initialize Airwallex adapter\n const { adapter, error: adapterError } = initializeAirwallexAdapter(startData, mockScenario);\n if (!adapter) {\n return { success: false, error: adapterError };\n }\n\n // Check availability\n const isAvailable = await adapter.canMakePayment();\n\n if (!isAvailable) {\n return { success: false, error: \"Google Pay not available on this device\" };\n }\n\n // Show payment sheet\n const paymentResult = await adapter.showPaymentSheet();\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { success: false, error: \"Google Pay cancelled by user\" };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { success: false, error: errorMessage };\n }\n\n // Return the token and payer email for passing to backend\n return { success: true, token: paymentResult.token, payerEmail: paymentResult.payerEmail };\n}\n\n// =============================================================================\n// Confirm & Verify Endpoints\n// =============================================================================\n\n/**\n * Call /confirm endpoint - processes Google Pay token (Airwallex) or records setup (Stripe).\n * For Airwallex, may return next_action if 3DS is required.\n */\nasync function callConfirmEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n googlePayToken?: GooglePayEncryptedToken,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayConfirmResponse> {\n const requestBody: GooglePayConfirmRequest = {\n mock_scenario: mockScenarioStr,\n };\n\n if (googlePayToken) {\n requestBody.google_pay_token = googlePayToken;\n }\n\n if (payerEmail) {\n requestBody.payer_email = payerEmail;\n }\n\n const result = await apiCall<GooglePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/confirm`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(requestBody),\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return {\n charge_status: \"fail\",\n error_message: result.error || \"Failed to confirm payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\n/**\n * Call /verify endpoint - verifies 3DS completion for Airwallex.\n * Called after user completes 3DS challenge. May return another next_action for retry.\n */\nasync function callVerifyEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n checkoutRequestId?: string,\n): Promise<GooglePayConfirmResponse> {\n const result = await apiCall<GooglePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/verify`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return {\n charge_status: \"fail\",\n error_message: result.error || \"Failed to verify payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\n/**\n * Convert GooglePayConfirmResponse to GooglePayResult for return to caller.\n */\nfunction toGooglePayResult(response: GooglePayConfirmResponse, secureToken: string): GooglePayResult {\n if (response.charge_status === \"success\") {\n return {\n data: {\n id: response.transaction_id,\n checkoutAttemptId: response.checkout_attempt_id,\n checkoutSessionId: response.checkout_session_id ?? secureToken,\n state: \"checkout_succeeded\",\n paymentIntentId: response.payment_intent_id,\n customerId: response.customer_id,\n paymentMethodId: response.payment_method_id,\n processorUsed: response.processor_used,\n subscriptionId: response.subscription_id,\n invoiceId: response.invoice_id,\n invoiceNumber: response.invoice_number,\n cardBrand: response.card_brand,\n cardLast4: response.card_last4,\n cardExpMonth: response.card_exp_month,\n cardExpYear: response.card_exp_year,\n errorCode: response.error_code,\n errorMessageForCustomer: response.error_message_for_customer,\n errorMessageForDebug: response.error_message_for_debug,\n nextAction: response.next_action,\n },\n };\n }\n return {\n errors: {\n google_pay:\n response.error_message_for_customer ||\n response.error_message_for_debug ||\n response.error_message ||\n \"Payment failed\",\n },\n };\n}\n\n// =============================================================================\n// Stripe Confirm (Simple - No 3DS Loop)\n// =============================================================================\n\n/**\n * Confirm Stripe Google Pay - simple flow without 3DS loop.\n * Stripe.js handles 3DS internally during confirmCardSetup().\n */\nasync function confirmStripeGooglePay(\n apiBaseUrl: string,\n secureToken: string,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayResult> {\n const response = await callConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n undefined,\n mockScenarioStr,\n checkoutRequestId,\n payerEmail,\n );\n return toGooglePayResult(response, secureToken);\n}\n\n// =============================================================================\n// Airwallex Confirm with 3DS Loop\n// =============================================================================\n\nconst MAX_USER_ACTIONS = 5;\n\n/**\n * Confirm Airwallex Google Pay with 3DS loop support.\n *\n * Flow:\n * 1. Call /confirm with token → may return next_action (3DS)\n * 2. If next_action: handle 3DS, then call /verify\n * 3. Loop if /verify returns another next_action (3DS retry)\n * 4. Return final result\n *\n * This mirrors the card.ts pattern for consistency.\n */\nasync function confirmAirwallexGooglePay(\n apiBaseUrl: string,\n secureToken: string,\n googlePayToken: GooglePayEncryptedToken,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayResult> {\n let userActionCount = 0;\n\n // Step 1: Initial confirm with token\n let response = await callConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n googlePayToken,\n mockScenarioStr,\n checkoutRequestId,\n payerEmail,\n );\n\n // Step 2: Handle 3DS loop (if required)\n while (response.charge_status === \"pending\" && response.next_action && userActionCount < MAX_USER_ACTIONS) {\n userActionCount++;\n\n // Handle 3DS challenge\n const actionResult = await handleNextAction(response.next_action);\n\n // Always call verify endpoint so backend can conclude properly\n // (even if 3DS failed, backend needs to know)\n const verifyResponse = await callVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId);\n\n // Check if another 3DS action is required (retry scenario)\n if (verifyResponse.charge_status === \"pending\" && verifyResponse.next_action) {\n if (!actionResult.success) {\n console.log(\"[GooglePay:Airwallex] 3DS failed but retry available, continuing loop...\");\n }\n response = verifyResponse;\n continue;\n }\n\n // No more actions - check final result\n if (!actionResult.success) {\n // 3DS failed and no retry available\n return {\n errors: {\n google_pay: verifyResponse.error_message || actionResult.error || \"3DS authentication failed\",\n },\n };\n }\n\n // 3DS succeeded - return verify result\n return toGooglePayResult(verifyResponse, secureToken);\n }\n\n // Check for max attempts exceeded\n if (userActionCount >= MAX_USER_ACTIONS) {\n return { errors: { google_pay: \"Too many authentication attempts. Please try again.\" } };\n }\n\n // No 3DS required - return initial confirm result\n return toGooglePayResult(response, secureToken);\n}\n\n// =============================================================================\n// Main Submit Function\n// =============================================================================\n\nconst defSubmitPayment = (states: PaymentKitStates, getAutoPrepareConfig: () => AutoPrepareConfig | null) => {\n const submitPayment: TInternalFuncs[\"submitPayment\"] = async (_fields, options) => {\n const { apiBaseUrl, secureToken, environment } = states;\n const gpayOptions = options as GooglePaySubmitOptions;\n const autoPrepareConfig = getAutoPrepareConfig();\n\n // Validate options\n const validationError = validateOptions(gpayOptions, autoPrepareConfig);\n if (validationError) {\n return { errors: validationError };\n }\n\n // Use autoPrepareConfig as fallback for processorId\n const effectiveOptions: GooglePaySubmitOptions = {\n ...gpayOptions,\n processorId: gpayOptions.processorId || autoPrepareConfig?.processorId || \"\",\n };\n\n try {\n const mockScenarioStr = getMockScenarioStr(gpayOptions.mockScenario);\n\n // Get or create checkout request ID for correlating all API calls\n const checkoutRequestId = getOrCreateCheckoutRequestId(environment);\n console.log(`[GooglePay] Using checkout_request_id: ${checkoutRequestId}`);\n\n // Step 1: Start Google Pay flow - backend selects processor\n const startResult = await callStartEndpoint(\n apiBaseUrl,\n secureToken,\n effectiveOptions,\n mockScenarioStr,\n checkoutRequestId,\n );\n if (startResult.error || !startResult.data) {\n return { errors: { google_pay: startResult.error || \"Failed to start Google Pay\" } };\n }\n\n const startData = startResult.data;\n\n // Step 2 & 3: Run processor-specific flow and confirm\n if (startData.processor === \"stripe\") {\n // Stripe flow: Uses Stripe.js PaymentRequest API (handles 3DS internally)\n const stripeResult = await runStripeFlow(startData, gpayOptions.mockScenario);\n if (!stripeResult.success) {\n return { errors: { google_pay: stripeResult.error } };\n }\n // Confirm with backend (no token needed, Stripe handled it)\n return await confirmStripeGooglePay(\n apiBaseUrl,\n secureToken,\n mockScenarioStr,\n checkoutRequestId,\n stripeResult.payerEmail,\n );\n }\n\n if (startData.processor === \"airwallex\") {\n // Airwallex flow: Uses Google Pay API directly, may need 3DS\n const airwallexResult = await runAirwallexFlow(startData, gpayOptions.mockScenario);\n if (!airwallexResult.success) {\n return { errors: { google_pay: airwallexResult.error } };\n }\n if (!airwallexResult.token) {\n return { errors: { google_pay: \"Google Pay token not received\" } };\n }\n // Confirm with 3DS loop support\n return await confirmAirwallexGooglePay(\n apiBaseUrl,\n secureToken,\n airwallexResult.token,\n mockScenarioStr,\n checkoutRequestId,\n airwallexResult.payerEmail,\n );\n }\n\n return { errors: { google_pay: `Unsupported processor: ${startData.processor}` } };\n } catch (error) {\n return { errors: { google_pay: `Google Pay error: ${error}` } };\n }\n };\n\n return submitPayment;\n};\n\n// =============================================================================\n// Payment Method Definition\n// =============================================================================\n\nconst GooglePayPaymentMethod = definePaymentMethod((paymentKitStates) => {\n const { apiBaseUrl, secureToken, environment } = paymentKitStates;\n\n // Per-instance auto-prepare state — isolated from other GooglePayPaymentMethod instances.\n let autoPrepareConfig: AutoPrepareConfig | null = null;\n let onGooglePayReadyCallbacks: ((isReady: boolean) => void)[] = [];\n let isGooglePayReadyState = false;\n let autoPrepareInProgress = false;\n // Incremented by cleanup() so that in-flight prepares can detect staleness and skip writes.\n let cleanupGeneration = 0;\n // Stores pending retry args when notifyAmountChanged is called while a prepare is in flight.\n let pendingAutoPrepareArgs: { apiBaseUrl: string; secureToken: string; environment: string } | null = null;\n // Resolvers waiting for a queued retry to complete (for correct notifyAmountChanged await).\n let pendingPrepareResolvers: (() => void)[] = [];\n\n function instanceSetGooglePayReady(ready: boolean): void {\n isGooglePayReadyState = ready;\n for (const cb of onGooglePayReadyCallbacks) cb(ready);\n }\n\n function instanceClearPreparedGooglePay(): void {\n instanceSetGooglePayReady(false);\n }\n\n async function instanceAutoPrepare(apBase: string, sToken: string, env: string): Promise<void> {\n if (autoPrepareInProgress) {\n // A prepare is already in flight; queue a retry and return a promise that resolves after it.\n pendingAutoPrepareArgs = { apiBaseUrl: apBase, secureToken: sToken, environment: env };\n return new Promise<void>((resolve) => pendingPrepareResolvers.push(resolve));\n }\n autoPrepareInProgress = true;\n // Capture generation so we can detect if cleanup() is called while we await.\n const capturedGeneration = cleanupGeneration;\n instanceSetGooglePayReady(false);\n\n try {\n const result = await apiCall<CheckoutSessionConfig>(`${apBase}/api/checkout-sessions/token/${sToken}`, {\n method: \"GET\",\n });\n\n if (cleanupGeneration !== capturedGeneration) return;\n\n if (result.error || !result.data) {\n console.warn(\"[GooglePay] Auto-prepare: failed to fetch session config:\", result.error);\n return;\n }\n\n const processorId = result.data.express_checkout_processor_id;\n if (!processorId) {\n console.log(\"[GooglePay] Auto-prepare: no express checkout processor configured\");\n return;\n }\n\n const processorTypeRaw = result.data.express_checkout_processor_type;\n const processorType =\n processorTypeRaw === \"airwallex\" || processorTypeRaw === \"stripe\" ? processorTypeRaw : undefined;\n\n autoPrepareConfig = { processorId, processorType };\n\n const isAvailable = await checkGooglePayAvailability();\n\n if (cleanupGeneration !== capturedGeneration) return;\n\n instanceSetGooglePayReady(isAvailable);\n } catch (err) {\n if (cleanupGeneration === capturedGeneration) {\n console.error(\"[GooglePay] Auto-prepare failed:\", err);\n }\n } finally {\n autoPrepareInProgress = false;\n const stale = cleanupGeneration !== capturedGeneration;\n const pending = pendingAutoPrepareArgs;\n const resolvers = pendingPrepareResolvers.splice(0);\n if (!stale && pending) {\n pendingAutoPrepareArgs = null;\n // Run the retry and resolve all callers that were waiting for it.\n instanceAutoPrepare(pending.apiBaseUrl, pending.secureToken, pending.environment).then(() => {\n for (const r of resolvers) r();\n });\n } else {\n pendingAutoPrepareArgs = null;\n for (const r of resolvers) r();\n }\n }\n }\n\n // Start auto-prepare immediately so the button is ready before first user interaction.\n instanceAutoPrepare(apiBaseUrl, secureToken, environment).catch((err) =>\n console.error(\"[GooglePay] Unhandled init error:\", err),\n );\n\n return {\n name: \"google_pay\",\n externalFuncs: {\n /**\n * Register a callback to be notified when Google Pay becomes ready (or stops being ready).\n * Fires immediately with the current state, then on every state change.\n * Multiple registrations are all notified — none are silently overwritten.\n *\n * @example\n * paymentKit.google_pay.onGooglePayReady((isReady) => {\n * googlePayButton.disabled = !isReady;\n * });\n */\n onGooglePayReady: (callback: (isReady: boolean) => void): void => {\n onGooglePayReadyCallbacks.push(callback);\n // Fire immediately with current state so caller doesn't miss a completed prepare.\n callback(isGooglePayReadyState);\n },\n\n /**\n * Notify the SDK that the payment amount has changed (e.g. coupon applied).\n * The SDK will disable Google Pay, re-prepare with the new amount, then re-enable.\n * The returned promise resolves when re-prepare is fully complete.\n *\n * @example\n * await paymentKit.google_pay.notifyAmountChanged();\n */\n notifyAmountChanged: (): Promise<void> => {\n instanceClearPreparedGooglePay();\n autoPrepareConfig = null;\n return instanceAutoPrepare(apiBaseUrl, secureToken, environment);\n },\n },\n internalFuncs: {\n submitPayment: defSubmitPayment(paymentKitStates, () => autoPrepareConfig),\n cleanup: () => {\n cleanupGeneration++;\n onGooglePayReadyCallbacks = [];\n isGooglePayReadyState = false;\n autoPrepareConfig = null;\n pendingAutoPrepareArgs = null;\n pendingPrepareResolvers = [];\n autoPrepareInProgress = false;\n },\n },\n };\n});\n\nexport { GooglePayMockScenario };\n\nexport default GooglePayPaymentMethod;\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import { r as PaymentMethod } from "../types-B3mjYfOm.mjs";
1
+ import { i as PaymentMethod } from "../types-Cjcc3xak.mjs";
2
2
  import "../connect-card-CZhzK_Tp.mjs";
3
3
  import "../connect-tunnel-x-BKtMfoGh.mjs";
4
- import { n as BnplCustomerInfo, s as BnplSubmitOptions, t as BnplCheckoutResponse } from "../bnpl-shared-BQwCBD45.mjs";
4
+ import { n as BnplCustomerInfo, s as BnplSubmitOptions, t as BnplCheckoutResponse } from "../bnpl-shared-D-Kd58Qz.mjs";
5
5
 
6
6
  //#region src/payment-methods/klarna.d.ts
7
7
  type KlarnaCustomerInfo = BnplCustomerInfo;
@@ -1,5 +1,5 @@
1
- import "../utils-Dc6zwOe1.mjs";
2
- import { t as createBnplPaymentMethod } from "../bnpl-shared-DGs1YzS9.mjs";
1
+ import "../utils-DIqrx4XF.mjs";
2
+ import { t as createBnplPaymentMethod } from "../bnpl-shared-CL900HFN.mjs";
3
3
 
4
4
  //#region src/payment-methods/klarna.ts
5
5
  const KlarnaPaymentMethod = createBnplPaymentMethod({
@@ -1,3 +1,3 @@
1
- import { t as handleNextAction } from "../next-action-handlers-CLOt1wzO.mjs";
1
+ import { t as handleNextAction } from "../next-action-handlers-BZ5gynXe.mjs";
2
2
 
3
3
  export { handleNextAction };
@@ -1,4 +1,4 @@
1
- import { r as PaymentMethod } from "../types-B3mjYfOm.mjs";
1
+ import { i as PaymentMethod } from "../types-Cjcc3xak.mjs";
2
2
  import "../connect-card-CZhzK_Tp.mjs";
3
3
  import "../connect-tunnel-x-BKtMfoGh.mjs";
4
4
 
@@ -1,4 +1,4 @@
1
- import { i as definePaymentMethod, n as collectFraudMetadata, o as getOrCreateCheckoutRequestId } from "../utils-Dc6zwOe1.mjs";
1
+ import { i as definePaymentMethod, n as collectFraudMetadata, o as getOrCreateCheckoutRequestId } from "../utils-DIqrx4XF.mjs";
2
2
 
3
3
  //#region src/payment-methods/paypal.ts
4
4
  const defSubmitPayment = (states) => {
@@ -64,14 +64,11 @@ declare class CheckoutTimingTracker {
64
64
  }
65
65
  //#endregion
66
66
  //#region src/types.d.ts
67
-
67
+ type PaymentKitEnvironment = "local" | "tunnel" | "sandbox" | "staging" | "production";
68
68
  type FormFieldNames = "customer_name" | "customer_email" | "customer_country" | "customer_zip_code" | "customer_business_name" | "customer_address_line1" | "customer_address_line2" | "customer_city" | "customer_state" | "customer_tax_ids" | "shipping_address_line1" | "shipping_address_line2" | "shipping_city" | "shipping_state" | "shipping_zip_code" | "shipping_country";
69
69
  type FormErrorCodes = "required" | "invalid";
70
- type CardSubmitOptions = {
71
- skipCustomerValidation?: boolean;
72
- };
73
70
  type TInternalFuncs = {
74
- submitPayment: (fields: PaymentKitFields, options?: CardSubmitOptions) => Promise<{
71
+ submitPayment: (fields: Partial<PaymentKitFields>, options?: unknown) => Promise<{
75
72
  data: {
76
73
  [key: string]: unknown;
77
74
  };
@@ -83,7 +80,7 @@ type TInternalFuncs = {
83
80
  cleanup?: () => void;
84
81
  };
85
82
  type PaymentKit = <T extends readonly PaymentMethod<unknown>[]>(options: {
86
- environment: string;
83
+ environment?: PaymentKitEnvironment;
87
84
  secureToken: string;
88
85
  paymentMethods: T;
89
86
  /** Card tokenization mode from checkout session */
@@ -111,7 +108,7 @@ type PaymentKitStates = {
111
108
  baseUrl: string;
112
109
  apiBaseUrl: string;
113
110
  secureToken: string;
114
- environment: string;
111
+ environment: PaymentKitEnvironment;
115
112
  tunnelXConnection: TunnelXIFrameConnection;
116
113
  timingTracker: CheckoutTimingTracker;
117
114
  /** Checkout request ID for correlating all API calls and analytics events */
@@ -146,5 +143,5 @@ type PaymentMethod<TExternalFuncs = unknown, TName = string> = (paymentKitStates
146
143
  };
147
144
  type ExternalFuncsMapByPm<T extends readonly PaymentMethod<unknown>[]> = { [K in T[number] as ReturnType<K>["name"]]: ReturnType<K>["externalFuncs"] };
148
145
  //#endregion
149
- export { PaymentKitFields as n, PaymentMethod as r, PaymentKit as t };
150
- //# sourceMappingURL=types-B3mjYfOm.d.mts.map
146
+ export { PaymentMethod as i, PaymentKitEnvironment as n, PaymentKitFields as r, PaymentKit as t };
147
+ //# sourceMappingURL=types-Cjcc3xak.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-Cjcc3xak.d.mts","names":[],"sources":["../src/analytics/checkout-timing.ts","../src/types.ts"],"sourcesContent":[],"mappings":"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"}
@@ -9,10 +9,10 @@ import * as v from "valibot";
9
9
  const ENV_TO_SLUG = {
10
10
  local: "dev",
11
11
  tunnel: "dev",
12
- sandbox: "stg",
12
+ sandbox: "prod",
13
+ staging: "stg",
13
14
  production: "prod"
14
15
  };
15
- const WINDOW_KEY = "__paymentKitRequestId__";
16
16
  /**
17
17
  * Generates a checkout request ID for correlating all API calls within a checkout session.
18
18
  *
@@ -24,7 +24,7 @@ const WINDOW_KEY = "__paymentKitRequestId__";
24
24
  * Example: pk_stg_a1b2c3d4e5f6
25
25
  */
26
26
  function generateCheckoutRequestId(environment) {
27
- return `pk_${ENV_TO_SLUG[environment] || "dev"}_${nanoid(12)}`;
27
+ return `pk_${ENV_TO_SLUG[environment] ?? "dev"}_${nanoid(12)}`;
28
28
  }
29
29
  /**
30
30
  * Gets or creates a checkout request ID, storing it in window for idempotency.
@@ -36,9 +36,9 @@ function generateCheckoutRequestId(environment) {
36
36
  * The ID is generated once on first call and reused thereafter.
37
37
  */
38
38
  function getOrCreateCheckoutRequestId(environment) {
39
- if (typeof window !== "undefined" && window[WINDOW_KEY]) return window[WINDOW_KEY];
39
+ if (typeof window !== "undefined" && window.__paymentKitRequestId__) return window.__paymentKitRequestId__;
40
40
  const requestId = generateCheckoutRequestId(environment);
41
- if (typeof window !== "undefined") window[WINDOW_KEY] = requestId;
41
+ if (typeof window !== "undefined") window.__paymentKitRequestId__ = requestId;
42
42
  return requestId;
43
43
  }
44
44
  /**
@@ -66,7 +66,10 @@ const validateFormFields = async (fields, options = {}) => {
66
66
  return errors;
67
67
  }, {})
68
68
  };
69
- return { isSuccess: true };
69
+ return {
70
+ isSuccess: true,
71
+ errors: {}
72
+ };
70
73
  };
71
74
 
72
75
  //#endregion
@@ -108,4 +111,4 @@ function collectFraudMetadata() {
108
111
 
109
112
  //#endregion
110
113
  export { validateFormFields as a, definePaymentMethod as i, collectFraudMetadata as n, getOrCreateCheckoutRequestId as o, createCheckoutIFrame as r, withRequestId as s, $ as t };
111
- //# sourceMappingURL=utils-Dc6zwOe1.mjs.map
114
+ //# sourceMappingURL=utils-DIqrx4XF.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils-DIqrx4XF.mjs","names":["ENV_TO_SLUG: Record<PaymentKitEnvironment, string>"],"sources":["../src/utils/checkout-request-id.ts","../src/utils/validate-form-fields.ts","../src/utils/index.ts"],"sourcesContent":["import { nanoid } from \"nanoid\";\nimport type { PaymentKitEnvironment } from \"../types\";\n\ndeclare global {\n interface Window {\n __paymentKitRequestId__?: string;\n }\n}\n\n/**\n * Maps PaymentKit environment to request ID env slug.\n * This must match the backend's env slug format.\n */\nconst ENV_TO_SLUG: Record<PaymentKitEnvironment, string> = {\n local: \"dev\",\n tunnel: \"dev\",\n sandbox: \"prod\",\n staging: \"stg\",\n production: \"prod\",\n};\n\n/**\n * Generates a checkout request ID for correlating all API calls within a checkout session.\n *\n * Format: pk_{env}_{nanoid(12)}\n * - pk = PaymentKit.js (client-generated)\n * - env = dev, stg, or prod\n * - nanoid(12) = 12 character random string\n *\n * Example: pk_stg_a1b2c3d4e5f6\n */\nexport function generateCheckoutRequestId(environment: PaymentKitEnvironment): string {\n const envSlug = ENV_TO_SLUG[environment] ?? \"dev\";\n const randomPart = nanoid(12);\n return `pk_${envSlug}_${randomPart}`;\n}\n\n/**\n * Gets or creates a checkout request ID, storing it in window for idempotency.\n *\n * This ensures the same request ID is used across:\n * - Multiple PaymentKit instantiations on the same page\n * - All analytics events and API calls within a checkout session\n *\n * The ID is generated once on first call and reused thereafter.\n */\nexport function getOrCreateCheckoutRequestId(environment: PaymentKitEnvironment): string {\n if (typeof window !== \"undefined\" && window.__paymentKitRequestId__) {\n return window.__paymentKitRequestId__;\n }\n\n const requestId = generateCheckoutRequestId(environment);\n\n if (typeof window !== \"undefined\") {\n window.__paymentKitRequestId__ = requestId;\n }\n\n return requestId;\n}\n\n/**\n * Creates RequestOptions with the x-request-id header set.\n */\nexport function withRequestId(checkoutRequestId: string) {\n return {\n headers: {\n \"x-request-id\": checkoutRequestId,\n },\n };\n}\n","import * as v from \"valibot\";\nimport type { FormErrorCodes, PaymentKitErrors, PaymentKitFields } from \"../types\";\n\ntype Options = {\n optionalZipCode?: boolean;\n};\n\nexport const validateFormFields = async (fields: PaymentKitFields, options: Options = {}) => {\n const schema = v.object({\n customer_name: v.pipe(\n v.string(\"required\"),\n v.nonEmpty(\"required\"),\n v.minLength(4, \"invalid\"),\n v.maxLength(40, \"invalid\"),\n ),\n customer_email: v.pipe(v.string(\"required\"), v.nonEmpty(\"required\"), v.email(\"invalid\")),\n customer_country: v.pipe(v.string(\"required\"), v.nonEmpty(\"required\")),\n customer_zip_code: options.optionalZipCode\n ? v.pipe(v.string(\"required\"))\n : v.pipe(v.string(\"required\"), v.nonEmpty(\"required\")),\n });\n\n const result = v.safeParse(schema, fields);\n\n if (result.issues) {\n const errors = result.issues.reduce((errors, issue) => {\n const field = v.getDotPath(issue) as keyof PaymentKitErrors;\n\n errors[field] = issue.kind === \"schema\" ? \"required\" : (issue.message as FormErrorCodes);\n return errors;\n }, {} as PaymentKitErrors);\n return { isSuccess: false, errors };\n }\n\n return { isSuccess: true, errors: {} as PaymentKitErrors };\n};\n","import type { PaymentMethod } from \"../types\";\n\nexport { generateCheckoutRequestId, getOrCreateCheckoutRequestId, withRequestId } from \"./checkout-request-id\";\nexport { validateFormFields } from \"./validate-form-fields\";\n\nexport const $ = (selector: string) => {\n const ele = document.querySelector(selector);\n if (!ele) {\n throw new Error(`Cannot find element with selector: ${selector}`);\n }\n return ele;\n};\n\nexport const definePaymentMethod = <TExternalFuncs, TName extends string>(\n paymentMethod: PaymentMethod<TExternalFuncs, TName>,\n) => paymentMethod;\n\nexport const createCheckoutIFrame = (type: string, baseUrl: string, params?: Record<string, string>) => {\n const iframe = document.createElement(\"iframe\");\n\n const searchParams = new URLSearchParams(params);\n const searchParamsStr = searchParams.toString();\n\n iframe.src = `${baseUrl}/embeds/v1/${type}${searchParamsStr ? `?${searchParamsStr}` : \"\"}`;\n\n Object.assign(iframe.style, { width: \"100%\", height: \"100%\", border: \"none\" });\n\n return iframe;\n};\n\n/**\n * Collects browser and client information for fraud detection.\n */\nexport function collectFraudMetadata() {\n return {\n ipAddress: undefined, // IP address should be collected server-side\n browserInfo: {\n userAgent: navigator.userAgent,\n language: navigator.language,\n screenHeight: window.screen.height,\n screenWidth: window.screen.width,\n colorDepth: window.screen.colorDepth,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n },\n processorFraudInfo: undefined,\n };\n}\n\ntype AddressInput = {\n line1?: string;\n line2?: string;\n city?: string;\n state?: string;\n zip_code?: string;\n country?: string;\n};\n\ntype AddressOutput = {\n line1?: string;\n line2?: string;\n city?: string;\n state?: string;\n zipCode?: string;\n country?: string;\n};\n\n/**\n * Maps address fields from snake_case to camelCase format.\n */\nexport function mapAddress(address?: AddressInput): AddressOutput | undefined {\n if (!address) return undefined;\n\n return {\n line1: address.line1,\n line2: address.line2,\n city: address.city,\n state: address.state,\n zipCode: address.zip_code,\n country: address.country,\n };\n}\n"],"mappings":";;;;;;;;AAaA,MAAMA,cAAqD;CACzD,OAAO;CACP,QAAQ;CACR,SAAS;CACT,SAAS;CACT,YAAY;CACb;;;;;;;;;;;AAYD,SAAgB,0BAA0B,aAA4C;AAGpF,QAAO,MAFS,YAAY,gBAAgB,MAEvB,GADF,OAAO,GAAG;;;;;;;;;;;AAa/B,SAAgB,6BAA6B,aAA4C;AACvF,KAAI,OAAO,WAAW,eAAe,OAAO,wBAC1C,QAAO,OAAO;CAGhB,MAAM,YAAY,0BAA0B,YAAY;AAExD,KAAI,OAAO,WAAW,YACpB,QAAO,0BAA0B;AAGnC,QAAO;;;;;AAMT,SAAgB,cAAc,mBAA2B;AACvD,QAAO,EACL,SAAS,EACP,gBAAgB,mBACjB,EACF;;;;;AC7DH,MAAa,qBAAqB,OAAO,QAA0B,UAAmB,EAAE,KAAK;CAC3F,MAAM,SAAS,EAAE,OAAO;EACtB,eAAe,EAAE,KACf,EAAE,OAAO,WAAW,EACpB,EAAE,SAAS,WAAW,EACtB,EAAE,UAAU,GAAG,UAAU,EACzB,EAAE,UAAU,IAAI,UAAU,CAC3B;EACD,gBAAgB,EAAE,KAAK,EAAE,OAAO,WAAW,EAAE,EAAE,SAAS,WAAW,EAAE,EAAE,MAAM,UAAU,CAAC;EACxF,kBAAkB,EAAE,KAAK,EAAE,OAAO,WAAW,EAAE,EAAE,SAAS,WAAW,CAAC;EACtE,mBAAmB,QAAQ,kBACvB,EAAE,KAAK,EAAE,OAAO,WAAW,CAAC,GAC5B,EAAE,KAAK,EAAE,OAAO,WAAW,EAAE,EAAE,SAAS,WAAW,CAAC;EACzD,CAAC;CAEF,MAAM,SAAS,EAAE,UAAU,QAAQ,OAAO;AAE1C,KAAI,OAAO,OAOT,QAAO;EAAE,WAAW;EAAO,QANZ,OAAO,OAAO,QAAQ,QAAQ,UAAU;GACrD,MAAM,QAAQ,EAAE,WAAW,MAAM;AAEjC,UAAO,SAAS,MAAM,SAAS,WAAW,aAAc,MAAM;AAC9D,UAAO;KACN,EAAE,CAAqB;EACS;AAGrC,QAAO;EAAE,WAAW;EAAM,QAAQ,EAAE;EAAsB;;;;;AC7B5D,MAAa,KAAK,aAAqB;CACrC,MAAM,MAAM,SAAS,cAAc,SAAS;AAC5C,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,sCAAsC,WAAW;AAEnE,QAAO;;AAGT,MAAa,uBACX,kBACG;AAEL,MAAa,wBAAwB,MAAc,SAAiB,WAAoC;CACtG,MAAM,SAAS,SAAS,cAAc,SAAS;CAG/C,MAAM,kBADe,IAAI,gBAAgB,OAAO,CACX,UAAU;AAE/C,QAAO,MAAM,GAAG,QAAQ,aAAa,OAAO,kBAAkB,IAAI,oBAAoB;AAEtF,QAAO,OAAO,OAAO,OAAO;EAAE,OAAO;EAAQ,QAAQ;EAAQ,QAAQ;EAAQ,CAAC;AAE9E,QAAO;;;;;AAMT,SAAgB,uBAAuB;AACrC,QAAO;EACL,WAAW;EACX,aAAa;GACX,WAAW,UAAU;GACrB,UAAU,UAAU;GACpB,cAAc,OAAO,OAAO;GAC5B,aAAa,OAAO,OAAO;GAC3B,YAAY,OAAO,OAAO;GAC1B,UAAU,KAAK,gBAAgB,CAAC,iBAAiB,CAAC;GACnD;EACD,oBAAoB;EACrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payment-kit-js/vanilla",
3
- "version": "0.5.17",
3
+ "version": "0.5.18",
4
4
  "main": "./dist/index.mjs",
5
5
  "types": "./dist/index.d.mts",
6
6
  "module": "./dist/index.mjs",
@@ -52,5 +52,5 @@
52
52
  "tsdown": "^0.15.10",
53
53
  "typescript": "^5.9.3"
54
54
  },
55
- "stableVersion": "0.5.17"
55
+ "stableVersion": "0.5.18"
56
56
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"next-action-handlers-CLOt1wzO.mjs","names":[],"sources":["../src/utils/3ds-iframe-modal.ts","../src/payment-methods/next-action-handlers.ts"],"sourcesContent":["/**\n * 3DS iframe modal for displaying authentication pages.\n *\n * This module provides an iframe modal used by payment processors\n * that need to display a 3DS authentication page.\n */\n\ntype IframeModalResult = { success: true; data: Record<string, unknown> } | { success: false; error: string };\n\ntype ThreeDSCompleteMessage = {\n type: \"3ds_complete\";\n processor: string | null;\n isSuccess: boolean;\n error?: string;\n};\n\ntype IframeModalMessageHandler = (\n event: MessageEvent<ThreeDSCompleteMessage>,\n) => { handled: true; result: IframeModalResult } | { handled: false };\n\ninterface IframeModalOptions {\n /** URL to load in the iframe */\n url: string;\n /** Size of the iframe in pixels */\n size: { width: number; height: number };\n /** Border radius for the iframe in pixels (default: 16) */\n radius?: number;\n /** Handler to process postMessage events from the iframe */\n onMessage: IframeModalMessageHandler;\n}\n\n/**\n * Shows an iframe modal and waits for a result via postMessage.\n *\n * Features:\n * - Close/cancel button positioned outside the iframe\n * - Responsive design (works on mobile)\n * - Keyboard accessibility (Escape to close, focus trap)\n * - Fade-in/fade-out animations\n * - Iframe load error handling\n *\n * @param options - Modal configuration options\n * @returns Promise that resolves with success/failure result\n *\n * @example\n * ```ts\n * const result = await show3DSIframeModal({\n * url: \"https://bank.com/3ds-auth\",\n * size: { width: 605, height: 500 },\n * radius: 6,\n * onMessage: (event) => {\n * if (event.data?.type === \"auth_complete\") {\n * return {\n * handled: true,\n * result: event.data.succeeded\n * ? { success: true, data: { id: event.data.id } }\n * : { success: false, error: event.data.error }\n * };\n * }\n * return { handled: false };\n * },\n * });\n * ```\n */\n\nexport default function show3DSIframeModal(options: IframeModalOptions): Promise<IframeModalResult> {\n const { url, size, radius = 6, onMessage } = options;\n\n return new Promise((resolve) => {\n let resolved = false;\n\n // Create modal overlay with fade-in animation\n const overlay = document.createElement(\"div\");\n overlay.id = \"pk-iframe-modal-overlay\";\n overlay.setAttribute(\"role\", \"dialog\");\n overlay.setAttribute(\"aria-modal\", \"true\");\n overlay.setAttribute(\"aria-label\", \"3D Secure Verification\");\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n transition: background 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n `;\n\n // Create container for iframe and close button\n const container = document.createElement(\"div\");\n container.style.cssText = `\n position: relative;\n width: ${size.width}px;\n height: ${size.height}px;\n max-width: calc(100vw - 32px);\n max-height: calc(100vh - 64px);\n overflow: visible;\n opacity: 0;\n transform: scale(0.95) translateY(10px);\n transition: opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n `;\n\n // Create close button (positioned outside top-right of iframe)\n const closeButton = document.createElement(\"button\");\n closeButton.id = \"pk-iframe-modal-close\";\n closeButton.setAttribute(\"aria-label\", \"Cancel verification\");\n closeButton.setAttribute(\"type\", \"button\");\n closeButton.style.cssText = `\n position: absolute;\n top: -40px;\n right: 0;\n width: 32px;\n height: 32px;\n border: none;\n background: white;\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n transition: background 0.15s ease;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n `;\n closeButton.innerHTML = `\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1 1L13 13M1 13L13 1\" stroke=\"#666\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n `;\n closeButton.onmouseenter = (): void => {\n closeButton.style.background = \"#f5f5f5\";\n };\n closeButton.onmouseleave = (): void => {\n closeButton.style.background = \"white\";\n };\n\n // Create iframe (hidden initially until loaded)\n const iframe = document.createElement(\"iframe\");\n iframe.src = url;\n iframe.setAttribute(\"title\", \"3D Secure Verification\");\n iframe.style.cssText = `\n width: 100%;\n height: 100%;\n border: none;\n opacity: 0;\n border-radius: ${radius}px;\n background: white;\n transition: opacity 0.2s ease;\n position: relative;\n z-index: 1;\n `;\n\n // Handle iframe load success\n iframe.onload = (): void => {\n iframe.style.opacity = \"1\";\n };\n\n // Handle iframe load error\n iframe.onerror = (): void => {\n if (!resolved) {\n console.error(\"[IframeModal] Failed to load iframe\");\n cleanupWithAnimation();\n resolve({ success: false, error: \"Failed to load verification page. Please try again.\" });\n }\n };\n\n container.appendChild(closeButton);\n container.appendChild(iframe);\n overlay.appendChild(container);\n document.body.appendChild(overlay);\n\n // Trigger fade-in animation\n requestAnimationFrame(() => {\n overlay.style.background = \"rgba(0, 0, 0, 0.5)\";\n container.style.opacity = \"1\";\n container.style.transform = \"scale(1) translateY(0)\";\n });\n\n // Cleanup with fade-out animation\n const cleanupWithAnimation = (): void => {\n if (resolved) return;\n resolved = true;\n\n window.removeEventListener(\"message\", handleMessage);\n window.removeEventListener(\"keydown\", handleKeydown);\n\n // Use requestAnimationFrame to ensure transition is applied\n requestAnimationFrame(() => {\n overlay.style.background = \"rgba(0, 0, 0, 0)\";\n container.style.opacity = \"0\";\n container.style.transform = \"scale(0.95) translateY(10px)\";\n\n setTimeout(() => {\n if (overlay.parentNode) {\n overlay.parentNode.removeChild(overlay);\n }\n }, 250);\n });\n };\n\n // Handle close button click\n const handleCancel = (): void => {\n if (!resolved) {\n console.log(\"[IframeModal] User cancelled\");\n cleanupWithAnimation();\n resolve({ success: false, error: \"Verification cancelled\" });\n }\n };\n\n closeButton.onclick = handleCancel;\n\n // Handle Escape key\n const handleKeydown = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n handleCancel();\n }\n // Trap focus within modal (Tab key cycles through close button and iframe)\n if (event.key === \"Tab\") {\n event.preventDefault();\n if (document.activeElement === closeButton) {\n iframe.focus();\n } else {\n closeButton.focus();\n }\n }\n };\n\n window.addEventListener(\"keydown\", handleKeydown);\n\n // Set initial focus to close button for accessibility\n closeButton.focus();\n\n const handleMessage = (event: MessageEvent): void => {\n const messageResult = onMessage(event);\n if (messageResult.handled) {\n cleanupWithAnimation();\n resolve(messageResult.result);\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n });\n}\n","/**\n * Next action handlers for processor-specific user actions (e.g., 3DS authentication).\n *\n * This module abstracts processor-specific logic away from the generic card payment flow.\n * Each handler implements the logic needed for a specific next action type.\n */\n\nimport type { PublicCardCheckoutResponse } from \"@pkg/sdk/models\";\nimport type { Stripe } from \"@stripe/stripe-js\";\nimport show3DSIframeModal from \"../utils/3ds-iframe-modal\";\n\n// Helper to wait for a condition\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n// Check if Stripe.js is loaded via script tag\nconst isStripeJsPresent = (): boolean => \"Stripe\" in window;\n\n/**\n * Get the Stripe instance from the global window object.\n * Expects Stripe.js to be loaded via HTML script tag.\n * Polls for up to 5 seconds waiting for Stripe to be available.\n */\nconst getLoadedStripe = async (publishableKey: string): Promise<Stripe> => {\n // Poll for Stripe.js to be loaded (up to 5 seconds)\n for (let i = 0; i < 10; i++) {\n if (isStripeJsPresent()) {\n break;\n }\n await sleep(500);\n }\n\n if (!isStripeJsPresent()) {\n throw new Error(\n \"Stripe.js not loaded. Add this script tag to your HTML <head>:\\n\" +\n '<script src=\"https://js.stripe.com/v3/\"></script>',\n );\n }\n\n // @ts-expect-error Stripe is loaded globally via script tag\n const stripe: Stripe = new window.Stripe(publishableKey);\n return stripe;\n};\n\n/**\n * Result of handling a next action.\n */\nexport type NextActionResult = { success: true } | { success: false; error: string };\n\n/**\n * Handle Stripe 3DS authentication.\n */\nconst handleStripe3ds = async (\n nextAction: Extract<PublicCardCheckoutResponse[\"nextAction\"], { type: \"stripe_3ds\" }>,\n): Promise<NextActionResult> => {\n const { clientSecret, stripePk } = nextAction;\n\n const stripe = await getLoadedStripe(stripePk);\n\n // Show 3DS modal\n const { error: stripeError } = await stripe.confirmCardPayment(clientSecret);\n\n if (stripeError) {\n console.error(\"[3DS:Stripe] Authentication failed:\", stripeError.message);\n return { success: false, error: stripeError.message || \"3DS authentication failed\" };\n }\n\n return { success: true };\n};\n\n/**\n * Handle Airwallex 3DS authentication via iframe.\n *\n * Renders an iframe with the 3DS authentication URL. The iframe will redirect\n * to the 3DS callback page which sends a postMessage back to complete the flow.\n */\nconst handleAirwallex3ds = async (\n nextAction: Extract<PublicCardCheckoutResponse[\"nextAction\"], { type: \"airwallex_3ds\" }>,\n): Promise<NextActionResult> => {\n return show3DSIframeModal({\n url: nextAction.url,\n size: { width: 605, height: 550 },\n onMessage: (event) => {\n if (event.data.type !== \"3ds_complete\") {\n return { handled: false };\n }\n\n const { isSuccess, error } = event.data;\n\n if (isSuccess) {\n return { handled: true, result: { success: true, data: {} } };\n } else {\n console.error(\"[3DS:Airwallex] Authentication failed:\", error);\n return {\n handled: true,\n result: { success: false, error: error || \"3DS authentication failed\" },\n };\n }\n },\n });\n};\n\n/**\n * Handle a next action based on its type.\n * Routes to the appropriate processor-specific handler.\n *\n * @param nextAction - The next action from the checkout response\n * @returns Result indicating success or failure with error message\n */\nexport const handleNextAction = async (\n nextAction: NonNullable<PublicCardCheckoutResponse[\"nextAction\"]>,\n): Promise<NextActionResult> => {\n switch (nextAction.type) {\n case \"stripe_3ds\":\n return handleStripe3ds(nextAction);\n case \"airwallex_3ds\":\n return handleAirwallex3ds(nextAction);\n default:\n // TypeScript will catch if we miss a case when new action types are added\n return { success: false, error: `Unknown next action type: ${(nextAction as { type: string }).type}` };\n }\n};\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-B3mjYfOm.d.mts","names":[],"sources":["../src/analytics/checkout-timing.ts","../src/types.ts"],"sourcesContent":[],"mappings":"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"}