@glomopay/react-native-sdk 4.1.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.
- package/CHANGELOG.md +29 -0
- package/MIGRATION.md +112 -0
- package/README.md +173 -36
- package/lib/bridge/file-input-handler.d.ts +25 -0
- package/lib/bridge/file-input-handler.d.ts.map +1 -0
- package/lib/bridge/file-input-handler.js +38 -0
- package/lib/bridge/file-save-handler.d.ts +32 -0
- package/lib/bridge/file-save-handler.d.ts.map +1 -0
- package/lib/bridge/file-save-handler.js +92 -0
- package/lib/bridge/message-router.d.ts +44 -0
- package/lib/bridge/message-router.d.ts.map +1 -0
- package/lib/bridge/message-router.js +48 -0
- package/lib/bridge/payment-payload.d.ts +18 -0
- package/lib/bridge/payment-payload.d.ts.map +1 -0
- package/lib/bridge/payment-payload.js +31 -0
- package/lib/capabilities/file-save.d.ts +40 -0
- package/lib/capabilities/file-save.d.ts.map +1 -0
- package/lib/capabilities/file-save.js +101 -0
- package/lib/capabilities/index.d.ts +22 -0
- package/lib/capabilities/index.d.ts.map +1 -0
- package/lib/capabilities/index.js +34 -0
- package/lib/capabilities/use-capability-reporting.d.ts +24 -0
- package/lib/capabilities/use-capability-reporting.d.ts.map +1 -0
- package/lib/capabilities/use-capability-reporting.js +44 -0
- package/lib/config/base.d.ts +12 -0
- package/lib/config/base.d.ts.map +1 -1
- package/lib/config/base.js +13 -1
- package/lib/glomo-checkout.d.ts +6 -1
- package/lib/glomo-checkout.d.ts.map +1 -1
- package/lib/glomo-checkout.js +11 -5
- package/lib/glomo-lrs-checkout.d.ts.map +1 -1
- package/lib/glomo-lrs-checkout.js +33 -10
- package/lib/glomo-standard-checkout.d.ts +3 -1
- package/lib/glomo-standard-checkout.d.ts.map +1 -1
- package/lib/glomo-standard-checkout.js +21 -13
- package/lib/glomo-subscriptions-checkout.d.ts.map +1 -1
- package/lib/glomo-subscriptions-checkout.js +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -3
- package/lib/injections/index.d.ts +24 -0
- package/lib/injections/index.d.ts.map +1 -1
- package/lib/injections/index.js +41 -0
- package/lib/injections/webview-flow.injection.d.ts.map +1 -1
- package/lib/injections/webview-flow.injection.js +76 -0
- package/lib/injections/webview-main.injection.d.ts.map +1 -1
- package/lib/injections/webview-main.injection.js +31 -0
- package/lib/injections/webview-standard.injection.d.ts.map +1 -1
- package/lib/injections/webview-standard.injection.js +31 -0
- package/lib/services/file-saver.d.ts +109 -0
- package/lib/services/file-saver.d.ts.map +1 -0
- package/lib/services/file-saver.js +416 -0
- package/lib/types/checkout.d.ts +58 -6
- package/lib/types/checkout.d.ts.map +1 -1
- package/lib/types/checkout.js +24 -2
- package/lib/types/standard-checkout.d.ts +6 -6
- package/lib/types/standard-checkout.d.ts.map +1 -1
- package/lib/types/subscriptions-checkout.d.ts +3 -3
- package/lib/types/subscriptions-checkout.d.ts.map +1 -1
- package/lib/use-glomo-checkout.js +2 -2
- package/lib/use-lrs-checkout.d.ts +9 -5
- package/lib/use-lrs-checkout.d.ts.map +1 -1
- package/lib/use-lrs-checkout.js +317 -171
- package/lib/use-standard-checkout.d.ts +17 -13
- package/lib/use-standard-checkout.d.ts.map +1 -1
- package/lib/use-standard-checkout.js +281 -207
- package/lib/utils/analytics.d.ts +177 -51
- package/lib/utils/analytics.d.ts.map +1 -1
- package/lib/utils/analytics.js +299 -81
- package/lib/utils/device-compliance.d.ts +57 -12
- package/lib/utils/device-compliance.d.ts.map +1 -1
- package/lib/utils/device-compliance.js +101 -37
- package/lib/utils/event-projections.d.ts +56 -0
- package/lib/utils/event-projections.d.ts.map +1 -0
- package/lib/utils/event-projections.js +42 -0
- package/lib/utils/file-metadata.d.ts +52 -0
- package/lib/utils/file-metadata.d.ts.map +1 -0
- package/lib/utils/file-metadata.js +134 -0
- package/lib/utils/use-sdk-session.d.ts +12 -0
- package/lib/utils/use-sdk-session.d.ts.map +1 -0
- package/lib/utils/use-sdk-session.js +37 -0
- package/lib/utils/validation.d.ts +37 -3
- package/lib/utils/validation.d.ts.map +1 -1
- package/lib/utils/validation.js +64 -8
- package/lib/webview/capability-props.d.ts +27 -0
- package/lib/webview/capability-props.d.ts.map +1 -0
- package/lib/webview/capability-props.js +61 -0
- package/lib/webview/use-permission-request.d.ts +33 -0
- package/lib/webview/use-permission-request.d.ts.map +1 -0
- package/lib/webview/use-permission-request.js +89 -0
- package/package.json +10 -2
- package/src/bridge/file-input-handler.ts +66 -0
- package/src/bridge/file-save-handler.ts +141 -0
- package/src/bridge/message-router.ts +92 -0
- package/src/bridge/payment-payload.ts +31 -0
- package/src/capabilities/file-save.ts +124 -0
- package/src/capabilities/index.ts +34 -0
- package/src/capabilities/use-capability-reporting.ts +55 -0
- package/src/config/base.ts +13 -0
- package/src/glomo-checkout.tsx +11 -7
- package/src/glomo-lrs-checkout.tsx +41 -26
- package/src/glomo-standard-checkout.tsx +31 -34
- package/src/glomo-subscriptions-checkout.tsx +1 -0
- package/src/index.ts +4 -2
- package/src/injections/index.ts +43 -0
- package/src/injections/webview-flow.injection.ts +76 -0
- package/src/injections/webview-main.injection.ts +31 -0
- package/src/injections/webview-standard.injection.ts +31 -0
- package/src/services/file-saver.ts +497 -0
- package/src/types/checkout.ts +62 -6
- package/src/types/standard-checkout.ts +6 -6
- package/src/types/subscriptions-checkout.ts +7 -3
- package/src/use-glomo-checkout.tsx +2 -2
- package/src/use-lrs-checkout.tsx +656 -365
- package/src/use-standard-checkout.tsx +728 -466
- package/src/utils/analytics.ts +422 -117
- package/src/utils/device-compliance.ts +148 -38
- package/src/utils/event-projections.ts +74 -0
- package/src/utils/file-metadata.ts +140 -0
- package/src/utils/use-sdk-session.ts +41 -0
- package/src/utils/validation.ts +70 -10
- package/src/webview/capability-props.ts +86 -0
- package/src/webview/use-permission-request.ts +114 -0
- package/src/jail-monkey.d.ts +0 -19
package/lib/glomo-checkout.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* The unified GlomoPay Checkout Component
|
|
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)(() =>
|
|
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} _testInjectionScript={props._testInjectionScript} _testCarouselInjectionScript={props._testCarouselInjectionScript} _onEducationCarouselStateChange={props._onEducationCarouselStateChange}/>);
|
|
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.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}
|
|
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}
|
|
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
|
|
@@ -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;
|
|
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
|
|
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, _testInjectionScript, _testCarouselInjectionScript, _onEducationCarouselStateChange, }, 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
|
-
|
|
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,6 +79,7 @@ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSucces
|
|
|
78
79
|
onConnectionError,
|
|
79
80
|
onPaymentTerminate,
|
|
80
81
|
onSdkError,
|
|
82
|
+
onUserRefusedDevicePermissions,
|
|
81
83
|
devMode,
|
|
82
84
|
}, mockMode, { _testInjectionScript, _testCarouselInjectionScript, _onEducationCarouselStateChange });
|
|
83
85
|
// Exposing the start() and getStatus() methods via the ref
|
|
@@ -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
|
|
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 }}
|
|
176
|
-
}, [
|
|
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
|
-
|
|
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,6 +9,8 @@ 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;
|
|
13
15
|
_testInjectionScript?: string;
|
|
14
16
|
}
|
|
@@ -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;
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
82
|
+
onUserRefusedDevicePermissions,
|
|
81
83
|
devMode,
|
|
82
|
-
}, mockMode, { analyticsTrackers: _analyticsTrackers, _skipOrderIdValidation, _testInjectionScript });
|
|
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
|
|
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 }}
|
|
120
|
-
|
|
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
|
-
|
|
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;
|
|
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
|
|
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";
|
package/lib/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
-
//
|
|
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"}
|
package/lib/injections/index.js
CHANGED
|
@@ -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,
|
|
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,
|
|
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,
|
|
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"}
|
|
@@ -206,6 +206,37 @@ 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
|
+
|
|
209
240
|
// Logging that injection is complete
|
|
210
241
|
console.log(LOG_PREFIX + 'GlomoPay WebView JavaScript injection complete');
|
|
211
242
|
|