@glomopay/react-native-sdk 4.0.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/MIGRATION.md +112 -0
  3. package/README.md +173 -36
  4. package/lib/bridge/file-input-handler.d.ts +25 -0
  5. package/lib/bridge/file-input-handler.d.ts.map +1 -0
  6. package/lib/bridge/file-input-handler.js +38 -0
  7. package/lib/bridge/file-save-handler.d.ts +32 -0
  8. package/lib/bridge/file-save-handler.d.ts.map +1 -0
  9. package/lib/bridge/file-save-handler.js +92 -0
  10. package/lib/bridge/message-router.d.ts +44 -0
  11. package/lib/bridge/message-router.d.ts.map +1 -0
  12. package/lib/bridge/message-router.js +48 -0
  13. package/lib/bridge/payment-payload.d.ts +18 -0
  14. package/lib/bridge/payment-payload.d.ts.map +1 -0
  15. package/lib/bridge/payment-payload.js +31 -0
  16. package/lib/capabilities/file-save.d.ts +40 -0
  17. package/lib/capabilities/file-save.d.ts.map +1 -0
  18. package/lib/capabilities/file-save.js +101 -0
  19. package/lib/capabilities/index.d.ts +22 -0
  20. package/lib/capabilities/index.d.ts.map +1 -0
  21. package/lib/capabilities/index.js +34 -0
  22. package/lib/capabilities/use-capability-reporting.d.ts +24 -0
  23. package/lib/capabilities/use-capability-reporting.d.ts.map +1 -0
  24. package/lib/capabilities/use-capability-reporting.js +44 -0
  25. package/lib/config/base.d.ts +12 -0
  26. package/lib/config/base.d.ts.map +1 -1
  27. package/lib/config/base.js +13 -1
  28. package/lib/glomo-checkout.d.ts +9 -1
  29. package/lib/glomo-checkout.d.ts.map +1 -1
  30. package/lib/glomo-checkout.js +14 -5
  31. package/lib/glomo-lrs-checkout.d.ts +3 -0
  32. package/lib/glomo-lrs-checkout.d.ts.map +1 -1
  33. package/lib/glomo-lrs-checkout.js +34 -11
  34. package/lib/glomo-standard-checkout.d.ts +4 -1
  35. package/lib/glomo-standard-checkout.d.ts.map +1 -1
  36. package/lib/glomo-standard-checkout.js +21 -13
  37. package/lib/glomo-subscriptions-checkout.d.ts.map +1 -1
  38. package/lib/glomo-subscriptions-checkout.js +1 -1
  39. package/lib/index.d.ts +2 -2
  40. package/lib/index.d.ts.map +1 -1
  41. package/lib/index.js +4 -3
  42. package/lib/injections/index.d.ts +24 -0
  43. package/lib/injections/index.d.ts.map +1 -1
  44. package/lib/injections/index.js +41 -0
  45. package/lib/injections/webview-flow.injection.d.ts.map +1 -1
  46. package/lib/injections/webview-flow.injection.js +76 -0
  47. package/lib/injections/webview-main.injection.d.ts.map +1 -1
  48. package/lib/injections/webview-main.injection.js +31 -0
  49. package/lib/injections/webview-standard.injection.d.ts.map +1 -1
  50. package/lib/injections/webview-standard.injection.js +31 -0
  51. package/lib/services/file-saver.d.ts +109 -0
  52. package/lib/services/file-saver.d.ts.map +1 -0
  53. package/lib/services/file-saver.js +416 -0
  54. package/lib/types/checkout.d.ts +67 -6
  55. package/lib/types/checkout.d.ts.map +1 -1
  56. package/lib/types/checkout.js +24 -2
  57. package/lib/types/standard-checkout.d.ts +6 -6
  58. package/lib/types/standard-checkout.d.ts.map +1 -1
  59. package/lib/types/subscriptions-checkout.d.ts +5 -3
  60. package/lib/types/subscriptions-checkout.d.ts.map +1 -1
  61. package/lib/use-glomo-checkout.d.ts +2 -2
  62. package/lib/use-glomo-checkout.d.ts.map +1 -1
  63. package/lib/use-glomo-checkout.js +25 -4
  64. package/lib/use-lrs-checkout.d.ts +18 -6
  65. package/lib/use-lrs-checkout.d.ts.map +1 -1
  66. package/lib/use-lrs-checkout.js +330 -171
  67. package/lib/use-standard-checkout.d.ts +18 -13
  68. package/lib/use-standard-checkout.d.ts.map +1 -1
  69. package/lib/use-standard-checkout.js +282 -206
  70. package/lib/utils/analytics.d.ts +177 -51
  71. package/lib/utils/analytics.d.ts.map +1 -1
  72. package/lib/utils/analytics.js +299 -81
  73. package/lib/utils/device-compliance.d.ts +57 -12
  74. package/lib/utils/device-compliance.d.ts.map +1 -1
  75. package/lib/utils/device-compliance.js +101 -37
  76. package/lib/utils/event-projections.d.ts +56 -0
  77. package/lib/utils/event-projections.d.ts.map +1 -0
  78. package/lib/utils/event-projections.js +42 -0
  79. package/lib/utils/file-metadata.d.ts +52 -0
  80. package/lib/utils/file-metadata.d.ts.map +1 -0
  81. package/lib/utils/file-metadata.js +134 -0
  82. package/lib/utils/use-sdk-session.d.ts +12 -0
  83. package/lib/utils/use-sdk-session.d.ts.map +1 -0
  84. package/lib/utils/use-sdk-session.js +37 -0
  85. package/lib/utils/validation.d.ts +37 -3
  86. package/lib/utils/validation.d.ts.map +1 -1
  87. package/lib/utils/validation.js +64 -8
  88. package/lib/webview/capability-props.d.ts +27 -0
  89. package/lib/webview/capability-props.d.ts.map +1 -0
  90. package/lib/webview/capability-props.js +61 -0
  91. package/lib/webview/use-permission-request.d.ts +33 -0
  92. package/lib/webview/use-permission-request.d.ts.map +1 -0
  93. package/lib/webview/use-permission-request.js +89 -0
  94. package/package.json +13 -3
  95. package/src/bridge/file-input-handler.ts +66 -0
  96. package/src/bridge/file-save-handler.ts +141 -0
  97. package/src/bridge/message-router.ts +92 -0
  98. package/src/bridge/payment-payload.ts +31 -0
  99. package/src/capabilities/file-save.ts +124 -0
  100. package/src/capabilities/index.ts +34 -0
  101. package/src/capabilities/use-capability-reporting.ts +55 -0
  102. package/src/config/base.ts +13 -0
  103. package/src/glomo-checkout.tsx +28 -11
  104. package/src/glomo-lrs-checkout.tsx +49 -27
  105. package/src/glomo-standard-checkout.tsx +33 -34
  106. package/src/glomo-subscriptions-checkout.tsx +1 -0
  107. package/src/index.ts +4 -2
  108. package/src/injections/index.ts +43 -0
  109. package/src/injections/webview-flow.injection.ts +76 -0
  110. package/src/injections/webview-main.injection.ts +31 -0
  111. package/src/injections/webview-standard.injection.ts +31 -0
  112. package/src/services/file-saver.ts +497 -0
  113. package/src/types/checkout.ts +72 -6
  114. package/src/types/standard-checkout.ts +6 -6
  115. package/src/types/subscriptions-checkout.ts +9 -3
  116. package/src/use-glomo-checkout.tsx +32 -7
  117. package/src/use-lrs-checkout.tsx +684 -366
  118. package/src/use-standard-checkout.tsx +731 -465
  119. package/src/utils/analytics.ts +422 -117
  120. package/src/utils/device-compliance.ts +148 -38
  121. package/src/utils/event-projections.ts +74 -0
  122. package/src/utils/file-metadata.ts +140 -0
  123. package/src/utils/use-sdk-session.ts +41 -0
  124. package/src/utils/validation.ts +70 -10
  125. package/src/webview/capability-props.ts +86 -0
  126. package/src/webview/use-permission-request.ts +114 -0
  127. package/src/jail-monkey.d.ts +0 -19
@@ -1,8 +1,13 @@
1
1
  "use strict";
2
2
  /**
3
- * The unified GlomoPay Checkout Component (v4).
3
+ * The unified GlomoPay Checkout Component.
4
4
  * Detects order type (LRS vs Standard) and delegates rendering to the appropriate inner component.
5
5
  * Enforces error handling via `onSdkError()` as a mandatory prop.
6
+ *
7
+ * Its props are a union over both flows, so a prop that only one flow uses is still accepted here.
8
+ * `onUserJourneyCompleted` is the one case where that matters: it is forwarded to the standard and
9
+ * subscriptions flows and silently ignored on LRS orders, because LRS never produces an
10
+ * asynchronous journey for it to report. Every other callback reaches every flow.
6
11
  */
7
12
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
13
  if (k2 === undefined) k2 = k;
@@ -45,6 +50,7 @@ const analytics_1 = require("./utils/analytics");
45
50
  const glomo_lrs_checkout_1 = require("./glomo-lrs-checkout");
46
51
  const glomo_standard_checkout_1 = require("./glomo-standard-checkout");
47
52
  const glomo_subscriptions_checkout_1 = require("./glomo-subscriptions-checkout");
53
+ const validation_1 = require("./utils/validation");
48
54
  function GlomoCheckoutComponent(props, ref) {
49
55
  var _a;
50
56
  // useGlomoCheckout handles order type detection and exposes start/getStatus for the ref
@@ -57,7 +63,7 @@ function GlomoCheckoutComponent(props, ref) {
57
63
  // Tracking unsupported callback props on subscription flows (fires once per mount)
58
64
  const hasTrackedUnsupportedRef = (0, react_1.useRef)(false);
59
65
  const devMode = (_a = passedProps.devMode) !== null && _a !== void 0 ? _a : false;
60
- const mockMode = (0, react_1.useMemo)(() => { var _a, _b; return (_b = (_a = passedProps.publicKey) === null || _a === void 0 ? void 0 : _a.toLowerCase().startsWith("test_")) !== null && _b !== void 0 ? _b : false; }, [passedProps.publicKey]);
66
+ const mockMode = (0, react_1.useMemo)(() => (0, validation_1.isMockModeKey)(passedProps.publicKey), [passedProps.publicKey]);
61
67
  // Extracting stable boolean for the tracking effect to avoid depending on passedProps object
62
68
  const hasUserJourneyCallback = !!passedProps.onUserJourneyCompleted;
63
69
  (0, react_1.useEffect)(() => {
@@ -70,15 +76,15 @@ function GlomoCheckoutComponent(props, ref) {
70
76
  }, [orderType, hasUserJourneyCallback, passedProps.subscriptionId, passedProps.publicKey, devMode, mockMode]);
71
77
  // Delegating to the LRS checkout component once order type is resolved as LRS
72
78
  if (orderType === "lrs") {
73
- return (<glomo_lrs_checkout_1.GlomoLrsCheckout ref={innerLrsRef} server={passedProps.server} publicKey={passedProps.publicKey} orderId={passedProps.orderId} onPaymentSuccess={passedProps.onPaymentSuccess} onPaymentFailure={passedProps.onPaymentFailure} onConnectionError={passedProps.onConnectionError} onPaymentTerminate={passedProps.onPaymentTerminate} onSdkError={passedProps.onSdkError} devMode={passedProps.devMode}/>);
79
+ return (<glomo_lrs_checkout_1.GlomoLrsCheckout ref={innerLrsRef} server={passedProps.server} publicKey={passedProps.publicKey} orderId={passedProps.orderId} onPaymentSuccess={passedProps.onPaymentSuccess} onPaymentFailure={passedProps.onPaymentFailure} onConnectionError={passedProps.onConnectionError} onPaymentTerminate={passedProps.onPaymentTerminate} onSdkError={passedProps.onSdkError} onUserRefusedDevicePermissions={passedProps.onUserRefusedDevicePermissions} devMode={passedProps.devMode} _testInjectionScript={props._testInjectionScript} _testCarouselInjectionScript={props._testCarouselInjectionScript} _onEducationCarouselStateChange={props._onEducationCarouselStateChange}/>);
74
80
  }
75
81
  // Delegating to the Standard checkout component once order type is resolved as Standard
76
82
  if (orderType === "standard") {
77
- return (<glomo_standard_checkout_1.GlomoStandardCheckout ref={innerStandardRef} server={passedProps.server} publicKey={passedProps.publicKey} orderId={passedProps.orderId} onPaymentSuccess={passedProps.onPaymentSuccess} onPaymentFailure={passedProps.onPaymentFailure} onConnectionError={passedProps.onConnectionError} onPaymentTerminate={passedProps.onPaymentTerminate} onSdkError={passedProps.onSdkError} onUserJourneyCompleted={passedProps.onUserJourneyCompleted} onUserRefusedCameraPermissions={passedProps.onUserRefusedCameraPermissions} devMode={passedProps.devMode}/>);
83
+ return (<glomo_standard_checkout_1.GlomoStandardCheckoutInternal ref={innerStandardRef} server={passedProps.server} publicKey={passedProps.publicKey} orderId={passedProps.orderId} onPaymentSuccess={passedProps.onPaymentSuccess} onPaymentFailure={passedProps.onPaymentFailure} onConnectionError={passedProps.onConnectionError} onPaymentTerminate={passedProps.onPaymentTerminate} onSdkError={passedProps.onSdkError} onUserJourneyCompleted={passedProps.onUserJourneyCompleted} onUserRefusedDevicePermissions={passedProps.onUserRefusedDevicePermissions} devMode={passedProps.devMode} _testInjectionScript={props._testInjectionScript}/>);
78
84
  }
79
85
  // Delegating to the Subscriptions checkout component when subscriptionId is provided (no API call)
80
86
  if (orderType === "subscriptions") {
81
- return (<glomo_subscriptions_checkout_1.GlomoSubscriptionsCheckout ref={innerSubscriptionsRef} server={passedProps.server} publicKey={passedProps.publicKey} subscriptionId={passedProps.subscriptionId} onPaymentSuccess={passedProps.onPaymentSuccess} onPaymentFailure={passedProps.onPaymentFailure} onConnectionError={passedProps.onConnectionError} onPaymentTerminate={passedProps.onPaymentTerminate} onSdkError={passedProps.onSdkError} onUserJourneyCompleted={passedProps.onUserJourneyCompleted} onUserRefusedCameraPermissions={passedProps.onUserRefusedCameraPermissions} devMode={passedProps.devMode}/>);
87
+ return (<glomo_subscriptions_checkout_1.GlomoSubscriptionsCheckout ref={innerSubscriptionsRef} server={passedProps.server} publicKey={passedProps.publicKey} subscriptionId={passedProps.subscriptionId} onPaymentSuccess={passedProps.onPaymentSuccess} onPaymentFailure={passedProps.onPaymentFailure} onConnectionError={passedProps.onConnectionError} onPaymentTerminate={passedProps.onPaymentTerminate} onSdkError={passedProps.onSdkError} onUserJourneyCompleted={passedProps.onUserJourneyCompleted} onUserRefusedDevicePermissions={passedProps.onUserRefusedDevicePermissions} devMode={passedProps.devMode} _testInjectionScript={props._testInjectionScript}/>);
82
88
  }
83
89
  /**
84
90
  * No modal for detecting state - avoids iOS pageSheet conflict where
@@ -87,5 +93,8 @@ function GlomoCheckoutComponent(props, ref) {
87
93
  */
88
94
  return null;
89
95
  }
96
+ /**
97
+ * Internal props if provided, should be used for automated testing only
98
+ */
90
99
  exports.GlomoCheckout = (0, react_1.forwardRef)(GlomoCheckoutComponent);
91
100
  exports.GlomoCheckout.displayName = "GlomoCheckout";
@@ -5,6 +5,9 @@ import { type SdkError } from "./utils/analytics";
5
5
  export interface GlomoLrsCheckoutProps extends UseLrsCheckoutOptions {
6
6
  visible?: boolean;
7
7
  onSdkError: (error: Array<SdkError>) => void;
8
+ _testInjectionScript?: string;
9
+ _testCarouselInjectionScript?: string;
10
+ _onEducationCarouselStateChange?: (state: string) => void;
8
11
  }
9
12
  export interface GlomoLrsCheckoutRef {
10
13
  start: () => boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"glomo-lrs-checkout.d.ts","sourceRoot":"","sources":["../src/glomo-lrs-checkout.tsx"],"names":[],"mappings":"AAAA,0CAA0C;AAE1C,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,OAAO,EAAkB,KAAK,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACxG,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlD,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAChE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,iBAAiB,CAAC;CACtC;AA2WD,eAAO,MAAM,gBAAgB,mGAAoF,CAAC"}
1
+ {"version":3,"file":"glomo-lrs-checkout.d.ts","sourceRoot":"","sources":["../src/glomo-lrs-checkout.tsx"],"names":[],"mappings":"AAAA,0CAA0C;AAE1C,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,OAAO,EAAkB,KAAK,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACxG,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAIlD,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAChE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAC7C,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,4BAA4B,CAAC,EAAE,MAAM,CAAC;IACtC,+BAA+B,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7D;AAED,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,iBAAiB,CAAC;CACtC;AAuXD,eAAO,MAAM,gBAAgB,mGAAoF,CAAC"}
@@ -40,6 +40,7 @@ const react_native_1 = require("react-native");
40
40
  const react_native_webview_1 = require("react-native-webview");
41
41
  const use_lrs_checkout_1 = require("./use-lrs-checkout");
42
42
  const validation_1 = require("./utils/validation");
43
+ const capability_props_1 = require("./webview/capability-props");
43
44
  /**
44
45
  * The Main GlomoPay LRS Checkout Component
45
46
  *
@@ -49,7 +50,8 @@ const validation_1 = require("./utils/validation");
49
50
  *
50
51
  * @param onPaymentSuccess - The success callback with payload, for a successful payment
51
52
  * @param onPaymentFailure - The failure callback with payload, for a failed payment
52
- * @param onPaymentTerminate - Optional callback called when the checkout is terminated either from the LRS webpage (back button or close button) or mobile component (user dismissing the modal on iOS or user pressing the back button on Android)
53
+ * @param onPaymentTerminate - Optional callback called when the checkout ends without a payment outcome. Receives a payload whose `source` is a TERMINATION_SOURCES value naming how it ended: the page's own close control, the Android back button/gesture, or an iOS swipe-down on the modal. The back chevron over a bank flow is deliberately not a termination - it returns the user to the checkout with the session intact.
54
+ * @param onUserRefusedDevicePermissions - Optional callback invoked when the user refuses a device permission the bank's page asked for - camera today. Upload-related permissions are requested by react-native-webview itself and do not reach this callback. Currently Android only: due to platform limitations on iOS, the WebView raises its own prompt and never reports the answer back, so this cannot fire there.
53
55
  *
54
56
  * @param onConnectionError - Optional callback for connection/network errors
55
57
  * @param onSdkError - Optional callback for handling SDK validation errors and configuration issues
@@ -59,17 +61,16 @@ const validation_1 = require("./utils/validation");
59
61
  *
60
62
  * @param visible - Advanced: If provided, the component visibility will be controlled by the visible prop. Otherwise, the component will be controlled internally by the SDK.
61
63
  */
62
- function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSuccess, onPaymentFailure, onConnectionError, onPaymentTerminate, onSdkError, devMode = false, visible: controlledVisible, }, ref) {
64
+ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSuccess, onPaymentFailure, onConnectionError, onPaymentTerminate, onSdkError, onUserRefusedDevicePermissions, devMode = false, visible: controlledVisible, _testInjectionScript, _testCarouselInjectionScript, _onEducationCarouselStateChange, }, ref) {
63
65
  // Computing mockMode based on the publicKey prefix
64
66
  const mockMode = (0, react_1.useMemo)(() => {
65
- var _a;
66
- const resolvedMockMode = (_a = publicKey === null || publicKey === void 0 ? void 0 : publicKey.toLowerCase().startsWith("test_")) !== null && _a !== void 0 ? _a : false;
67
+ const resolvedMockMode = (0, validation_1.isMockModeKey)(publicKey);
67
68
  if (devMode) {
68
69
  console.log(`[Glomo-RN-SDK LRS] ${resolvedMockMode ? "Using" : "Not using"} Mock mode for publicKey: ${publicKey}`);
69
70
  }
70
71
  return resolvedMockMode;
71
72
  }, [publicKey, devMode]);
72
- const { start, status, showCheckout, flowWebViewUrl, showFlowWebView, educationCarouselUrl: resolvedEducationCarouselUrl, educationCarouselState, checkoutUrl, mainWebViewRef, flowWebViewRef, educationCarouselWebViewRef, handleMainWebViewMessage, handleFlowWebViewMessage, handleEducationCarouselWebViewMessage, handleError, handleHttpError, handleNavigationStateChange, handleModalBackButton, handleFlowBack, injectedMain, injectedFlow, injectedEducationCarousel, } = (0, use_lrs_checkout_1.useLrsCheckout)({
73
+ const { start, status, showCheckout, flowWebViewUrl, showFlowWebView, educationCarouselUrl: resolvedEducationCarouselUrl, educationCarouselState, checkoutUrl, mainWebViewRef, flowWebViewRef, educationCarouselWebViewRef, handleMainWebViewMessage, handleFlowWebViewMessage, handleEducationCarouselWebViewMessage, handleError, handleHttpError, handleNavigationStateChange, handleModalBackButton, handleFlowBack, handlePermissionRequest, injectedMain, injectedFlow, injectedEducationCarousel, } = (0, use_lrs_checkout_1.useLrsCheckout)({
73
74
  server,
74
75
  publicKey,
75
76
  orderId,
@@ -78,8 +79,9 @@ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSucces
78
79
  onConnectionError,
79
80
  onPaymentTerminate,
80
81
  onSdkError,
82
+ onUserRefusedDevicePermissions,
81
83
  devMode,
82
- }, mockMode);
84
+ }, mockMode, { _testInjectionScript, _testCarouselInjectionScript, _onEducationCarouselStateChange });
83
85
  // Exposing the start() and getStatus() methods via the ref
84
86
  (0, react_1.useImperativeHandle)(ref, () => ({
85
87
  start,
@@ -129,11 +131,19 @@ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSucces
129
131
  * textZoom=100 on Android normalises the system font-size setting so the carousel isn't affected.
130
132
  */
131
133
  const carouselWebViewProps = (0, react_1.useMemo)(() => ({
134
+ /**
135
+ * The carousel renders our own content, which never asks for a device permission.
136
+ * Capabilities are advertised only where something can exercise them, so it opts out
137
+ * of the handler the other two WebViews share.
138
+ */
139
+ onPermissionRequest: undefined,
132
140
  setSupportZoom: false,
133
141
  scalesPageToFit: false,
134
142
  overScrollMode: "never",
135
143
  textZoom: react_native_1.Platform.OS === "android" ? 100 : undefined,
136
144
  }), []);
145
+ // Configuration shared by every WebView the SDK renders, regardless of flow
146
+ const capabilityProps = (0, react_1.useMemo)(() => (0, capability_props_1.buildCapabilityProps)({ devMode, onPermissionRequest: handlePermissionRequest }), [devMode, handlePermissionRequest]);
137
147
  // Making the WebView component
138
148
  const makeWebView = react_1.default.useCallback((ref, url, messageHandler, identifier, injectedJavaScript, injectedJavaScriptBeforeContentLoaded, additionalProps) => {
139
149
  // Preventing a render if no injection script is provided
@@ -157,7 +167,7 @@ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSucces
157
167
  }
158
168
  return null;
159
169
  }
160
- return (<react_native_webview_1.WebView ref={ref} webviewDebuggingEnabled={__DEV__ && devMode} javaScriptEnabled={true} domStorageEnabled={true} onMessage={messageHandler} onError={handleError} onHttpError={handleHttpError} onNavigationStateChange={handleNavigationStateChange} onLoadStart={() => {
170
+ return (<react_native_webview_1.WebView {...capabilityProps} ref={ref} onMessage={messageHandler} onError={handleError} onHttpError={handleHttpError} onNavigationStateChange={handleNavigationStateChange} onLoadStart={() => {
161
171
  if (devMode) {
162
172
  console.log(`[Glomo-RN-SDK LRS] [${identifier}] WebView load started for ${url}`);
163
173
  }
@@ -172,8 +182,15 @@ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSucces
172
182
  if (devMode && identifier === "educationCarousel") {
173
183
  console.log(`[Glomo-RN-SDK LRS] [educationCarousel] load progress=${nativeEvent.progress} url=${nativeEvent.url}`);
174
184
  }
175
- }} source={{ uri: url }} javaScriptCanOpenWindowsAutomatically={true} setSupportMultipleWindows={true} incognito={true} cacheEnabled={false} cacheMode='LOAD_NO_CACHE' pullToRefreshEnabled={false} limitsNavigationsToAppBoundDomains={false} menuItems={[]} injectedJavaScript={injectedJavaScript} injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded} style={styles.webview} showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} mixedContentMode='always' thirdPartyCookiesEnabled={true} sharedCookiesEnabled={true} allowsInlineMediaPlayback={true} mediaPlaybackRequiresUserAction={false} {...additionalProps}/>);
176
- }, [handleError, handleHttpError, handleNavigationStateChange, devMode, carouselViewportGuardScript]);
185
+ }} source={{ uri: url }} injectedJavaScript={injectedJavaScript} injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded} style={styles.webview} {...additionalProps}/>);
186
+ }, [
187
+ handleError,
188
+ handleHttpError,
189
+ handleNavigationStateChange,
190
+ devMode,
191
+ carouselViewportGuardScript,
192
+ capabilityProps,
193
+ ]);
177
194
  const MainWebViewComponent = (0, react_1.useMemo)(() => makeWebView(mainWebViewRef, checkoutUrl, handleMainWebViewMessage, "main", injectedMain), [makeWebView, checkoutUrl, handleMainWebViewMessage, injectedMain, mainWebViewRef]);
178
195
  const FlowWebViewComponent = (0, react_1.useMemo)(() => flowWebViewUrl
179
196
  ? makeWebView(flowWebViewRef, flowWebViewUrl, handleFlowWebViewMessage, "flow", injectedFlow)
@@ -218,7 +235,7 @@ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSucces
218
235
 
219
236
  {shouldRenderFlowOverlay && (<react_native_1.View style={styles.flowWebViewContainer}>
220
237
  <react_native_1.SafeAreaView style={styles.flowHeader}>
221
- <react_native_1.TouchableOpacity onPress={handleFlowBack} style={styles.flowBackButton}>
238
+ <react_native_1.TouchableOpacity onPress={handleFlowBack} style={styles.flowBackButton} accessibilityRole='button' accessibilityLabel='Go back to checkout'>
222
239
  <react_native_1.Text style={styles.flowBackChevron}>‹</react_native_1.Text>
223
240
  </react_native_1.TouchableOpacity>
224
241
  </react_native_1.SafeAreaView>
@@ -273,8 +290,14 @@ const styles = react_native_1.StyleSheet.create({
273
290
  borderBottomColor: "#e0e0e0",
274
291
  },
275
292
  flowBackButton: {
276
- paddingVertical: 0,
293
+ /**
294
+ * Sized to the 44dp / 44pt minimum touch target both platforms specify. The glyph alone is
295
+ * 42px tall and the hit area used to hug it horizontally, which is the only SDK-drawn
296
+ * control in this package and the one a user reaches mid-payment.
297
+ */
298
+ paddingVertical: 6,
277
299
  paddingLeft: 20,
300
+ paddingRight: 20,
278
301
  },
279
302
  flowBackChevron: {
280
303
  fontSize: 42,
@@ -1,7 +1,7 @@
1
1
  /** The GlomoPay Standard Checkout Component */
2
2
  import React from "react";
3
3
  import { type GlomoStandardCheckoutRef, type GlomoStandardCheckoutProps } from "./types/standard-checkout";
4
- import { type CheckoutAnalyticsTrackers } from "./utils/analytics";
4
+ import { type CheckoutAnalyticsTrackers, type FlowType } from "./utils/analytics";
5
5
  /**
6
6
  * Internal-only props for GlomoStandardCheckout.
7
7
  * Used by GlomoSubscriptionsCheckout to inject subscription analytics trackers.
@@ -9,7 +9,10 @@ import { type CheckoutAnalyticsTrackers } from "./utils/analytics";
9
9
  */
10
10
  export interface GlomoStandardCheckoutInternalProps extends GlomoStandardCheckoutProps {
11
11
  _analyticsTrackers?: CheckoutAnalyticsTrackers;
12
+ /** Names the flow for telemetry the tracker map does not cover - see UseStandardCheckoutInternalOptions */
13
+ _flowType?: FlowType;
12
14
  _skipOrderIdValidation?: boolean;
15
+ _testInjectionScript?: string;
13
16
  }
14
17
  /**
15
18
  * Widening the internal type to GlomoStandardCheckoutInternalProps for internal SDK use,
@@ -1 +1 @@
1
- {"version":3,"file":"glomo-standard-checkout.d.ts","sourceRoot":"","sources":["../src/glomo-standard-checkout.tsx"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,OAAO,KAAmD,MAAM,OAAO,CAAC;AAKxE,OAAO,EAAE,KAAK,wBAAwB,EAAE,KAAK,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAC3G,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAGnE;;;;GAIG;AACH,MAAM,WAAW,kCAAmC,SAAQ,0BAA0B;IAClF,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;IAC/C,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACpC;AA+PD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAiD,KAAK,CAAC,yBAAyB,CAC9G,0BAA0B,GAAG,KAAK,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAC7E,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,qHAEzC,CAAC"}
1
+ {"version":3,"file":"glomo-standard-checkout.d.ts","sourceRoot":"","sources":["../src/glomo-standard-checkout.tsx"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,OAAO,KAAmD,MAAM,OAAO,CAAC;AAKxE,OAAO,EAAE,KAAK,wBAAwB,EAAE,KAAK,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAC3G,OAAO,EAAE,KAAK,yBAAyB,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAIlF;;;;GAIG;AACH,MAAM,WAAW,kCAAmC,SAAQ,0BAA0B;IAClF,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;IAE/C,2GAA2G;IAC3G,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACjC;AAmPD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAiD,KAAK,CAAC,yBAAyB,CAC9G,0BAA0B,GAAG,KAAK,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAC7E,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,qHAEzC,CAAC"}
@@ -40,6 +40,7 @@ const react_native_1 = require("react-native");
40
40
  const react_native_webview_1 = require("react-native-webview");
41
41
  const use_standard_checkout_1 = require("./use-standard-checkout");
42
42
  const validation_1 = require("./utils/validation");
43
+ const capability_props_1 = require("./webview/capability-props");
43
44
  /**
44
45
  * The Main GlomoPay Standard Checkout Component
45
46
  *
@@ -49,7 +50,9 @@ const validation_1 = require("./utils/validation");
49
50
  *
50
51
  * @param onPaymentSuccess - The success callback with payload, for a successful payment
51
52
  * @param onPaymentFailure - The failure callback with payload, for a failed payment
52
- * @param onPaymentTerminate - Optional callback called when the checkout is terminated either from the webpage (back button or close button) or mobile component (user dismissing the modal on iOS or user pressing the back button on Android)
53
+ * @param onUserJourneyCompleted - Optional callback for asynchronous payment journeys - bank transfers and pay via bank. Carries the journey type and the transfer details the page reported, not a confirmed payment. LRS/Cards flows will never trigger this.
54
+ * @param onPaymentTerminate - Optional callback called when the checkout ends without a payment outcome. Receives a payload whose `source` is a TERMINATION_SOURCES value naming how it ended: the page's own close control, the Android back button/gesture, or an iOS swipe-down on the modal. The back chevron over a bank flow is deliberately not a termination - it returns the user to the checkout with the session intact.
55
+ * @param onUserRefusedDevicePermissions - Optional callback invoked when the user refuses a device permission the bank's page asked for - camera today. Upload-related permissions are requested by react-native-webview itself and do not reach this callback. Currently Android only: due to platform limitations on iOS, the WebView raises its own prompt and never reports the answer back, so this cannot fire there.
53
56
  *
54
57
  * @param onConnectionError - Optional callback for connection/network errors
55
58
  * @param onSdkError - Optional callback for handling SDK validation errors and configuration issues
@@ -57,11 +60,10 @@ const validation_1 = require("./utils/validation");
57
60
  * @param ref - The ref for the component
58
61
  * @param devMode - Turn on to see all logs, warnings, and errors in the console. Off by default
59
62
  */
60
- function GlomoStandardCheckoutComponent({ server, publicKey, orderId, onPaymentSuccess, onPaymentFailure, onConnectionError, onPaymentTerminate, onSdkError, onUserJourneyCompleted, onUserRefusedCameraPermissions, devMode = false, _analyticsTrackers, _skipOrderIdValidation, }, ref) {
63
+ function GlomoStandardCheckoutComponent({ server, publicKey, orderId, onPaymentSuccess, onPaymentFailure, onConnectionError, onPaymentTerminate, onSdkError, onUserJourneyCompleted, onUserRefusedDevicePermissions, devMode = false, _analyticsTrackers, _flowType, _skipOrderIdValidation, _testInjectionScript, }, ref) {
61
64
  // Computing mockMode based on the publicKey prefix
62
65
  const mockMode = (0, react_1.useMemo)(() => {
63
- var _a;
64
- const resolvedMockMode = (_a = publicKey === null || publicKey === void 0 ? void 0 : publicKey.toLowerCase().startsWith("test_")) !== null && _a !== void 0 ? _a : false;
66
+ const resolvedMockMode = (0, validation_1.isMockModeKey)(publicKey);
65
67
  if (devMode) {
66
68
  console.log(`[Glomo-RN-SDK Standard] ${resolvedMockMode ? "Using" : "Not using"} Mock mode for publicKey: ${publicKey}`);
67
69
  }
@@ -77,14 +79,16 @@ function GlomoStandardCheckoutComponent({ server, publicKey, orderId, onPaymentS
77
79
  onPaymentTerminate,
78
80
  onSdkError,
79
81
  onUserJourneyCompleted,
80
- onUserRefusedCameraPermissions,
82
+ onUserRefusedDevicePermissions,
81
83
  devMode,
82
- }, mockMode, { analyticsTrackers: _analyticsTrackers, _skipOrderIdValidation });
84
+ }, mockMode, { analyticsTrackers: _analyticsTrackers, flowType: _flowType, _skipOrderIdValidation, _testInjectionScript });
83
85
  // Exposing the start() and getStatus() methods via the ref
84
86
  (0, react_1.useImperativeHandle)(ref, () => ({
85
87
  start,
86
88
  getStatus: () => status,
87
89
  }));
90
+ // Configuration shared by every WebView the SDK renders, regardless of flow
91
+ const capabilityProps = (0, react_1.useMemo)(() => (0, capability_props_1.buildCapabilityProps)({ devMode, onPermissionRequest: handlePermissionRequest }), [devMode, handlePermissionRequest]);
88
92
  // Making the WebView component
89
93
  const makeWebView = react_1.default.useCallback((ref, url, messageHandler, identifier, injectedJavaScript, injectedJavaScriptBeforeContentLoaded, additionalProps) => {
90
94
  // Preventing a render if no injection script is provided
@@ -108,7 +112,7 @@ function GlomoStandardCheckoutComponent({ server, publicKey, orderId, onPaymentS
108
112
  }
109
113
  return null;
110
114
  }
111
- return (<react_native_webview_1.WebView ref={ref} webviewDebuggingEnabled={__DEV__ && devMode} javaScriptEnabled={true} domStorageEnabled={true} onMessage={messageHandler} onError={handleError} onHttpError={handleHttpError} onNavigationStateChange={handleNavigationStateChange} onLoadStart={() => {
115
+ return (<react_native_webview_1.WebView {...capabilityProps} ref={ref} onMessage={messageHandler} onError={handleError} onHttpError={handleHttpError} onNavigationStateChange={handleNavigationStateChange} onLoadStart={() => {
112
116
  if (devMode) {
113
117
  console.log(`[Glomo-RN-SDK Standard] [${identifier}] WebView load started for ${url}`);
114
118
  }
@@ -116,10 +120,8 @@ function GlomoStandardCheckoutComponent({ server, publicKey, orderId, onPaymentS
116
120
  if (devMode) {
117
121
  console.log(`[Glomo-RN-SDK Standard] [${identifier}] WebView load ended for ${url}`);
118
122
  }
119
- }} source={{ uri: url }} javaScriptCanOpenWindowsAutomatically={true} setSupportMultipleWindows={true} incognito={true} cacheEnabled={false} cacheMode='LOAD_NO_CACHE' pullToRefreshEnabled={false} limitsNavigationsToAppBoundDomains={false} menuItems={[]} injectedJavaScript={injectedJavaScript} injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded} style={styles.webview} showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} mixedContentMode='always' thirdPartyCookiesEnabled={true} sharedCookiesEnabled={true} allowsInlineMediaPlayback={true} mediaPlaybackRequiresUserAction={false} mediaCapturePermissionGrantType='prompt' allowFileAccess={true} allowUniversalAccessFromFileURLs={true} allowFileAccessFromFileURLs={true} androidLayerType='hardware'
120
- // @ts-expect-error onPermissionRequest is an Android-only WebView prop not yet in react-native-webview type definitions
121
- onPermissionRequest={handlePermissionRequest} {...additionalProps}/>);
122
- }, [handleError, handleHttpError, handleNavigationStateChange, handlePermissionRequest, devMode]);
123
+ }} source={{ uri: url }} injectedJavaScript={injectedJavaScript} injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded} style={styles.webview} {...additionalProps}/>);
124
+ }, [handleError, handleHttpError, handleNavigationStateChange, capabilityProps, devMode]);
123
125
  const MainWebViewComponent = (0, react_1.useMemo)(() => makeWebView(mainWebViewRef, checkoutUrl, handleMainWebViewMessage, "main", injectedMain), [makeWebView, checkoutUrl, handleMainWebViewMessage, injectedMain, mainWebViewRef]);
124
126
  const FlowWebViewComponent = (0, react_1.useMemo)(() => flowWebViewUrl
125
127
  ? makeWebView(flowWebViewRef, flowWebViewUrl, handleFlowWebViewMessage, "flow", injectedFlow)
@@ -149,7 +151,7 @@ function GlomoStandardCheckoutComponent({ server, publicKey, orderId, onPaymentS
149
151
 
150
152
  {shouldRenderFlowOverlay && (<react_native_1.View style={styles.flowWebViewContainer}>
151
153
  <react_native_1.SafeAreaView style={styles.flowHeader}>
152
- <react_native_1.TouchableOpacity onPress={handleFlowBack} style={styles.flowBackButton}>
154
+ <react_native_1.TouchableOpacity onPress={handleFlowBack} style={styles.flowBackButton} accessibilityRole='button' accessibilityLabel='Go back to checkout'>
153
155
  <react_native_1.Text style={styles.flowBackChevron}>{"\u2039"}</react_native_1.Text>
154
156
  </react_native_1.TouchableOpacity>
155
157
  </react_native_1.SafeAreaView>
@@ -200,8 +202,14 @@ const styles = react_native_1.StyleSheet.create({
200
202
  borderBottomColor: "#e0e0e0",
201
203
  },
202
204
  flowBackButton: {
203
- paddingVertical: 0,
205
+ /**
206
+ * Sized to the 44dp / 44pt minimum touch target both platforms specify. The glyph alone is
207
+ * 42px tall and the hit area used to hug it horizontally, which is the only SDK-drawn
208
+ * control in this package and the one a user reaches mid-payment.
209
+ */
210
+ paddingVertical: 6,
204
211
  paddingLeft: 20,
212
+ paddingRight: 20,
205
213
  },
206
214
  flowBackChevron: {
207
215
  fontSize: 42,
@@ -1 +1 @@
1
- {"version":3,"file":"glomo-subscriptions-checkout.d.ts","sourceRoot":"","sources":["../src/glomo-subscriptions-checkout.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA6D,MAAM,OAAO,CAAC;AAIlF,OAAO,EACH,KAAK,+BAA+B,EACpC,KAAK,6BAA6B,EACrC,MAAM,gCAAgC,CAAC;AAkExC,eAAO,MAAM,0BAA0B,uHAEtC,CAAC"}
1
+ {"version":3,"file":"glomo-subscriptions-checkout.d.ts","sourceRoot":"","sources":["../src/glomo-subscriptions-checkout.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA6D,MAAM,OAAO,CAAC;AAIlF,OAAO,EACH,KAAK,+BAA+B,EACpC,KAAK,6BAA6B,EACrC,MAAM,gCAAgC,CAAC;AAmExC,eAAO,MAAM,0BAA0B,uHAEtC,CAAC"}
@@ -79,7 +79,7 @@ function GlomoSubscriptionsCheckoutComponent(props, ref) {
79
79
  if (validationError) {
80
80
  return null;
81
81
  }
82
- return (<glomo_standard_checkout_1.GlomoStandardCheckoutInternal ref={innerRef} {...rest} orderId={subscriptionId} onSdkError={onSdkError} devMode={devMode} _analyticsTrackers={analytics_1.subscriptionCheckoutTrackers} _skipOrderIdValidation={true}/>);
82
+ return (<glomo_standard_checkout_1.GlomoStandardCheckoutInternal ref={innerRef} {...rest} orderId={subscriptionId} onSdkError={onSdkError} devMode={devMode} _analyticsTrackers={analytics_1.subscriptionCheckoutTrackers} _flowType='subscriptions' _skipOrderIdValidation={true}/>);
83
83
  }
84
84
  exports.GlomoSubscriptionsCheckout = (0, react_1.forwardRef)(GlomoSubscriptionsCheckoutComponent);
85
85
  exports.GlomoSubscriptionsCheckout.displayName = "GlomoSubscriptionsCheckout";
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- /** The GlomoPay RN SDK v4 exports */
1
+ /** The GlomoPay RN SDK v5 exports */
2
2
  export { GlomoCheckout } from "./glomo-checkout";
3
- export { type GlomoCheckoutRef, type GlomoCheckoutProps, type GlomoCheckoutPayload, type CheckoutStatus, type GlomoUserJourneyCompletedPayload, ASYNC_PAYMENT_EVENTS, } from "./types/checkout";
3
+ export { type GlomoCheckoutRef, type GlomoCheckoutProps, type GlomoCheckoutPayload, type CheckoutStatus, type GlomoUserJourneyCompletedPayload, type GlomoTerminationPayload, ASYNC_PAYMENT_EVENTS, TERMINATION_SOURCES, } from "./types/checkout";
4
4
  export { type GlomoServer } from "./config/base";
5
5
  export { type SdkError } from "./utils/analytics";
6
6
  export { useGlomoCheckout, type UseGlomoCheckoutReturn } from "./use-glomo-checkout";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAGrC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EACH,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,gCAAgC,EACrC,oBAAoB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAGrC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EACH,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,gCAAgC,EACrC,KAAK,uBAAuB,EAC5B,oBAAoB,EACpB,mBAAmB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC"}
package/lib/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
- /** The GlomoPay RN SDK v4 exports */
2
+ /** The GlomoPay RN SDK v5 exports */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.useGlomoCheckout = exports.ASYNC_PAYMENT_EVENTS = exports.GlomoCheckout = void 0;
5
- // v4 public API - unified checkout
4
+ exports.useGlomoCheckout = exports.TERMINATION_SOURCES = exports.ASYNC_PAYMENT_EVENTS = exports.GlomoCheckout = void 0;
5
+ // v5 public API - unified checkout
6
6
  var glomo_checkout_1 = require("./glomo-checkout");
7
7
  Object.defineProperty(exports, "GlomoCheckout", { enumerable: true, get: function () { return glomo_checkout_1.GlomoCheckout; } });
8
8
  var checkout_1 = require("./types/checkout");
9
9
  Object.defineProperty(exports, "ASYNC_PAYMENT_EVENTS", { enumerable: true, get: function () { return checkout_1.ASYNC_PAYMENT_EVENTS; } });
10
+ Object.defineProperty(exports, "TERMINATION_SOURCES", { enumerable: true, get: function () { return checkout_1.TERMINATION_SOURCES; } });
10
11
  var use_glomo_checkout_1 = require("./use-glomo-checkout");
11
12
  Object.defineProperty(exports, "useGlomoCheckout", { enumerable: true, get: function () { return use_glomo_checkout_1.useGlomoCheckout; } });
@@ -1,3 +1,27 @@
1
+ /**
2
+ * Publishes what this SDK build can handle, for the checkout page to gate on.
3
+ *
4
+ * Appends rather than assigns, and de-duplicates, because the array is shared with anything else
5
+ * that writes to it. The page reads it at the moment it needs a capability rather than snapshotting
6
+ * it at load, so a script that runs after the page has mounted still takes effect.
7
+ *
8
+ * Returns an empty string when there is nothing to advertise - the page treats a missing array and
9
+ * an empty one the same way, so there is no reason to inject the assignment.
10
+ */
11
+ export declare function buildCapabilityAdvertisement(capabilities: string[]): string;
12
+ /**
13
+ * The scripts injected into each WebView, for a build with the given capabilities.
14
+ *
15
+ * Capabilities are advertised on the WebViews that load a checkout or a bank page, and not on the
16
+ * education carousel - that renders our own content, which has nothing to gate. Advertising a
17
+ * capability where nothing can exercise it is noise on a contract the page reads.
18
+ */
19
+ export declare function buildInjectionScripts(capabilities: string[]): {
20
+ main: string;
21
+ flow: string;
22
+ standard: string;
23
+ educationCarousel: string;
24
+ };
1
25
  export declare const InjectionScripts: {
2
26
  main: string;
3
27
  flow: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/injections/index.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,gBAAgB;;;;;CAK5B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/injections/index.ts"],"names":[],"mappings":"AAQA;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,CAa3E;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE;;;;;EAS3D;AAED,eAAO,MAAM,gBAAgB;;;;;CAK5B,CAAC"}
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InjectionScripts = void 0;
4
+ exports.buildCapabilityAdvertisement = buildCapabilityAdvertisement;
5
+ exports.buildInjectionScripts = buildInjectionScripts;
4
6
  /**
5
7
  * Injection scripts for WebView bridging
6
8
  */
@@ -8,6 +10,45 @@ const webview_main_injection_1 = require("./webview-main.injection");
8
10
  const webview_flow_injection_1 = require("./webview-flow.injection");
9
11
  const webview_education_carousel_injection_1 = require("./webview-education-carousel.injection");
10
12
  const webview_standard_injection_1 = require("./webview-standard.injection");
13
+ /**
14
+ * Publishes what this SDK build can handle, for the checkout page to gate on.
15
+ *
16
+ * Appends rather than assigns, and de-duplicates, because the array is shared with anything else
17
+ * that writes to it. The page reads it at the moment it needs a capability rather than snapshotting
18
+ * it at load, so a script that runs after the page has mounted still takes effect.
19
+ *
20
+ * Returns an empty string when there is nothing to advertise - the page treats a missing array and
21
+ * an empty one the same way, so there is no reason to inject the assignment.
22
+ */
23
+ function buildCapabilityAdvertisement(capabilities) {
24
+ if (capabilities.length === 0) {
25
+ return "";
26
+ }
27
+ return `
28
+ (function() {
29
+ window.__glomoSdkCapabilities__ = (window.__glomoSdkCapabilities__ || [])
30
+ .concat(${JSON.stringify(capabilities)})
31
+ .filter(function(cap, i, all) { return all.indexOf(cap) === i; });
32
+ })();
33
+ true;
34
+ `;
35
+ }
36
+ /**
37
+ * The scripts injected into each WebView, for a build with the given capabilities.
38
+ *
39
+ * Capabilities are advertised on the WebViews that load a checkout or a bank page, and not on the
40
+ * education carousel - that renders our own content, which has nothing to gate. Advertising a
41
+ * capability where nothing can exercise it is noise on a contract the page reads.
42
+ */
43
+ function buildInjectionScripts(capabilities) {
44
+ const advertisement = buildCapabilityAdvertisement(capabilities);
45
+ return {
46
+ main: webview_main_injection_1.injectedScript + advertisement,
47
+ flow: webview_flow_injection_1.injectedScript + advertisement,
48
+ standard: webview_standard_injection_1.injectedScript + advertisement,
49
+ educationCarousel: webview_education_carousel_injection_1.injectedScript,
50
+ };
51
+ }
11
52
  exports.InjectionScripts = {
12
53
  main: webview_main_injection_1.injectedScript,
13
54
  flow: webview_flow_injection_1.injectedScript,
@@ -1 +1 @@
1
- {"version":3,"file":"webview-flow.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-flow.injection.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,eAAO,MAAM,cAAc,EAAE,MAiN5B,CAAC"}
1
+ {"version":3,"file":"webview-flow.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-flow.injection.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,eAAO,MAAM,cAAc,EAAE,MA6R5B,CAAC"}
@@ -206,6 +206,82 @@ exports.injectedScript = `
206
206
  });
207
207
  });
208
208
 
209
+
210
+ /**
211
+ * File-input click detection.
212
+ *
213
+ * Does not open the picker - react-native-webview does that natively through
214
+ * onShowFileChooser, and the SDK never sees the rest of it. This carries the only record
215
+ * that an upload was attempted, and on iOS it is the only file signal at all, since
216
+ * WKWebView runs its own picker and reports nothing back.
217
+ *
218
+ * Capture phase, so a page that stops propagation on its own handler cannot silence it.
219
+ *
220
+ * Posts the shape of the input and nothing that identifies it. The id and name of a KYC
221
+ * upload control are third-party identity, and unconsumed page data sitting on the bridge is
222
+ * how identity ends up spread into a tracker by someone who never read this.
223
+ */
224
+ document.addEventListener('click', function(event) {
225
+ try {
226
+ const target = event.target;
227
+ if (!target || target.tagName !== 'INPUT' || target.type !== 'file') {
228
+ return;
229
+ }
230
+ safePostMessage({
231
+ type: 'file.input',
232
+ accept: target.getAttribute('accept') || '',
233
+ hasCapture: target.hasAttribute('capture')
234
+ });
235
+ } catch (error) {
236
+ // Never let this break a bank's own upload handling
237
+ }
238
+ }, true);
239
+
240
+
241
+ /**
242
+ * getUserMedia observation.
243
+ *
244
+ * Telemetry only, and it must stay that way. A rejection with NotAllowedError IS the user
245
+ * denying camera access - an observation, not an inference - and on iOS it is the only one
246
+ * available, because WKWebView raises its own prompt and never reports the answer back.
247
+ *
248
+ * It deliberately does NOT drive onUserRefusedDevicePermissions. Coverage depends on whether
249
+ * a given bank uses getUserMedia or a capture-enabled file input, which is third-party
250
+ * markup we do not control and are not told about when it changes. A callback that fires for
251
+ * some banks would leave a merchant unable to tell "the user did not deny" from "this bank's
252
+ * flow is not observable". Silence is unambiguous; partial coverage is not.
253
+ *
254
+ * Wrapped thinly and never allowed to throw: this runs inside a bank's page, and a fault in
255
+ * our handler must not be able to break their capture flow.
256
+ */
257
+ (function() {
258
+ try {
259
+ const media = navigator.mediaDevices;
260
+ if (!media || typeof media.getUserMedia !== 'function') {
261
+ return;
262
+ }
263
+ const originalGetUserMedia = media.getUserMedia.bind(media);
264
+ media.getUserMedia = function(constraints) {
265
+ return originalGetUserMedia(constraints).catch(function(error) {
266
+ try {
267
+ if (error && error.name === 'NotAllowedError') {
268
+ safePostMessage({
269
+ type: 'permission.denied',
270
+ resource: (constraints && constraints.video) ? 'camera' : 'microphone',
271
+ errorName: error.name
272
+ });
273
+ }
274
+ } catch (reportingError) {
275
+ // Reporting must never change what the page sees
276
+ }
277
+ throw error;
278
+ });
279
+ };
280
+ } catch (error) {
281
+ // A page that has frozen navigator.mediaDevices keeps working, unobserved
282
+ }
283
+ })();
284
+
209
285
  // Logging that injection is complete
210
286
  console.log(LOG_PREFIX + 'GlomoPay WebView JavaScript injection complete');
211
287
 
@@ -1 +1 @@
1
- {"version":3,"file":"webview-main.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-main.injection.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,eAAO,MAAM,cAAc,EAAE,MAuN5B,CAAC"}
1
+ {"version":3,"file":"webview-main.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-main.injection.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,eAAO,MAAM,cAAc,EAAE,MAsP5B,CAAC"}
@@ -212,6 +212,37 @@ exports.injectedScript = `
212
212
  });
213
213
  });
214
214
 
215
+
216
+ /**
217
+ * File-input click detection.
218
+ *
219
+ * Does not open the picker - react-native-webview does that natively through
220
+ * onShowFileChooser, and the SDK never sees the rest of it. This carries the only record
221
+ * that an upload was attempted, and on iOS it is the only file signal at all, since
222
+ * WKWebView runs its own picker and reports nothing back.
223
+ *
224
+ * Capture phase, so a page that stops propagation on its own handler cannot silence it.
225
+ *
226
+ * Posts the shape of the input and nothing that identifies it. The id and name of a KYC
227
+ * upload control are third-party identity, and unconsumed page data sitting on the bridge is
228
+ * how identity ends up spread into a tracker by someone who never read this.
229
+ */
230
+ document.addEventListener('click', function(event) {
231
+ try {
232
+ const target = event.target;
233
+ if (!target || target.tagName !== 'INPUT' || target.type !== 'file') {
234
+ return;
235
+ }
236
+ safePostMessage({
237
+ type: 'file.input',
238
+ accept: target.getAttribute('accept') || '',
239
+ hasCapture: target.hasAttribute('capture')
240
+ });
241
+ } catch (error) {
242
+ // Never let this break a bank's own upload handling
243
+ }
244
+ }, true);
245
+
215
246
  // Logging that injection is complete
216
247
  console.log(LOG_PREFIX + 'GlomoPay WebView JavaScript injection complete');
217
248
 
@@ -1 +1 @@
1
- {"version":3,"file":"webview-standard.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-standard.injection.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,eAAO,MAAM,cAAc,EAAE,MAiN5B,CAAC"}
1
+ {"version":3,"file":"webview-standard.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-standard.injection.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,eAAO,MAAM,cAAc,EAAE,MAgP5B,CAAC"}