@paypal/checkout-components 5.0.409 → 5.0.411

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.
@@ -0,0 +1,797 @@
1
+ /* @flow */
2
+ /** @jsx node */
3
+ /* eslint max-lines: 0 */
4
+
5
+ import {
6
+ getLogger,
7
+ getLocale,
8
+ getClientID,
9
+ getEnv,
10
+ getMerchantID,
11
+ getPayPalDomainRegex,
12
+ getSDKMeta,
13
+ getCSPNonce,
14
+ getPayPalDomain,
15
+ getVersion,
16
+ getCurrency,
17
+ getUserIDToken,
18
+ getAmount,
19
+ getAPIStageHost,
20
+ getBuyerCountry,
21
+ getClientAccessToken,
22
+ getClientMetadataID,
23
+ getCommit,
24
+ getCorrelationID,
25
+ getCustomerId,
26
+ getDebug,
27
+ getDisableSetCookie,
28
+ getExperimentation,
29
+ getIntent,
30
+ getJsSdkLibrary,
31
+ getMerchantRequestedPopupsDisabled,
32
+ getPartnerAttributionID,
33
+ getPlatform,
34
+ getSDKInitTime,
35
+ getSDKIntegrationSource,
36
+ getSDKToken,
37
+ getStageHost,
38
+ getStorageID,
39
+ getUserExperienceFlow,
40
+ getVault,
41
+ getSDKAttribute,
42
+ } from "@paypal/sdk-client/src";
43
+ import { getRefinedFundingEligibility } from "@paypal/funding-components/src";
44
+ import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
45
+ import { ENV, FPTI_KEY, SDK_SETTINGS } from "@paypal/sdk-constants/src";
46
+ import { create, EVENT, type ZoidComponent } from "@krakenjs/zoid/src";
47
+ import {
48
+ uniqueID,
49
+ memoize,
50
+ getUserAgent,
51
+ noop,
52
+ supportsPopups as userAgentSupportsPopups,
53
+ } from "@krakenjs/belter/src";
54
+ import { node, dom } from "@krakenjs/jsx-pragmatic/src";
55
+
56
+ import {
57
+ getSessionID,
58
+ logLatencyInstrumentationPhase,
59
+ prepareInstrumentationPayload,
60
+ sessionState,
61
+ storageState,
62
+ } from "../../lib";
63
+ import {
64
+ getButtonExperiments,
65
+ isSupportedNativeBrowser,
66
+ sendPostRobotMessageToButtonIframe,
67
+ } from "../buttons/util";
68
+ import { isSupportedNativeVenmoBrowser } from "../../funding/util";
69
+ import { PayPalAppSwitchOverlay } from "../../ui/overlay/paypal-app-switch/overlay";
70
+
71
+ import { containerTemplate } from "./container";
72
+ import { PrerenderedSavedPaymentMethods } from "./prerender";
73
+ import { type SavedPaymentMethodsProps } from "./props";
74
+ import { validateSavedPaymentMethodsStyle } from "./util";
75
+
76
+ export type SavedPaymentMethodsComponent = ZoidComponent<
77
+ SavedPaymentMethodsProps,
78
+ void,
79
+ void,
80
+ void
81
+ >;
82
+
83
+ // $FlowIssue
84
+ export const getSavedPaymentMethodsComponent: () => SavedPaymentMethodsComponent =
85
+ memoize(() => {
86
+ const queriedEligibleFunding = [];
87
+
88
+ // $FlowIssue
89
+ return create({
90
+ tag: "paypal-saved-payment-methods",
91
+ url: () =>
92
+ `${getPayPalDomain()}${
93
+ __PAYPAL_CHECKOUT__.__URI__.__SAVED_PAYMENT_METHODS__
94
+ }`,
95
+
96
+ domain: getPayPalDomainRegex(),
97
+
98
+ autoResize: {
99
+ width: false,
100
+ height: true,
101
+ element: ".saved-payment-methods-container",
102
+ },
103
+
104
+ dimensions: {
105
+ width: "400px",
106
+ height: "30px",
107
+ },
108
+
109
+ containerTemplate,
110
+
111
+ // $FlowIssue mismatch between beaver-logger and zoid logger types
112
+ logger: getLogger(),
113
+
114
+ prerenderTemplate: ({ props, doc, event }) => {
115
+ const { buttonSessionID } = props;
116
+
117
+ event.on(EVENT.PRERENDERED, () => {
118
+ logLatencyInstrumentationPhase({
119
+ buttonSessionID,
120
+ phase: "saved-payment-methods-first-render-end",
121
+ });
122
+
123
+ getLogger()
124
+ .info("saved_payment_methods_prerendered", {
125
+ buttonSessionID,
126
+ })
127
+ .flush();
128
+
129
+ try {
130
+ const cplPhases = prepareInstrumentationPayload(
131
+ buttonSessionID,
132
+ "saved-payment-methods"
133
+ );
134
+ const cplLatencyMetrics = {
135
+ [FPTI_KEY.STATE]: "CPL_LATENCY_METRICS",
136
+ [FPTI_KEY.TRANSITION]: "process_client_metrics",
137
+ [FPTI_KEY.CONTEXT_ID]: buttonSessionID,
138
+ [FPTI_KEY.PAGE]:
139
+ "main:xo:paypal-components:saved-payment-methods",
140
+ [FPTI_KEY.CPL_COMP_METRICS]: JSON.stringify(
141
+ cplPhases?.comp || {}
142
+ ),
143
+ };
144
+ getLogger().track(cplLatencyMetrics);
145
+ } catch (err) {
146
+ getLogger().track({
147
+ err: err.message || "CPL_LOG_PHASE_ERROR",
148
+ details: err.details,
149
+ stack: JSON.stringify(err.stack || err),
150
+ });
151
+ }
152
+ });
153
+
154
+ return (
155
+ <PrerenderedSavedPaymentMethods nonce={props.nonce} props={props} />
156
+ ).render(dom({ doc }));
157
+ },
158
+
159
+ attributes: {
160
+ iframe: {
161
+ scrolling: "no",
162
+ title: "PayPal Saved Payment Methods",
163
+ },
164
+ },
165
+
166
+ props: {
167
+ appSwitchWhenAvailable: {
168
+ type: "boolean",
169
+ queryParam: true,
170
+ required: false,
171
+ },
172
+
173
+ preferences: {
174
+ type: "object",
175
+ queryParam: true,
176
+ required: false,
177
+ serialization: "json",
178
+ },
179
+
180
+ showPayPalAppSwitchOverlay: {
181
+ type: "function",
182
+ queryParam: false,
183
+ value:
184
+ ({ props: { buttonSessionID } }) =>
185
+ ({ close, focus }) => {
186
+ const overlay = (
187
+ <PayPalAppSwitchOverlay
188
+ buttonSessionID={buttonSessionID}
189
+ close={close}
190
+ focus={focus}
191
+ />
192
+ ).render(dom({ doc: document }));
193
+
194
+ document.body?.appendChild(overlay);
195
+ },
196
+ },
197
+
198
+ hidePayPalAppSwitchOverlay: {
199
+ type: "function",
200
+ queryParam: false,
201
+ value:
202
+ ({ props: { buttonSessionID } }) =>
203
+ ({ close }) => {
204
+ const overlay = document.getElementsByName(
205
+ `paypal-overlay-${buttonSessionID}`
206
+ )?.[0];
207
+
208
+ if (overlay) {
209
+ close();
210
+ overlay.remove();
211
+ }
212
+ },
213
+ },
214
+
215
+ redirect: {
216
+ type: "function",
217
+ sendToChild: true,
218
+ value: () => (url) => {
219
+ location.href = url;
220
+ },
221
+ },
222
+
223
+ hashChangeHandler: {
224
+ type: "function",
225
+ sendToChild: false,
226
+ queryParam: false,
227
+ value: () => (event) => {
228
+ sendPostRobotMessageToButtonIframe({
229
+ eventName: "paypal-hashchange",
230
+ payload: {
231
+ url: event.newURL,
232
+ },
233
+ });
234
+ },
235
+ },
236
+
237
+ visibilityChangeHandler: {
238
+ type: "function",
239
+ sendToChild: false,
240
+ queryParam: false,
241
+ value: () => () => {
242
+ sendPostRobotMessageToButtonIframe({
243
+ eventName: "paypal-visibilitychange",
244
+ payload: {
245
+ url: window.location.href,
246
+ visibilityState: document.visibilityState,
247
+ },
248
+ });
249
+ },
250
+ },
251
+
252
+ listenForVisibilityChange: {
253
+ type: "function",
254
+ queryParam: false,
255
+ value:
256
+ ({ props }) =>
257
+ () => {
258
+ window.addEventListener(
259
+ "visibilitychange",
260
+ props.visibilityChangeHandler
261
+ );
262
+ },
263
+ },
264
+
265
+ removeListenerForVisibilityChanges: {
266
+ type: "function",
267
+ queryParam: false,
268
+ value:
269
+ ({ props }) =>
270
+ () => {
271
+ window.removeEventListener(
272
+ "visibilitychange",
273
+ props.visibilityChangeHandler
274
+ );
275
+ },
276
+ },
277
+
278
+ // allowBillingPayments prop is used by Honey Extension to render the one-click button
279
+ // with payment methods & to use the payment methods instead of the Billing Agreement
280
+ allowBillingPayments: {
281
+ type: "boolean",
282
+ queryParam: true,
283
+ required: false,
284
+ default: () => true,
285
+ },
286
+
287
+ amount: {
288
+ type: "string",
289
+ required: false,
290
+ queryParam: true,
291
+ value: getAmount,
292
+ },
293
+
294
+ apiStageHost: {
295
+ type: "string",
296
+ value: getAPIStageHost,
297
+ required: false,
298
+ },
299
+
300
+ buttonLocation: {
301
+ type: "string",
302
+ value: () => window.location.hostname,
303
+ queryParam: false,
304
+ },
305
+
306
+ buttonSessionID: {
307
+ type: "string",
308
+ value: uniqueID,
309
+ queryParam: true,
310
+ },
311
+
312
+ buyerCountry: {
313
+ type: "string",
314
+ queryParam: true,
315
+ required: false,
316
+ value: getBuyerCountry,
317
+ },
318
+
319
+ clientAccessToken: {
320
+ type: "string",
321
+ required: false,
322
+ queryParam: true,
323
+ value: getClientAccessToken,
324
+ },
325
+
326
+ customerId: {
327
+ type: "string",
328
+ required: false,
329
+ queryParam: true,
330
+ value: getCustomerId,
331
+ },
332
+
333
+ clientID: {
334
+ type: "string",
335
+ value: getClientID,
336
+ queryParam: true,
337
+ },
338
+
339
+ clientMetadataID: {
340
+ type: "string",
341
+ required: false,
342
+ default: () => {
343
+ const clientMetadataId = getClientMetadataID();
344
+ const sessionID = getSessionID();
345
+
346
+ return clientMetadataId || sessionID;
347
+ },
348
+ queryParam: true,
349
+ },
350
+
351
+ commit: {
352
+ type: "boolean",
353
+ queryParam: true,
354
+ value: getCommit,
355
+ },
356
+
357
+ createOrder: {
358
+ type: "function",
359
+ required: false,
360
+ },
361
+
362
+ csp: {
363
+ type: "object",
364
+ required: false,
365
+ value: () => {
366
+ return {
367
+ nonce: getCSPNonce(),
368
+ };
369
+ },
370
+ },
371
+
372
+ currency: {
373
+ type: "string",
374
+ queryParam: true,
375
+ value: getCurrency,
376
+ },
377
+
378
+ debug: {
379
+ type: "boolean",
380
+ value: getDebug,
381
+ queryParam: true,
382
+ },
383
+
384
+ disableSetCookie: {
385
+ type: "boolean",
386
+ queryParam: true,
387
+ required: false,
388
+ value: getDisableSetCookie,
389
+ },
390
+
391
+ env: {
392
+ type: "string",
393
+ queryParam: true,
394
+ value: getEnv,
395
+ },
396
+
397
+ experiment: {
398
+ type: "object",
399
+ queryParam: true,
400
+ value: getButtonExperiments,
401
+ },
402
+
403
+ experimentation: {
404
+ type: "object",
405
+ queryParam: true,
406
+ required: false,
407
+ value: getExperimentation,
408
+ },
409
+
410
+ fundingEligibility: {
411
+ type: "object",
412
+ default: getRefinedFundingEligibility,
413
+ value:
414
+ __ENV__ === ENV.LOCAL ? undefined : getRefinedFundingEligibility,
415
+ queryParam: true,
416
+ serialization: "base64",
417
+ },
418
+
419
+ getPageUrl: {
420
+ type: "function",
421
+ value: () => {
422
+ return () => window.location.href;
423
+ },
424
+ },
425
+
426
+ getPopupBridge: {
427
+ type: "function",
428
+ required: false,
429
+ value: () => {
430
+ return () => {
431
+ if (!window.popupBridge) {
432
+ return;
433
+ }
434
+
435
+ return {
436
+ nativeUrl: window.popupBridge.getReturnUrlPrefix(),
437
+ start: (url) => {
438
+ return new ZalgoPromise((resolve, reject) => {
439
+ window.popupBridge.onComplete = (err, result) => {
440
+ if (!err && !result) {
441
+ resolve({
442
+ opType: "user_closed_window",
443
+ });
444
+ }
445
+ const queryItems =
446
+ result && result.queryItems ? result.queryItems : {};
447
+ return err ? reject(err) : resolve(queryItems);
448
+ };
449
+ window.popupBridge.open(url);
450
+ });
451
+ },
452
+ };
453
+ };
454
+ },
455
+ },
456
+
457
+ getPrerenderDetails: {
458
+ type: "function",
459
+ value:
460
+ ({ state }) =>
461
+ () =>
462
+ state.prerenderDetails,
463
+ },
464
+
465
+ getQueriedEligibleFunding: {
466
+ type: "function",
467
+ value: () => {
468
+ return () => queriedEligibleFunding;
469
+ },
470
+ },
471
+
472
+ intent: {
473
+ type: "string",
474
+ queryParam: true,
475
+ value: getIntent,
476
+ },
477
+
478
+ jsSdkLibrary: {
479
+ type: "string",
480
+ queryParam: true,
481
+ required: false,
482
+ value: getJsSdkLibrary,
483
+ },
484
+
485
+ locale: {
486
+ type: "object",
487
+ queryParam: true,
488
+ value: getLocale,
489
+ },
490
+
491
+ merchantID: {
492
+ type: "array",
493
+ queryParam: true,
494
+ value: getMerchantID,
495
+ },
496
+
497
+ merchantRequestedPopupsDisabled: {
498
+ type: "boolean",
499
+ required: false,
500
+ value: getMerchantRequestedPopupsDisabled,
501
+ },
502
+
503
+ message: {
504
+ type: "object",
505
+ queryParam: true,
506
+ required: false,
507
+ },
508
+
509
+ nonce: {
510
+ type: "string",
511
+ default: getCSPNonce,
512
+ },
513
+
514
+ onApprove: {
515
+ type: "function",
516
+ required: false,
517
+ },
518
+
519
+ onCancel: {
520
+ type: "function",
521
+ required: false,
522
+ },
523
+
524
+ onClick: {
525
+ type: "function",
526
+ required: false,
527
+ },
528
+
529
+ onComplete: {
530
+ type: "function",
531
+ required: false,
532
+ },
533
+
534
+ onInit: {
535
+ type: "function",
536
+ required: false,
537
+ default: () => noop,
538
+ decorate: ({ props, value = noop }) => {
539
+ logLatencyInstrumentationPhase({
540
+ buttonSessionID: props.buttonSessionID,
541
+ phase: "saved-payment-methods-first-render",
542
+ });
543
+
544
+ return (...args) => {
545
+ return value(...args);
546
+ };
547
+ },
548
+ },
549
+
550
+ onShippingAddressChange: {
551
+ type: "function",
552
+ required: false,
553
+ },
554
+
555
+ onShippingOptionsChange: {
556
+ type: "function",
557
+ required: false,
558
+ },
559
+
560
+ hasShippingCallback: {
561
+ type: "boolean",
562
+ required: false,
563
+ queryParam: true,
564
+ value: ({ props }) => {
565
+ return Boolean(
566
+ props.onShippingAddressChange || props.onShippingOptionsChange
567
+ );
568
+ },
569
+ },
570
+
571
+ pageType: {
572
+ type: "string",
573
+ required: false,
574
+ queryParam: true,
575
+ value: () => getSDKAttribute(SDK_SETTINGS.PAGE_TYPE),
576
+ },
577
+
578
+ partnerAttributionID: {
579
+ type: "string",
580
+ required: false,
581
+ value: getPartnerAttributionID,
582
+ },
583
+
584
+ paymentMethodNonce: {
585
+ type: "string",
586
+ queryParam: true,
587
+ required: false,
588
+ },
589
+
590
+ paymentMethodToken: {
591
+ type: "string",
592
+ queryParam: true,
593
+ required: false,
594
+ },
595
+
596
+ paymentRequest: {
597
+ type: "object",
598
+ queryParam: false,
599
+ required: false,
600
+ },
601
+
602
+ platform: {
603
+ type: "string",
604
+ queryParam: true,
605
+ value: getPlatform,
606
+ },
607
+
608
+ referrerDomain: {
609
+ type: "string",
610
+ required: false,
611
+ value: () => {
612
+ if (window.document.referrer) {
613
+ return new URL(window.document.referrer).host || undefined;
614
+ }
615
+ },
616
+ },
617
+
618
+ sessionID: {
619
+ type: "string",
620
+ value: getSessionID,
621
+ queryParam: true,
622
+ },
623
+
624
+ sdkCorrelationID: {
625
+ type: "string",
626
+ required: false,
627
+ value: getCorrelationID,
628
+ queryParam: true,
629
+ },
630
+
631
+ sdkInitTimings: {
632
+ type: "object",
633
+ queryParam: false,
634
+ required: false,
635
+ value: () => {
636
+ // eslint-disable-next-line compat/compat
637
+ const sdkScript = window?.performance
638
+ ?.getEntriesByType("resource")
639
+ // eslint-disable-next-line security/detect-unsafe-regex
640
+ .find(({ name }) => /paypal\.com(?::\d+)?\/sdk\/js/.test(name));
641
+
642
+ const isCached = (performanceEntry) => {
643
+ if (
644
+ !performanceEntry ||
645
+ typeof performanceEntry.duration === "undefined"
646
+ ) {
647
+ return "unknown";
648
+ }
649
+
650
+ return performanceEntry.duration === 0 ? "yes" : "no";
651
+ };
652
+
653
+ let sdkInitTimeStamp;
654
+
655
+ try {
656
+ sdkInitTimeStamp = getSDKInitTime();
657
+ } catch (error) {
658
+ // do nothing
659
+ }
660
+
661
+ return {
662
+ sdkInitTimeStamp,
663
+ sdkScriptDownloadDuration: sdkScript?.duration,
664
+ isSdkCached: isCached(sdkScript),
665
+ };
666
+ },
667
+ },
668
+
669
+ sdkMeta: {
670
+ type: "string",
671
+ queryParam: true,
672
+ sendToChild: false,
673
+ value: getSDKMeta,
674
+ },
675
+
676
+ sdkToken: {
677
+ type: "string",
678
+ required: false,
679
+ value: getSDKToken,
680
+ },
681
+
682
+ /**
683
+ * Version of the SDK used in first render.
684
+ * This is passed to the `/smart/saved-payment-methods` endpoint in order for the second render
685
+ * to be aware of what sdk version to load during SSR
686
+ */
687
+ sdkVersion: {
688
+ type: "string",
689
+ queryParam: true,
690
+ sendToChild: false,
691
+ value: getVersion,
692
+ },
693
+
694
+ sessionState: {
695
+ type: "object",
696
+ value: () => sessionState,
697
+ },
698
+
699
+ stageHost: {
700
+ type: "string",
701
+ value: getStageHost,
702
+ required: false,
703
+ },
704
+
705
+ storageID: {
706
+ type: "string",
707
+ value: getStorageID,
708
+ queryParam: true,
709
+ },
710
+
711
+ storageState: {
712
+ type: "object",
713
+ value: () => storageState,
714
+ },
715
+
716
+ style: {
717
+ type: "object",
718
+ queryParam: true,
719
+ required: false,
720
+
721
+ validate: ({ value = {} }) => {
722
+ validateSavedPaymentMethodsStyle(value);
723
+ },
724
+
725
+ default: () => ({}),
726
+ },
727
+
728
+ supportedNativeBrowser: {
729
+ type: "boolean",
730
+ value: isSupportedNativeBrowser,
731
+ queryParam: true,
732
+ },
733
+
734
+ supportedNativeVenmoBrowser: {
735
+ type: "boolean",
736
+ value: ({ props }) => {
737
+ return isSupportedNativeVenmoBrowser(
738
+ props.experiment,
739
+ props.userAgent
740
+ );
741
+ },
742
+ queryParam: true,
743
+ required: false,
744
+ },
745
+
746
+ supportsPopups: {
747
+ type: "boolean",
748
+ value: () => {
749
+ return userAgentSupportsPopups();
750
+ },
751
+ queryParam: true,
752
+ },
753
+
754
+ test: {
755
+ type: "object",
756
+ default(): Object {
757
+ return {
758
+ action: "checkout",
759
+ };
760
+ },
761
+ },
762
+
763
+ userExperienceFlow: {
764
+ type: "string",
765
+ required: false,
766
+ value: getUserExperienceFlow,
767
+ },
768
+
769
+ userIDToken: {
770
+ type: "string",
771
+ default: getUserIDToken,
772
+ required: false,
773
+ queryParam: true,
774
+ },
775
+
776
+ sdkSource: {
777
+ type: "string",
778
+ value: () => getSDKIntegrationSource(),
779
+ required: false,
780
+ queryParam: true,
781
+ },
782
+
783
+ vault: {
784
+ type: "boolean",
785
+ queryParam: true,
786
+ value: getVault,
787
+ },
788
+
789
+ userAgent: {
790
+ type: "string",
791
+ required: false,
792
+ queryParam: true,
793
+ value: getUserAgent,
794
+ },
795
+ },
796
+ });
797
+ });